Skip to content

Commit e5239e4

Browse files
fix: state usage in headless demos
1 parent 0559fde commit e5239e4

12 files changed

Lines changed: 194 additions & 192 deletions

File tree

apps/showcase/demo/headless/accordion/basic-demo.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ export default function BasicDemo() {
2727
<span>{title}</span>
2828
<span
2929
{...panel.indicatorProps}
30-
className="transition-transform duration-200"
31-
style={{ transform: panel.state.open ? 'rotate(180deg)' : 'rotate(0deg)' }}
30+
className="transition-transform duration-200 data-[open]:rotate-180"
3231
>
3332
<ChevronDown />
3433
</span>
Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,11 @@
11
'use client';
22
import { useAutoComplete, type useAutoCompleteCompleteEvent } from '@primereact/headless/autocomplete';
33
import { useListboxOption } from '@primereact/headless/listbox';
4+
import { usePortal } from '@primereact/headless/portal';
45
import { usePositioner } from '@primereact/headless/positioner';
56
import type { useListboxInstance } from '@primereact/types/headless/listbox';
67
import * as React from 'react';
7-
8-
const countries = [
9-
'Argentina',
10-
'Australia',
11-
'Brazil',
12-
'Canada',
13-
'China',
14-
'Egypt',
15-
'France',
16-
'Germany',
17-
'India',
18-
'Italy',
19-
'Japan',
20-
'Mexico',
21-
'Netherlands',
22-
'Norway',
23-
'Poland',
24-
'South Korea',
25-
'Spain',
26-
'Sweden',
27-
'Switzerland',
28-
'Turkey',
29-
'United Kingdom',
30-
'United States'
31-
];
8+
import { createPortal } from 'react-dom';
329

3310
function OptionItem({ option, index, listbox }: { option: unknown; index: number; listbox: useListboxInstance }) {
3411
const { optionProps } = useListboxOption({ option, index, context: listbox });
@@ -57,6 +34,8 @@ export default function BasicDemo() {
5734
onComplete: search
5835
});
5936

37+
const portal = usePortal();
38+
6039
usePositioner({
6140
anchor: state.anchorElement,
6241
content: state.positionerElement,
@@ -74,22 +53,50 @@ export default function BasicDemo() {
7453
placeholder="Search a country..."
7554
className="w-full px-3 py-2 text-sm bg-transparent border border-surface-200 dark:border-surface-700 rounded-lg outline-none text-surface-700 dark:text-surface-0 placeholder:text-surface-400 transition-[border-color] duration-200 focus:border-primary"
7655
/>
77-
{state.opened && (
78-
<div {...positionerProps}>
79-
<div
80-
{...popupProps}
81-
className="border border-surface-200 dark:border-surface-700 rounded-lg bg-surface-0 dark:bg-surface-900 shadow-md overflow-hidden"
82-
>
83-
<ul {...listProps} className="list-none m-0 p-1 outline-none max-h-56 overflow-auto">
84-
{listbox?.getOptions().map((option: unknown, index: number) => (
85-
<OptionItem key={index} option={option} index={index} listbox={listbox} />
86-
))}
87-
</ul>
88-
{filteredCountries.length === 0 && <div className="px-3 py-2 text-sm text-surface-400">No countries found</div>}
89-
</div>
90-
</div>
91-
)}
56+
{portal.state.mounted &&
57+
state.opened &&
58+
createPortal(
59+
<div {...positionerProps}>
60+
<div
61+
{...popupProps}
62+
className="border border-surface-200 dark:border-surface-700 rounded-lg bg-surface-0 dark:bg-surface-900 shadow-md overflow-hidden"
63+
>
64+
<ul {...listProps} className="list-none m-0 p-1 outline-none max-h-56 overflow-auto">
65+
{listbox?.getOptions().map((option: unknown, index: number) => (
66+
<OptionItem key={index} option={option} index={index} listbox={listbox} />
67+
))}
68+
</ul>
69+
{filteredCountries.length === 0 && <div className="px-3 py-2 text-sm text-surface-400">No countries found</div>}
70+
</div>
71+
</div>,
72+
document.body
73+
)}
9274
</div>
9375
</div>
9476
);
9577
}
78+
79+
const countries = [
80+
'Argentina',
81+
'Australia',
82+
'Brazil',
83+
'Canada',
84+
'China',
85+
'Egypt',
86+
'France',
87+
'Germany',
88+
'India',
89+
'Italy',
90+
'Japan',
91+
'Mexico',
92+
'Netherlands',
93+
'Norway',
94+
'Poland',
95+
'South Korea',
96+
'Spain',
97+
'Sweden',
98+
'Switzerland',
99+
'Turkey',
100+
'United Kingdom',
101+
'United States'
102+
];

apps/showcase/demo/headless/checkbox/basic-demo.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Check } from '@primeicons/react/check';
33
import { useCheckbox } from '@primereact/headless/checkbox';
44

55
export default function BasicDemo() {
6-
const { rootProps, inputProps, boxProps, indicatorProps, state } = useCheckbox({ defaultChecked: true });
6+
const { rootProps, inputProps, boxProps, indicatorProps } = useCheckbox({ defaultChecked: true });
77

88
return (
99
<div className="flex justify-center">
@@ -20,13 +20,11 @@ export default function BasicDemo() {
2020
/>
2121
<div
2222
{...boxProps}
23-
className={`flex items-center justify-center w-5 h-5 rounded-sm border-2 ${state.checked ? 'bg-primary border-primary' : 'border-gray-300 hover:border-primary'}`}
23+
className="flex items-center justify-center w-5 h-5 rounded-sm border-2 data-checked:bg-primary data-checked:border-primary data-unchecked:border-gray-300 data-unchecked:hover:border-primary"
2424
>
25-
{state.checked && (
26-
<span {...indicatorProps}>
27-
<Check className="w-3 h-3 text-primary-contrast" />
28-
</span>
29-
)}
25+
<span {...indicatorProps} className="data-unchecked:hidden">
26+
<Check className="w-3 h-3 text-primary-contrast" />
27+
</span>
3028
</div>
3129
</div>
3230
<label htmlFor="basic-cb" className="cursor-pointer select-none text-sm">

apps/showcase/demo/headless/fieldset/basic-demo.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Plus } from '@primeicons/react/plus';
44
import { useFieldset } from '@primereact/headless/fieldset';
55

66
export default function BasicDemo() {
7-
const { rootProps, triggerProps, contentProps, indicatorProps, state } = useFieldset({ defaultOpen: true });
7+
const { rootProps, triggerProps, contentProps, indicatorProps } = useFieldset({ defaultOpen: true });
88

99
return (
1010
<fieldset {...rootProps} className="max-w-lg mx-auto border border-surface-200 dark:border-surface-700 rounded-xl overflow-visible px-4 pb-4">
@@ -13,18 +13,17 @@ export default function BasicDemo() {
1313
{...triggerProps}
1414
className="flex items-center gap-2 px-2 py-1 text-[0.9375rem] font-semibold text-surface-700 dark:text-surface-0 bg-transparent border-none rounded-md cursor-pointer hover:bg-surface-50 dark:hover:bg-surface-800 focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary transition"
1515
>
16-
<span {...indicatorProps} className="flex items-center text-surface-500 dark:text-surface-400">
17-
{state.open ? <Minus className="w-3 h-3" /> : <Plus className="w-3 h-3" />}
16+
<span {...indicatorProps} className="group flex items-center text-surface-500 dark:text-surface-400">
17+
<Minus className="w-3 h-3 group-data-closed:hidden!" />
18+
<Plus className="w-3 h-3 hidden! group-data-closed:block!" />
1819
</span>
1920
<span>Legend</span>
2021
</button>
2122
</legend>
22-
{state.open && (
23-
<div {...contentProps} className="text-sm leading-relaxed text-surface-500 dark:text-surface-400">
24-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
25-
enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
26-
</div>
27-
)}
23+
<div {...contentProps} className="text-sm leading-relaxed text-surface-500 dark:text-surface-400 data-closed:hidden">
24+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
25+
minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
26+
</div>
2827
</fieldset>
2928
);
3029
}

apps/showcase/demo/headless/inputtags/basic-demo.tsx

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,11 @@
22
import { Times } from '@primeicons/react/times';
33
import { useInputTags, useInputTagsCompleteEvent, type useInputTagsValueChangeEvent } from '@primereact/headless/inputtags';
44
import { useListboxOption } from '@primereact/headless/listbox';
5+
import { usePortal } from '@primereact/headless/portal';
56
import { usePositioner } from '@primereact/headless/positioner';
67
import type { useListboxInstance } from '@primereact/types/headless/listbox';
78
import * as React from 'react';
8-
9-
const countries = [
10-
'Argentina',
11-
'Australia',
12-
'Brazil',
13-
'Canada',
14-
'China',
15-
'Egypt',
16-
'France',
17-
'Germany',
18-
'India',
19-
'Italy',
20-
'Japan',
21-
'Mexico',
22-
'Netherlands',
23-
'Norway',
24-
'Poland',
25-
'South Korea',
26-
'Spain',
27-
'Sweden',
28-
'Switzerland',
29-
'Turkey',
30-
'United Kingdom',
31-
'United States'
32-
];
9+
import { createPortal } from 'react-dom';
3310

3411
function OptionItem({ option, index, listbox }: { option: unknown; index: number; listbox: useListboxInstance }) {
3512
const { optionProps } = useListboxOption({ option, index, context: listbox });
@@ -61,6 +38,8 @@ export default function BasicDemo() {
6138
onComplete: (e: useInputTagsCompleteEvent) => setQuery(e.query)
6239
});
6340

41+
const portal = usePortal();
42+
6443
usePositioner({
6544
anchor: state.anchorElement,
6645
content: state.positionerElement,
@@ -96,22 +75,50 @@ export default function BasicDemo() {
9675
placeholder={state.value.length === 0 ? 'Add countries...' : ''}
9776
className="flex-1 min-w-20 px-1 py-0.5 text-sm bg-transparent outline-none border-none text-surface-700 dark:text-surface-0 placeholder:text-surface-400"
9877
/>
99-
{state.opened && (
100-
<div {...positionerProps}>
101-
<div
102-
{...popupProps}
103-
className="border border-surface-200 dark:border-surface-700 rounded-lg bg-surface-0 dark:bg-surface-900 shadow-md overflow-hidden"
104-
>
105-
<ul {...listProps} className="list-none m-0 p-1 outline-none max-h-56 overflow-auto">
106-
{listbox?.getOptions().map((option: unknown, index: number) => (
107-
<OptionItem key={index} option={option} index={index} listbox={listbox} />
108-
))}
109-
</ul>
110-
{filteredCountries.length === 0 && <div className="px-3 py-2 text-sm text-surface-400">No countries found</div>}
111-
</div>
112-
</div>
113-
)}
78+
{portal.state.mounted &&
79+
state.opened &&
80+
createPortal(
81+
<div {...positionerProps}>
82+
<div
83+
{...popupProps}
84+
className="border border-surface-200 dark:border-surface-700 rounded-lg bg-surface-0 dark:bg-surface-900 shadow-md overflow-hidden"
85+
>
86+
<ul {...listProps} className="list-none m-0 p-1 outline-none max-h-56 overflow-auto">
87+
{listbox?.getOptions().map((option: unknown, index: number) => (
88+
<OptionItem key={index} option={option} index={index} listbox={listbox} />
89+
))}
90+
</ul>
91+
{filteredCountries.length === 0 && <div className="px-3 py-2 text-sm text-surface-400">No countries found</div>}
92+
</div>
93+
</div>,
94+
document.body
95+
)}
11496
</div>
11597
</div>
11698
);
11799
}
100+
101+
const countries = [
102+
'Argentina',
103+
'Australia',
104+
'Brazil',
105+
'Canada',
106+
'China',
107+
'Egypt',
108+
'France',
109+
'Germany',
110+
'India',
111+
'Italy',
112+
'Japan',
113+
'Mexico',
114+
'Netherlands',
115+
'Norway',
116+
'Poland',
117+
'South Korea',
118+
'Spain',
119+
'Sweden',
120+
'Switzerland',
121+
'Turkey',
122+
'United Kingdom',
123+
'United States'
124+
];

apps/showcase/demo/headless/positioner/basic-demo.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
'use client';
2+
import { usePortal } from '@primereact/headless/portal';
23
import { usePositioner } from '@primereact/headless/positioner';
3-
import { Portal } from 'primereact/portal';
44
import * as React from 'react';
5+
import { createPortal } from 'react-dom';
56

67
export default function BasicDemo() {
78
const [open, setOpen] = React.useState(false);
89
const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null);
910
const [contentEl, setContentEl] = React.useState<HTMLDivElement | null>(null);
1011

12+
const portal = usePortal();
13+
1114
const positioner = usePositioner({
1215
anchor: anchorEl ?? undefined,
1316
content: contentEl ?? undefined,
@@ -28,17 +31,18 @@ export default function BasicDemo() {
2831
{open ? 'Hide' : 'Show'} Tooltip
2932
</button>
3033
</div>
31-
<Portal>
32-
{open && (
34+
{portal.state.mounted &&
35+
open &&
36+
createPortal(
3337
<div
3438
ref={setContentEl}
3539
className="bg-gray-900 text-white text-xs rounded-md px-3 py-1.5 shadow-lg"
3640
data-side={positioner.state.actualSide}
3741
>
3842
Positioned on {positioner.state.actualSide ?? 'bottom'}
39-
</div>
43+
</div>,
44+
document.body
4045
)}
41-
</Portal>
4246
</>
4347
);
4448
}

apps/showcase/demo/headless/radiobutton/basic-demo.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function BasicDemo() {
1515
<div className="flex justify-center">
1616
<div {...groupRootProps} className="flex flex-col gap-3">
1717
{items.map((item) => {
18-
const { rootProps, inputProps, boxProps, indicatorProps, state } = useRadioButton({
18+
const { rootProps, inputProps, boxProps, indicatorProps } = useRadioButton({
1919
name: 'delivery',
2020
value: item.value,
2121
checked: groupState.value === item.value,
@@ -36,14 +36,12 @@ export default function BasicDemo() {
3636
/>
3737
<div
3838
{...boxProps}
39-
className={`flex items-center justify-center w-[1.125rem] h-[1.125rem] rounded-full border transition-colors duration-200 ${state.checked ? 'bg-primary border-primary' : 'border-surface-300 hover:border-surface-400'}`}
39+
className="flex items-center justify-center w-[1.125rem] h-[1.125rem] rounded-full border transition-colors duration-200 data-checked:bg-primary data-checked:border-primary data-unchecked:border-surface-300 data-unchecked:hover:border-surface-400"
4040
>
41-
{state.checked && (
42-
<span
43-
{...indicatorProps}
44-
className="w-2.5 h-2.5 rounded-full bg-primary-contrast transition-transform duration-200"
45-
/>
46-
)}
41+
<span
42+
{...indicatorProps}
43+
className="w-2.5 h-2.5 rounded-full bg-primary-contrast transition-transform duration-200 data-unchecked:hidden"
44+
/>
4745
</div>
4846
</div>
4947
<label htmlFor={`rb-${item.value}`} className="cursor-pointer select-none text-sm">

0 commit comments

Comments
 (0)