Skip to content

Commit b152ed3

Browse files
committed
refactor: useOrderList & usePickList
1 parent 072ac1e commit b152ed3

29 files changed

Lines changed: 527 additions & 1829 deletions

File tree

apps/showcase/__store__/index.tsx

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,6 +1713,24 @@ export const Store: Record<string, Record<string, Record<string, { component: Re
17131713
'component': React.lazy(() => import('demo/styled/orderlist/drag-drop-demo')),
17141714
'filePath': 'demo/styled/orderlist/drag-drop-demo.tsx',
17151715
},
1716+
'placeholder-demo': {
1717+
'component': React.lazy(() => import('demo/styled/orderlist/placeholder-demo')),
1718+
'filePath': 'demo/styled/orderlist/placeholder-demo.tsx',
1719+
},
1720+
},
1721+
'orderlist2': {
1722+
'basic-demo': {
1723+
'component': React.lazy(() => import('demo/styled/orderlist2/basic-demo')),
1724+
'filePath': 'demo/styled/orderlist2/basic-demo.tsx',
1725+
},
1726+
'filter-demo': {
1727+
'component': React.lazy(() => import('demo/styled/orderlist2/filter-demo')),
1728+
'filePath': 'demo/styled/orderlist2/filter-demo.tsx',
1729+
},
1730+
'multiple-demo': {
1731+
'component': React.lazy(() => import('demo/styled/orderlist2/multiple-demo')),
1732+
'filePath': 'demo/styled/orderlist2/multiple-demo.tsx',
1733+
},
17161734
},
17171735
'orgchart': {
17181736
'basic-demo': {
@@ -1871,14 +1889,36 @@ export const Store: Record<string, Record<string, Record<string, { component: Re
18711889
'component': React.lazy(() => import('demo/styled/picklist/checkbox-demo')),
18721890
'filePath': 'demo/styled/picklist/checkbox-demo.tsx',
18731891
},
1874-
'custom-demo': {
1875-
'component': React.lazy(() => import('demo/styled/picklist/custom-demo')),
1876-
'filePath': 'demo/styled/picklist/custom-demo.tsx',
1877-
},
18781892
'drag-drop-demo': {
18791893
'component': React.lazy(() => import('demo/styled/picklist/drag-drop-demo')),
18801894
'filePath': 'demo/styled/picklist/drag-drop-demo.tsx',
18811895
},
1896+
'placeholder-demo': {
1897+
'component': React.lazy(() => import('demo/styled/picklist/placeholder-demo')),
1898+
'filePath': 'demo/styled/picklist/placeholder-demo.tsx',
1899+
},
1900+
},
1901+
'picklist2': {
1902+
'basic-demo': {
1903+
'component': React.lazy(() => import('demo/styled/picklist2/basic-demo')),
1904+
'filePath': 'demo/styled/picklist2/basic-demo.tsx',
1905+
},
1906+
'checkbox-demo': {
1907+
'component': React.lazy(() => import('demo/styled/picklist2/checkbox-demo')),
1908+
'filePath': 'demo/styled/picklist2/checkbox-demo.tsx',
1909+
},
1910+
'filter-demo': {
1911+
'component': React.lazy(() => import('demo/styled/picklist2/filter-demo')),
1912+
'filePath': 'demo/styled/picklist2/filter-demo.tsx',
1913+
},
1914+
'group-demo': {
1915+
'component': React.lazy(() => import('demo/styled/picklist2/group-demo')),
1916+
'filePath': 'demo/styled/picklist2/group-demo.tsx',
1917+
},
1918+
'multi-orderlist-demo': {
1919+
'component': React.lazy(() => import('demo/styled/picklist2/multi-orderlist-demo')),
1920+
'filePath': 'demo/styled/picklist2/multi-orderlist-demo.tsx',
1921+
},
18821922
},
18831923
'popover': {
18841924
'accessibility-demo': {

apps/showcase/app/(app)/playground/page.tsx

Lines changed: 18 additions & 216 deletions
Large diffs are not rendered by default.

apps/showcase/demo/styled/orderlist/basic-demo.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ const cities = [
1717
{ name: 'Paris', code: 'PRS' }
1818
];
1919

20+
type City = (typeof cities)[0];
21+
2022
export default function BasicDemo() {
2123
const [items, setItems] = useState(cities);
22-
const [selection, setSelection] = useState<string[]>([]);
24+
const [selection, setSelection] = useState<City[]>([]);
2325

2426
const orderList = useOrderList({
2527
value: items,
2628
selection,
27-
dataKey: 'code',
28-
optionValue: 'code',
2929
onReorder: (e: useOrderListReorderEvent) => setItems(e.value as typeof cities)
3030
});
3131

@@ -49,10 +49,9 @@ export default function BasicDemo() {
4949
</div>
5050
<Listbox.Root
5151
value={selection}
52-
onValueChange={(e) => setSelection((e.value as string[]) ?? [])}
52+
onValueChange={(e) => setSelection((e.value as City[]) ?? [])}
5353
options={orderList.state.value as typeof cities}
5454
optionLabel="name"
55-
optionValue="code"
5655
multiple
5756
className="flex-1"
5857
>

apps/showcase/demo/styled/orderlist/checkbox-demo.tsx

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
'use client';
2+
import { Check } from '@primeicons/react';
23
import { AngleDoubleDown } from '@primeicons/react/angle-double-down';
34
import { AngleDoubleUp } from '@primeicons/react/angle-double-up';
45
import { AngleDown } from '@primeicons/react/angle-down';
56
import { AngleUp } from '@primeicons/react/angle-up';
6-
import { Check } from '@primeicons/react';
77
import { useOrderList } from '@primereact/headless/orderlist';
88
import type { useOrderListReorderEvent } from '@primereact/types/shared/orderlist';
99
import { Button } from '@primereact/ui/button';
1010
import { Checkbox } from '@primereact/ui/checkbox';
1111
import { Listbox, type ListboxListInstance } from '@primereact/ui/listbox';
1212
import { cn } from '@primeuix/utils';
13-
import { useState, useRef, useEffect } from 'react';
13+
import { useState } from 'react';
1414

1515
const cities = [
1616
{ name: 'New York', code: 'NY' },
@@ -20,6 +20,8 @@ const cities = [
2020
{ name: 'Paris', code: 'PRS' }
2121
];
2222

23+
type City = (typeof cities)[0];
24+
2325
const optionClassName = cn(
2426
'cursor-grab select-none transition-transform duration-200',
2527
'data-dragging:transition-none data-dragging:fixed data-dragging:z-50 data-dragging:cursor-grabbing data-dragging:shadow-xl data-dragging:pointer-events-none',
@@ -30,25 +32,15 @@ const optionClassName = cn(
3032

3133
export default function CheckboxDemo() {
3234
const [items, setItems] = useState(cities);
33-
const [selection, setSelection] = useState<string[]>([]);
35+
const [selection, setSelection] = useState<City[]>([]);
3436

3537
const orderList = useOrderList({
3638
value: items,
3739
selection,
38-
dataKey: 'code',
39-
optionValue: 'code',
4040
draggable: true,
4141
onReorder: (e: useOrderListReorderEvent) => setItems(e.value as typeof cities)
4242
});
4343

44-
const wrapperRef = useRef<HTMLDivElement>(null);
45-
46-
useEffect(() => {
47-
const ul = wrapperRef.current?.querySelector('[role="listbox"]') as HTMLElement | null;
48-
49-
(orderList.listRef as React.RefObject<HTMLElement | null>).current = ul;
50-
});
51-
5244
return (
5345
<div className="flex justify-center">
5446
<div className="w-full md:w-56">
@@ -67,26 +59,25 @@ export default function CheckboxDemo() {
6759
<AngleDoubleDown />
6860
</Button>
6961
</div>
70-
<div ref={wrapperRef} className="flex-1">
62+
<div className="flex-1">
7163
<Listbox.Root
7264
value={selection}
73-
onValueChange={(e) => setSelection((e.value as string[]) ?? [])}
65+
onValueChange={(e) => setSelection((e.value as City[]) ?? [])}
7466
options={orderList.state.value as typeof cities}
7567
optionLabel="name"
76-
optionValue="code"
7768
multiple
7869
>
79-
<Listbox.List style={{ touchAction: 'none' }}>
70+
<Listbox.List {...orderList.listProps} style={{ touchAction: 'none' }}>
8071
{(instance: ListboxListInstance) => {
8172
const { listbox } = instance;
8273

8374
return orderList.state.value.map((item, index) => {
84-
const city = item as (typeof cities)[0];
75+
const city = item as City;
8576
const selected = listbox?.isSelected(city);
86-
const { onPointerDown } = orderList.getOptionProps(item, index) as { onPointerDown?: React.PointerEventHandler<HTMLElement> };
77+
const optionProps = orderList.getOptionProps(item, index);
8778

8879
return (
89-
<Listbox.Option key={city.code} uKey={city.code} index={index} onPointerDown={onPointerDown} className={cn(optionClassName, 'gap-2')}>
80+
<Listbox.Option key={city.code} uKey={city.code} index={index} {...optionProps} className={cn(optionClassName, 'gap-2')}>
9081
<Checkbox.Root defaultChecked={!!selected} tabIndex={-1} readOnly>
9182
<Checkbox.Box>
9283
<Checkbox.Indicator match="checked">

apps/showcase/demo/styled/orderlist/drag-drop-demo.tsx

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { useOrderListReorderEvent } from '@primereact/types/shared/orderlis
88
import { Button } from '@primereact/ui/button';
99
import { Listbox } from '@primereact/ui/listbox';
1010
import { cn } from '@primeuix/utils';
11-
import { useState, useRef, useEffect } from 'react';
11+
import { useState } from 'react';
1212

1313
const cities = [
1414
{ name: 'New York', code: 'NY' },
@@ -18,6 +18,8 @@ const cities = [
1818
{ name: 'Paris', code: 'PRS' }
1919
];
2020

21+
type City = (typeof cities)[0];
22+
2123
const optionClassName = cn(
2224
'cursor-grab select-none transition-transform duration-200',
2325
'data-dragging:transition-none data-dragging:fixed data-dragging:z-50 data-dragging:cursor-grabbing data-dragging:shadow-xl data-dragging:pointer-events-none',
@@ -28,25 +30,15 @@ const optionClassName = cn(
2830

2931
export default function DragDropDemo() {
3032
const [items, setItems] = useState(cities);
31-
const [selection, setSelection] = useState<string[]>([]);
33+
const [selection, setSelection] = useState<City[]>([]);
3234

3335
const orderList = useOrderList({
3436
value: items,
3537
selection,
36-
dataKey: 'code',
37-
optionValue: 'code',
3838
draggable: true,
3939
onReorder: (e: useOrderListReorderEvent) => setItems(e.value as typeof cities)
4040
});
4141

42-
const wrapperRef = useRef<HTMLDivElement>(null);
43-
44-
useEffect(() => {
45-
const ul = wrapperRef.current?.querySelector('[role="listbox"]') as HTMLElement | null;
46-
47-
(orderList.listRef as React.RefObject<HTMLElement | null>).current = ul;
48-
});
49-
5042
return (
5143
<div className="flex justify-center">
5244
<div className="w-full md:w-56">
@@ -65,22 +57,21 @@ export default function DragDropDemo() {
6557
<AngleDoubleDown />
6658
</Button>
6759
</div>
68-
<div ref={wrapperRef} className="flex-1">
60+
<div className="flex-1">
6961
<Listbox.Root
7062
value={selection}
71-
onValueChange={(e) => setSelection((e.value as string[]) ?? [])}
63+
onValueChange={(e) => setSelection((e.value as City[]) ?? [])}
7264
options={orderList.state.value as typeof cities}
7365
optionLabel="name"
74-
optionValue="code"
7566
multiple
7667
>
77-
<Listbox.List style={{ touchAction: 'none' }}>
68+
<Listbox.List {...orderList.listProps} style={{ touchAction: 'none' }}>
7869
{orderList.state.value.map((item, index) => {
79-
const city = item as (typeof cities)[0];
80-
const { onPointerDown } = orderList.getOptionProps(item, index) as { onPointerDown?: React.PointerEventHandler<HTMLElement> };
70+
const city = item as City;
71+
const optionProps = orderList.getOptionProps(item, index);
8172

8273
return (
83-
<Listbox.Option key={city.code} uKey={city.code} index={index} onPointerDown={onPointerDown} className={optionClassName}>
74+
<Listbox.Option key={city.code} uKey={city.code} index={index} {...optionProps} className={optionClassName}>
8475
{city.name}
8576
</Listbox.Option>
8677
);
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
'use client';
2+
import { AngleDoubleDown } from '@primeicons/react/angle-double-down';
3+
import { AngleDoubleUp } from '@primeicons/react/angle-double-up';
4+
import { AngleDown } from '@primeicons/react/angle-down';
5+
import { AngleUp } from '@primeicons/react/angle-up';
6+
import { useOrderList } from '@primereact/headless/orderlist';
7+
import type { useOrderListReorderEvent } from '@primereact/types/shared/orderlist';
8+
import { Button } from '@primereact/ui/button';
9+
import { Listbox } from '@primereact/ui/listbox';
10+
import { cn } from '@primeuix/utils';
11+
import { useState } from 'react';
12+
13+
const cities = [
14+
{ name: 'New York', code: 'NY' },
15+
{ name: 'Rome', code: 'RM' },
16+
{ name: 'London', code: 'LDN' },
17+
{ name: 'Istanbul', code: 'IST' },
18+
{ name: 'Paris', code: 'PRS' }
19+
];
20+
21+
type City = (typeof cities)[0];
22+
23+
const optionClassName = cn(
24+
'cursor-grab select-none transition-[transform,opacity] duration-200',
25+
'data-dragging:transition-none data-dragging:fixed data-dragging:z-50 data-dragging:cursor-grabbing data-dragging:shadow-xl data-dragging:pointer-events-none',
26+
'data-dragging:w-(--width) data-dragging:h-(--height) data-dragging:left-(--left) data-dragging:top-(--top)',
27+
'data-dragging:translate-x-(--dnd-x) data-dragging:translate-y-(--dnd-y)',
28+
'data-dropping:transition-[translate] data-dropping:duration-200 data-dropping:ease-out',
29+
'data-[sortable-placeholder]:opacity-50'
30+
);
31+
32+
export default function PlaceholderDemo() {
33+
const [items, setItems] = useState(cities);
34+
const [selection, setSelection] = useState<City[]>([]);
35+
36+
const orderList = useOrderList({
37+
value: items,
38+
selection,
39+
draggable: true,
40+
placeholder: 'clone',
41+
onReorder: (e: useOrderListReorderEvent) => setItems(e.value as typeof cities)
42+
});
43+
44+
return (
45+
<div className="flex justify-center">
46+
<div className="w-full md:w-56">
47+
<div className="flex gap-2">
48+
<div className="flex flex-col gap-1">
49+
<Button {...orderList.firstProps} severity="secondary" size="small" iconOnly aria-label="Move to first">
50+
<AngleDoubleUp />
51+
</Button>
52+
<Button {...orderList.prevProps} severity="secondary" size="small" iconOnly aria-label="Move up">
53+
<AngleUp />
54+
</Button>
55+
<Button {...orderList.nextProps} severity="secondary" size="small" iconOnly aria-label="Move down">
56+
<AngleDown />
57+
</Button>
58+
<Button {...orderList.lastProps} severity="secondary" size="small" iconOnly aria-label="Move to last">
59+
<AngleDoubleDown />
60+
</Button>
61+
</div>
62+
<div className="flex-1">
63+
<Listbox.Root
64+
value={selection}
65+
onValueChange={(e) => setSelection((e.value as City[]) ?? [])}
66+
options={orderList.state.value as typeof cities}
67+
optionLabel="name"
68+
multiple
69+
>
70+
<Listbox.List {...orderList.listProps} style={{ touchAction: 'none' }}>
71+
{orderList.state.value.map((item, index) => {
72+
const city = item as City;
73+
const optionProps = orderList.getOptionProps(item, index);
74+
75+
return (
76+
<Listbox.Option key={city.code} uKey={city.code} index={index} {...optionProps} className={optionClassName}>
77+
{city.name}
78+
</Listbox.Option>
79+
);
80+
})}
81+
</Listbox.List>
82+
</Listbox.Root>
83+
</div>
84+
</div>
85+
</div>
86+
</div>
87+
);
88+
}

0 commit comments

Comments
 (0)