@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
|
@@ -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 { RadioGroup } from "../RadioGroup";
|
|
6
6
|
|
|
7
7
|
describe("RadioGroup reading direction", () => {
|
package/src/RadioGroup/index.ts
CHANGED
package/src/RadioGroup/types.ts
CHANGED
|
@@ -10,7 +10,12 @@ export type RadioGroupOrientation = "horizontal" | "vertical" | "both";
|
|
|
10
10
|
/** Reading direction — swaps the horizontal arrow pair when `"rtl"`. */
|
|
11
11
|
export type RadioGroupReadingDirection = "ltr" | "rtl";
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Shared base for both {@link RadioGroupRootProps} variants — the native
|
|
15
|
+
* `<div>` attributes (minus `role`) plus the `asChild` escape hatch,
|
|
16
|
+
* orientation, reading direction, and a typed `ref`.
|
|
17
|
+
*/
|
|
18
|
+
export type RadioGroupRootBaseProps = Omit<ComponentProps<"div">, "role"> & {
|
|
14
19
|
children?: ReactNode;
|
|
15
20
|
ref?: Ref<HTMLDivElement>;
|
|
16
21
|
asChild?: boolean;
|
|
@@ -18,22 +23,43 @@ type RadioGroupRootBaseProps = Omit<ComponentProps<"div">, "role"> & {
|
|
|
18
23
|
dir?: RadioGroupReadingDirection;
|
|
19
24
|
};
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Uncontrolled variant of {@link RadioGroupRootProps}: the component owns
|
|
28
|
+
* the selected value. Pass `defaultValue` (or omit it); `onValueChange` is
|
|
29
|
+
* optional and `value` is forbidden.
|
|
30
|
+
*/
|
|
31
|
+
export type RadioGroupRootUncontrolledProps = RadioGroupRootBaseProps & {
|
|
22
32
|
defaultValue?: string;
|
|
23
33
|
value?: never;
|
|
24
34
|
onValueChange?: (value: string) => void;
|
|
25
35
|
};
|
|
26
36
|
|
|
27
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Controlled variant of {@link RadioGroupRootProps}: the parent owns the
|
|
39
|
+
* selected value. Pass `value` and `onValueChange` together; `defaultValue`
|
|
40
|
+
* is forbidden.
|
|
41
|
+
*/
|
|
42
|
+
export type RadioGroupRootControlledProps = RadioGroupRootBaseProps & {
|
|
28
43
|
defaultValue?: never;
|
|
29
44
|
value: string;
|
|
30
45
|
onValueChange: (value: string) => void;
|
|
31
46
|
};
|
|
32
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Props for {@link RadioGroup.Root}. A discriminated union of
|
|
50
|
+
* {@link RadioGroupRootUncontrolledProps} and
|
|
51
|
+
* {@link RadioGroupRootControlledProps}, so TypeScript accepts exactly one
|
|
52
|
+
* state mode.
|
|
53
|
+
*/
|
|
33
54
|
export type RadioGroupRootProps =
|
|
34
55
|
| RadioGroupRootUncontrolledProps
|
|
35
56
|
| RadioGroupRootControlledProps;
|
|
36
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Props for {@link RadioGroup.Item} — the radio button. `value` identifies
|
|
60
|
+
* the option; all native `<button>` attributes (minus the component-owned
|
|
61
|
+
* ones) plus the `asChild` escape hatch and a typed `ref` are passed through.
|
|
62
|
+
*/
|
|
37
63
|
export type RadioGroupItemProps = Omit<
|
|
38
64
|
ComponentProps<"button">,
|
|
39
65
|
"type" | "role" | "aria-checked" | "value"
|
|
@@ -44,6 +70,11 @@ export type RadioGroupItemProps = Omit<
|
|
|
44
70
|
asChild?: boolean;
|
|
45
71
|
};
|
|
46
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Props for {@link RadioGroup.Indicator} — all `<span>` attributes plus
|
|
75
|
+
* `forceMount` (keep mounted while unselected for exit animations) and the
|
|
76
|
+
* `asChild` escape hatch.
|
|
77
|
+
*/
|
|
47
78
|
export type RadioGroupIndicatorProps = ComponentProps<"span"> & {
|
|
48
79
|
children?: ReactNode;
|
|
49
80
|
forceMount?: boolean;
|
package/src/Select/Select.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ChangeEvent, Children, isValidElement, ReactNode } from "react";
|
|
2
|
+
import type { ReactElement } from "react";
|
|
2
3
|
|
|
3
|
-
import { useFieldProps } from "../Field/hooks";
|
|
4
|
-
import { Slot } from "../Slot";
|
|
4
|
+
import { useFieldProps } from "../Field/hooks/index.ts";
|
|
5
|
+
import { Slot } from "../Slot/index.ts";
|
|
5
6
|
|
|
6
7
|
import {
|
|
7
8
|
SelectGroupProps,
|
|
@@ -51,7 +52,7 @@ function hasPlaceholderChild(children: ReactNode): boolean {
|
|
|
51
52
|
* ids first, then field-supplied description / error ids). Outside a
|
|
52
53
|
* `<Field.Root>`, behaviour is unchanged.
|
|
53
54
|
*/
|
|
54
|
-
function SelectRoot({
|
|
55
|
+
export function SelectRoot({
|
|
55
56
|
children,
|
|
56
57
|
asChild = false,
|
|
57
58
|
onChange,
|
|
@@ -59,7 +60,7 @@ function SelectRoot({
|
|
|
59
60
|
value,
|
|
60
61
|
defaultValue,
|
|
61
62
|
...consumer
|
|
62
|
-
}: SelectRootProps) {
|
|
63
|
+
}: SelectRootProps): ReactElement {
|
|
63
64
|
const merged = useFieldProps(consumer);
|
|
64
65
|
|
|
65
66
|
const handleChange = (event: ChangeEvent<HTMLSelectElement>) => {
|
|
@@ -95,6 +96,7 @@ function SelectRoot({
|
|
|
95
96
|
return <select {...rootProps}>{children}</select>;
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
/** @internal */
|
|
98
100
|
SelectRoot.displayName = "SelectRoot";
|
|
99
101
|
|
|
100
102
|
/**
|
|
@@ -104,10 +106,14 @@ SelectRoot.displayName = "SelectRoot";
|
|
|
104
106
|
* Native `<option>` only renders text; rich content (icons, descriptions)
|
|
105
107
|
* is not supported.
|
|
106
108
|
*/
|
|
107
|
-
function SelectOption({
|
|
109
|
+
export function SelectOption({
|
|
110
|
+
children,
|
|
111
|
+
...rest
|
|
112
|
+
}: SelectOptionProps): ReactElement {
|
|
108
113
|
return <option {...rest}>{children}</option>;
|
|
109
114
|
}
|
|
110
115
|
|
|
116
|
+
/** @internal */
|
|
111
117
|
SelectOption.displayName = "SelectOption";
|
|
112
118
|
|
|
113
119
|
/**
|
|
@@ -115,10 +121,14 @@ SelectOption.displayName = "SelectOption";
|
|
|
115
121
|
* native `<optgroup>` element. The `label` is shown by the browser as a
|
|
116
122
|
* non-selectable heading and is announced as the group's accessible name.
|
|
117
123
|
*/
|
|
118
|
-
function SelectGroup({
|
|
124
|
+
export function SelectGroup({
|
|
125
|
+
children,
|
|
126
|
+
...rest
|
|
127
|
+
}: SelectGroupProps): ReactElement {
|
|
119
128
|
return <optgroup {...rest}>{children}</optgroup>;
|
|
120
129
|
}
|
|
121
130
|
|
|
131
|
+
/** @internal */
|
|
122
132
|
SelectGroup.displayName = "SelectGroup";
|
|
123
133
|
|
|
124
134
|
/**
|
|
@@ -131,7 +141,10 @@ SelectGroup.displayName = "SelectGroup";
|
|
|
131
141
|
* Pair with `required` on {@link Select.Root} to make the browser's
|
|
132
142
|
* native form validation catch an unchosen value at submission.
|
|
133
143
|
*/
|
|
134
|
-
function SelectPlaceholder({
|
|
144
|
+
export function SelectPlaceholder({
|
|
145
|
+
children,
|
|
146
|
+
...rest
|
|
147
|
+
}: SelectPlaceholderProps): ReactElement {
|
|
135
148
|
return (
|
|
136
149
|
<option {...rest} value="" disabled hidden>
|
|
137
150
|
{children}
|
|
@@ -139,9 +152,11 @@ function SelectPlaceholder({ children, ...rest }: SelectPlaceholderProps) {
|
|
|
139
152
|
);
|
|
140
153
|
}
|
|
141
154
|
|
|
155
|
+
/** @internal */
|
|
142
156
|
SelectPlaceholder.displayName = "SelectPlaceholder";
|
|
143
157
|
|
|
144
|
-
|
|
158
|
+
/** Type of the {@link Select} compound: the root callable plus its attached sub-components. */
|
|
159
|
+
export type TSelectCompound = typeof SelectRoot & {
|
|
145
160
|
Root: typeof SelectRoot;
|
|
146
161
|
Option: typeof SelectOption;
|
|
147
162
|
Group: typeof SelectGroup;
|
package/src/Select/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from "./Select";
|
|
2
2
|
export * from "./types";
|
package/src/Select/types.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ChangeEventHandler, ComponentProps, ReactNode, Ref } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Shared base for both {@link SelectRootProps} variants — the native
|
|
5
|
+
* `<select>` attributes (minus the state-owning ones), the `asChild`
|
|
6
|
+
* escape hatch, and the raw `onChange` passthrough.
|
|
7
|
+
*/
|
|
8
|
+
export type SelectRootBaseProps = Omit<
|
|
4
9
|
ComponentProps<"select">,
|
|
5
10
|
"value" | "defaultValue" | "multiple" | "onChange"
|
|
6
11
|
> & {
|
|
@@ -22,13 +27,23 @@ type SelectRootBaseProps = Omit<
|
|
|
22
27
|
asChild?: boolean;
|
|
23
28
|
};
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Uncontrolled variant of {@link SelectRootProps}: the browser owns the
|
|
32
|
+
* selection. Pass `defaultValue` (or omit it); `onValueChange` is optional
|
|
33
|
+
* and `value` is forbidden.
|
|
34
|
+
*/
|
|
35
|
+
export type SelectRootUncontrolledProps = SelectRootBaseProps & {
|
|
26
36
|
defaultValue?: string;
|
|
27
37
|
value?: never;
|
|
28
38
|
onValueChange?: (value: string) => void;
|
|
29
39
|
};
|
|
30
40
|
|
|
31
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Controlled variant of {@link SelectRootProps}: the parent owns the
|
|
43
|
+
* selection. Pass `value` and `onValueChange` together; `defaultValue` is
|
|
44
|
+
* forbidden.
|
|
45
|
+
*/
|
|
46
|
+
export type SelectRootControlledProps = SelectRootBaseProps & {
|
|
32
47
|
defaultValue?: never;
|
|
33
48
|
value: string;
|
|
34
49
|
onValueChange: (value: string) => void;
|
package/src/SkipNav/SkipNav.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
|
|
1
3
|
import { SkipNavContentProps, SkipNavLinkProps } from "./types";
|
|
2
4
|
|
|
3
5
|
const DEFAULT_CONTENT_ID = "primitiv-skip-nav";
|
|
@@ -34,7 +36,7 @@ function SkipNavLink({
|
|
|
34
36
|
children,
|
|
35
37
|
contentId = DEFAULT_CONTENT_ID,
|
|
36
38
|
...rest
|
|
37
|
-
}: SkipNavLinkProps) {
|
|
39
|
+
}: SkipNavLinkProps): ReactElement {
|
|
38
40
|
return (
|
|
39
41
|
<a href={`#${contentId}`} {...rest}>
|
|
40
42
|
{children}
|
|
@@ -63,7 +65,10 @@ SkipNavLink.displayName = "SkipNavLink";
|
|
|
63
65
|
* </SkipNav.Content>
|
|
64
66
|
* ```
|
|
65
67
|
*/
|
|
66
|
-
function SkipNavContent({
|
|
68
|
+
function SkipNavContent({
|
|
69
|
+
children,
|
|
70
|
+
...rest
|
|
71
|
+
}: SkipNavContentProps): ReactElement {
|
|
67
72
|
return (
|
|
68
73
|
<div id={DEFAULT_CONTENT_ID} tabIndex={-1} {...rest}>
|
|
69
74
|
{children}
|
package/src/Slider/Slider.tsx
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
|
|
3
|
+
import { useDirection } from "../DirectionProvider/index.ts";
|
|
4
|
+
import { Slot, composeEventHandlers, composeRefs } from "../Slot/index.ts";
|
|
3
5
|
|
|
4
6
|
import { SliderContext } from "./SliderContext";
|
|
5
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
useSliderContext,
|
|
9
|
+
useSliderRoot,
|
|
10
|
+
useSliderThumb,
|
|
11
|
+
} from "./hooks/index.ts";
|
|
6
12
|
import type {
|
|
7
13
|
SliderRangeProps,
|
|
8
14
|
SliderRootProps,
|
|
@@ -68,7 +74,7 @@ import { getRangeStyle } from "./utils";
|
|
|
68
74
|
* </Slider.Root>
|
|
69
75
|
* ```
|
|
70
76
|
*/
|
|
71
|
-
function SliderRoot({
|
|
77
|
+
export function SliderRoot({
|
|
72
78
|
min = 0,
|
|
73
79
|
max = 100,
|
|
74
80
|
step = 1,
|
|
@@ -87,7 +93,7 @@ function SliderRoot({
|
|
|
87
93
|
ref,
|
|
88
94
|
children,
|
|
89
95
|
...rest
|
|
90
|
-
}: SliderRootProps) {
|
|
96
|
+
}: SliderRootProps): ReactElement {
|
|
91
97
|
const resolvedDir = dir ?? useDirection();
|
|
92
98
|
const {
|
|
93
99
|
contextValue,
|
|
@@ -136,6 +142,7 @@ function SliderRoot({
|
|
|
136
142
|
);
|
|
137
143
|
}
|
|
138
144
|
|
|
145
|
+
/** @internal */
|
|
139
146
|
SliderRoot.displayName = "SliderRoot";
|
|
140
147
|
|
|
141
148
|
/**
|
|
@@ -147,7 +154,11 @@ SliderRoot.displayName = "SliderRoot";
|
|
|
147
154
|
*
|
|
148
155
|
* @throws if rendered outside a `Slider.Root`.
|
|
149
156
|
*/
|
|
150
|
-
function SliderTrack({
|
|
157
|
+
export function SliderTrack({
|
|
158
|
+
children,
|
|
159
|
+
asChild = false,
|
|
160
|
+
...rest
|
|
161
|
+
}: SliderTrackProps): ReactElement {
|
|
151
162
|
const { orientation, disabled } = useSliderContext();
|
|
152
163
|
const trackProps = {
|
|
153
164
|
...rest,
|
|
@@ -161,6 +172,7 @@ function SliderTrack({ children, asChild = false, ...rest }: SliderTrackProps) {
|
|
|
161
172
|
);
|
|
162
173
|
}
|
|
163
174
|
|
|
175
|
+
/** @internal */
|
|
164
176
|
SliderTrack.displayName = "SliderTrack";
|
|
165
177
|
|
|
166
178
|
/**
|
|
@@ -173,12 +185,12 @@ SliderTrack.displayName = "SliderTrack";
|
|
|
173
185
|
*
|
|
174
186
|
* @throws if rendered outside a `Slider.Root`.
|
|
175
187
|
*/
|
|
176
|
-
function SliderRange({
|
|
188
|
+
export function SliderRange({
|
|
177
189
|
style,
|
|
178
190
|
asChild = false,
|
|
179
191
|
children,
|
|
180
192
|
...rest
|
|
181
|
-
}: SliderRangeProps) {
|
|
193
|
+
}: SliderRangeProps): ReactElement {
|
|
182
194
|
const { values, min, max, orientation, dir, inverted, disabled } =
|
|
183
195
|
useSliderContext();
|
|
184
196
|
const rangeProps = {
|
|
@@ -197,6 +209,7 @@ function SliderRange({
|
|
|
197
209
|
);
|
|
198
210
|
}
|
|
199
211
|
|
|
212
|
+
/** @internal */
|
|
200
213
|
SliderRange.displayName = "SliderRange";
|
|
201
214
|
|
|
202
215
|
/**
|
|
@@ -220,14 +233,14 @@ SliderRange.displayName = "SliderRange";
|
|
|
220
233
|
*
|
|
221
234
|
* @throws if rendered outside a `Slider.Root`.
|
|
222
235
|
*/
|
|
223
|
-
function SliderThumb({
|
|
236
|
+
export function SliderThumb({
|
|
224
237
|
style,
|
|
225
238
|
ref: forwardedRef,
|
|
226
239
|
onKeyDown,
|
|
227
240
|
asChild = false,
|
|
228
241
|
children,
|
|
229
242
|
...rest
|
|
230
|
-
}: SliderThumbProps) {
|
|
243
|
+
}: SliderThumbProps): ReactElement {
|
|
231
244
|
const {
|
|
232
245
|
ref,
|
|
233
246
|
value,
|
|
@@ -260,9 +273,11 @@ function SliderThumb({
|
|
|
260
273
|
);
|
|
261
274
|
}
|
|
262
275
|
|
|
276
|
+
/** @internal */
|
|
263
277
|
SliderThumb.displayName = "SliderThumb";
|
|
264
278
|
|
|
265
|
-
|
|
279
|
+
/** Static-property shape of the compound {@link Slider} export: the callable {@link SliderRoot} plus its namespaced sub-components. */
|
|
280
|
+
export type TSliderCompound = typeof SliderRoot & {
|
|
266
281
|
Root: typeof SliderRoot;
|
|
267
282
|
Track: typeof SliderTrack;
|
|
268
283
|
Range: typeof SliderRange;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Context } from "react";
|
|
2
|
+
import { createStrictContext } from "../utils/index.ts";
|
|
2
3
|
|
|
3
4
|
import type { SliderDirection, SliderOrientation } from "./types";
|
|
4
5
|
|
|
6
|
+
/** Shared state published by `Slider.Root` to its sub-components: the current values, range/step bounds, orientation and direction, thumb registration, and value-commit callbacks. */
|
|
5
7
|
export type SliderContextValue = {
|
|
6
8
|
values: number[];
|
|
7
9
|
min: number;
|
|
@@ -17,8 +19,13 @@ export type SliderContextValue = {
|
|
|
17
19
|
commit: (values: number[]) => void;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
const sliderContextPair = createStrictContext<SliderContextValue>(
|
|
23
|
+
"Slider sub-components must be rendered inside a <Slider.Root>.",
|
|
24
|
+
"SliderContext",
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
/** React context carrying the {@link SliderContextValue} shared by the slider's sub-components. */
|
|
28
|
+
export const SliderContext: Context<SliderContextValue | null> =
|
|
29
|
+
sliderContextPair[0];
|
|
30
|
+
/** Hook returning the {@link SliderContextValue}; throws when used outside a `<Slider.Root>`. */
|
|
31
|
+
export const useSliderContext: () => SliderContextValue = sliderContextPair[1];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fireEvent, 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 { Slider } from "../Slider";
|
|
6
6
|
|
|
7
7
|
import { rtlKeyboardCases } from "./Slider.fixtures";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
2
2
|
import type { PointerEvent as ReactPointerEvent } from "react";
|
|
3
3
|
|
|
4
|
-
import { useCollection, useControllableState } from "../../hooks";
|
|
4
|
+
import { useCollection, useControllableState } from "../../hooks/index.ts";
|
|
5
5
|
import type { SliderContextValue } from "../SliderContext";
|
|
6
6
|
import type { SliderDirection, SliderOrientation } from "../types";
|
|
7
7
|
import { clamp, getClosestThumbIndex, getPointerValue } from "../utils";
|
package/src/Slider/types.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ComponentProps } from "react";
|
|
2
2
|
|
|
3
|
+
/** Layout axis of the slider track. */
|
|
3
4
|
export type SliderOrientation = "horizontal" | "vertical";
|
|
5
|
+
/** Reading direction of the slider, affecting which end is the minimum. */
|
|
4
6
|
export type SliderDirection = "ltr" | "rtl";
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
/** Props common to both controlled and uncontrolled `Slider.Root`: range/step bounds, orientation, direction, and the native `<span>` attributes. */
|
|
9
|
+
export type SliderRootSharedProps = Omit<
|
|
7
10
|
ComponentProps<"span">,
|
|
8
11
|
"defaultValue" | "dir"
|
|
9
12
|
> & {
|
|
@@ -19,30 +22,36 @@ type SliderRootSharedProps = Omit<
|
|
|
19
22
|
asChild?: boolean;
|
|
20
23
|
};
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
/** Uncontrolled `Slider.Root` props: seed with `defaultValue`; `value` is disallowed. */
|
|
26
|
+
export type SliderRootUncontrolledProps = SliderRootSharedProps & {
|
|
23
27
|
defaultValue?: number[];
|
|
24
28
|
value?: never;
|
|
25
29
|
onValueChange?: (value: number[]) => void;
|
|
26
30
|
onValueCommit?: (value: number[]) => void;
|
|
27
31
|
};
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
/** Controlled `Slider.Root` props: drive with `value`; `defaultValue` is disallowed. */
|
|
34
|
+
export type SliderRootControlledProps = SliderRootSharedProps & {
|
|
30
35
|
defaultValue?: never;
|
|
31
36
|
value: number[];
|
|
32
37
|
onValueChange?: (value: number[]) => void;
|
|
33
38
|
onValueCommit?: (value: number[]) => void;
|
|
34
39
|
};
|
|
35
40
|
|
|
41
|
+
/** Props for `Slider.Root` — the discriminated union of controlled ({@link SliderRootControlledProps}) and uncontrolled ({@link SliderRootUncontrolledProps}) modes. */
|
|
36
42
|
export type SliderRootProps =
|
|
37
43
|
| SliderRootUncontrolledProps
|
|
38
44
|
| SliderRootControlledProps;
|
|
39
45
|
|
|
46
|
+
/** Props for `Slider.Track` — the full-length rail; native `<span>` props plus `asChild`. */
|
|
40
47
|
export type SliderTrackProps = ComponentProps<"span"> & {
|
|
41
48
|
asChild?: boolean;
|
|
42
49
|
};
|
|
50
|
+
/** Props for `Slider.Range` — the filled segment between the minimum and the active thumb; native `<span>` props plus `asChild`. */
|
|
43
51
|
export type SliderRangeProps = ComponentProps<"span"> & {
|
|
44
52
|
asChild?: boolean;
|
|
45
53
|
};
|
|
54
|
+
/** Props for `Slider.Thumb` — a draggable handle; native `<span>` props plus `asChild`. */
|
|
46
55
|
export type SliderThumbProps = ComponentProps<"span"> & {
|
|
47
56
|
asChild?: boolean;
|
|
48
57
|
};
|
package/src/Status/Status.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 { StatusProps } from "./types";
|
|
3
5
|
|
|
4
6
|
/**
|
|
@@ -31,7 +33,11 @@ import { StatusProps } from "./types";
|
|
|
31
33
|
* </Status>
|
|
32
34
|
* ```
|
|
33
35
|
*/
|
|
34
|
-
export function Status({
|
|
36
|
+
export function Status({
|
|
37
|
+
asChild = false,
|
|
38
|
+
children,
|
|
39
|
+
...rest
|
|
40
|
+
}: StatusProps): ReactElement {
|
|
35
41
|
const rootProps = { role: "status", ...rest };
|
|
36
42
|
|
|
37
43
|
if (asChild) {
|
|
@@ -41,4 +47,5 @@ export function Status({ asChild = false, children, ...rest }: StatusProps) {
|
|
|
41
47
|
return <div {...rootProps}>{children}</div>;
|
|
42
48
|
}
|
|
43
49
|
|
|
50
|
+
/** @internal */
|
|
44
51
|
Status.displayName = "Status";
|
package/src/Status/types.ts
CHANGED
package/src/Switch/Switch.tsx
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
|
+
import type { ReactElement } from "react";
|
|
2
3
|
|
|
3
|
-
import { Slot, composeEventHandlers } from "../Slot";
|
|
4
|
+
import { Slot, composeEventHandlers } from "../Slot/index.ts";
|
|
4
5
|
|
|
5
6
|
import { SwitchContext } from "./SwitchContext";
|
|
6
|
-
import { useSwitchContext, useSwitchRoot } from "./hooks";
|
|
7
|
+
import { useSwitchContext, useSwitchRoot } from "./hooks/index.ts";
|
|
7
8
|
import { SwitchRootProps, SwitchThumbProps } from "./types";
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -48,7 +49,7 @@ import { SwitchRootProps, SwitchThumbProps } from "./types";
|
|
|
48
49
|
* </Switch.Root>
|
|
49
50
|
* ```
|
|
50
51
|
*/
|
|
51
|
-
function SwitchRoot({
|
|
52
|
+
export function SwitchRoot({
|
|
52
53
|
defaultChecked,
|
|
53
54
|
checked,
|
|
54
55
|
onCheckedChange,
|
|
@@ -58,7 +59,7 @@ function SwitchRoot({
|
|
|
58
59
|
children,
|
|
59
60
|
ref,
|
|
60
61
|
...rest
|
|
61
|
-
}: SwitchRootProps) {
|
|
62
|
+
}: SwitchRootProps): ReactElement {
|
|
62
63
|
const { checked: isChecked, toggle } = useSwitchRoot({
|
|
63
64
|
defaultChecked,
|
|
64
65
|
checked,
|
|
@@ -88,6 +89,7 @@ function SwitchRoot({
|
|
|
88
89
|
);
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
/** @internal */
|
|
91
93
|
SwitchRoot.displayName = "SwitchRoot";
|
|
92
94
|
|
|
93
95
|
/**
|
|
@@ -111,7 +113,11 @@ SwitchRoot.displayName = "SwitchRoot";
|
|
|
111
113
|
*
|
|
112
114
|
* @throws if rendered outside a `Switch.Root`.
|
|
113
115
|
*/
|
|
114
|
-
function SwitchThumb({
|
|
116
|
+
export function SwitchThumb({
|
|
117
|
+
children,
|
|
118
|
+
asChild = false,
|
|
119
|
+
...rest
|
|
120
|
+
}: SwitchThumbProps): ReactElement {
|
|
115
121
|
const { checked } = useSwitchContext();
|
|
116
122
|
const thumbProps = {
|
|
117
123
|
...rest,
|
|
@@ -124,10 +130,14 @@ function SwitchThumb({ children, asChild = false, ...rest }: SwitchThumbProps) {
|
|
|
124
130
|
return <span {...thumbProps}>{children}</span>;
|
|
125
131
|
}
|
|
126
132
|
|
|
133
|
+
/** @internal */
|
|
127
134
|
SwitchThumb.displayName = "SwitchThumb";
|
|
128
135
|
|
|
129
|
-
|
|
136
|
+
/** Type of the {@link Switch} compound — the Root callable plus its sub-components. */
|
|
137
|
+
export type TSwitchCompound = typeof SwitchRoot & {
|
|
138
|
+
/** The root toggle button, owning checked state and context. */
|
|
130
139
|
Root: typeof SwitchRoot;
|
|
140
|
+
/** The sliding thumb indicator. */
|
|
131
141
|
Thumb: typeof SwitchThumb;
|
|
132
142
|
};
|
|
133
143
|
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Context } from "react";
|
|
2
|
+
import { createStrictContext } from "../utils/index.ts";
|
|
2
3
|
|
|
4
|
+
/** Value shared from `Switch.Root` to `Switch.Thumb` through context. */
|
|
3
5
|
export type SwitchContextValue = {
|
|
6
|
+
/** Whether the switch is currently checked. */
|
|
4
7
|
checked: boolean;
|
|
5
8
|
};
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const switchContextPair = createStrictContext<SwitchContextValue>(
|
|
11
|
+
"Switch.Thumb must be rendered inside a <Switch.Root>.",
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
/** React context carrying the {@link SwitchContextValue} for `Switch.Thumb`. */
|
|
15
|
+
export const SwitchContext: Context<SwitchContextValue | null> =
|
|
16
|
+
switchContextPair[0];
|
|
17
|
+
/** Read the nearest {@link SwitchContextValue}; throws outside `Switch.Root`. */
|
|
18
|
+
export const useSwitchContext: () => SwitchContextValue = switchContextPair[1];
|