@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/src/Tooltip/types.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { ComponentProps, ReactNode } from "react";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Context published by {@link Tooltip.Provider} — the shared open / skip
|
|
5
|
+
* delays and the group-wide open coordination callbacks used to suppress
|
|
6
|
+
* the open delay while another tooltip in the group is already showing.
|
|
7
|
+
*/
|
|
3
8
|
export type TooltipProviderContextValue = {
|
|
4
9
|
delayDuration: number;
|
|
5
10
|
skipDelayDuration: number;
|
|
@@ -8,6 +13,11 @@ export type TooltipProviderContextValue = {
|
|
|
8
13
|
onCloseGlobally: () => void;
|
|
9
14
|
};
|
|
10
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Context published by {@link Tooltip.Root} to its descendants — the live
|
|
18
|
+
* `open` state, the content `id` for ARIA wiring, and the timing callbacks
|
|
19
|
+
* the trigger and content use to open / close with the correct delays.
|
|
20
|
+
*/
|
|
11
21
|
export type TooltipContextValue = {
|
|
12
22
|
open: boolean;
|
|
13
23
|
contentId: string;
|
|
@@ -19,46 +29,84 @@ export type TooltipContextValue = {
|
|
|
19
29
|
cancelGrace: () => void;
|
|
20
30
|
};
|
|
21
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Props for {@link Tooltip.Provider} — sets the `delayDuration` and
|
|
34
|
+
* `skipDelayDuration` shared by every tooltip in the subtree.
|
|
35
|
+
*/
|
|
22
36
|
export type TooltipProviderProps = {
|
|
23
37
|
children?: ReactNode;
|
|
24
38
|
delayDuration?: number;
|
|
25
39
|
skipDelayDuration?: number;
|
|
26
40
|
};
|
|
27
41
|
|
|
28
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Uncontrolled variant of {@link TooltipRootProps}: the component owns the
|
|
44
|
+
* open state. Pass `defaultOpen` (or omit it); `onOpenChange` is optional
|
|
45
|
+
* and `open` is forbidden.
|
|
46
|
+
*/
|
|
47
|
+
export type UncontrolledTooltipRootProps = {
|
|
29
48
|
defaultOpen?: boolean;
|
|
30
49
|
open?: never;
|
|
31
50
|
onOpenChange?: (open: boolean) => void;
|
|
32
51
|
};
|
|
33
52
|
|
|
34
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Controlled variant of {@link TooltipRootProps}: the parent owns the open
|
|
55
|
+
* state. Pass `open` (with an optional `onOpenChange`); `defaultOpen` is
|
|
56
|
+
* forbidden.
|
|
57
|
+
*/
|
|
58
|
+
export type ControlledTooltipRootProps = {
|
|
35
59
|
open: boolean;
|
|
36
60
|
onOpenChange?: (open: boolean) => void;
|
|
37
61
|
defaultOpen?: never;
|
|
38
62
|
};
|
|
39
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Props for {@link Tooltip.Root}. Combines the per-tooltip timing /
|
|
66
|
+
* hoverable-content options with one of the two state modes
|
|
67
|
+
* ({@link UncontrolledTooltipRootProps} | {@link ControlledTooltipRootProps}),
|
|
68
|
+
* so TypeScript accepts exactly one mode.
|
|
69
|
+
*/
|
|
40
70
|
export type TooltipRootProps = {
|
|
41
71
|
children?: ReactNode;
|
|
42
72
|
delayDuration?: number;
|
|
43
73
|
disableHoverableContent?: boolean;
|
|
44
74
|
} & (UncontrolledTooltipRootProps | ControlledTooltipRootProps);
|
|
45
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Props for {@link Tooltip.Trigger} — all native `<button>` attributes plus
|
|
78
|
+
* the `asChild` escape hatch.
|
|
79
|
+
*/
|
|
46
80
|
export type TooltipTriggerProps = ComponentProps<"button"> & {
|
|
47
81
|
asChild?: boolean;
|
|
48
82
|
};
|
|
49
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Props for {@link Tooltip.Portal} — the `container` to render the content
|
|
86
|
+
* into (defaults to `document.body`) and `forceMount` to keep the content
|
|
87
|
+
* in the DOM while closed for exit animations.
|
|
88
|
+
*/
|
|
50
89
|
export type TooltipPortalProps = {
|
|
51
90
|
children?: ReactNode;
|
|
52
91
|
container?: HTMLElement;
|
|
53
92
|
forceMount?: boolean;
|
|
54
93
|
};
|
|
55
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Props for {@link Tooltip.Content} — all native `<div>` attributes plus
|
|
97
|
+
* `forceMount` and the dismissal callbacks fired on Escape
|
|
98
|
+
* (`onEscapeKeyDown`) and outside pointer-down (`onPointerDownOutside`).
|
|
99
|
+
*/
|
|
56
100
|
export type TooltipContentProps = ComponentProps<"div"> & {
|
|
57
101
|
forceMount?: boolean;
|
|
58
102
|
onEscapeKeyDown?: (event: KeyboardEvent) => void;
|
|
59
103
|
onPointerDownOutside?: (event: PointerEvent) => void;
|
|
60
104
|
};
|
|
61
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Props for {@link Tooltip.Arrow} — all native `<span>` attributes plus the
|
|
108
|
+
* `asChild` escape hatch.
|
|
109
|
+
*/
|
|
62
110
|
export type TooltipArrowProps = ComponentProps<"span"> & {
|
|
63
111
|
asChild?: boolean;
|
|
64
112
|
};
|
package/src/Tree/Tree.tsx
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Fragment, useLayoutEffect, useRef } from "react";
|
|
2
|
+
import type { ReactElement } from "react";
|
|
2
3
|
|
|
3
|
-
import { Breadcrumb } from "../Breadcrumb";
|
|
4
|
-
import { Slot, composeEventHandlers } from "../Slot";
|
|
5
|
-
import { deriveId } from "../utils";
|
|
4
|
+
import { Breadcrumb } from "../Breadcrumb/index.ts";
|
|
5
|
+
import { Slot, composeEventHandlers } from "../Slot/index.ts";
|
|
6
|
+
import { deriveId } from "../utils/index.ts";
|
|
6
7
|
|
|
7
8
|
import {
|
|
8
9
|
TreeContext,
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
useTreeItemKeyboard,
|
|
17
18
|
useTreeRoot,
|
|
18
19
|
useTreeSelectionPaths,
|
|
19
|
-
} from "./hooks";
|
|
20
|
+
} from "./hooks/index.ts";
|
|
20
21
|
import { partitionBranchChildren } from "./utils";
|
|
21
22
|
|
|
22
23
|
import type {
|
|
@@ -63,7 +64,7 @@ import type {
|
|
|
63
64
|
* </Tree.Root>
|
|
64
65
|
* ```
|
|
65
66
|
*/
|
|
66
|
-
export function TreeRoot(props: TreeRootProps) {
|
|
67
|
+
export function TreeRoot(props: TreeRootProps): ReactElement {
|
|
67
68
|
const {
|
|
68
69
|
children,
|
|
69
70
|
expandedValues,
|
|
@@ -115,6 +116,7 @@ export function TreeRoot(props: TreeRootProps) {
|
|
|
115
116
|
);
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
/** @internal */
|
|
118
120
|
TreeRoot.displayName = "TreeRoot";
|
|
119
121
|
|
|
120
122
|
/**
|
|
@@ -141,7 +143,7 @@ export function TreeItem({
|
|
|
141
143
|
onFocus,
|
|
142
144
|
onKeyDown,
|
|
143
145
|
...rest
|
|
144
|
-
}: TreeItemProps) {
|
|
146
|
+
}: TreeItemProps): ReactElement {
|
|
145
147
|
const { depth, parentValue } = useTreeLevelContext();
|
|
146
148
|
const { isSelected, select, registerNode, tabStop, setActiveValue } =
|
|
147
149
|
useTreeContext();
|
|
@@ -200,6 +202,7 @@ export function TreeItem({
|
|
|
200
202
|
);
|
|
201
203
|
}
|
|
202
204
|
|
|
205
|
+
/** @internal */
|
|
203
206
|
TreeItem.displayName = "TreeItem";
|
|
204
207
|
|
|
205
208
|
/**
|
|
@@ -235,7 +238,7 @@ export function TreeBranch({
|
|
|
235
238
|
onFocus,
|
|
236
239
|
onKeyDown,
|
|
237
240
|
...rest
|
|
238
|
-
}: TreeBranchProps) {
|
|
241
|
+
}: TreeBranchProps): ReactElement {
|
|
239
242
|
const { depth, parentValue } = useTreeLevelContext();
|
|
240
243
|
const {
|
|
241
244
|
rootId,
|
|
@@ -300,6 +303,7 @@ export function TreeBranch({
|
|
|
300
303
|
);
|
|
301
304
|
}
|
|
302
305
|
|
|
306
|
+
/** @internal */
|
|
303
307
|
TreeBranch.displayName = "TreeBranch";
|
|
304
308
|
|
|
305
309
|
/**
|
|
@@ -321,7 +325,7 @@ export function TreeBranchControl({
|
|
|
321
325
|
children,
|
|
322
326
|
onClick,
|
|
323
327
|
...rest
|
|
324
|
-
}: TreeBranchControlProps) {
|
|
328
|
+
}: TreeBranchControlProps): ReactElement {
|
|
325
329
|
const { value, disabled, controlId } = useTreeItemContext();
|
|
326
330
|
const { toggleExpanded, select } = useTreeContext();
|
|
327
331
|
|
|
@@ -348,6 +352,7 @@ export function TreeBranchControl({
|
|
|
348
352
|
);
|
|
349
353
|
}
|
|
350
354
|
|
|
355
|
+
/** @internal */
|
|
351
356
|
TreeBranchControl.displayName = "TreeBranchControl";
|
|
352
357
|
|
|
353
358
|
/**
|
|
@@ -363,7 +368,7 @@ export function TreeBranchContent({
|
|
|
363
368
|
children,
|
|
364
369
|
forceMount = false,
|
|
365
370
|
...rest
|
|
366
|
-
}: TreeBranchContentProps) {
|
|
371
|
+
}: TreeBranchContentProps): ReactElement {
|
|
367
372
|
const { depth } = useTreeLevelContext();
|
|
368
373
|
const { value: branchValue, expanded } = useTreeItemContext();
|
|
369
374
|
|
|
@@ -384,6 +389,7 @@ export function TreeBranchContent({
|
|
|
384
389
|
);
|
|
385
390
|
}
|
|
386
391
|
|
|
392
|
+
/** @internal */
|
|
387
393
|
TreeBranchContent.displayName = "TreeBranchContent";
|
|
388
394
|
|
|
389
395
|
/**
|
|
@@ -413,7 +419,7 @@ export function TreeBranchIndicator({
|
|
|
413
419
|
children,
|
|
414
420
|
asChild = false,
|
|
415
421
|
...rest
|
|
416
|
-
}: TreeBranchIndicatorProps) {
|
|
422
|
+
}: TreeBranchIndicatorProps): ReactElement {
|
|
417
423
|
const { expanded } = useTreeItemContext();
|
|
418
424
|
|
|
419
425
|
const indicatorProps = {
|
|
@@ -429,6 +435,7 @@ export function TreeBranchIndicator({
|
|
|
429
435
|
);
|
|
430
436
|
}
|
|
431
437
|
|
|
438
|
+
/** @internal */
|
|
432
439
|
TreeBranchIndicator.displayName = "TreeBranchIndicator";
|
|
433
440
|
|
|
434
441
|
/**
|
|
@@ -483,7 +490,7 @@ export function TreeSelectionPath({
|
|
|
483
490
|
children,
|
|
484
491
|
separator,
|
|
485
492
|
...rest
|
|
486
|
-
}: TreeSelectionPathProps) {
|
|
493
|
+
}: TreeSelectionPathProps): ReactElement {
|
|
487
494
|
const paths = useTreeSelectionPaths();
|
|
488
495
|
const empty = paths.length === 0;
|
|
489
496
|
|
|
@@ -544,9 +551,14 @@ export function TreeSelectionPath({
|
|
|
544
551
|
);
|
|
545
552
|
}
|
|
546
553
|
|
|
554
|
+
/** @internal */
|
|
547
555
|
TreeSelectionPath.displayName = "TreeSelectionPath";
|
|
548
556
|
|
|
549
|
-
|
|
557
|
+
/**
|
|
558
|
+
* The shape of the exported `Tree` value — callable as `Tree.Root` and
|
|
559
|
+
* carrying every sub-component as a static property.
|
|
560
|
+
*/
|
|
561
|
+
export type TreeCompound = typeof TreeRoot & {
|
|
550
562
|
Root: typeof TreeRoot;
|
|
551
563
|
Item: typeof TreeItem;
|
|
552
564
|
Branch: typeof TreeBranch;
|
|
@@ -556,6 +568,39 @@ type TreeCompound = typeof TreeRoot & {
|
|
|
556
568
|
SelectionPath: typeof TreeSelectionPath;
|
|
557
569
|
};
|
|
558
570
|
|
|
571
|
+
/**
|
|
572
|
+
* Headless, accessible **Tree** — a compound component implementing the
|
|
573
|
+
* WAI-ARIA tree view pattern (`role="tree"` / `treeitem` / `group`) with
|
|
574
|
+
* roving tabindex, single or multiple selection, and expandable branches,
|
|
575
|
+
* with zero styles.
|
|
576
|
+
*
|
|
577
|
+
* `Tree` is both callable (an alias of {@link TreeRoot | `Tree.Root`}) and
|
|
578
|
+
* carries its sub-components as static properties:
|
|
579
|
+
*
|
|
580
|
+
* - {@link TreeRoot | `Tree.Root`} — state owner, context provider, `role="tree"`.
|
|
581
|
+
* - {@link TreeItem | `Tree.Item`} — a leaf `role="treeitem"`.
|
|
582
|
+
* - {@link TreeBranch | `Tree.Branch`} — an expandable `role="treeitem"` with children.
|
|
583
|
+
* - {@link TreeBranchControl | `Tree.BranchControl`} — the branch's selectable / toggling control.
|
|
584
|
+
* - {@link TreeBranchContent | `Tree.BranchContent`} — the collapsible `role="group"` of child nodes.
|
|
585
|
+
* - {@link TreeBranchIndicator | `Tree.BranchIndicator`} — expand/collapse affordance.
|
|
586
|
+
* - {@link TreeSelectionPath | `Tree.SelectionPath`} — breadcrumb of the selected node's ancestry.
|
|
587
|
+
*
|
|
588
|
+
* @example
|
|
589
|
+
* ```tsx
|
|
590
|
+
* import { Tree } from "@primitiv-ui/react";
|
|
591
|
+
*
|
|
592
|
+
* <Tree.Root>
|
|
593
|
+
* <Tree.Branch value="src">
|
|
594
|
+
* <Tree.BranchControl>
|
|
595
|
+
* src <Tree.BranchIndicator />
|
|
596
|
+
* </Tree.BranchControl>
|
|
597
|
+
* <Tree.BranchContent>
|
|
598
|
+
* <Tree.Item value="index">index.ts</Tree.Item>
|
|
599
|
+
* </Tree.BranchContent>
|
|
600
|
+
* </Tree.Branch>
|
|
601
|
+
* </Tree.Root>;
|
|
602
|
+
* ```
|
|
603
|
+
*/
|
|
559
604
|
const TreeCompound: TreeCompound = Object.assign(TreeRoot, {
|
|
560
605
|
Root: TreeRoot,
|
|
561
606
|
Item: TreeItem,
|
|
@@ -566,6 +611,7 @@ const TreeCompound: TreeCompound = Object.assign(TreeRoot, {
|
|
|
566
611
|
SelectionPath: TreeSelectionPath,
|
|
567
612
|
});
|
|
568
613
|
|
|
614
|
+
/** @internal */
|
|
569
615
|
TreeCompound.displayName = "Tree";
|
|
570
616
|
|
|
571
617
|
export { TreeCompound as Tree };
|
package/src/Tree/TreeContext.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { useState } from "react";
|
|
|
3
3
|
import { render, screen, within } from "@testing-library/react";
|
|
4
4
|
import userEvent from "@testing-library/user-event";
|
|
5
5
|
|
|
6
|
-
import { Tree, useTreePath, useTreeSelectionPaths } from "../../Tree";
|
|
7
|
-
import type { TreePathSegment } from "../../Tree";
|
|
6
|
+
import { Tree, useTreePath, useTreeSelectionPaths } from "../../Tree/index.ts";
|
|
7
|
+
import type { TreePathSegment } from "../../Tree/index.ts";
|
|
8
8
|
|
|
9
9
|
function PathProbe({ value }: { value: string }) {
|
|
10
10
|
const path = useTreePath(value);
|
package/src/Tree/index.ts
CHANGED
package/src/Tree/types.ts
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
import type { ComponentProps, ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/** Mode-independent props shared by every `Tree.Root` variant. */
|
|
4
|
+
export type TreeRootBaseProps = ComponentProps<"div"> & {
|
|
4
5
|
children: ReactNode;
|
|
5
6
|
};
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
/** Uncontrolled expansion — initial expanded branches via `defaultExpandedValues`. */
|
|
9
|
+
export type TreeRootUncontrolledExpansionProps = {
|
|
8
10
|
/** Branch values expanded on first render when uncontrolled. */
|
|
9
11
|
defaultExpandedValues?: string[];
|
|
10
12
|
expandedValues?: never;
|
|
11
13
|
onExpandedChange?: (values: string[]) => void;
|
|
12
14
|
};
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
/** Controlled expansion — the expanded set is owned by the consumer. */
|
|
17
|
+
export type TreeRootControlledExpansionProps = {
|
|
15
18
|
defaultExpandedValues?: never;
|
|
16
19
|
/** The set of expanded branch values, owned by the consumer. */
|
|
17
20
|
expandedValues: string[];
|
|
18
21
|
onExpandedChange: (values: string[]) => void;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
/** Single-selection mode, uncontrolled — initial value via `defaultSelectedValue`. */
|
|
25
|
+
export type TreeRootSingleUncontrolledSelectionProps = {
|
|
22
26
|
selectionMode?: "single";
|
|
23
27
|
/** The value selected on first render when uncontrolled. */
|
|
24
28
|
defaultSelectedValue?: string | null;
|
|
@@ -29,7 +33,8 @@ type TreeRootSingleUncontrolledSelectionProps = {
|
|
|
29
33
|
onSelectedValuesChange?: never;
|
|
30
34
|
};
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
/** Single-selection mode, controlled — the selected value is owned by the consumer. */
|
|
37
|
+
export type TreeRootSingleControlledSelectionProps = {
|
|
33
38
|
selectionMode?: "single";
|
|
34
39
|
defaultSelectedValue?: never;
|
|
35
40
|
/** The selected value, owned by the consumer. */
|
|
@@ -40,7 +45,8 @@ type TreeRootSingleControlledSelectionProps = {
|
|
|
40
45
|
onSelectedValuesChange?: never;
|
|
41
46
|
};
|
|
42
47
|
|
|
43
|
-
|
|
48
|
+
/** Multiple-selection mode, uncontrolled — initial values via `defaultSelectedValues`. */
|
|
49
|
+
export type TreeRootMultipleUncontrolledSelectionProps = {
|
|
44
50
|
selectionMode: "multiple";
|
|
45
51
|
/** The values selected on first render when uncontrolled. */
|
|
46
52
|
defaultSelectedValues?: string[];
|
|
@@ -51,7 +57,8 @@ type TreeRootMultipleUncontrolledSelectionProps = {
|
|
|
51
57
|
onSelectedValueChange?: never;
|
|
52
58
|
};
|
|
53
59
|
|
|
54
|
-
|
|
60
|
+
/** Multiple-selection mode, controlled — the selected values are owned by the consumer. */
|
|
61
|
+
export type TreeRootMultipleControlledSelectionProps = {
|
|
55
62
|
selectionMode: "multiple";
|
|
56
63
|
defaultSelectedValues?: never;
|
|
57
64
|
/** The selected values, owned by the consumer. */
|
|
@@ -62,6 +69,12 @@ type TreeRootMultipleControlledSelectionProps = {
|
|
|
62
69
|
onSelectedValueChange?: never;
|
|
63
70
|
};
|
|
64
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Props for `Tree.Root`. Combines the shared {@link TreeRootBaseProps} with
|
|
74
|
+
* one expansion arm (controlled / uncontrolled) and one selection arm
|
|
75
|
+
* (single / multiple, controlled / uncontrolled), so the relevant
|
|
76
|
+
* `value` / `defaultValue` / `onChange` shape is enforced per mode.
|
|
77
|
+
*/
|
|
65
78
|
export type TreeRootProps = TreeRootBaseProps &
|
|
66
79
|
(TreeRootUncontrolledExpansionProps | TreeRootControlledExpansionProps) &
|
|
67
80
|
(
|
|
@@ -71,6 +84,7 @@ export type TreeRootProps = TreeRootBaseProps &
|
|
|
71
84
|
| TreeRootMultipleControlledSelectionProps
|
|
72
85
|
);
|
|
73
86
|
|
|
87
|
+
/** Props for `Tree.Item` — a selectable, focusable leaf treeitem. */
|
|
74
88
|
export type TreeItemProps = ComponentProps<"div"> & {
|
|
75
89
|
/** Stable identifier for this item, unique within the tree. */
|
|
76
90
|
value: string;
|
|
@@ -88,6 +102,7 @@ export type TreeItemProps = ComponentProps<"div"> & {
|
|
|
88
102
|
children: ReactNode;
|
|
89
103
|
};
|
|
90
104
|
|
|
105
|
+
/** Props for `Tree.Branch` — an expandable treeitem with nested children. */
|
|
91
106
|
export type TreeBranchProps = Omit<ComponentProps<"div">, "ref"> & {
|
|
92
107
|
/** Stable identifier for this branch, unique within the tree. */
|
|
93
108
|
value: string;
|
|
@@ -106,12 +121,14 @@ export type TreeBranchProps = Omit<ComponentProps<"div">, "ref"> & {
|
|
|
106
121
|
children: ReactNode;
|
|
107
122
|
};
|
|
108
123
|
|
|
124
|
+
/** Props for `Tree.BranchControl` — the branch's selectable, toggling control row. */
|
|
109
125
|
export type TreeBranchControlProps = ComponentProps<"div"> & {
|
|
110
126
|
/** Render the control as the supplied child element instead of `<div>`. */
|
|
111
127
|
asChild?: boolean;
|
|
112
128
|
children: ReactNode;
|
|
113
129
|
};
|
|
114
130
|
|
|
131
|
+
/** Props for `Tree.BranchContent` — the collapsible group of a branch's child nodes. */
|
|
115
132
|
export type TreeBranchContentProps = ComponentProps<"div"> & {
|
|
116
133
|
children: ReactNode;
|
|
117
134
|
/**
|
|
@@ -122,6 +139,7 @@ export type TreeBranchContentProps = ComponentProps<"div"> & {
|
|
|
122
139
|
forceMount?: boolean;
|
|
123
140
|
};
|
|
124
141
|
|
|
142
|
+
/** Props for `Tree.BranchIndicator` — the expand/collapse affordance. */
|
|
125
143
|
export type TreeBranchIndicatorProps = ComponentProps<"span"> & {
|
|
126
144
|
/** Render as the supplied child element instead of `<span>`. */
|
|
127
145
|
asChild?: boolean;
|
|
@@ -133,6 +151,10 @@ export type TreeSelectionPathRenderProps = {
|
|
|
133
151
|
paths: TreePathSegment[][];
|
|
134
152
|
};
|
|
135
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Props for `Tree.SelectionPath` — a breadcrumb of the selected node's
|
|
156
|
+
* root-to-leaf ancestry, with an optional render-prop for custom layout.
|
|
157
|
+
*/
|
|
136
158
|
export type TreeSelectionPathProps = Omit<ComponentProps<"div">, "children"> & {
|
|
137
159
|
/**
|
|
138
160
|
* Either standard React children (ignored — the subcomponent does its
|
|
@@ -147,6 +169,7 @@ export type TreeSelectionPathProps = Omit<ComponentProps<"div">, "children"> & {
|
|
|
147
169
|
separator?: ReactNode;
|
|
148
170
|
};
|
|
149
171
|
|
|
172
|
+
/** Per-level context — the nesting depth and enclosing branch value, shared down each subtree. */
|
|
150
173
|
export type TreeLevelContextValue = {
|
|
151
174
|
/** Zero-based nesting depth — `0` for items directly inside `Tree.Root`. */
|
|
152
175
|
depth: number;
|
|
@@ -154,6 +177,7 @@ export type TreeLevelContextValue = {
|
|
|
154
177
|
parentValue: string | null;
|
|
155
178
|
};
|
|
156
179
|
|
|
180
|
+
/** Registry entry for one tree node — its value, element, and structural metadata. */
|
|
157
181
|
export type TreeNodeMeta = {
|
|
158
182
|
value: string;
|
|
159
183
|
element: HTMLElement;
|
|
@@ -177,14 +201,21 @@ export type TreePathSegment = {
|
|
|
177
201
|
depth: number;
|
|
178
202
|
};
|
|
179
203
|
|
|
204
|
+
/** Whether the tree allows one selected node (`"single"`) or many (`"multiple"`). */
|
|
180
205
|
export type SelectionMode = "single" | "multiple";
|
|
181
206
|
|
|
207
|
+
/** Keyboard/pointer modifiers that influence a selection gesture. */
|
|
182
208
|
export type TreeSelectModifiers = {
|
|
183
209
|
meta: boolean;
|
|
184
210
|
ctrl: boolean;
|
|
185
211
|
shift: boolean;
|
|
186
212
|
};
|
|
187
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Context shared from `Tree.Root` to every descendant — selection and
|
|
216
|
+
* expansion state, the node registry, roving-tabindex bookkeeping, and the
|
|
217
|
+
* path resolver.
|
|
218
|
+
*/
|
|
188
219
|
export type TreeContextValue = {
|
|
189
220
|
/** Stable id shared across the tree, used to derive ARIA wiring ids. */
|
|
190
221
|
rootId: string;
|
|
@@ -215,6 +246,7 @@ export type TreeContextValue = {
|
|
|
215
246
|
selectedOrder: readonly string[];
|
|
216
247
|
};
|
|
217
248
|
|
|
249
|
+
/** Context a branch shares with its own control and content — its value, expanded/disabled state, and control id. */
|
|
218
250
|
export type TreeItemContextValue = {
|
|
219
251
|
value: string;
|
|
220
252
|
expanded: boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CSSProperties } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import type { ReactElement } from "react";
|
|
3
|
+
import { Slot } from "../Slot/index.ts";
|
|
3
4
|
import { VisuallyHiddenProps } from "./types";
|
|
4
5
|
|
|
5
6
|
const visuallyHiddenStyle: CSSProperties = {
|
|
@@ -51,7 +52,7 @@ export function VisuallyHidden({
|
|
|
51
52
|
children,
|
|
52
53
|
style,
|
|
53
54
|
...rest
|
|
54
|
-
}: VisuallyHiddenProps) {
|
|
55
|
+
}: VisuallyHiddenProps): ReactElement {
|
|
55
56
|
const rootProps = {
|
|
56
57
|
...rest,
|
|
57
58
|
style: { ...visuallyHiddenStyle, ...style },
|
|
@@ -64,4 +65,5 @@ export function VisuallyHidden({
|
|
|
64
65
|
return <span {...rootProps}>{children}</span>;
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
/** @internal */
|
|
67
69
|
VisuallyHidden.displayName = "VisuallyHidden";
|
package/src/index.ts
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
1
|
-
export * from "./AccessibleIcon";
|
|
2
|
-
export * from "./Accordion";
|
|
3
|
-
export * from "./Alert";
|
|
4
|
-
export * from "./Avatar";
|
|
5
|
-
export * from "./Breadcrumb";
|
|
6
|
-
export * from "./Button";
|
|
7
|
-
export * from "./Carousel";
|
|
8
|
-
export * from "./Checkbox";
|
|
9
|
-
export * from "./CheckboxCard";
|
|
10
|
-
export * from "./Collapsible";
|
|
11
|
-
export * from "./ContextMenu";
|
|
12
|
-
export * from "./DirectionProvider";
|
|
13
|
-
export * from "./Divider";
|
|
14
|
-
export * from "./Dropdown";
|
|
15
|
-
export * from "./EmptyState";
|
|
16
|
-
export * from "./Field";
|
|
17
|
-
export * from "./Fieldset";
|
|
18
|
-
export * from "./Input";
|
|
19
|
-
export * from "./InputGroup";
|
|
20
|
-
export * from "./MillerColumns";
|
|
21
|
-
export * from "./Modal";
|
|
22
|
-
export * from "./Portal";
|
|
23
|
-
export * from "./Progress";
|
|
24
|
-
export * from "./RadioCard";
|
|
25
|
-
export * from "./RadioGroup";
|
|
26
|
-
export * from "./Select";
|
|
27
|
-
export * from "./SkipNav";
|
|
28
|
-
export * from "./Slider";
|
|
29
|
-
export * from "./Status";
|
|
30
|
-
export * from "./Switch";
|
|
31
|
-
export * from "./Table";
|
|
32
|
-
export * from "./Tabs";
|
|
33
|
-
export * from "./Textarea";
|
|
34
|
-
export * from "./Toggle";
|
|
35
|
-
export * from "./ToggleGroup";
|
|
36
|
-
export * from "./Tooltip";
|
|
37
|
-
export * from "./Tree";
|
|
38
|
-
export * from "./VisuallyHidden";
|
|
1
|
+
export * from "./AccessibleIcon/index.ts";
|
|
2
|
+
export * from "./Accordion/index.ts";
|
|
3
|
+
export * from "./Alert/index.ts";
|
|
4
|
+
export * from "./Avatar/index.ts";
|
|
5
|
+
export * from "./Breadcrumb/index.ts";
|
|
6
|
+
export * from "./Button/index.ts";
|
|
7
|
+
export * from "./Carousel/index.ts";
|
|
8
|
+
export * from "./Checkbox/index.ts";
|
|
9
|
+
export * from "./CheckboxCard/index.ts";
|
|
10
|
+
export * from "./Collapsible/index.ts";
|
|
11
|
+
export * from "./ContextMenu/index.ts";
|
|
12
|
+
export * from "./DirectionProvider/index.ts";
|
|
13
|
+
export * from "./Divider/index.ts";
|
|
14
|
+
export * from "./Dropdown/index.ts";
|
|
15
|
+
export * from "./EmptyState/index.ts";
|
|
16
|
+
export * from "./Field/index.ts";
|
|
17
|
+
export * from "./Fieldset/index.ts";
|
|
18
|
+
export * from "./Input/index.ts";
|
|
19
|
+
export * from "./InputGroup/index.ts";
|
|
20
|
+
export * from "./MillerColumns/index.ts";
|
|
21
|
+
export * from "./Modal/index.ts";
|
|
22
|
+
export * from "./Portal/index.ts";
|
|
23
|
+
export * from "./Progress/index.ts";
|
|
24
|
+
export * from "./RadioCard/index.ts";
|
|
25
|
+
export * from "./RadioGroup/index.ts";
|
|
26
|
+
export * from "./Select/index.ts";
|
|
27
|
+
export * from "./SkipNav/index.ts";
|
|
28
|
+
export * from "./Slider/index.ts";
|
|
29
|
+
export * from "./Status/index.ts";
|
|
30
|
+
export * from "./Switch/index.ts";
|
|
31
|
+
export * from "./Table/index.ts";
|
|
32
|
+
export * from "./Tabs/index.ts";
|
|
33
|
+
export * from "./Textarea/index.ts";
|
|
34
|
+
export * from "./Toggle/index.ts";
|
|
35
|
+
export * from "./ToggleGroup/index.ts";
|
|
36
|
+
export * from "./Tooltip/index.ts";
|
|
37
|
+
export * from "./Tree/index.ts";
|
|
38
|
+
export * from "./VisuallyHidden/index.ts";
|
|
39
|
+
export type { HeadingLevel } from "./types.ts";
|
package/src/types.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type PossibleRef<T> = Ref<T> | undefined;
|
|
|
8
8
|
|
|
9
9
|
export type AnyProps = Record<string, unknown>;
|
|
10
10
|
|
|
11
|
+
/** A heading level, `1`–`6`, mapped to an `<h1>`–`<h6>` element. */
|
|
11
12
|
export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
12
13
|
|
|
13
14
|
export type HeadingTag = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
|
@@ -20,11 +20,15 @@ import { createContext, useContext, type Context } from "react";
|
|
|
20
20
|
* ```ts
|
|
21
21
|
* type FooContextValue = { count: number };
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
23
|
+
* // JSR rejects array-destructured exports as a "slow type", so bind the
|
|
24
|
+
* // pair locally and re-export each half with an explicit type:
|
|
25
|
+
* const fooContext = createStrictContext<FooContextValue>(
|
|
26
|
+
* "Foo sub-components must be rendered inside <Foo.Root>.",
|
|
27
|
+
* "FooContext",
|
|
28
|
+
* );
|
|
29
|
+
*
|
|
30
|
+
* export const FooContext: Context<FooContextValue | null> = fooContext[0];
|
|
31
|
+
* export const useFooContext: () => FooContextValue = fooContext[1];
|
|
28
32
|
* ```
|
|
29
33
|
*/
|
|
30
34
|
export function createStrictContext<T>(
|