@itwin/itwinui-react 5.0.0-alpha.1 → 5.0.0-alpha.3

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 (62) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/DEV/bricks/Anchor.js +1 -1
  3. package/dist/DEV/bricks/Button.js +1 -1
  4. package/dist/DEV/bricks/Checkbox.js +3 -1
  5. package/dist/DEV/bricks/Chip.js +21 -0
  6. package/dist/DEV/bricks/Description.js +27 -0
  7. package/dist/DEV/bricks/DropdownMenu.js +20 -1
  8. package/dist/DEV/bricks/Field.js +56 -5
  9. package/dist/DEV/bricks/Icon.js +32 -1
  10. package/dist/DEV/bricks/IconButton.js +3 -0
  11. package/dist/DEV/bricks/Kbd.js +36 -4
  12. package/dist/DEV/bricks/Radio.js +3 -1
  13. package/dist/DEV/bricks/Select.js +6 -3
  14. package/dist/DEV/bricks/Spinner.js +40 -0
  15. package/dist/DEV/bricks/Switch.js +3 -1
  16. package/dist/DEV/bricks/Tabs.js +1 -1
  17. package/dist/DEV/bricks/TextBox.js +30 -3
  18. package/dist/DEV/bricks/Tooltip.js +3 -3
  19. package/dist/DEV/bricks/Tree.js +119 -34
  20. package/dist/DEV/bricks/index.js +8 -0
  21. package/dist/DEV/bricks/styles.css.js +1 -1
  22. package/dist/DEV/bricks/~hooks.js +15 -2
  23. package/dist/DEV/foundations/styles.css.js +1 -1
  24. package/dist/bricks/Anchor.js +1 -1
  25. package/dist/bricks/Button.js +1 -1
  26. package/dist/bricks/Checkbox.js +3 -1
  27. package/dist/bricks/Chip.d.ts +22 -0
  28. package/dist/bricks/Chip.js +20 -0
  29. package/dist/bricks/Description.d.ts +20 -0
  30. package/dist/bricks/Description.js +27 -0
  31. package/dist/bricks/DropdownMenu.d.ts +13 -1
  32. package/dist/bricks/DropdownMenu.js +19 -1
  33. package/dist/bricks/Field.d.ts +8 -0
  34. package/dist/bricks/Field.js +56 -5
  35. package/dist/bricks/Icon.d.ts +3 -0
  36. package/dist/bricks/Icon.js +31 -1
  37. package/dist/bricks/IconButton.js +3 -0
  38. package/dist/bricks/Kbd.d.ts +30 -0
  39. package/dist/bricks/Kbd.js +29 -4
  40. package/dist/bricks/Radio.js +3 -1
  41. package/dist/bricks/Select.d.ts +8 -1
  42. package/dist/bricks/Select.js +6 -3
  43. package/dist/bricks/Spinner.d.ts +31 -0
  44. package/dist/bricks/Spinner.js +39 -0
  45. package/dist/bricks/Switch.js +3 -1
  46. package/dist/bricks/Tabs.d.ts +1 -1
  47. package/dist/bricks/Tabs.js +1 -1
  48. package/dist/bricks/TextBox.d.ts +23 -2
  49. package/dist/bricks/TextBox.js +29 -3
  50. package/dist/bricks/Tooltip.js +3 -3
  51. package/dist/bricks/Tree.d.ts +76 -13
  52. package/dist/bricks/Tree.js +116 -32
  53. package/dist/bricks/index.d.ts +4 -0
  54. package/dist/bricks/index.js +8 -0
  55. package/dist/bricks/styles.css.js +1 -1
  56. package/dist/bricks/~hooks.d.ts +16 -0
  57. package/dist/bricks/~hooks.js +15 -2
  58. package/dist/foundations/styles.css.js +1 -1
  59. package/package.json +2 -2
  60. package/dist/DEV/bricks/Textarea.js +0 -30
  61. package/dist/bricks/Textarea.d.ts +0 -24
  62. package/dist/bricks/Textarea.js +0 -29
