@itwin/itwinui-react 5.0.0-alpha.1 → 5.0.0-alpha.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.
Files changed (55) hide show
  1. package/CHANGELOG.md +10 -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/Field.js +56 -5
  8. package/dist/DEV/bricks/Icon.js +1 -1
  9. package/dist/DEV/bricks/IconButton.js +3 -0
  10. package/dist/DEV/bricks/Kbd.js +36 -4
  11. package/dist/DEV/bricks/Radio.js +3 -1
  12. package/dist/DEV/bricks/Select.js +3 -1
  13. package/dist/DEV/bricks/Spinner.js +40 -0
  14. package/dist/DEV/bricks/Switch.js +3 -1
  15. package/dist/DEV/bricks/Tabs.js +1 -1
  16. package/dist/DEV/bricks/TextBox.js +3 -1
  17. package/dist/DEV/bricks/Textarea.js +3 -1
  18. package/dist/DEV/bricks/Tooltip.js +3 -3
  19. package/dist/DEV/bricks/Tree.js +77 -16
  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 +13 -0
  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/Field.d.ts +8 -0
  32. package/dist/bricks/Field.js +56 -5
  33. package/dist/bricks/Icon.js +1 -1
  34. package/dist/bricks/IconButton.js +3 -0
  35. package/dist/bricks/Kbd.d.ts +30 -0
  36. package/dist/bricks/Kbd.js +29 -4
  37. package/dist/bricks/Radio.js +3 -1
  38. package/dist/bricks/Select.js +3 -1
  39. package/dist/bricks/Spinner.d.ts +31 -0
  40. package/dist/bricks/Spinner.js +39 -0
  41. package/dist/bricks/Switch.js +3 -1
  42. package/dist/bricks/Tabs.d.ts +1 -1
  43. package/dist/bricks/Tabs.js +1 -1
  44. package/dist/bricks/TextBox.js +3 -1
  45. package/dist/bricks/Textarea.js +3 -1
  46. package/dist/bricks/Tooltip.js +3 -3
  47. package/dist/bricks/Tree.d.ts +76 -13
  48. package/dist/bricks/Tree.js +74 -14
  49. package/dist/bricks/index.d.ts +4 -0
  50. package/dist/bricks/index.js +8 -0
  51. package/dist/bricks/styles.css.js +1 -1
  52. package/dist/bricks/~hooks.d.ts +15 -0
  53. package/dist/bricks/~hooks.js +13 -0
  54. package/dist/foundations/styles.css.js +1 -1
  55. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.0.0-alpha.2
4
+
5
+ - Added initial `Tree` component, exposed as `<Tree.Root>` and `<Tree.Item>` subcomponents.
6
+ - Added initial `<Spinner>` component for indicating quick, indeterminate progress.
7
+ - Added `<Description>` component to be used within a `<Field>`.
8
+ - Added initial `<Chip>` component.
9
+ - Added `symbol` prop to `<Kbd>` for displaying predefined symbols.
10
+ - Added `focusable` prop to `<Tabs.TabPanel>` component.
11
+ - Fixed a visual issue where light color-scheme was using dark shadows.
12
+
3
13
  ## 5.0.0-alpha.1
4
14
 
5
15
  - Added `<Text>` component with a `variant` prop to support all text styles from Figma.
@@ -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,21 @@
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
+ DEV: Chip.displayName = "Chip";
19
+ export {
20
+ Chip
21
+ };
@@ -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
+ };
@@ -5,23 +5,74 @@ 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
19
  DEV: Field.displayName = "Field";
