@primitiv-ui/react 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/package.json +2 -1
- package/src/AccessibleIcon/AccessibleIcon.tsx +6 -2
- package/src/AccessibleIcon/__tests__/AccessibleIcon.test.tsx +1 -1
- package/src/AccessibleIcon/types.ts +4 -0
- package/src/Accordion/Accordion.tsx +34 -12
- package/src/Accordion/AccordionContext.ts +1 -1
- package/src/Accordion/__tests__/Accordion.reading-direction.test.tsx +1 -1
- package/src/Accordion/hooks/useAccordionItem.ts +1 -1
- package/src/Accordion/hooks/useAccordionRoot.ts +1 -1
- package/src/Accordion/hooks/useAccordionTrigger.ts +2 -2
- package/src/Accordion/index.ts +2 -1
- package/src/Accordion/types.ts +55 -13
- package/src/Alert/Alert.tsx +9 -2
- package/src/Alert/__tests__/Alert.test.tsx +1 -1
- package/src/Alert/types.ts +1 -0
- package/src/Avatar/Avatar.tsx +20 -7
- package/src/Avatar/AvatarContext.ts +12 -6
- package/src/Breadcrumb/Breadcrumb.tsx +32 -10
- package/src/Button/Button.tsx +5 -2
- package/src/Button/types.ts +4 -0
- package/src/Carousel/Carousel.tsx +30 -14
- package/src/Carousel/CarouselContext.ts +7 -3
- package/src/Carousel/__tests__/Carousel.asChild.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.auto-play.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.basic-rendering.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.controlled-state.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.error-handling.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.ids.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.imperative-api.test.tsx +2 -2
- package/src/Carousel/__tests__/Carousel.indicators.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.intersection-observer.test.tsx +2 -2
- package/src/Carousel/__tests__/Carousel.keyboard-navigation.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.play-pause.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.prev-next.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.reduced-motion.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.refresh-progress.test.tsx +2 -2
- package/src/Carousel/__tests__/Carousel.scroll-snap-change.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.scroll-sync.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.slides-per-move.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.slides-per-page.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.touch-interaction.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.transition-modes.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.translations.test.tsx +1 -1
- package/src/Carousel/__tests__/Carousel.uncontrolled-state.test.tsx +1 -1
- package/src/Carousel/types.ts +8 -0
- package/src/Checkbox/Checkbox.tsx +11 -6
- package/src/Checkbox/CheckboxContext.ts +1 -1
- package/src/Checkbox/hooks/useCheckboxRoot.ts +1 -1
- package/src/Checkbox/index.ts +1 -0
- package/src/Checkbox/types.ts +30 -3
- package/src/CheckboxCard/CheckboxCard.tsx +13 -11
- package/src/CheckboxCard/CheckboxCardContext.ts +19 -6
- package/src/CheckboxCard/hooks/useCheckboxCardRoot.ts +2 -2
- package/src/CheckboxCard/types.ts +21 -5
- package/src/Collapsible/Collapsible.tsx +37 -21
- package/src/Collapsible/CollapsibleContext.ts +1 -1
- package/src/Collapsible/hooks/useCollapsibleRoot.ts +1 -1
- package/src/Collapsible/hooks/useCollapsibleTrigger.ts +1 -1
- package/src/Collapsible/index.ts +1 -0
- package/src/Collapsible/types.ts +45 -12
- package/src/ContextMenu/ContextMenu.tsx +60 -34
- package/src/ContextMenu/ContextMenuContext.ts +2 -2
- package/src/ContextMenu/ContextMenuSubContext.ts +1 -1
- package/src/ContextMenu/__tests__/ContextMenu.reading-direction.test.tsx +1 -1
- package/src/ContextMenu/index.ts +2 -1
- package/src/ContextMenu/types.ts +160 -17
- package/src/DirectionProvider/DirectionProvider.tsx +7 -1
- package/src/DirectionProvider/__tests__/DirectionProvider.test.tsx +1 -1
- package/src/DirectionProvider/types.ts +1 -0
- package/src/Divider/Divider.tsx +4 -1
- package/src/Divider/__tests__/Divider.test.tsx +1 -1
- package/src/Divider/index.ts +2 -1
- package/src/Divider/types.ts +5 -0
- package/src/Dropdown/Dropdown.tsx +60 -34
- package/src/Dropdown/DropdownContext.ts +2 -2
- package/src/Dropdown/DropdownSubContext.ts +1 -1
- package/src/Dropdown/__tests__/Dropdown.reading-direction.test.tsx +1 -1
- package/src/Dropdown/hooks/useDropdownContent.ts +1 -1
- package/src/Dropdown/hooks/useDropdownItem.ts +1 -1
- package/src/Dropdown/hooks/useDropdownRoot.ts +2 -2
- package/src/Dropdown/hooks/useDropdownTrigger.ts +1 -1
- package/src/Dropdown/index.ts +2 -1
- package/src/Dropdown/types.ts +153 -25
- package/src/EmptyState/EmptyState.tsx +34 -20
- package/src/EmptyState/__tests__/EmptyState.Actions.test.tsx +1 -1
- package/src/EmptyState/__tests__/EmptyState.Description.test.tsx +1 -1
- package/src/EmptyState/__tests__/EmptyState.Media.test.tsx +1 -1
- package/src/EmptyState/__tests__/EmptyState.Root.test.tsx +1 -1
- package/src/EmptyState/__tests__/EmptyState.Title.test.tsx +1 -1
- package/src/EmptyState/types.ts +2 -1
- package/src/Field/Field.tsx +24 -10
- package/src/Field/FieldContext.ts +1 -1
- package/src/Field/types.ts +4 -0
- package/src/Fieldset/Fieldset.tsx +26 -10
- package/src/Fieldset/types.ts +2 -0
- package/src/Input/Input.tsx +6 -3
- package/src/Input/__tests__/Input.field-integration.test.tsx +1 -1
- package/src/Input/types.ts +4 -0
- package/src/InputGroup/InputGroup.tsx +15 -8
- package/src/InputGroup/types.ts +9 -0
- package/src/MillerColumns/MillerColumns.tsx +28 -8
- package/src/MillerColumns/MillerColumnsContext.ts +1 -1
- package/src/MillerColumns/hooks/useMillerColumnsItem.ts +2 -2
- package/src/MillerColumns/hooks/useMillerColumnsRoot.ts +0 -0
- package/src/MillerColumns/index.ts +1 -1
- package/src/MillerColumns/types.ts +67 -14
- package/src/MillerColumns/useMillerColumnsSelection.ts +1 -1
- package/src/Modal/Modal.tsx +25 -11
- package/src/Modal/ModalContext.ts +14 -7
- package/src/Modal/hooks/useModalRoot.ts +1 -1
- package/src/Modal/hooks/useModalTrigger.ts +2 -2
- package/src/Modal/types.ts +51 -2
- package/src/Portal/Portal.tsx +3 -1
- package/src/Portal/types.ts +4 -0
- package/src/Progress/Progress.tsx +12 -7
- package/src/Progress/ProgressContext.ts +18 -6
- package/src/RadioCard/RadioCard.tsx +17 -11
- package/src/RadioCard/RadioCardContext.ts +17 -5
- package/src/RadioCard/RadioCardItemContext.ts +18 -5
- package/src/RadioCard/__tests__/RadioCard.reading-direction.test.tsx +1 -1
- package/src/RadioCard/hooks/useRadioCardRoot.ts +1 -1
- package/src/RadioCard/types.ts +24 -3
- package/src/RadioGroup/RadioGroup.tsx +17 -11
- package/src/RadioGroup/RadioGroupContext.ts +1 -1
- package/src/RadioGroup/RadioGroupItemContext.ts +1 -1
- package/src/RadioGroup/__tests__/RadioGroup.reading-direction.test.tsx +1 -1
- package/src/RadioGroup/hooks/useRadioGroupRoot.ts +1 -1
- package/src/RadioGroup/index.ts +1 -0
- package/src/RadioGroup/types.ts +34 -3
- package/src/Select/Select.tsx +23 -8
- package/src/Select/__tests__/Select.field-integration.test.tsx +1 -1
- package/src/Select/index.ts +1 -1
- package/src/Select/types.ts +18 -3
- package/src/SkipNav/SkipNav.tsx +7 -2
- package/src/SkipNav/__tests__/SkipNav.ids.test.tsx +1 -1
- package/src/Slider/Slider.tsx +26 -11
- package/src/Slider/SliderContext.ts +13 -6
- package/src/Slider/__tests__/Slider.reading-direction.test.tsx +1 -1
- package/src/Slider/hooks/useSliderRoot.ts +1 -1
- package/src/Slider/types.ts +12 -3
- package/src/Status/Status.tsx +9 -2
- package/src/Status/__tests__/Status.test.tsx +1 -1
- package/src/Status/types.ts +4 -0
- package/src/Switch/Switch.tsx +16 -6
- package/src/Switch/SwitchContext.ts +13 -5
- package/src/Switch/hooks/useSwitchRoot.ts +1 -1
- package/src/Switch/types.ts +24 -3
- package/src/Table/Table.tsx +51 -25
- package/src/Table/__tests__/Table.Body.test.tsx +1 -1
- package/src/Table/__tests__/Table.Caption.test.tsx +1 -1
- package/src/Table/__tests__/Table.Cell.test.tsx +1 -1
- package/src/Table/__tests__/Table.Footer.test.tsx +1 -1
- package/src/Table/__tests__/Table.Head.test.tsx +1 -1
- package/src/Table/__tests__/Table.Header.test.tsx +1 -1
- package/src/Table/__tests__/Table.Root.test.tsx +1 -1
- package/src/Table/__tests__/Table.Row.test.tsx +1 -1
- package/src/Table/__tests__/Table.ScrollArea.test.tsx +1 -1
- package/src/Table/index.ts +2 -1
- package/src/Tabs/Tabs.tsx +30 -10
- package/src/Tabs/TabsContext.ts +15 -7
- package/src/Tabs/__tests__/Tabs.asChild.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.basic-rendering.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.change-event-callbacks.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.controlled-state.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.error-handling.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.imperative-api.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.keyboard-interaction.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.lazy-mount.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.mouse-interaction.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.reading-direction.test.tsx +1 -1
- package/src/Tabs/__tests__/Tabs.uncontrolled-state.test.tsx +1 -1
- package/src/Tabs/hooks/useTabsContent.ts +1 -1
- package/src/Tabs/hooks/useTabsRoot.ts +1 -1
- package/src/Tabs/hooks/useTabsTrigger.ts +1 -1
- package/src/Tabs/types.ts +35 -1
- package/src/Tabs/utils.ts +1 -1
- package/src/Textarea/Textarea.tsx +6 -3
- package/src/Textarea/__tests__/Textarea.field-integration.test.tsx +1 -1
- package/src/Textarea/types.ts +4 -0
- package/src/Toggle/Toggle.tsx +11 -4
- package/src/Toggle/types.ts +7 -3
- package/src/ToggleGroup/ToggleGroup.tsx +23 -13
- package/src/ToggleGroup/ToggleGroupContext.ts +1 -1
- package/src/ToggleGroup/__tests__/ToggleGroup.reading-direction.test.tsx +1 -1
- package/src/ToggleGroup/hooks/useToggleGroupRoot.ts +1 -1
- package/src/ToggleGroup/types.ts +45 -5
- package/src/Tooltip/Tooltip.tsx +46 -15
- package/src/Tooltip/TooltipContext.ts +1 -1
- package/src/Tooltip/hooks/useTooltipContent.ts +1 -1
- package/src/Tooltip/hooks/useTooltipRoot.ts +1 -1
- package/src/Tooltip/hooks/useTooltipTrigger.ts +1 -1
- package/src/Tooltip/index.ts +1 -0
- package/src/Tooltip/types.ts +50 -2
- package/src/Tree/Tree.tsx +58 -12
- package/src/Tree/TreeContext.ts +1 -1
- package/src/Tree/__tests__/Tree.selection-path.test.tsx +2 -2
- package/src/Tree/hooks/useTreeItemKeyboard.ts +1 -1
- package/src/Tree/hooks/useTreeRoot.ts +1 -1
- package/src/Tree/index.ts +1 -1
- package/src/Tree/types.ts +39 -7
- package/src/VisuallyHidden/VisuallyHidden.tsx +4 -2
- package/src/VisuallyHidden/__tests__/VisuallyHidden.test.tsx +1 -1
- package/src/VisuallyHidden/types.ts +4 -0
- package/src/index.ts +39 -38
- package/src/types.ts +1 -0
- package/src/utils/createStrictContext.ts +9 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Simon Revill
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primitiv-ui/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Headless, accessible React components built on the WAI-ARIA authoring patterns. Zero styles ship with this package — bring your own (CSS, Tailwind, CSS-in-JS, design tokens).",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"main": "./src/index.ts",
|
|
6
7
|
"types": "./src/index.ts",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Children, cloneElement, ReactElement } from "react";
|
|
2
|
-
import { VisuallyHidden } from "../VisuallyHidden";
|
|
2
|
+
import { VisuallyHidden } from "../VisuallyHidden/index.ts";
|
|
3
3
|
import { AccessibleIconProps } from "./types";
|
|
4
4
|
|
|
5
5
|
type DecorativeIconProps = { "aria-hidden": string; focusable: string };
|
|
@@ -26,7 +26,10 @@ type DecorativeIconProps = { "aria-hidden": string; focusable: string };
|
|
|
26
26
|
* </button>
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
|
-
export function AccessibleIcon({
|
|
29
|
+
export function AccessibleIcon({
|
|
30
|
+
label,
|
|
31
|
+
children,
|
|
32
|
+
}: AccessibleIconProps): ReactElement {
|
|
30
33
|
const icon = Children.only(children) as ReactElement<DecorativeIconProps>;
|
|
31
34
|
|
|
32
35
|
return (
|
|
@@ -37,4 +40,5 @@ export function AccessibleIcon({ label, children }: AccessibleIconProps) {
|
|
|
37
40
|
);
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
/** @internal */
|
|
40
44
|
AccessibleIcon.displayName = "AccessibleIcon";
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { ReactElement } from "react";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Props for {@link AccessibleIcon} — a single icon element plus the
|
|
5
|
+
* visually-hidden `label` announced as its accessible name.
|
|
6
|
+
*/
|
|
3
7
|
export type AccessibleIconProps = {
|
|
4
8
|
/** Text announced by assistive technology as the icon's accessible name. */
|
|
5
9
|
label: string;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Ref, useEffect } from "react";
|
|
2
|
+
import type { ReactElement } from "react";
|
|
2
3
|
|
|
3
|
-
import { useDirection } from "../DirectionProvider";
|
|
4
|
-
import { Slot } from "../Slot";
|
|
4
|
+
import { useDirection } from "../DirectionProvider/index.ts";
|
|
5
|
+
import { Slot } from "../Slot/index.ts";
|
|
5
6
|
|
|
6
7
|
import type {
|
|
7
8
|
AccordionRootProps,
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
useAccordionItem,
|
|
22
23
|
useAccordionItemContext,
|
|
23
24
|
useAccordionRoot,
|
|
24
|
-
} from "./hooks";
|
|
25
|
+
} from "./hooks/index.ts";
|
|
25
26
|
import { useAccordionTrigger } from "./hooks/useAccordionTrigger";
|
|
26
27
|
|
|
27
28
|
/**
|
|
@@ -78,7 +79,7 @@ export function AccordionRoot({
|
|
|
78
79
|
orientation = "vertical",
|
|
79
80
|
dir,
|
|
80
81
|
...rest
|
|
81
|
-
}: AccordionRootProps) {
|
|
82
|
+
}: AccordionRootProps): ReactElement {
|
|
82
83
|
const resolvedDir = dir ?? useDirection();
|
|
83
84
|
const { contextValue } = useAccordionRoot(
|
|
84
85
|
controlledValue,
|
|
@@ -98,6 +99,7 @@ export function AccordionRoot({
|
|
|
98
99
|
);
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
/** @internal */
|
|
101
103
|
AccordionRoot.displayName = "AccordionRoot";
|
|
102
104
|
|
|
103
105
|
/**
|
|
@@ -124,7 +126,7 @@ export function AccordionItem({
|
|
|
124
126
|
children,
|
|
125
127
|
value,
|
|
126
128
|
...rest
|
|
127
|
-
}: AccordionItemProps) {
|
|
129
|
+
}: AccordionItemProps): ReactElement {
|
|
128
130
|
const { contextValue } = useAccordionItem(value);
|
|
129
131
|
|
|
130
132
|
return (
|
|
@@ -134,6 +136,7 @@ export function AccordionItem({
|
|
|
134
136
|
);
|
|
135
137
|
}
|
|
136
138
|
|
|
139
|
+
/** @internal */
|
|
137
140
|
AccordionItem.displayName = "AccordionItem";
|
|
138
141
|
|
|
139
142
|
/**
|
|
@@ -156,13 +159,14 @@ export function AccordionHeader({
|
|
|
156
159
|
children,
|
|
157
160
|
level = 3,
|
|
158
161
|
...rest
|
|
159
|
-
}: AccordionHeaderProps) {
|
|
162
|
+
}: AccordionHeaderProps): ReactElement {
|
|
160
163
|
useAccordionHeaderContext();
|
|
161
164
|
const HeadingTag: HeadingTag = `h${level}`;
|
|
162
165
|
|
|
163
166
|
return <HeadingTag {...rest}>{children}</HeadingTag>;
|
|
164
167
|
}
|
|
165
168
|
|
|
169
|
+
/** @internal */
|
|
166
170
|
AccordionHeader.displayName = "AccordionHeader";
|
|
167
171
|
|
|
168
172
|
/**
|
|
@@ -229,16 +233,14 @@ AccordionHeader.displayName = "AccordionHeader";
|
|
|
229
233
|
* </Accordion.Trigger>
|
|
230
234
|
* ```
|
|
231
235
|
*/
|
|
232
|
-
export function AccordionTrigger<
|
|
233
|
-
T extends HTMLElement = HTMLButtonElement,
|
|
234
|
-
>({
|
|
236
|
+
export function AccordionTrigger<T extends HTMLElement = HTMLButtonElement>({
|
|
235
237
|
ref,
|
|
236
238
|
children,
|
|
237
239
|
onClick,
|
|
238
240
|
disabled = false,
|
|
239
241
|
asChild = false,
|
|
240
242
|
...rest
|
|
241
|
-
}: AccordionTriggerProps<T>) {
|
|
243
|
+
}: AccordionTriggerProps<T>): ReactElement {
|
|
242
244
|
// Cast the external ref to match the internal button ref's element type —
|
|
243
245
|
// RefObject<T> is invariant in React's types, but at runtime the callback
|
|
244
246
|
// receives whatever DOM element is actually rendered (button or asChild).
|
|
@@ -261,6 +263,7 @@ export function AccordionTrigger<
|
|
|
261
263
|
);
|
|
262
264
|
}
|
|
263
265
|
|
|
266
|
+
/** @internal */
|
|
264
267
|
AccordionTrigger.displayName = "AccordionTrigger";
|
|
265
268
|
|
|
266
269
|
/**
|
|
@@ -306,7 +309,7 @@ export function AccordionContent({
|
|
|
306
309
|
children,
|
|
307
310
|
forceMount = false,
|
|
308
311
|
...rest
|
|
309
|
-
}: AccordionContentProps) {
|
|
312
|
+
}: AccordionContentProps): ReactElement {
|
|
310
313
|
const { panelId, buttonId, itemId, isExpanded } = useAccordionItemContext();
|
|
311
314
|
const { registerPanel, unregisterPanel } = useAccordionContext();
|
|
312
315
|
|
|
@@ -330,6 +333,7 @@ export function AccordionContent({
|
|
|
330
333
|
);
|
|
331
334
|
}
|
|
332
335
|
|
|
336
|
+
/** @internal */
|
|
333
337
|
AccordionContent.displayName = "AccordionContent";
|
|
334
338
|
|
|
335
339
|
/**
|
|
@@ -373,7 +377,7 @@ AccordionContent.displayName = "AccordionContent";
|
|
|
373
377
|
export function AccordionTriggerIcon({
|
|
374
378
|
children,
|
|
375
379
|
...rest
|
|
376
|
-
}: AccordionTriggerIconProps) {
|
|
380
|
+
}: AccordionTriggerIconProps): ReactElement {
|
|
377
381
|
const { isExpanded } = useAccordionItemContext();
|
|
378
382
|
|
|
379
383
|
return (
|
|
@@ -387,8 +391,10 @@ export function AccordionTriggerIcon({
|
|
|
387
391
|
);
|
|
388
392
|
}
|
|
389
393
|
|
|
394
|
+
/** @internal */
|
|
390
395
|
AccordionTriggerIcon.displayName = "AccordionTriggerIcon";
|
|
391
396
|
|
|
397
|
+
/** @internal */
|
|
392
398
|
type AccordionCompound = typeof AccordionRoot & {
|
|
393
399
|
Root: typeof AccordionRoot;
|
|
394
400
|
Item: typeof AccordionItem;
|
|
@@ -398,6 +404,22 @@ type AccordionCompound = typeof AccordionRoot & {
|
|
|
398
404
|
TriggerIcon: typeof AccordionTriggerIcon;
|
|
399
405
|
};
|
|
400
406
|
|
|
407
|
+
/**
|
|
408
|
+
* Headless, accessible **Accordion** — a compound component for a vertically
|
|
409
|
+
* (or horizontally) stacked set of collapsible sections, following the
|
|
410
|
+
* [WAI-ARIA Accordion pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/)
|
|
411
|
+
* with zero styles.
|
|
412
|
+
*
|
|
413
|
+
* `Accordion` is both callable (an alias of {@link AccordionRoot | `Accordion.Root`})
|
|
414
|
+
* and carries its sub-components as static properties:
|
|
415
|
+
*
|
|
416
|
+
* - {@link AccordionRoot | `Accordion.Root`} — state owner and context provider.
|
|
417
|
+
* - {@link AccordionItem | `Accordion.Item`} — one collapsible section.
|
|
418
|
+
* - {@link AccordionHeader | `Accordion.Header`} — heading wrapper for the trigger.
|
|
419
|
+
* - {@link AccordionTrigger | `Accordion.Trigger`} — button that toggles the section.
|
|
420
|
+
* - {@link AccordionContent | `Accordion.Content`} — the collapsible panel.
|
|
421
|
+
* - {@link AccordionTriggerIcon | `Accordion.TriggerIcon`} — decorative state indicator.
|
|
422
|
+
*/
|
|
401
423
|
const AccordionCompound: AccordionCompound = Object.assign(AccordionRoot, {
|
|
402
424
|
Root: AccordionRoot,
|
|
403
425
|
Item: AccordionItem,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { render, screen } from "@testing-library/react";
|
|
2
2
|
import userEvent from "@testing-library/user-event";
|
|
3
3
|
|
|
4
|
-
import { DirectionProvider } from "../../DirectionProvider";
|
|
4
|
+
import { DirectionProvider } from "../../DirectionProvider/index.ts";
|
|
5
5
|
import { Accordion } from "../Accordion";
|
|
6
6
|
|
|
7
7
|
describe("Accordion reading direction tests", () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useRef, useMemo, useCallback, useId, useEffect } from "react";
|
|
2
2
|
|
|
3
|
-
import { useCollection, useControllableState } from "../../hooks";
|
|
3
|
+
import { useCollection, useControllableState } from "../../hooks/index.ts";
|
|
4
4
|
|
|
5
5
|
import type { AccordionReadingDirection } from "../types";
|
|
6
6
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useMemo, useRef, useEffect, MouseEvent, KeyboardEvent } from "react";
|
|
2
2
|
|
|
3
|
-
import { useRovingTabindex } from "../../hooks";
|
|
4
|
-
import { composeRefs } from "../../Slot";
|
|
3
|
+
import { useRovingTabindex } from "../../hooks/index.ts";
|
|
4
|
+
import { composeRefs } from "../../Slot/index.ts";
|
|
5
5
|
|
|
6
6
|
import { AccordionTriggerProps } from "../types";
|
|
7
7
|
|
package/src/Accordion/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from
|
|
1
|
+
export * from "./Accordion";
|
|
2
|
+
export * from "./types";
|
package/src/Accordion/types.ts
CHANGED
|
@@ -1,81 +1,123 @@
|
|
|
1
1
|
import { ComponentProps, ReactNode, Ref } from "react";
|
|
2
2
|
import { HeadingLevel } from "../types";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/** Props shared by both control modes of `Accordion.Root`. */
|
|
5
|
+
export type AccordionRootBaseProps = ComponentProps<"div"> & {
|
|
6
|
+
/** Allow more than one section to be expanded at a time. */
|
|
5
7
|
multiple?: boolean;
|
|
8
|
+
/** Layout axis, controlling arrow-key navigation. Defaults to `"vertical"`. */
|
|
6
9
|
orientation?: "vertical" | "horizontal";
|
|
10
|
+
/** Reading direction, controlling left/right key semantics. */
|
|
7
11
|
dir?: AccordionReadingDirection;
|
|
8
12
|
};
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
/** `Accordion.Root` props for the uncontrolled (self-managed) expanded state. */
|
|
15
|
+
export type AccordionRootUncontrolledProps = AccordionRootBaseProps & {
|
|
16
|
+
/** Initially expanded item value when uncontrolled. */
|
|
11
17
|
defaultValue?: string;
|
|
12
18
|
value?: never;
|
|
13
19
|
onValueChange?: never;
|
|
14
20
|
};
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
/** `Accordion.Root` props for the controlled expanded state. */
|
|
23
|
+
export type AccordionRootControlledProps = AccordionRootBaseProps & {
|
|
17
24
|
defaultValue?: never;
|
|
25
|
+
/** Controlled set of expanded item values. */
|
|
18
26
|
value: string[];
|
|
27
|
+
/** Called whenever the set of expanded item values changes. */
|
|
19
28
|
onValueChange: (values: string[]) => void;
|
|
20
29
|
};
|
|
21
30
|
|
|
31
|
+
/** Reading direction for an accordion. */
|
|
22
32
|
export type AccordionReadingDirection = "ltr" | "rtl";
|
|
23
33
|
|
|
34
|
+
/** Props for `Accordion.Root`, in either the controlled or uncontrolled mode. */
|
|
24
35
|
export type AccordionRootProps =
|
|
25
36
|
| AccordionRootUncontrolledProps
|
|
26
37
|
| AccordionRootControlledProps;
|
|
27
38
|
|
|
39
|
+
/** Props for `Accordion.Item` — a single collapsible section. */
|
|
28
40
|
export type AccordionItemProps = ComponentProps<"div"> & {
|
|
41
|
+
/** Section contents — typically a `Header` + `Content` pair. */
|
|
29
42
|
children: ReactNode;
|
|
43
|
+
/** Stable value identifying the item; auto-generated via `useId()` when omitted. */
|
|
30
44
|
value?: string; // Optional - if not provided, useId() will generate one
|
|
31
45
|
};
|
|
32
46
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
/** Props for `Accordion.Trigger` — the button that toggles a section. */
|
|
48
|
+
export type AccordionTriggerProps<T extends HTMLElement = HTMLButtonElement> =
|
|
49
|
+
Omit<ComponentProps<"button">, "disabled" | "ref"> & {
|
|
50
|
+
/** Trigger label / contents. */
|
|
51
|
+
children: ReactNode;
|
|
52
|
+
/** Disable the trigger, removing it from keyboard navigation. */
|
|
53
|
+
disabled?: boolean;
|
|
54
|
+
/** Render into the consumer's own element instead of a `<button>`. */
|
|
55
|
+
asChild?: boolean;
|
|
56
|
+
/** Ref to the rendered element. Defaults to `HTMLButtonElement`; when using
|
|
57
|
+
* `asChild`, specify the child's element type (e.g. `HTMLAnchorElement`). */
|
|
58
|
+
ref?: Ref<T>;
|
|
59
|
+
};
|
|
43
60
|
|
|
61
|
+
/** Props for `Accordion.Header` — the heading wrapping a trigger. */
|
|
44
62
|
export type AccordionHeaderProps = ComponentProps<"h3"> & {
|
|
63
|
+
/** Header contents — typically an `Accordion.Trigger`. */
|
|
45
64
|
children: ReactNode;
|
|
65
|
+
/** Heading level rendered (`h1`–`h6`). Defaults to `3`. */
|
|
46
66
|
level?: HeadingLevel;
|
|
47
67
|
};
|
|
48
68
|
|
|
69
|
+
/** Props for `Accordion.Content` — the collapsible panel. */
|
|
49
70
|
export type AccordionContentProps = ComponentProps<"div"> & {
|
|
71
|
+
/** Panel contents. */
|
|
50
72
|
children: ReactNode;
|
|
73
|
+
/** Keep the panel mounted even while collapsed. */
|
|
51
74
|
forceMount?: boolean;
|
|
52
75
|
};
|
|
53
76
|
|
|
77
|
+
/** Props for `Accordion.TriggerIcon` — a decorative open/closed indicator. */
|
|
54
78
|
export type AccordionTriggerIconProps = ComponentProps<"span"> & {
|
|
79
|
+
/** Icon contents. */
|
|
55
80
|
children: ReactNode;
|
|
56
81
|
};
|
|
57
82
|
|
|
83
|
+
/** Context value published by `Accordion.Root` to coordinate its sections. */
|
|
58
84
|
export type AccordionContextValue = {
|
|
85
|
+
/** Generated id namespacing the accordion's element ids. */
|
|
59
86
|
accordionId: string;
|
|
87
|
+
/** Set of currently expanded item values. */
|
|
60
88
|
expandedItems: Set<string>;
|
|
89
|
+
/** Layout axis used for arrow-key navigation. */
|
|
61
90
|
orientation: "vertical" | "horizontal";
|
|
91
|
+
/** Reading direction used for left/right key semantics. */
|
|
62
92
|
dir: AccordionReadingDirection;
|
|
93
|
+
/** Toggles the expanded state of the given item. */
|
|
63
94
|
toggleItem: (itemId: string) => void;
|
|
95
|
+
/** Registers a trigger element so roving focus can reach it. */
|
|
64
96
|
registerTrigger: (
|
|
65
97
|
itemId: string,
|
|
66
98
|
element: HTMLButtonElement | null,
|
|
67
99
|
disabled?: boolean,
|
|
68
100
|
) => void;
|
|
101
|
+
/** Ordered ids of registered triggers, used for focus movement. */
|
|
69
102
|
registeredTriggerItemIds: string[];
|
|
103
|
+
/** Set of item ids whose triggers are disabled. */
|
|
70
104
|
disabledItemIds: Set<string>;
|
|
105
|
+
/** Moves focus to the given item's trigger. */
|
|
71
106
|
focusTrigger: (itemId: string) => void;
|
|
107
|
+
/** Registers a content panel as mounted. */
|
|
72
108
|
registerPanel: (itemId: string) => void;
|
|
109
|
+
/** Removes a previously registered content panel. */
|
|
73
110
|
unregisterPanel: (itemId: string) => void;
|
|
74
111
|
};
|
|
75
112
|
|
|
113
|
+
/** Context value published by `Accordion.Item` to its header and content. */
|
|
76
114
|
export type AccordionItemContextValue = {
|
|
115
|
+
/** Id of the trigger button. */
|
|
77
116
|
buttonId: string;
|
|
117
|
+
/** Id of the content panel. */
|
|
78
118
|
panelId: string;
|
|
119
|
+
/** Stable value identifying this item. */
|
|
79
120
|
itemId: string;
|
|
121
|
+
/** Whether this item is currently expanded. */
|
|
80
122
|
isExpanded: boolean;
|
|
81
123
|
};
|
package/src/Alert/Alert.tsx
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
|
|
3
|
+
import { Slot } from "../Slot/index.ts";
|
|
2
4
|
import { AlertProps } from "./types";
|
|
3
5
|
|
|
4
6
|
/**
|
|
@@ -30,7 +32,11 @@ import { AlertProps } from "./types";
|
|
|
30
32
|
* </Alert>
|
|
31
33
|
* ```
|
|
32
34
|
*/
|
|
33
|
-
export function Alert({
|
|
35
|
+
export function Alert({
|
|
36
|
+
asChild = false,
|
|
37
|
+
children,
|
|
38
|
+
...rest
|
|
39
|
+
}: AlertProps): ReactElement {
|
|
34
40
|
const rootProps = { role: "alert", ...rest };
|
|
35
41
|
|
|
36
42
|
if (asChild) {
|
|
@@ -40,4 +46,5 @@ export function Alert({ asChild = false, children, ...rest }: AlertProps) {
|
|
|
40
46
|
return <div {...rootProps}>{children}</div>;
|
|
41
47
|
}
|
|
42
48
|
|
|
49
|
+
/** @internal */
|
|
43
50
|
Alert.displayName = "Alert";
|
package/src/Alert/types.ts
CHANGED
package/src/Avatar/Avatar.tsx
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useEffect, useMemo, useState } from "react";
|
|
2
|
+
import type { ReactElement } from "react";
|
|
2
3
|
|
|
3
|
-
import { Slot } from "../Slot";
|
|
4
|
+
import { Slot } from "../Slot/index.ts";
|
|
4
5
|
|
|
5
6
|
import { AvatarContext } from "./AvatarContext";
|
|
6
|
-
import { useAvatarContext, useAvatarImage } from "./hooks";
|
|
7
|
+
import { useAvatarContext, useAvatarImage } from "./hooks/index.ts";
|
|
7
8
|
import {
|
|
8
9
|
AvatarFallbackProps,
|
|
9
10
|
AvatarImageLoadingStatus,
|
|
@@ -22,7 +23,11 @@ import {
|
|
|
22
23
|
* **`asChild` prop.** Pass `asChild` to render the consumer's own element as
|
|
23
24
|
* the container, with the `data-status` hook merged in.
|
|
24
25
|
*/
|
|
25
|
-
function AvatarRoot({
|
|
26
|
+
export function AvatarRoot({
|
|
27
|
+
asChild = false,
|
|
28
|
+
children,
|
|
29
|
+
...rest
|
|
30
|
+
}: AvatarRootProps): ReactElement {
|
|
26
31
|
const [status, setStatus] = useState<AvatarImageLoadingStatus>("idle");
|
|
27
32
|
|
|
28
33
|
const contextValue = useMemo(() => ({ status, setStatus }), [status]);
|
|
@@ -40,6 +45,7 @@ function AvatarRoot({ asChild = false, children, ...rest }: AvatarRootProps) {
|
|
|
40
45
|
);
|
|
41
46
|
}
|
|
42
47
|
|
|
48
|
+
/** @internal */
|
|
43
49
|
AvatarRoot.displayName = "AvatarRoot";
|
|
44
50
|
|
|
45
51
|
/**
|
|
@@ -55,7 +61,11 @@ AvatarRoot.displayName = "AvatarRoot";
|
|
|
55
61
|
*
|
|
56
62
|
* @throws if rendered outside an `Avatar.Root`.
|
|
57
63
|
*/
|
|
58
|
-
function AvatarImage({
|
|
64
|
+
export function AvatarImage({
|
|
65
|
+
asChild = false,
|
|
66
|
+
children,
|
|
67
|
+
...rest
|
|
68
|
+
}: AvatarImageProps): ReactElement {
|
|
59
69
|
const { status, setStatus } = useAvatarContext();
|
|
60
70
|
const { ref, onLoad, onError } = useAvatarImage(setStatus);
|
|
61
71
|
|
|
@@ -77,6 +87,7 @@ function AvatarImage({ asChild = false, children, ...rest }: AvatarImageProps) {
|
|
|
77
87
|
return <img {...imageProps} ref={ref} />;
|
|
78
88
|
}
|
|
79
89
|
|
|
90
|
+
/** @internal */
|
|
80
91
|
AvatarImage.displayName = "AvatarImage";
|
|
81
92
|
|
|
82
93
|
/**
|
|
@@ -92,12 +103,12 @@ AvatarImage.displayName = "AvatarImage";
|
|
|
92
103
|
*
|
|
93
104
|
* @throws if rendered outside an `Avatar.Root`.
|
|
94
105
|
*/
|
|
95
|
-
function AvatarFallback({
|
|
106
|
+
export function AvatarFallback({
|
|
96
107
|
delayMs,
|
|
97
108
|
asChild = false,
|
|
98
109
|
children,
|
|
99
110
|
...rest
|
|
100
|
-
}: AvatarFallbackProps) {
|
|
111
|
+
}: AvatarFallbackProps): ReactElement | null {
|
|
101
112
|
const { status } = useAvatarContext();
|
|
102
113
|
const [delayElapsed, setDelayElapsed] = useState(delayMs === undefined);
|
|
103
114
|
|
|
@@ -122,9 +133,11 @@ function AvatarFallback({
|
|
|
122
133
|
return <span {...fallbackProps}>{children}</span>;
|
|
123
134
|
}
|
|
124
135
|
|
|
136
|
+
/** @internal */
|
|
125
137
|
AvatarFallback.displayName = "AvatarFallback";
|
|
126
138
|
|
|
127
|
-
|
|
139
|
+
/** Static-property shape of the compound {@link Avatar} export: the callable {@link AvatarRoot} plus its namespaced sub-components. */
|
|
140
|
+
export type TAvatarCompound = typeof AvatarRoot & {
|
|
128
141
|
Root: typeof AvatarRoot;
|
|
129
142
|
Image: typeof AvatarImage;
|
|
130
143
|
Fallback: typeof AvatarFallback;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Context } from "react";
|
|
2
|
+
import { createStrictContext } from "../utils/index.ts";
|
|
2
3
|
|
|
3
4
|
import { AvatarImageLoadingStatus } from "./types";
|
|
4
5
|
|
|
@@ -13,8 +14,13 @@ export type AvatarContextValue = {
|
|
|
13
14
|
setStatus: (status: AvatarImageLoadingStatus) => void;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
const avatarContextPair = createStrictContext<AvatarContextValue>(
|
|
18
|
+
"Avatar.Image and Avatar.Fallback must be rendered inside an <Avatar.Root>.",
|
|
19
|
+
"AvatarContext",
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
/** React context carrying the {@link AvatarContextValue} shared by the avatar's sub-components. */
|
|
23
|
+
export const AvatarContext: Context<AvatarContextValue | null> =
|
|
24
|
+
avatarContextPair[0];
|
|
25
|
+
/** Hook returning the {@link AvatarContextValue}; throws when used outside an `<Avatar.Root>`. */
|
|
26
|
+
export const useAvatarContext: () => AvatarContextValue = avatarContextPair[1];
|