@itwin/itwinui-react 5.0.0-alpha.10 → 5.0.0-alpha.12

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.
Files changed (69) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/README.md +13 -2
  3. package/dist/DEV/bricks/Checkbox.js +7 -14
  4. package/dist/DEV/bricks/Description.js +7 -14
  5. package/dist/DEV/bricks/DropdownMenu.js +58 -20
  6. package/dist/DEV/bricks/Field.internal.js +47 -0
  7. package/dist/DEV/bricks/Field.js +116 -85
  8. package/dist/DEV/bricks/Icon.js +144 -7
  9. package/dist/DEV/bricks/Label.js +4 -10
  10. package/dist/DEV/bricks/Radio.js +7 -14
  11. package/dist/DEV/bricks/Root.internal.js +17 -0
  12. package/dist/DEV/bricks/Root.js +73 -27
  13. package/dist/DEV/bricks/Select.js +9 -15
  14. package/dist/DEV/bricks/Spinner.js +23 -8
  15. package/dist/DEV/bricks/Switch.js +8 -15
  16. package/dist/DEV/bricks/Table.js +71 -37
  17. package/dist/DEV/bricks/Tabs.js +4 -29
  18. package/dist/DEV/bricks/TextBox.js +23 -37
  19. package/dist/DEV/bricks/Tooltip.js +1 -1
  20. package/dist/DEV/bricks/TreeItem.js +92 -10
  21. package/dist/DEV/bricks/index.js +3 -1
  22. package/dist/DEV/bricks/styles.css.js +1 -1
  23. package/dist/DEV/bricks/~hooks.js +3 -1
  24. package/dist/DEV/bricks/~utils.js +17 -0
  25. package/dist/DEV/foundations/styles.css.js +1 -1
  26. package/dist/bricks/Badge.d.ts +1 -1
  27. package/dist/bricks/Checkbox.d.ts +13 -5
  28. package/dist/bricks/Checkbox.js +7 -14
  29. package/dist/bricks/Description.d.ts +2 -6
  30. package/dist/bricks/Description.js +7 -14
  31. package/dist/bricks/DropdownMenu.d.ts +9 -9
  32. package/dist/bricks/DropdownMenu.js +57 -19
  33. package/dist/bricks/Field.d.ts +63 -27
  34. package/dist/bricks/Field.internal.d.ts +33 -0
  35. package/dist/bricks/Field.internal.js +47 -0
  36. package/dist/bricks/Field.js +111 -84
  37. package/dist/bricks/Icon.d.ts +12 -1
  38. package/dist/bricks/Icon.js +142 -7
  39. package/dist/bricks/Label.d.ts +5 -12
  40. package/dist/bricks/Label.js +4 -10
  41. package/dist/bricks/Radio.d.ts +14 -5
  42. package/dist/bricks/Radio.js +7 -14
  43. package/dist/bricks/Root.d.ts +12 -0
  44. package/dist/bricks/Root.internal.d.ts +6 -0
  45. package/dist/bricks/Root.internal.js +17 -0
  46. package/dist/bricks/Root.js +73 -27
  47. package/dist/bricks/Select.d.ts +29 -12
  48. package/dist/bricks/Select.js +9 -15
  49. package/dist/bricks/Spinner.js +23 -8
  50. package/dist/bricks/Switch.d.ts +12 -5
  51. package/dist/bricks/Switch.js +8 -15
  52. package/dist/bricks/Table.d.ts +94 -37
  53. package/dist/bricks/Table.js +69 -36
  54. package/dist/bricks/Tabs.d.ts +3 -4
  55. package/dist/bricks/Tabs.js +4 -29
  56. package/dist/bricks/TextBox.d.ts +42 -19
  57. package/dist/bricks/TextBox.js +23 -37
  58. package/dist/bricks/Tooltip.js +1 -1
  59. package/dist/bricks/TreeItem.d.ts +53 -9
  60. package/dist/bricks/TreeItem.js +81 -10
  61. package/dist/bricks/index.d.ts +2 -1
  62. package/dist/bricks/index.js +3 -1
  63. package/dist/bricks/styles.css.js +1 -1
  64. package/dist/bricks/~hooks.d.ts +8 -0
  65. package/dist/bricks/~hooks.js +3 -1
  66. package/dist/bricks/~utils.d.ts +8 -0
  67. package/dist/bricks/~utils.js +17 -0
  68. package/dist/foundations/styles.css.js +1 -1
  69. package/package.json +1 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,134 @@