20
+ const FieldDescribedByContext = React.createContext(void 0);
21
+ function FieldDescribedByProvider(props) {
22
+ const [describedBy, setDescribedBy] = React.useState(/* @__PURE__ */ new Set());
23
+ const register = React.useCallback((id) => {
24
+ setDescribedBy((describedBy2) => {
25
+ const updated = new Set(describedBy2);
26
+ updated.add(id);
27
+ return updated;
28
+ });
29
+ }, []);
30
+ const unregister = React.useCallback((id) => {
31
+ setDescribedBy((describedBy2) => {
32
+ const updated = new Set(describedBy2);
33
+ updated.delete(id);
34
+ return updated;
35
+ });
36
+ }, []);
37
+ return /* @__PURE__ */ jsx(
38
+ FieldDescribedByContext.Provider,
39
+ {
40
+ value: React.useMemo(
41
+ () => ({
42
+ describedBy,
43
+ register,
44
+ unregister
45
+ }),
46
+ [describedBy, register, unregister]
47
+ ),
48
+ children: props.children
49
+ }
50
+ );
51
+ }
52
+ function useFieldDescribedBy(ariaDescribedByProp) {
53
+ const describedBySet = React.useContext(FieldDescribedByContext)?.describedBy;
54
+ return React.useMemo(
55
+ () => !describedBySet || describedBySet.size === 0 ? ariaDescribedByProp : [...describedBySet, ariaDescribedByProp].filter(Boolean).join(" "),
56
+ [describedBySet, ariaDescribedByProp]
57
+ );
58
+ }
59
+ function useFieldRegisterDescribedBy(id) {
60
+ const context = React.useContext(FieldDescribedByContext);
61
+ const register = context?.register;
62
+ const unregister = context?.unregister;
63
+ React.useEffect(() => {
64
+ if (!register || !unregister) return;
65
+ register(id);
66
+ return () => unregister(id);
67
+ }, [id, register, unregister]);
68
+ }
20
69
  const FieldIdContext = React.createContext(void 0);
21
70
  function useFieldId() {
22
71
  return React.useContext(FieldIdContext);
23
72
  }
24
73
  export {
25
74
  Field,
26
- useFieldId
75
+ useFieldDescribedBy,
76
+ useFieldId,
77
+ useFieldRegisterDescribedBy
27
78
  };