@@ -7,8 +7,8 @@ const Anchor = forwardRef((props, forwardedRef) => {
7
7
  return /* @__PURE__ */ jsx(
8
8
  Ariakit.Role.a,
9
9
  {
10
- "data-kiwi-tone": tone,
11
10
  ...rest,
11
+ "data-kiwi-tone": tone,
12
12
  className: cx("\u{1F95D}-anchor", props.className),
13
13
  render: /* @__PURE__ */ jsx(
14
14
  Ariakit.Focusable,
@@ -9,9 +9,9 @@ const Button = forwardRef(
9
9
  Ariakit.Button,
10
10
  {
11
11
  accessibleWhenDisabled: true,
12
+ ...rest,
12
13
  "data-kiwi-variant": variant,
13
14
  "data-kiwi-tone": tone,
14
- ...rest,
15
15
  className: cx("\u{1F95D}-button", props.className),
16
16
  ref: forwardedRef
17
17
  }
@@ -1,11 +1,12 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import cx from "classnames";
3
3
  import * as Ariakit from "@ariakit/react";
4
- import { useFieldId } from "./Field.js";
4
+ import { useFieldDescribedBy, useFieldId } from "./Field.js";
5
5
  import { forwardRef } from "./~utils.js";
6
6
  const Checkbox = forwardRef(
7
7
  (props, forwardedRef) => {
8
8
  const fieldId = useFieldId();
9
+ const describedBy = useFieldDescribedBy(props["aria-describedby"]);
9
10
  return /* @__PURE__ */ jsx(
10
11
  Ariakit.Checkbox,
11
12
  {
@@ -13,6 +14,7 @@ const Checkbox = forwardRef(
13
14
  id: fieldId,
14
15
  ...props,
15
16
  className: cx("\u{1F95D}-checkbox", props.className),
17
+ "aria-describedby": describedBy,
16
18
  ref: forwardedRef
17
19
  }
18
20
  );
@@ -0,0 +1,22 @@
1
+ import { type BaseProps } from "./~utils.js";
2
+ interface ChipProps extends BaseProps<"div"> {
3
+ /**
4
+ * The variant style of the Chip.
5
+ * Use "solid" for primary states and "outline" for less prominent states.
6
+ *
7
+ * @default "solid"
8
+ */
9
+ variant?: "solid" | "outline";
10
+ }
11
+ /**
12
+ * Chip is a UI component used to represent an item, attribute, or action in a compact visual style.
13
+ * It supports two visual variants: `solid` for primary emphasis and `outline` for less prominent states.
14
+ *
15
+ * Example : Render a Chip with the default "solid" variant
16
+ * ```tsx
17
+ * <Chip>Default Chip</Chip>
18
+ * <Chip variant="outline">Outline Chip</Chip>
19
+ * ```
20
+ */
21
+ export declare const Chip: import("react").ForwardRefExoticComponent<ChipProps & import("react").RefAttributes<HTMLElement | HTMLDivElement>>;
22
+ export {};
@@ -0,0 +1,20 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import cx from "classnames";
3
+ import * as Ariakit from "@ariakit/react";
4
+ import { forwardRef } from "./~utils.js";
5
+ const Chip = forwardRef((props, forwardedRef) => {
6
+ const { variant = "solid", children, ...rest } = props;
7
+ return /* @__PURE__ */ jsx(
8
+ Ariakit.Role.div,
9
+ {
10
+ "data-kiwi-variant": variant,
11
+ ...rest,
12
+ className: cx("\u{1F95D}-chip", props.className),
13
+ ref: forwardedRef,
14
+ children
15
+ }
16
+ );
17
+ });
18
+ export {
19
+ Chip
20
+ };
@@ -0,0 +1,20 @@
1
+ import * as React from "react";
2
+ import { type BaseProps } from "./~utils.js";
3
+ interface DescriptionProps extends BaseProps {
4
+ /**
5
+ * The tone of the description.
6
+ * @default "neutral"
7
+ */
8
+ tone?: "neutral" | "critical";
9
+ }
10
+ /**
11
+ * An additional description for a form control.
12
+ *
13
+ * Should not include content without an adequate text alternative.
14
+ *
15
+ * Either give this component an `id` and manually associate with a form control
16
+ * * using `aria-describedby` on said control or use the `<Field>` component *
17
+ * (WIP).
18
+ */
19
+ export declare const Description: React.ForwardRefExoticComponent<DescriptionProps & React.RefAttributes<HTMLElement | HTMLDivElement>>;
20
+ export {};
@@ -0,0 +1,27 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { forwardRef } from "./~utils.js";
4
+ import cx from "classnames";
5
+ import { Text } from "./Text.js";
6
+ import { useFieldRegisterDescribedBy } from "./Field.js";
7
+ const Description = forwardRef(
8
+ (props, forwardedRef) => {
9
+ const generatedId = React.useId();
10
+ const { id = generatedId, tone, ...rest } = props;
11
+ useFieldRegisterDescribedBy(id);
12
+ return /* @__PURE__ */ jsx(
13
+ Text,
14
+ {
15
+ ...rest,
16
+ id,
17
+ variant: "caption-md",
18
+ "data-kiwi-tone": tone ?? "neutral",
19
+ className: cx("\u{1F95D}-description", props.className),
20
+ ref: forwardedRef
21
+ }
22
+ );
23
+ }
24
+ );
25
+ export {
26
+ Description
27
+ };
@@ -81,4 +81,16 @@ interface DropdownMenuItemProps extends FocusableProps {
81
81
  * ```
82
82
  */
83
83
  declare const DropdownMenuItem: React.ForwardRefExoticComponent<DropdownMenuItemProps & React.RefAttributes<HTMLElement | HTMLDivElement>>;
84
- export { DropdownMenu as Root, DropdownMenuButton as Button, DropdownMenuContent as Content, DropdownMenuItem as Item, };
84
+ interface DropdownMenuCheckboxItemProps extends Omit<FocusableProps, "onChange">, Pick<Ariakit.MenuItemCheckboxProps, "checked" | "onChange" | "name" | "value"> {
85
+ }
86
+ /**
87
+ * A single menu item within the dropdown menu. Should be used as a child of `DropdownMenu.Content`.
88
+ *
89
+ * Example:
90
+ * ```tsx
91
+ * <DropdownMenu.CheckboxItem name="add">Add</DropdownMenu.Item>
92
+ * <DropdownMenu.CheckboxItem name="edit">Edit</DropdownMenu.Item>
93
+ * ```
94
+ */
95
+ declare const DropdownMenuCheckboxItem: React.ForwardRefExoticComponent<DropdownMenuCheckboxItemProps & React.RefAttributes<HTMLElement | HTMLDivElement>>;
96
+ export { DropdownMenu as Root, DropdownMenuButton as Button, DropdownMenuContent as Content, DropdownMenuItem as Item, DropdownMenuCheckboxItem as CheckboxItem, };
@@ -5,7 +5,7 @@ import * as Ariakit from "@ariakit/react";
5
5
  import * as ListItem from "./ListItem.js";
6
6
  import { Button } from "./Button.js";
7
7
  import { Kbd } from "./Kbd.js";
8
- import { DisclosureArrow } from "./Icon.js";
8
+ import { Checkmark, DisclosureArrow } from "./Icon.js";
9
9
  import { forwardRef, supportsPopover } from "./~utils.js";
10
10
  function DropdownMenu(props) {
11
11
  const {
@@ -94,8 +94,26 @@ const DropdownMenuItem = forwardRef(
94
94
  );
95
95
  }
96
96
  );
97
+ const DropdownMenuCheckboxItem = forwardRef((props, forwardedRef) => {
98
+ return /* @__PURE__ */ jsxs(
99
+ Ariakit.MenuItemCheckbox,
100
+ {
101
+ accessibleWhenDisabled: true,
102
+ value: props.defaultChecked ? "on" : void 0,
103
+ ...props,
104
+ render: /* @__PURE__ */ jsx(ListItem.Root, { render: props.render }),
105
+ className: cx("\u{1F95D}-dropdown-menu-checkbox-item", props.className),
106
+ ref: forwardedRef,
107
+ children: [
108
+ /* @__PURE__ */ jsx(ListItem.Content, { children: props.children }),
109
+ /* @__PURE__ */ jsx(Checkmark, { className: "\u{1F95D}-dropdown-menu-checkmark" })
110
+ ]
111
+ }
112
+ );
113
+ });
97
114
  export {
98
115
  DropdownMenuButton as Button,
116
+ DropdownMenuCheckboxItem as CheckboxItem,
99
117
  DropdownMenuContent as Content,
100
118
  DropdownMenuItem as Item,
101
119
  DropdownMenu as Root
@@ -27,5 +27,13 @@ interface FieldProps extends BaseProps {
27
27
  * - `Switch`
28
28
  */
29
29
  export declare const Field: React.ForwardRefExoticComponent<FieldProps & React.RefAttributes<HTMLElement | HTMLDivElement>>;
30
+ /**
31
+ * Use the description IDs for a field.
32
+ */
33
+ export declare function useFieldDescribedBy(ariaDescribedByProp?: string): string | undefined;
34
+ /**
35
+ * Registers a description for an associated control.
36
+ */
37
+ export declare function useFieldRegisterDescribedBy(id: string): void;
30
38
  export declare function useFieldId(): string | undefined;
31
39
  export {};
@@ -5,22 +5,73 @@ import cx from "classnames";
5
5
  import { forwardRef } from "./~utils.js";
6
6
  const Field = forwardRef((props, forwardedRef) => {
7
7
  const fieldId = React.useId();
8
- const { className, layout, ...rest } = props;
9
- return /* @__PURE__ */ jsx(FieldIdContext.Provider, { value: fieldId, children: /* @__PURE__ */ jsx(
8
+ const { layout, ...rest } = props;
9
+ return /* @__PURE__ */ jsx(FieldIdContext.Provider, { value: fieldId, children: /* @__PURE__ */ jsx(FieldDescribedByProvider, { children: /* @__PURE__ */ jsx(
10
10
  Ariakit.Role,
11
11
  {
12
12
  ...rest,
13
- className: cx("\u{1F95D}-field", className),
13
+ className: cx("\u{1F95D}-field", props.className),
14
14
  "data-kiwi-layout": layout,
15
15
  ref: forwardedRef
16
16
  }
17
- ) });
17
+ ) }) });
18
18
  });
19
+ const FieldDescribedByContext = React.createContext(void 0);
20
+ function FieldDescribedByProvider(props) {
21
+ const [describedBy, setDescribedBy] = React.useState(/* @__PURE__ */ new Set());
22
+ const register = React.useCallback((id) => {
23
+ setDescribedBy((describedBy2) => {
24
+ const updated = new Set(describedBy2);
25
+ updated.add(id);
26
+ return updated;
27
+ });
28
+ }, []);
29
+ const unregister = React.useCallback((id) => {
30
+ setDescribedBy((describedBy2) => {
31
+ const updated = new Set(describedBy2);
32
+ updated.delete(id);
33
+ return updated;
34
+ });
35
+ }, []);
36
+ return /* @__PURE__ */ jsx(
37
+ FieldDescribedByContext.Provider,
38
+ {
39
+ value: React.useMemo(
40
+ () => ({
41
+ describedBy,
42
+ register,
43
+ unregister
44
+ }),
45
+ [describedBy, register, unregister]
46
+ ),
47
+ children: props.children
48
+ }
49
+ );
50
+ }
51
+ function useFieldDescribedBy(ariaDescribedByProp) {
52
+ const describedBySet = React.useContext(FieldDescribedByContext)?.describedBy;
53
+ return React.useMemo(
54
+ () => !describedBySet || describedBySet.size === 0 ? ariaDescribedByProp : [...describedBySet, ariaDescribedByProp].filter(Boolean).join(" "),
55
+ [describedBySet, ariaDescribedByProp]
56
+ );
57
+ }
58
+ function useFieldRegisterDescribedBy(id) {
59
+ const context = React.useContext(FieldDescribedByContext);
60
+ const register = context?.register;
61
+ const unregister = context?.unregister;
62
+ React.useEffect(() => {
63
+ if (!register || !unregister) return;
64
+ register(id);
65
+ return () => unregister(id);
66
+ }, [id, register, unregister]);
67
+ }
19
68
  const FieldIdContext = React.createContext(void 0);
20
69
  function useFieldId() {
21
70
  return React.useContext(FieldIdContext);
22
71
  }
23
72
  export {
24
73
  Field,
25
- useFieldId
74
+ useFieldDescribedBy,
75
+ useFieldId,
76
+ useFieldRegisterDescribedBy
26
77
  };
@@ -32,4 +32,7 @@ interface DisclosureArrowProps extends Omit<BaseProps<"svg">, "children"> {
32
32
  direction?: "down" | "right";
33
33
  }
34
34
  export declare const DisclosureArrow: React.ForwardRefExoticComponent<DisclosureArrowProps & React.RefAttributes<HTMLElement | SVGSVGElement>>;
35
+ interface CheckmarkProps extends Omit<BaseProps<"svg">, "children"> {
36
+ }
37
+ export declare const Checkmark: React.ForwardRefExoticComponent<CheckmarkProps & React.RefAttributes<HTMLElement | SVGSVGElement>>;
35
38
  export {};
@@ -9,9 +9,9 @@ const Icon = forwardRef((props, forwardedRef) => {
9
9
  return /* @__PURE__ */ jsx(
10
10
  Ariakit.Role.svg,
11
11
  {
12
- "data-kiwi-size": size,
13
12
  "aria-hidden": true,
14
13
  ...rest,
14
+ "data-kiwi-size": size,
15
15
  className: cx("\u{1F95D}-icon", props.className),
16
16
  ref: forwardedRef,
17
17
  children: /* @__PURE__ */ jsx("use", { href: `${props.href}#${iconId}` })
@@ -54,7 +54,37 @@ const DisclosureArrow = forwardRef(
54
54
  );
55
55
  }
56
56
  );
57
+ const Checkmark = forwardRef(
58
+ (props, forwardedRef) => {
59
+ return /* @__PURE__ */ jsx(
60
+ Icon,
61
+ {
62
+ ...props,
63
+ render: /* @__PURE__ */ jsx(
64
+ Ariakit.Role.svg,
65
+ {
66
+ width: "16",
67
+ height: "16",
68
+ fill: "currentColor",
69
+ viewBox: "0 0 16 16",
70
+ render: props.render,
71
+ children: /* @__PURE__ */ jsx(
72
+ "path",
73
+ {
74
+ fillRule: "evenodd",
75
+ d: "M13.854 4.146a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3-3a.5.5 0 1 1 .708-.708L6.5 10.793l6.646-6.647a.5.5 0 0 1 .708 0Z",
76
+ clipRule: "evenodd"
77
+ }
78
+ )
79
+ }
80
+ ),
81
+ ref: forwardedRef
82
+ }
83
+ );
84
+ }
85
+ );
57
86
  export {
87
+ Checkmark,
58
88
  DisclosureArrow,
59
89
  Icon
60
90
  };
@@ -1,5 +1,6 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import cx from "classnames";
3
+ import * as Ariakit from "@ariakit/react";
3
4
  import { Button } from "./Button.js";
4
5
  import { VisuallyHidden } from "./VisuallyHidden.js";
5
6
  import { Icon } from "./Icon.js";
@@ -8,11 +9,13 @@ import { forwardRef } from "./~utils.js";
8
9
  const IconButton = forwardRef(
9
10
  (props, forwardedRef) => {
10
11
  const { label, icon, isActive, labelVariant, ...rest } = props;
12
+ const toolbar = Ariakit.useToolbarContext();
11
13
  const button = /* @__PURE__ */ jsxs(
12
14
  Button,
13
15
  {
14
16
  "aria-pressed": isActive,
15
17
  ...rest,
18
+ render: toolbar ? /* @__PURE__ */ jsx(Ariakit.ToolbarItem, { render: props.render }) : props.render,
16
19
  className: cx("\u{1F95D}-icon-button", props.className),
17
20
  ref: forwardedRef,
18
21
  children: [
@@ -1,7 +1,33 @@
1
1
  import { type BaseProps } from "./~utils.js";
2
+ declare const predefinedSymbols: {
3
+ readonly Backspace: "⌫";
4
+ readonly Command: "⌘";
5
+ readonly Control: "Ctrl";
6
+ readonly Down: "↓";
7
+ readonly Eject: "⏏";
8
+ readonly Enter: "↵";
9
+ readonly Escape: "Esc";
10
+ readonly Left: "←";
11
+ readonly Option: "⌥";
12
+ readonly Right: "→";
13
+ readonly Shift: "⇧";
14
+ readonly Space: "␣";
15
+ readonly Tab: "Tab";
16
+ readonly Up: "↑";
17
+ };
2
18
  interface KbdProps extends BaseProps<"kbd"> {
3
19
  /** @default "solid" */
4
20
  variant?: "solid" | "muted" | "ghost";
21
+ /**
22
+ * Display a specific key symbol from a predefined list. This is useful for
23
+ * displaying modifier keys or special keys, such as `Control`, `Shift`, `Enter`, etc.
24
+ *
25
+ * Example:
26
+ * ```tsx
27
+ * <Kbd symbol="Control" />
28
+ * ```
29
+ */
30
+ symbol?: keyof typeof predefinedSymbols;
5
31
  }
6
32
  /**
7
33
  * A styled wrapper over the HTML `<kbd>` element. This is typically
@@ -10,6 +36,10 @@ interface KbdProps extends BaseProps<"kbd"> {
10
36
  * ```tsx
11
37
  * <Kbd>Ctrl</Kbd> <Kbd>S</Kbd>
12
38
  * ```
39
+ *
40
+ * ```tsx
41
+ * <Kbd symbol="Control" />
42
+ * ```
13
43
  */
14
44
  export declare const Kbd: import("react").ForwardRefExoticComponent<KbdProps & import("react").RefAttributes<HTMLElement>>;
15
45
  export {};
@@ -1,17 +1,42 @@
1
- import { jsx } from "react/jsx-runtime";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import cx from "classnames";
3
3
  import * as Ariakit from "@ariakit/react";
4
4
  import { forwardRef } from "./~utils.js";
5
+ import { VisuallyHidden } from "./VisuallyHidden.js";
6
+ const predefinedSymbols = {
7
+ Backspace: "\u232B",
8
+ Command: "\u2318",
9
+ Control: "Ctrl",
10
+ Down: "\u2193",
11
+ Eject: "\u23CF",
12
+ Enter: "\u21B5",
13
+ Escape: "Esc",
14
+ Left: "\u2190",
15
+ Option: "\u2325",
16
+ Right: "\u2192",
17
+ Shift: "\u21E7",
18
+ Space: "\u2423",
19
+ Tab: "Tab",
20
+ Up: "\u2191"
21
+ };
5
22
  const Kbd = forwardRef((props, forwardedRef) => {
6
- const { variant = "solid", ...rest } = props;
23
+ const { variant = "solid", symbol, children, ...rest } = props;
24
+ let content = children;
25
+ if (symbol) {
26
+ content = /* @__PURE__ */ jsxs(Fragment, { children: [
27
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: predefinedSymbols[symbol] }),
28
+ children || /* @__PURE__ */ jsx(VisuallyHidden, { children: symbol })
29
+ ] });
30
+ }
7
31
  return /* @__PURE__ */ jsx(
8
32
  Ariakit.Role,
9
33
  {
10
- "data-kiwi-variant": variant,
11
34
  ...rest,
35
+ "data-kiwi-variant": variant,
12
36
  className: cx("\u{1F95D}-kbd", props.className),
13
37
  render: props.render || /* @__PURE__ */ jsx("kbd", {}),
14
- ref: forwardedRef
38
+ ref: forwardedRef,
39
+ children: content
15
40
  }
16
41
  );
17
42
  });
@@ -1,10 +1,11 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import cx from "classnames";
3
3
  import * as Ariakit from "@ariakit/react";
4
- import { useFieldId } from "./Field.js";
4
+ import { useFieldDescribedBy, useFieldId } from "./Field.js";
5
5
  import { forwardRef } from "./~utils.js";
6
6
  const Radio = forwardRef((props, forwardedRef) => {
7
7
  const fieldId = useFieldId();
8
+ const describedBy = useFieldDescribedBy(props["aria-describedby"]);
8
9
  return /* @__PURE__ */ jsx(
9
10
  Ariakit.Radio,
10
11
  {
@@ -12,6 +13,7 @@ const Radio = forwardRef((props, forwardedRef) => {
12
13
  id: fieldId,
13
14
  ...props,
14
15
  className: cx("\u{1F95D}-checkbox", "\u{1F95D}-radio", props.className),
16
+ "aria-describedby": describedBy,
15
17
  ref: forwardedRef
16
18
  }
17
19
  );
@@ -21,7 +21,14 @@ import { type FocusableProps } from "./~utils.js";
21
21
  * ```
22
22
  */
23
23
  declare const SelectRoot: React.ForwardRefExoticComponent<Pick<Ariakit.RoleProps, "render"> & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "render"> & React.RefAttributes<HTMLElement | HTMLDivElement>>;
24
- interface HtmlSelectProps extends Omit<FocusableProps<"select">, "multiple" | "size"> {
24
+ type HtmlSelectBaseProps = Omit<FocusableProps<"select">, "multiple" | "size">;
25
+ interface HtmlSelectProps extends HtmlSelectBaseProps {
26
+ /**
27
+ * The variant of the `HtmlSelect`, i.e. solid, outline, or ghost.
28
+ *
29
+ * @default "solid"
30
+ */
31
+ variant?: "solid" | "outline" | "ghost";
25
32
  }
26
33
  /**
27
34
  * The actual select element to be used inside `Select.Root`. This is a wrapper around the
@@ -7,7 +7,7 @@ import {
7
7
  isBrowser
8
8
  } from "./~utils.js";
9
9
  import { DisclosureArrow } from "./Icon.js";
10
- import { useFieldId } from "./Field.js";
10
+ import { useFieldDescribedBy, useFieldId } from "./Field.js";
11
11
  const supportsHas = isBrowser && CSS?.supports?.("selector(:has(+ *))");
12
12
  const HtmlSelectContext = React.createContext(() => {
13
13
  });
@@ -25,8 +25,10 @@ const SelectRoot = forwardRef((props, forwardedRef) => {
25
25
  });
26
26
  const HtmlSelect = forwardRef(
27
27
  (props, forwardedRef) => {
28
+ const { variant = "solid", ...rest } = props;
28
29
  const setIsHtmlSelect = React.useContext(HtmlSelectContext);
29
30
  const fieldId = useFieldId();
31
+ const describedBy = useFieldDescribedBy(props["aria-describedby"]);
30
32
  React.useEffect(
31
33
  function updateContext() {
32
34
  setIsHtmlSelect(true);
@@ -38,10 +40,11 @@ const HtmlSelect = forwardRef(
38
40
  Ariakit.Role.select,
39
41
  {
40
42
  id: fieldId,
41
- ...props,
43
+ ...rest,
42
44
  className: cx("\u{1F95D}-button", "\u{1F95D}-select", props.className),
45
+ "aria-describedby": describedBy,
43
46
  "data-kiwi-tone": "neutral",
44
- "data-kiwi-variant": "solid",
47
+ "data-kiwi-variant": variant,
45
48
  ref: forwardedRef
46
49
  }
47
50
  ),
@@ -0,0 +1,31 @@
1
+ import { type BaseProps } from "./~utils.js";
2
+ interface SpinnerProps extends BaseProps {
3
+ /**
4
+ * A text alternative for the spinner.
5
+ * @default "Loading…"
6
+ */
7
+ alt?: string;
8
+ /**
9
+ * The size of the spinner.
10
+ * @default "medium"
11
+ */
12
+ size?: "small" | "medium" | "large" | "xlarge";
13
+ /**
14
+ * The tone of the spinner.
15
+ * @default "neutral"
16
+ */
17
+ tone?: "neutral" | "accent";
18
+ }
19
+ /**
20
+ * A loading spinner.
21
+ *
22
+ * Example:
23
+ * ```tsx
24
+ * <Spinner />
25
+ * ```
26
+ *
27
+ * Supports a `tone` prop to change the tone (color) of the spinner.
28
+ * Supports a `size` prop to change the size of the spinner.
29
+ */
30
+ export declare const Spinner: import("react").ForwardRefExoticComponent<SpinnerProps & import("react").RefAttributes<HTMLElement | HTMLDivElement>>;
31
+ export {};
@@ -0,0 +1,39 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import * as Ariakit from "@ariakit/react";
3
+ import cx from "classnames";
4
+ import { VisuallyHidden } from "./VisuallyHidden.js";
5
+ import { forwardRef } from "./~utils.js";
6
+ const Spinner = forwardRef(
7
+ (props, forwardedRef) => {
8
+ const {
9
+ alt = "Loading\u2026",
10
+ size = "medium",
11
+ tone = "neutral",
12
+ ...rest
13
+ } = props;
14
+ return /* @__PURE__ */ jsxs(
15
+ Ariakit.Role,
16
+ {
17
+ ...rest,
18
+ "data-kiwi-size": size,
19
+ "data-kiwi-tone": tone,
20
+ className: cx("\u{1F95D}-spinner", props.className),
21
+ ref: forwardedRef,
22
+ children: [
23
+ /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", className: "\u{1F95D}-spinner-svg", viewBox: "0 0 16 16", children: /* @__PURE__ */ jsx(
24
+ "path",
25
+ {
26
+ stroke: "currentColor",
27
+ "stroke-linecap": "round",
28
+ d: "M9.5 1.674a6.503 6.503 0 0 1 0 12.652m-3-12.652a6.503 6.503 0 0 0 0 12.652"
29
+ }
30
+ ) }),
31
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: alt })
32
+ ]
33
+ }
34
+ );
35
+ }
36
+ );
37
+ export {
38
+ Spinner
39
+ };
@@ -1,11 +1,12 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import cx from "classnames";
3
3
  import * as Ariakit from "@ariakit/react";
4
- import { useFieldId } from "./Field.js";
4
+ import { useFieldDescribedBy, useFieldId } from "./Field.js";
5
5
  import { forwardRef } from "./~utils.js";
6
6
  const Switch = forwardRef(
7
7
  (props, forwardedRef) => {
8
8
  const fieldId = useFieldId();
9
+ const describedBy = useFieldDescribedBy(props["aria-describedby"]);
9
10
  return /* @__PURE__ */ jsx(
10
11
  Ariakit.Checkbox,
11
12
  {
@@ -13,6 +14,7 @@ const Switch = forwardRef(
13
14
  id: fieldId,
14
15
  ...props,
15
16
  className: cx("\u{1F95D}-switch", props.className),
17
+ "aria-describedby": describedBy,
16
18
  role: "switch",
17
19
  ref: forwardedRef
18
20
  }
@@ -67,7 +67,7 @@ interface TabProps extends FocusableProps<"button">, Pick<Ariakit.TabProps, "id"
67
67
  * ```
68
68
  */
69
69
  declare const Tab: React.ForwardRefExoticComponent<TabProps & React.RefAttributes<HTMLElement | HTMLButtonElement>>;
70
- interface TabPanelProps extends BaseProps<"div">, Pick<Ariakit.TabPanelProps, "tabId" | "unmountOnHide"> {
70
+ interface TabPanelProps extends FocusableProps<"div">, Pick<Ariakit.TabPanelProps, "tabId" | "unmountOnHide" | "focusable"> {
71
71
  }
72
72
  /**
73
73
  * The actual content of a tab, shown when the tab is selected. Should be used as a child of `Tabs.Root`.
@@ -47,8 +47,8 @@ const TabList = forwardRef((props, forwardedRef) => {
47
47
  return /* @__PURE__ */ jsx(
48
48
  Ariakit.TabList,
49
49
  {
50
- "data-kiwi-tone": tone,
51
50
  ...rest,
51
+ "data-kiwi-tone": tone,
52
52
  className: cx("\u{1F95D}-tab-list", props.className),
53
53
  style: {
54
54
  "--\u{1F95D}tab-active-stripe-view-transition-name": viewTransitionName,