1
+ # Changelog
2
+
3
+ ## 5.0.0-alpha.12
4
+
5
+ - **breaking**: Introduce composition API for `Field`. See [#449](https://github.com/iTwin/design-system/pull/449).
6
+ - Includes `<Field.Root>`, `<Field.Label>`, `<Field.Control>`, `<Field.Description>`.
7
+ - Added a new `<Field.ErrorMessage>` subcomponent.
8
+ - `Tree.Item`: Added automatic overflow handling for `actions`.
9
+ - **breaking**: `DropdownMenu` is no longer allowed to be passed into `actions`. See [#404](https://github.com/iTwin/design-system/pull/404).
10
+ - Added a new `Table` component, usable as `<Table.HtmlTable>` or `<Table.CustomTable>`.
11
+ - `DropdownMenu`: menuitems will now be rendered as `<button>`.
12
+ - Styling changes:
13
+ - Reset `<button>` styles.
14
+ - Added popover-open state styles to `<Button>` and `<IconButton>`.
15
+ - Improved forced-colors mode styling for `<Checkbox>`, `<Radio>` and `<Switch>`.
16
+ - Bug fixes:
17
+ - Fixed `<Select.HtmlSelect>` overflowing beyond its container.
18
+ - Fixed `<Select.HtmlSelect>` options text not appearing in Windows in certain cases.
19
+ - Added missing `border-radius` to `<Skeleton>`.
20
+
21
+ ## 5.0.0-alpha.11
22
+
23
+ - Added `error` prop to `<Tree.Item>`.
24
+ - Implemented fallback strategy for `<Icon>`, so that non-HTTP URLs are fetched at runtime.
25
+ - Added `unstable_htmlSanitizer` prop to `<Root>`.
26
+ - Added `tone="accent"` support to `<Badge>`.
27
+ - Adjusted `DropdownMenu` and `Tooltip` to be portaled by default.
28
+ - Styling changes:
29
+ - Added shimmer animation to `<Skeleton>`.
30
+ - Updated `<Spinner>` visuals and animation to match `<ProgressBar>`.
31
+ - Bug fixes:
32
+ - Fixed styles not unloading when `<Root>` is unmounted.
33
+ - Fixed `<Anchor>` underline not showing when rendered as a `<button>`.
34
+ - Fixed `<Tree.ItemAction visible>` affecting the visibility of all actions.
35
+ - Fixed vertical centering in `<Tab.TabList>`.
36
+ - Fixed `Tab` active stripe positioning and animation.
37
+ - Fixed `<Button variant="solid" tone="accent">` icon fill in pressed state.
38
+
39
+ ## 5.0.0-alpha.10
40
+
41
+ - Added initial `<Skeleton>` component.
42
+ - Added initial `<ProgressBar>` component.
43
+ - Fixed various UX and accessibility issues related to `<Tree.Item>` actions visibility.
44
+ - Actions no longer get stuck.
45
+ - Tooltips can now be hovered.
46
+ - Focus correctly returns to actions after menu closes.
47
+ - Keyboard events no longer affect the main treeitem.
48
+ - Reduced `<Field>` spacing.
49
+ - Experimental changes in `<Icon>` component's `href` handling.
50
+
51
+ ## 5.0.0-alpha.9
52
+
53
+ - Added `dot` prop to `<IconButton>` for showing a small "dot" next to the icon.
54
+ - Added `unstable_decorations` prop to `<Tree.Item>` for showing multiple decorations (e.g. icons).
55
+ - **breaking**: Replaced `<DropdownMenu.Item>` children with new `label` prop (see [#423](https://github.com/iTwin/design-system/pull/423)).
56
+ - Added `icon` prop to `<DropdownMenu.Item>` and `<DropdownMenu.CheckboxItem>`.
57
+ - Updated the `shortcuts` prop of `<DropdownMenu.Item>` to recognize predefined "symbols" (e.g. modifier keys).
58
+ - Updated `<Anchor>` and `<Badge>` visuals to match the latest design.
59
+ - Fixed forced-colors mode styling for `DropdownMenu`.
60
+
61
+ ## 5.0.0-alpha.8
62
+
63
+ - Added `description` prop to `<Tree.Item>` component for showing "sublabels".
64
+ - **breaking**: Updated `<Text>` component to require `variant` prop.
65
+ - (soft breaking) Removed `children` from `<Tree.Item>` prop types.
66
+ - Updated `DropdownMenu` padding.
67
+
68
+ ## 5.0.0-alpha.7
69
+
70
+ - Added new `<Avatar>` component.
71
+ - Added new `<Badge>` component.
72
+ - Added `alt` prop to `<Icon>` component.
73
+ - Fixed all color tokens to use the correct `oklch` values.
74
+ - Fixed an issue where `<Tree.Item>` was not respecting its `style` prop.
75
+
76
+ ## 5.0.0-alpha.6
77
+
78
+ - **breaking**: All CSS variables have been renamed to use the `--ids` prefix. See [#369](https://github.com/iTwin/kiwi/pull/369).
79
+ - **breaking**: Some CSS variables were renamed further. See [#368](https://github.com/iTwin/kiwi/pull/368).
80
+ - Notably, the "surface" backgrounds have been split into two different "page" and "elevation" scales.
81
+ - Background colors have been updated to match the latest design.
82
+ - All styles are now loaded into `@layer itwinui`. The one exception is the CSS reset which remains in `@layer reset`.
83
+ - `<Field>` now respects the order of `<Description>`s when creating associations.
84
+
85
+ ## 5.0.0-alpha.5
86
+
87
+ - **breaking**: `Tree` API has changed to require flat structure, with explicit ARIA props (see [#300](https://github.com/iTwin/kiwi/pull/300)). `<Tree.Item>` no longer allows passing `children`.
88
+ - **breaking**: `Tree.Item`s `action` prop now requires a list of `<Tree.ItemAction>` components (see [#355](https://github.com/iTwin/kiwi/pull/355) and [#362](https://github.com/iTwin/kiwi/pull/362)).
89
+ - **breaking**: Replaced `<Chip>` children with new `label` prop (see [#349](https://github.com/iTwin/kiwi/pull/349)).
90
+ - Added `<Tree.ItemAction>` component with `visible` prop for more granular control over action visibility.
91
+ - Updated the layout of `<Field>` so that `<Description>` is placed in the best spot according on the label position and control type.
92
+ - `<Field>` now considers the presence of explicit control `id`s when creating associations.
93
+
94
+ ## 5.0.0-alpha.4
95
+
96
+ - Added `onDismiss` prop and dismiss button to `<Chip>`.
97
+ - Fixed a rare issue where `TextBox` was still editable when `disabled`.
98
+ - Fixed "forced colors" mode styling for `<Button>` and `<IconButton>`.
99
+ - Explicitly set typography styles on `<Root>` to improve compatibility with iTwinUI theme bridge.
100
+ - Updated `DropdownMenu` visuals.
101
+
102
+ ## 5.0.0-alpha.3
103
+
104
+ - Added `<DropdownMenu.CheckboxItem>` component for rendering menu items with a checkable state.
105
+ - Added `variant` prop to `<Select.HtmlSelect>` component for displaying different visual variants of the component.
106
+ - Updated event handling of `Tree` components to avoid firing `onClick` event of the `<Tree.Item>` component when the expander or one of the actions is clicked.
107
+ - Updated `Tree` components to implement a tree view pattern instead of the previously used nested list approach.
108
+ - Updated size and spacing of `<Tree.Item>`, `<DropdownMenu.Item>` and `<Select>` components.
109
+ - Fixed `<Label>` component alignment with `TextBox` components.
110
+ - Fixed action rendering of `<Tree.Item>` component.
111
+ - Fixed `<Checkbox>` component styling, which caused the mixed checkbox to be displayed as unchecked in the light theme.
112
+
113
+ ## 5.0.0-alpha.2
114
+
115
+ - Added initial `Tree` component, exposed as `<Tree.Root>` and `<Tree.Item>` subcomponents.
116
+ - Added initial `<Spinner>` component for indicating quick, indeterminate progress.
117
+ - Added `<Description>` component to be used within a `<Field>`.
118
+ - Added initial `<Chip>` component.
119
+ - Added `symbol` prop to `<Kbd>` for displaying predefined symbols.
120
+ - Added `focusable` prop to `<Tabs.TabPanel>` component.
121
+ - Fixed a visual issue where light color-scheme was using dark shadows.
122
+
123
+ ## 5.0.0-alpha.1
124
+
125
+ - Added `<Text>` component with a `variant` prop to support all text styles from Figma.
126
+ - Added `Select` component built on top of the HTML `<select>` element. Exposed as `<Select.Root>` and `<Select.HtmlSelect>`.
127
+ - Added `shortcuts` prop to `<DropdownMenu.Item>`.
128
+ - Added JSDoc comments to all components for inline IDE hints.
129
+ - Fixed `<Kbd>` component using the wrong font.
130
+ - Fixed some visual issues.
131
+
132
+ ## 5.0.0-alpha.0
133
+
134
+ Initial release 🥳
package/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # @itwin/itwinui-react
2
2
 
3
- A React component library for the next evolution of the iTwinUI design system.
3
+ A React component library for the [next evolution of the iTwinUI design system](https://github.com/iTwin/design-system/discussions/481).
4
+
5
+ ## Installation
6
+
7
+ Using your package manager of choice, install the latest **alpha** version of [`@itwin/itwinui-react`](https://www.npmjs.com/package/@itwin/itwinui-react?activeTab=versions).
8
+
9
+ ```console
10
+ npm add @itwin/itwinui-react@alpha
11
+ ```
4
12
 
5
13
  ## Usage
6
14
 
@@ -20,7 +28,10 @@ export function App() {
20
28
 
21
29
  This will ensure iTwinUI's styles are loaded to either the document or the encompassing shadow root.
22
30
 
23
- Once that’s in place you can import and use components from `@itwin/itwinui-react/bricks`.
31
+ Once that’s in place, you can import and use components from `@itwin/itwinui-react/bricks`.
32
+
33
+ > [!NOTE]
34
+ > If you are trying to use this package alongside the current stable version of iTwinUI, you will need to set up the [iTwinUI theme bridge](https://github.com/iTwin/iTwinUI/wiki/iTwinUI-v5-theme-bridge).
24
35
 
25
36
  ## Contributing
26
37
 
@@ -3,25 +3,18 @@ import cx from "classnames";
3
3
  import {
4
4
  Checkbox as AkCheckbox
5
5
  } from "@ariakit/react/checkbox";
6
- import { FieldControl } from "./Field.js";
7
6
  import { forwardRef } from "./~utils.js";
7
+ import { useFieldControlType } from "./Field.internal.js";
8
8
  const Checkbox = forwardRef(
9
9
  (props, forwardedRef) => {
10
- const { id, ...rest } = props;
10
+ useFieldControlType("checkable");
11
11
  return /* @__PURE__ */ jsx(
12
- FieldControl,
12
+ AkCheckbox,
13
13
  {
14
- type: "checkable",
15
- id,
16
- render: /* @__PURE__ */ jsx(
17
- AkCheckbox,
18
- {
19
- accessibleWhenDisabled: true,
20
- ...rest,
21
- className: cx("\u{1F95D}-checkbox", props.className),
22
- ref: forwardedRef
23
- }
24
- )
14
+ accessibleWhenDisabled: true,
15
+ ...props,
16
+ className: cx("\u{1F95D}-checkbox", props.className),
17
+ ref: forwardedRef
25
18
  }
26
19
  );
27
20
  }
@@ -2,24 +2,17 @@ import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "./~utils.js";
3
3
  import cx from "classnames";
4
4
  import { Text } from "./Text.js";
5
- import { FieldDescription } from "./Field.js";
6
5
  const Description = forwardRef(
7
6
  (props, forwardedRef) => {
8
- const { id, tone, ...rest } = props;
7
+ const { tone, ...rest } = props;
9
8
  return /* @__PURE__ */ jsx(
10
- FieldDescription,
9
+ Text,
11
10
  {
12
- id,
13
- render: /* @__PURE__ */ jsx(
14
- Text,
15
- {
16
- ...rest,
17
- variant: "caption-md",
18
- "data-kiwi-tone": tone ?? "neutral",
19
- className: cx("\u{1F95D}-description", props.className),
20
- ref: forwardedRef
21
- }
22
- )
11
+ ...rest,
12
+ variant: "caption-md",
13
+ "data-kiwi-tone": tone ?? "neutral",
14
+ className: cx("\u{1F95D}-description", props.className),
15
+ ref: forwardedRef
23
16
  }
24
17
  );
25
18
  }
@@ -3,6 +3,7 @@ import * as React from "react";
3
3
  import cx from "classnames";
4
4
  import * as ListItem from "./~utils.ListItem.js";
5
5
  import { Button } from "./Button.js";
6
+ import { Button as ButtonAk } from "@ariakit/react/button";
6
7
  import { Kbd } from "./Kbd.js";
7
8
  import { Checkmark, DisclosureArrow, Icon } from "./Icon.js";
8
9
  import {
@@ -19,7 +20,8 @@ import {
19
20
  } from "@ariakit/react/menu";
20
21
  import { useStoreState } from "@ariakit/react/store";
21
22
  import { predefinedSymbols } from "./Kbd.internal.js";
22
- function DropdownMenu(props) {
23
+ import { usePopoverContext } from "@ariakit/react/popover";
24
+ function DropdownMenuRoot(props) {
23
25
  const {
24
26
  children,
25
27
  placement,
@@ -34,18 +36,19 @@ function DropdownMenu(props) {
34
36
  defaultOpen: defaultOpenProp,
35
37
  open: openProp,
36
38
  setOpen: setOpenProp,
39
+ popover: usePopoverContext(),
37
40
  children
38
41
  }
39
42
  );
40
43
  }
41
- DEV: DropdownMenu.displayName = "DropdownMenu.Root";
44
+ DEV: DropdownMenuRoot.displayName = "DropdownMenu.Root";
42
45
  const DropdownMenuContent = forwardRef(
43
46
  (props, forwardedRef) => {
44
47
  const popover = usePopoverApi(useMenuContext());
45
48
  return /* @__PURE__ */ jsx(
46
49
  Menu,
47
50
  {
48
- portal: popover.portal,
51
+ portal: true,
49
52
  unmountOnHide: true,
50
53
  ...props,
51
54
  gutter: 4,
@@ -86,13 +89,23 @@ const DropdownMenuItem = forwardRef(
86
89
  MenuItem,
87
90
  {
88
91
  accessibleWhenDisabled: true,
89
- ...rest,
90
- render: /* @__PURE__ */ jsx(ListItem.Root, { render: props.render }),
91
- className: cx("\u{1F95D}-dropdown-menu-item", props.className),
92
- ref: forwardedRef,
92
+ render: /* @__PURE__ */ jsx(
93
+ ListItem.Root,
94
+ {
95
+ render: /* @__PURE__ */ jsx(
96
+ ButtonAk,
97
+ {
98
+ accessibleWhenDisabled: true,
99
+ ...rest,
100
+ className: cx("\u{1F95D}-dropdown-menu-item", props.className),
101
+ ref: forwardedRef
102
+ }
103
+ )
104
+ }
105
+ ),
93
106
  children: [
94
107
  icon ? /* @__PURE__ */ jsx(DropdownMenuIcon, { icon }) : null,
95
- /* @__PURE__ */ jsx(ListItem.Content, { children: label }),
108
+ /* @__PURE__ */ jsx(ListItem.Content, { render: /* @__PURE__ */ jsx("span", {}), children: label }),
96
109
  shortcuts ? /* @__PURE__ */ jsx(DropdownMenuItemShortcuts, { shortcuts }) : null
97
110
  ]
98
111
  }
@@ -111,6 +124,7 @@ const DropdownMenuItemShortcuts = forwardRef((props, forwardedRef) => {
111
124
  return /* @__PURE__ */ jsx(
112
125
  ListItem.Decoration,
113
126
  {
127
+ render: /* @__PURE__ */ jsx("span", {}),
114
128
  ...rest,
115
129
  className: cx("\u{1F95D}-dropdown-menu-item-shortcuts", props.className),
116
130
  ref: forwardedRef,
@@ -141,30 +155,54 @@ const DropdownMenuIcon = forwardRef(
141
155
  Icon,
142
156
  {
143
157
  href: typeof icon === "string" ? icon : void 0,
144
- render: React.isValidElement(icon) ? icon : void 0
158
+ render: React.isValidElement(icon) ? icon : void 0,
159
+ ...rest,
160
+ ref: forwardedRef
145
161
  }
146
- ),
147
- ...rest,
148
- ref: forwardedRef
162
+ )
149
163
  }
150
164
  );
151
165
  }
152
166
  );
153
167
  DEV: DropdownMenuIcon.displayName = "DropdownMenuIcon";
154
168
  const DropdownMenuCheckboxItem = forwardRef((props, forwardedRef) => {
155
- const { label, icon, ...rest } = props;
169
+ const {
170
+ label,
171
+ icon,
172
+ defaultChecked,
173
+ checked,
174
+ onChange,
175
+ name,
176
+ value = defaultChecked ? "on" : void 0,
177
+ // For defaultChecked to work
178
+ ...rest
179
+ } = props;
156
180
  return /* @__PURE__ */ jsxs(
157
181
  MenuItemCheckbox,
158
182
  {
159
183
  accessibleWhenDisabled: true,
160
- value: props.defaultChecked ? "on" : void 0,
161
- ...rest,
162
- render: /* @__PURE__ */ jsx(ListItem.Root, { render: props.render }),
163
- className: cx("\u{1F95D}-dropdown-menu-item", props.className),
164
- ref: forwardedRef,
184
+ defaultChecked,
185
+ checked,
186
+ name,
187
+ value,
188
+ onChange,
189
+ render: /* @__PURE__ */ jsx(
190
+ ListItem.Root,
191
+ {
192
+ render: /* @__PURE__ */ jsx(
193
+ ButtonAk,
194
+ {
195
+ accessibleWhenDisabled: true,
196
+ ...rest,
197
+ className: cx("\u{1F95D}-dropdown-menu-item", props.className),
198
+ ref: forwardedRef
199
+ }
200
+ )
201
+ }
202
+ ),
165
203
  children: [
166
204
  icon ? /* @__PURE__ */ jsx(DropdownMenuIcon, { icon }) : null,
167
- /* @__PURE__ */ jsx(ListItem.Content, { children: label }),
205
+ /* @__PURE__ */ jsx(ListItem.Content, { render: /* @__PURE__ */ jsx("span", {}), children: label }),
168
206
  /* @__PURE__ */ jsx(
169
207
  ListItem.Decoration,
170
208
  {
@@ -181,5 +219,5 @@ export {
181
219
  DropdownMenuCheckboxItem as CheckboxItem,
182
220
  DropdownMenuContent as Content,
183
221
  DropdownMenuItem as Item,
184
- DropdownMenu as Root
222
+ DropdownMenuRoot as Root
185
223
  };
@@ -0,0 +1,47 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import {
4
+ useCollectionStore,
5
+ Collection
6
+ } from "@ariakit/react/collection";
7
+ import { useStoreState } from "@ariakit/react/store";
8
+ function FieldCollection(props) {
9
+ const fieldElementCollection = useCollectionStore({
10
+ defaultItems: []
11
+ });
12
+ const renderedItems = useStoreState(fieldElementCollection, "renderedItems");
13
+ const [controlType, controlIndex] = React.useMemo(() => {
14
+ const controlIndex2 = renderedItems.findIndex(
15
+ (item) => item.elementType === "control"
16
+ );
17
+ return [renderedItems[controlIndex2]?.controlType, controlIndex2];
18
+ }, [renderedItems]);
19
+ const labelPlacement = React.useMemo(() => {
20
+ const labelIndex = renderedItems.findIndex(
21
+ (item) => item.elementType === "label"
22
+ );
23
+ if (controlIndex === -1 || labelIndex === -1) return;
24
+ return labelIndex < controlIndex ? "before" : "after";
25
+ }, [renderedItems, controlIndex]);
26
+ return /* @__PURE__ */ jsx(
27
+ Collection,
28
+ {
29
+ ...props,
30
+ store: fieldElementCollection,
31
+ "data-kiwi-label-placement": labelPlacement,
32
+ "data-kiwi-control-type": controlType
33
+ }
34
+ );
35
+ }
36
+ const FieldControlTypeContext = React.createContext(void 0);
37
+ function useFieldControlType(controlType) {
38
+ const setControlType = React.useContext(FieldControlTypeContext);
39
+ React.useEffect(() => {
40
+ setControlType?.(controlType);
41
+ }, [controlType, setControlType]);
42
+ }
43
+ export {
44
+ FieldCollection,
45
+ FieldControlTypeContext,
46
+ useFieldControlType
47
+ };
@@ -3,14 +3,18 @@ import * as React from "react";
3
3
  import cx from "classnames";
4
4
  import { Role } from "@ariakit/react/role";
5
5
  import {
6
- useCollectionStore,
7
- Collection,
8
6
  useCollectionContext,
9
7
  CollectionItem
10
8
  } from "@ariakit/react/collection";
11
9
  import { useStoreState } from "@ariakit/react/store";
12
10
  import { forwardRef } from "./~utils.js";
13
- const Field = forwardRef((props, forwardedRef) => {
11
+ import {
12
+ FieldCollection,
13
+ FieldControlTypeContext
14
+ } from "./Field.internal.js";
15
+ import { Label } from "./Label.js";
16
+ import { Description } from "./Description.js";
17
+ const FieldRoot = forwardRef((props, forwardedRef) => {
14
18
  const { layout, ...rest } = props;
15
19
  return /* @__PURE__ */ jsx(
16
20
  FieldCollection,
@@ -27,76 +31,42 @@ const Field = forwardRef((props, forwardedRef) => {
27
31
  }
28
32
  );
29
33
  });
30
- DEV: Field.displayName = "Field";
31
- function FieldCollection(props) {
32
- const fieldElementCollection = useCollectionStore({
33
- defaultItems: []
34
- });
35
- const renderedItems = useStoreState(fieldElementCollection, "renderedItems");
36
- const [controlType, controlIndex] = React.useMemo(() => {
37
- const controlIndex2 = renderedItems.findIndex(
38
- (item) => item.elementType === "control"
34
+ DEV: FieldRoot.displayName = "Field";
35
+ const FieldLabel = forwardRef(
36
+ (props, forwardedRef) => {
37
+ const store = useCollectionContext();
38
+ const renderedItems = useStoreState(store, "renderedItems");
39
+ const fieldId = React.useMemo(
40
+ () => renderedItems?.find(
41
+ (item) => item.elementType === "control"
42
+ )?.id,
43
+ [renderedItems]
39
44
  );
40
- return [renderedItems[controlIndex2]?.controlType, controlIndex2];
41
- }, [renderedItems]);
42
- const labelPlacement = React.useMemo(() => {
43
- const labelIndex = renderedItems.findIndex(
44
- (item) => item.elementType === "label"
45
+ const getData = React.useCallback(
46
+ (data) => ({
47
+ ...data,
48
+ elementType: "label"
49
+ }),
50
+ []
45
51
  );
46
- if (controlIndex === -1 || labelIndex === -1) return;
47
- return labelIndex < controlIndex ? "before" : "after";
48
- }, [renderedItems, controlIndex]);
49
- return /* @__PURE__ */ jsx(
50
- Collection,
51
- {
52
- ...props,
53
- store: fieldElementCollection,
54
- "data-kiwi-label-placement": labelPlacement,
55
- "data-kiwi-control-type": controlType
56
- }
57
- );
58
- }
59
- function FieldControl(props) {
60
- const store = useCollectionContext();
52
+ return /* @__PURE__ */ jsx(
53
+ CollectionItem,
54
+ {
55
+ getItem: getData,
56
+ render: /* @__PURE__ */ jsx(Label, { ...props, htmlFor: fieldId }),
57
+ ref: forwardedRef
58
+ }
59
+ );
60
+ }
61
+ );
62
+ DEV: FieldLabel.displayName = "Field.Label";
63
+ const FieldDescription = forwardRef((props, forwardedRef) => {
61
64
  const generatedId = React.useId();
62
- const { id = store ? generatedId : void 0, type, ...rest } = props;
63
- const renderedItems = useStoreState(store, "renderedItems");
64
- const describedBy = React.useMemo(() => {
65
- const idRefList = renderedItems?.filter(
66
- (item) => item.elementType === "description"
67
- )?.map((item) => item.id).join(" ");
68
- return idRefList || void 0;
69
- }, [renderedItems]);
70
- const getData = React.useCallback(
71
- (data) => ({
72
- ...data,
73
- elementType: "control",
74
- controlType: type
75
- }),
76
- [type]
77
- );
78
- return /* @__PURE__ */ jsx(
79
- CollectionItem,
80
- {
81
- id,
82
- getItem: getData,
83
- render: /* @__PURE__ */ jsx(Role, { ...rest, "aria-describedby": describedBy })
84
- }
85
- );
86
- }
87
- function FieldLabel(props) {
88
- const store = useCollectionContext();
89
- const renderedItems = useStoreState(store, "renderedItems");
90
- const fieldId = React.useMemo(
91
- () => renderedItems?.find(
92
- (item) => item.elementType === "control"
93
- )?.id,
94
- [renderedItems]
95
- );
65
+ const { id = generatedId, ...rest } = props;
96
66
  const getData = React.useCallback(
97
67
  (data) => ({
98
68
  ...data,
99
- elementType: "label"
69
+ elementType: "description"
100
70
  }),
101
71
  []
102
72
  );
@@ -104,25 +74,86 @@ function FieldLabel(props) {
104
74
  CollectionItem,
105
75
  {
106
76
  getItem: getData,
107
- render: /* @__PURE__ */ jsx(Role.label, { ...props, htmlFor: fieldId })
77
+ id,
78
+ render: /* @__PURE__ */ jsx(Description, { ...rest }),
79
+ ref: forwardedRef
108
80
  }
109
81
  );
110
- }
111
- function FieldDescription(props) {
112
- const generatedId = React.useId();
113
- const { id = generatedId, ...rest } = props;
114
- const getData = React.useCallback(
115
- (data) => ({
116
- ...data,
117
- elementType: "description"
118
- }),
119
- []
120
- );
121
- return /* @__PURE__ */ jsx(CollectionItem, { ...rest, id, getItem: getData });
122
- }
82
+ });
83
+ DEV: FieldDescription.displayName = "Field.Description";
84
+ const FieldControl = forwardRef(
85
+ (props, forwardedRef) => {
86
+ const [controlType, setControlType] = React.useState();
87
+ const store = useCollectionContext();
88
+ const generatedId = React.useId();
89
+ const { id = store ? generatedId : void 0, ...rest } = props;
90
+ const renderedItems = useStoreState(store, "renderedItems");
91
+ const describedBy = React.useMemo(() => {
92
+ const idRefList = renderedItems?.filter(
93
+ (item) => item.elementType === "description" || item.elementType === "error"
94
+ )?.map((item) => item.id).join(" ");
95
+ return idRefList || void 0;
96
+ }, [renderedItems]);
97
+ const getData = React.useCallback(
98
+ (data) => ({
99
+ ...data,
100
+ elementType: "control",
101
+ controlType
102
+ }),
103
+ [controlType]
104
+ );
105
+ const invalid = React.useMemo(
106
+ () => renderedItems?.some(
107
+ (item) => item.elementType === "error"
108
+ ),
109
+ [renderedItems]
110
+ );
111
+ return /* @__PURE__ */ jsx(FieldControlTypeContext.Provider, { value: setControlType, children: /* @__PURE__ */ jsx(
112
+ CollectionItem,
113
+ {
114
+ id,
115
+ getItem: getData,
116
+ render: /* @__PURE__ */ jsx(
117
+ Role,
118
+ {
119
+ ...rest,
120
+ "aria-invalid": invalid ? "true" : void 0,
121
+ "aria-describedby": describedBy
122
+ }
123
+ ),
124
+ ref: forwardedRef
125
+ }
126
+ ) });
127
+ }
128
+ );
129
+ DEV: FieldControl.displayName = "Field.Control";
130
+ const FieldErrorMessage = forwardRef(
131
+ (props, forwardedRef) => {
132
+ const generatedId = React.useId();
133
+ const { id = generatedId, ...rest } = props;
134
+ const getData = React.useCallback(
135
+ (data) => ({
136
+ ...data,
137
+ elementType: "error"
138
+ }),
139
+ []
140
+ );
141
+ return /* @__PURE__ */ jsx(
142
+ CollectionItem,
143
+ {
144
+ id,
145
+ getItem: getData,
146
+ render: /* @__PURE__ */ jsx(Description, { ...rest, tone: "critical" }),
147
+ ref: forwardedRef
148
+ }
149
+ );
150
+ }
151
+ );
152
+ DEV: FieldErrorMessage.displayName = "Field.ErrorMessage";
123
153
  export {
124
- Field,
125
- FieldControl,
126
- FieldDescription,
127
- FieldLabel
154
+ FieldControl as Control,
155
+ FieldDescription as Description,
156
+ FieldErrorMessage as ErrorMessage,
157
+ FieldLabel as Label,
158
+ FieldRoot as Root
128
159
  };