@@ -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}` })
@@ -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,17 +1,49 @@
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
+ DEV: {
25
+ if (symbol && !(symbol in predefinedSymbols)) {
26
+ console.error(
27
+ `Kbd: Invalid symbol "${symbol}". Must be one of: ${Object.keys(predefinedSymbols).join(", ")}`
28
+ );
29
+ }
30
+ }
31
+ let content = children;
32
+ if (symbol) {
33
+ content = /* @__PURE__ */ jsxs(Fragment, { children: [
34
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: predefinedSymbols[symbol] }),
35
+ children || /* @__PURE__ */ jsx(VisuallyHidden, { children: symbol })
36
+ ] });
37
+ }
7
38
  return /* @__PURE__ */ jsx(
8
39
  Ariakit.Role,
9
40
  {
10
- "data-kiwi-variant": variant,
11
41
  ...rest,
42
+ "data-kiwi-variant": variant,
12
43
  className: cx("\u{1F95D}-kbd", props.className),
13
44
  render: props.render || /* @__PURE__ */ jsx("kbd", {}),
14
- ref: forwardedRef
45
+ ref: forwardedRef,
46
+ children: content
15
47
  }
16
48
  );
17
49
  });
@@ -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
  );
@@ -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
  });
@@ -27,6 +27,7 @@ const HtmlSelect = forwardRef(
27
27
  (props, forwardedRef) => {
28
28
  const setIsHtmlSelect = React.useContext(HtmlSelectContext);
29
29
  const fieldId = useFieldId();
30
+ const describedBy = useFieldDescribedBy(props["aria-describedby"]);
30
31
  React.useEffect(
31
32
  function updateContext() {
32
33
  setIsHtmlSelect(true);
@@ -40,6 +41,7 @@ const HtmlSelect = forwardRef(
40
41
  id: fieldId,
41
42
  ...props,
42
43
  className: cx("\u{1F95D}-button", "\u{1F95D}-select", props.className),
44
+ "aria-describedby": describedBy,
43
45
  "data-kiwi-tone": "neutral",
44
46
  "data-kiwi-variant": "solid",
45
47
  ref: forwardedRef
@@ -0,0 +1,40 @@
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
+ DEV: Spinner.displayName = "Spinner";
38
+ export {
39
+ Spinner
40
+ };
@@ -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
  }
@@ -48,8 +48,8 @@ const TabList = forwardRef((props, forwardedRef) => {
48
48
  return /* @__PURE__ */ jsx(
49
49
  Ariakit.TabList,
50
50
  {
51
- "data-kiwi-tone": tone,
52
51
  ...rest,
52
+ "data-kiwi-tone": tone,
53
53
  className: cx("\u{1F95D}-tab-list", props.className),
54
54
  style: {
55
55
  "--\u{1F95D}tab-active-stripe-view-transition-name": viewTransitionName,
@@ -2,13 +2,14 @@ import { jsx } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import * as Ariakit from "@ariakit/react";
4
4
  import cx from "classnames";
5
- import { useFieldId } from "./Field.js";
5
+ import { useFieldDescribedBy, useFieldId } from "./Field.js";
6
6
  import { Icon } from "./Icon.js";
7
7
  import { Textarea } from "./Textarea.js";
8
8
  import { useMergedRefs } from "./~hooks.js";
9
9
  import { forwardRef } from "./~utils.js";
10
10
  const TextBoxInput = forwardRef(
11
11
  (props, forwardedRef) => {
12
+ const describedBy = useFieldDescribedBy(props["aria-describedby"]);
12
13
  const fieldId = useFieldId();
13
14
  const rootContext = React.useContext(TextBoxRootContext);
14
15
  const setDisabled = rootContext?.setDisabled;
@@ -20,6 +21,7 @@ const TextBoxInput = forwardRef(
20
21
  {
21
22
  id: fieldId,
22
23
  ...props,
24
+ "aria-describedby": describedBy,
23
25
  className: cx({ "\u{1F95D}-text-box": !rootContext }, props.className),
24
26
  render: /* @__PURE__ */ jsx(
25
27
  Ariakit.Focusable,
@@ -1,17 +1,19 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import * as Ariakit from "@ariakit/react";
3
3
  import cx from "classnames";
4
- import { useFieldId } from "./Field.js";
4
+ import { useFieldDescribedBy, useFieldId } from "./Field.js";
5
5
  import { forwardRef } from "./~utils.js";
6
6
  const Textarea = 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.Role.textarea,
11
12
  {
12
13
  id: fieldId,
13
14
  ...props,
14
15
  className: cx("\u{1F95D}-text-box", props.className),
16
+ "aria-describedby": describedBy,
15
17
  render: /* @__PURE__ */ jsx(
16
18
  Ariakit.Focusable,
17
19
  {
@@ -5,12 +5,12 @@ import * as Ariakit from "@ariakit/react";
5
5
  import { forwardRef, supportsPopover } from "./~utils.js";
6
6
  const Tooltip = forwardRef(
7
7
  (props, forwardedRef) => {
8
+ const generatedId = React.useId();
8
9
  const {
9
10
  content,
10
11
  children,
11
- className,
12
12
  type = "description",
13
- id = React.useId(),
13
+ id = generatedId,
14
14
  defaultOpen: defaultOpenProp,
15
15
  open: openProp,
16
16
  setOpen: setOpenProp,
@@ -53,7 +53,7 @@ const Tooltip = forwardRef(
53
53
  "aria-hidden": "true",
54
54
  ...rest,
55
55
  unmountOnHide,
56
- className: cx("\u{1F95D}-tooltip", className),
56
+ className: cx("\u{1F95D}-tooltip", props.className),
57
57
  ref: forwardedRef,
58
58
  id,
59
59
  style: {
@@ -6,15 +6,34 @@ import * as ListItem from "./ListItem.js";
6
6
  import { IconButton } from "./IconButton.js";
7
7
  import { Icon } from "./Icon.js";
8
8
  import { forwardRef } from "./~utils.js";
9
+ import { VisuallyHidden } from "./VisuallyHidden.js";
9
10
  const Tree = forwardRef((props, forwardedRef) => {
10
- return /* @__PURE__ */ jsx(Ariakit.Role.div, { ...props, role: "list", ref: forwardedRef, children: props.children });
11
+ return /* @__PURE__ */ jsx(
12
+ Ariakit.Role.div,
13
+ {
14
+ ...props,
15
+ className: cx("\u{1F95D}-tree", props.className),
16
+ ref: forwardedRef,
17
+ children: /* @__PURE__ */ jsx("div", { role: "list", children: props.children })
18
+ }
19
+ );
11
20
  });
12
21
  DEV: Tree.displayName = "Tree.Root";
13
22
  const TreeItem = forwardRef((props, forwardedRef) => {
14
- const { selected, content, children, className, expanded, style, ...rest } = props;
23
+ const {
24
+ selected,
25
+ children,
26
+ expanded,
27
+ icon,
28
+ label,
29
+ actions,
30
+ style,
31
+ onSelectedChange,
32
+ onExpandedChange,
33
+ ...rest
34
+ } = props;
15
35
  const parentContext = React.useContext(TreeItemContext);
16
36
  const level = parentContext ? parentContext.level + 1 : 1;
17
- const firstSelected = !!selected && !parentContext?.selected;
18
37
  return /* @__PURE__ */ jsx(
19
38
  TreeItemContext.Provider,
20
39
  {
@@ -22,26 +41,39 @@ const TreeItem = forwardRef((props, forwardedRef) => {
22
41
  () => ({
23
42
  level,
24
43
  expanded,
25
- selected
44
+ selected,
45
+ onSelectedChange
26
46
  }),
27
- [level, expanded, selected]
47
+ [level, expanded, selected, onSelectedChange]
28
48
  ),
29
- children: /* @__PURE__ */ jsxs("div", { role: "listitem", "aria-current": firstSelected ? true : void 0, children: [
30
- /* @__PURE__ */ jsx(
49
+ children: /* @__PURE__ */ jsxs("div", { role: "listitem", children: [
50
+ /* @__PURE__ */ jsxs(
31
51
  ListItem.Root,
32
52
  {
33
53
  ...rest,
34
54
  "data-kiwi-expanded": expanded,
35
55
  "data-kiwi-selected": selected,
36
- "data-kiwi-parent-selected": parentContext?.selected,
37
- className: cx("\u{1F95D}-tree-item", className),
56
+ className: cx("\u{1F95D}-tree-item", props.className),
38
57
  style: {
39
58
  ...style,
40
59
  "--\u{1F95D}tree-item-level": level
41
60
  },
42
61
  ref: forwardedRef,
43
62
  role: void 0,
44
- children: content
63
+ children: [
64
+ /* @__PURE__ */ jsx(
65
+ TreeItemExpander,
66
+ {
67
+ onClick: () => {
68
+ if (expanded === void 0) return;
69
+ onExpandedChange?.(!expanded);
70
+ }
71
+ }
72
+ ),
73
+ typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { href: icon }) : icon,
74
+ /* @__PURE__ */ jsx(TreeItemContent, { label }),
75
+ /* @__PURE__ */ jsx(TreeItemActions, { children: actions })
76
+ ]
45
77
  }
46
78
  ),
47
79
  children && /* @__PURE__ */ jsx("div", { role: "list", children })
@@ -52,19 +84,50 @@ const TreeItem = forwardRef((props, forwardedRef) => {
52
84
  DEV: TreeItem.displayName = "Tree.Item";
53
85
  const TreeItemContent = forwardRef(
54
86
  (props, forwardedRef) => {
55
- const { children, ...rest } = props;
87
+ const { label, ...rest } = props;
88
+ const context = React.useContext(TreeItemContext);
56
89
  return /* @__PURE__ */ jsx(
57
90
  ListItem.Content,
58
91
  {
59
92
  ...rest,
60
93
  className: cx("\u{1F95D}-tree-item-content", props.className),
61
94
  ref: forwardedRef,
62
- children: /* @__PURE__ */ jsx("button", { type: "button", children })
95
+ children: /* @__PURE__ */ jsxs(
96
+ "button",
97
+ {
98
+ type: "button",
99
+ onClick: () => {
100
+ if (!context?.onSelectedChange || context.selected === void 0)
101
+ return;
102
+ context.onSelectedChange(!context.selected);
103
+ },
104
+ children: [
105
+ label,
106
+ context?.selected && /* @__PURE__ */ jsx(VisuallyHidden, { children: "Selected item" })
107
+ ]
108
+ }
109
+ )
110
+ }
111
+ );
112
+ }
113
+ );
114
+ DEV: TreeItemContent.displayName = "TreeItemContent";
115
+ const TreeItemActions = forwardRef(
116
+ (props, forwardedRef) => {
117
+ const { visible, ...rest } = props;
118
+ return /* @__PURE__ */ jsx(
119
+ Ariakit.Toolbar,
120
+ {
121
+ ...rest,
122
+ className: cx("\u{1F95D}-tree-item-actions", props.className),
123
+ "data-kiwi-visible": visible,
124
+ ref: forwardedRef,
125
+ children: props.children
63
126
  }
64
127
  );
65
128
  }
66
129
  );
67
- DEV: TreeItemContent.displayName = "Tree.Content";
130
+ DEV: TreeItemActions.displayName = "TreeItemActions";
68
131
  const TreeItemExpander = forwardRef(
69
132
  (props, forwardedRef) => {
70
133
  const context = React.useContext(TreeItemContext);
@@ -84,7 +147,7 @@ const TreeItemExpander = forwardRef(
84
147
  );
85
148
  }
86
149
  );
87
- DEV: TreeItemExpander.displayName = "Tree.Expander";
150
+ DEV: TreeItemExpander.displayName = "TreeItemExpander";
88
151
  const TreeChevron = forwardRef(
89
152
  (props, forwardedRef) => {
90
153
  return /* @__PURE__ */ jsx(
@@ -111,8 +174,6 @@ const TreeChevron = forwardRef(
111
174
  DEV: TreeChevron.displayName = "TreeChevron";
112
175
  const TreeItemContext = React.createContext(void 0);
113
176
  export {
114
- TreeItemContent as Content,
115
- TreeItemExpander as Expander,
116
177
  TreeItem as Item,
117
178
  Tree as Root
118
179
  };
@@ -3,6 +3,8 @@ import { Root } from "./Root.js";
3
3
  import { Anchor } from "./Anchor.js";
4
4
  import { Button } from "./Button.js";
5
5
  import { Checkbox } from "./Checkbox.js";
6
+ import { Chip } from "./Chip.js";
7
+ import { Description } from "./Description.js";
6
8
  import * as DropdownMenu from "./DropdownMenu.js";
7
9
  import { Divider } from "./Divider.js";
8
10
  import { Icon } from "./Icon.js";
@@ -12,16 +14,20 @@ import { Kbd } from "./Kbd.js";
12
14
  import { Label } from "./Label.js";
13
15
  import { Radio } from "./Radio.js";
14
16
  import * as Select from "./Select.js";
17
+ import { Spinner } from "./Spinner.js";
15
18
  import { Switch } from "./Switch.js";
16
19
  import * as Tabs from "./Tabs.js";
17
20
  import { Text } from "./Text.js";
18
21
  import * as TextBox from "./TextBox.js";
22
+ import * as Tree from "./Tree.js";
19
23
  import { Tooltip } from "./Tooltip.js";
20
24
  import { VisuallyHidden } from "./VisuallyHidden.js";
21
25
  export {
22
26
  Anchor,
23
27
  Button,
24
28
  Checkbox,
29
+ Chip,
30
+ Description,
25
31
  Divider,
26
32
  DropdownMenu,
27
33
  Field,
@@ -32,10 +38,12 @@ export {
32
38
  Radio,
33
39
  Root,
34
40
  Select,
41
+ Spinner,
35
42
  Switch,
36
43
  Tabs,
37
44
  Text,
38
45
  TextBox,
39
46
  Tooltip,
47
+ Tree,
40
48
  VisuallyHidden
41
49
  };