@ctrl-ui/react 0.8.20 → 0.9.0

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 (161) hide show
  1. package/README.md +1 -0
  2. package/dist/action-bar.d.ts +1 -2
  3. package/dist/action-bar.js +7 -8
  4. package/dist/blocks/design-canvas-inspector.js +4 -1
  5. package/dist/blocks/file-explorer.js +1 -1
  6. package/dist/chat-message.js +4 -13
  7. package/dist/hooks/use-textarea-trigger-menu.d.ts +21 -3
  8. package/dist/hooks/use-textarea-trigger-menu.js +36 -40
  9. package/dist/hooks/use-user-ask.d.ts +1 -0
  10. package/dist/hooks/use-user-ask.js +5 -1
  11. package/dist/knob-contracts/audio-recorder-knobs.d.ts +1 -1
  12. package/dist/knob-contracts/audio-recorder-knobs.js +2 -1
  13. package/dist/knob-contracts/chart-knobs.d.ts +4 -0
  14. package/dist/knob-contracts/chart-knobs.js +24 -0
  15. package/dist/knob-contracts/choice-knobs.d.ts +1 -1
  16. package/dist/knob-contracts/choice-knobs.js +1 -0
  17. package/dist/knob-contracts/dockable-panel-knobs.d.ts +1 -1
  18. package/dist/knob-contracts/dockable-panel-knobs.js +2 -1
  19. package/dist/knob-contracts/emoji-picker-knobs.d.ts +1 -1
  20. package/dist/knob-contracts/emoji-picker-knobs.js +1 -0
  21. package/dist/knob-contracts/empty-knobs.d.ts +1 -1
  22. package/dist/knob-contracts/empty-knobs.js +2 -1
  23. package/dist/knob-contracts/icon-picker-knobs.d.ts +1 -1
  24. package/dist/knob-contracts/icon-picker-knobs.js +3 -1
  25. package/dist/knob-contracts/resizable-knobs.d.ts +1 -1
  26. package/dist/knob-contracts/resizable-knobs.js +2 -2
  27. package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
  28. package/dist/knob-contracts/sidebar-knobs.js +3 -1
  29. package/dist/knob-contracts/tabs-knobs.d.ts +1 -1
  30. package/dist/knob-contracts/tabs-knobs.js +2 -1
  31. package/dist/knob-contracts/tree-knobs.d.ts +1 -1
  32. package/dist/knob-contracts/tree-knobs.js +2 -1
  33. package/dist/lib/color.d.ts +2 -6
  34. package/dist/lib/color.js +45 -28
  35. package/dist/lib/contrast.d.ts +6 -0
  36. package/dist/lib/contrast.js +33 -1
  37. package/dist/lib/gradient.d.ts +17 -0
  38. package/dist/lib/gradient.js +69 -0
  39. package/dist/markdown-editor/drag-handle.js +73 -10
  40. package/dist/markdown-editor/drag-preview.d.ts +3 -0
  41. package/dist/markdown-editor/drag-preview.js +31 -0
  42. package/dist/markdown-editor/extensions.d.ts +2 -2
  43. package/dist/markdown-editor/extensions.js +25 -3
  44. package/dist/markdown-editor/suggestions.js +5 -5
  45. package/dist/markdown-editor/task-item.d.ts +3 -0
  46. package/dist/markdown-editor/task-item.js +50 -0
  47. package/dist/markdown-editor/toolbar.js +122 -63
  48. package/dist/markdown-editor.js +3 -3
  49. package/dist/skin.d.ts +0 -1
  50. package/dist/styles/index.css +3 -2
  51. package/dist/styles/recipes/action-bar.css +1 -1
  52. package/dist/styles/recipes/activity.css +1 -1
  53. package/dist/styles/recipes/alert.css +9 -10
  54. package/dist/styles/recipes/app-shell-header.css +2 -2
  55. package/dist/styles/recipes/audio-recorder.css +15 -4
  56. package/dist/styles/recipes/audio-visualizer.css +4 -4
  57. package/dist/styles/recipes/avatar.css +3 -3
  58. package/dist/styles/recipes/badge.css +2 -2
  59. package/dist/styles/recipes/button.css +2 -5
  60. package/dist/styles/recipes/card.css +0 -2
  61. package/dist/styles/recipes/chart.css +378 -0
  62. package/dist/styles/recipes/chat-composer-attachment.css +3 -3
  63. package/dist/styles/recipes/chat-composer.css +3 -3
  64. package/dist/styles/recipes/chat-layout.css +2 -2
  65. package/dist/styles/recipes/chat-message-social.css +1 -1
  66. package/dist/styles/recipes/chat-message.css +1 -1
  67. package/dist/styles/recipes/choice.css +9 -3
  68. package/dist/styles/recipes/code-diff.css +1 -1
  69. package/dist/styles/recipes/code.css +1 -1
  70. package/dist/styles/recipes/color-picker-details.css +17 -11
  71. package/dist/styles/recipes/color-picker-values.css +17 -7
  72. package/dist/styles/recipes/color-picker.css +88 -70
  73. package/dist/styles/recipes/context.css +2 -2
  74. package/dist/styles/recipes/dockable-panel.css +9 -2
  75. package/dist/styles/recipes/dynamic-notification-motion.css +1 -55
  76. package/dist/styles/recipes/dynamic-notification.css +0 -1
  77. package/dist/styles/recipes/emoji-picker.css +35 -19
  78. package/dist/styles/recipes/empty.css +19 -14
  79. package/dist/styles/recipes/field-parts.css +2 -2
  80. package/dist/styles/recipes/field.css +6 -4
  81. package/dist/styles/recipes/filter-bar.css +10 -10
  82. package/dist/styles/recipes/flow.css +5 -3
  83. package/dist/styles/recipes/gradient-editor.css +8 -0
  84. package/dist/styles/recipes/icon-picker.css +45 -10
  85. package/dist/styles/recipes/inline-attachment.css +4 -4
  86. package/dist/styles/recipes/inline-citation.css +2 -2
  87. package/dist/styles/recipes/item.css +4 -4
  88. package/dist/styles/recipes/markdown-editor.css +35 -24
  89. package/dist/styles/recipes/markdown.css +23 -27
  90. package/dist/styles/recipes/page-layout.css +13 -11
  91. package/dist/styles/recipes/popup-controls.css +2 -2
  92. package/dist/styles/recipes/popup-lists.css +3 -3
  93. package/dist/styles/recipes/popup.css +11 -9
  94. package/dist/styles/recipes/range.css +4 -5
  95. package/dist/styles/recipes/resizable.css +15 -10
  96. package/dist/styles/recipes/resize-handle.css +2 -2
  97. package/dist/styles/recipes/scroll-area.css +1 -1
  98. package/dist/styles/recipes/sidebar-menu.css +5 -15
  99. package/dist/styles/recipes/sidebar-mobile.css +4 -4
  100. package/dist/styles/recipes/sidebar-parts.css +26 -1
  101. package/dist/styles/recipes/sidebar.css +18 -31
  102. package/dist/styles/recipes/skeleton.css +10 -5
  103. package/dist/styles/recipes/stepper.css +1 -1
  104. package/dist/styles/recipes/switch.css +12 -11
  105. package/dist/styles/recipes/table-of-contents.css +6 -8
  106. package/dist/styles/recipes/table.css +4 -4
  107. package/dist/styles/recipes/tabs.css +10 -5
  108. package/dist/styles/recipes/task-list.css +3 -3
  109. package/dist/styles/recipes/tree.css +10 -3
  110. package/dist/styles/recipes/user-ask-details.css +5 -4
  111. package/dist/styles/recipes/user-ask.css +5 -5
  112. package/dist/styles/theme.css +158 -177
  113. package/dist/ui/chart-cartesian.d.ts +801 -0
  114. package/dist/ui/chart-cartesian.js +420 -0
  115. package/dist/ui/chart-colors.d.ts +7 -0
  116. package/dist/ui/chart-colors.js +27 -0
  117. package/dist/ui/chart-curves.d.ts +7 -0
  118. package/dist/ui/chart-curves.js +87 -0
  119. package/dist/ui/chart-marks.d.ts +68 -0
  120. package/dist/ui/chart-marks.js +227 -0
  121. package/dist/ui/chart-polar.d.ts +103 -0
  122. package/dist/ui/chart-polar.js +124 -0
  123. package/dist/ui/chart-series.d.ts +36 -0
  124. package/dist/ui/chart-series.js +71 -0
  125. package/dist/ui/chart.d.ts +32 -0
  126. package/dist/ui/chart.js +257 -0
  127. package/dist/ui/color-picker-area.d.ts +16 -0
  128. package/dist/ui/color-picker-area.js +175 -0
  129. package/dist/ui/color-picker-context.d.ts +27 -0
  130. package/dist/ui/color-picker-context.js +87 -0
  131. package/dist/ui/color-picker-contrast.d.ts +20 -0
  132. package/dist/ui/color-picker-contrast.js +129 -0
  133. package/dist/ui/color-picker-sliders.d.ts +15 -0
  134. package/dist/ui/color-picker-sliders.js +146 -0
  135. package/dist/ui/color-picker-swatches.d.ts +23 -0
  136. package/dist/ui/color-picker-swatches.js +94 -0
  137. package/dist/ui/color-picker-values.d.ts +59 -0
  138. package/dist/ui/color-picker-values.js +244 -0
  139. package/dist/ui/color-picker.d.ts +15 -110
  140. package/dist/ui/color-picker.js +30 -759
  141. package/dist/ui/emoji-picker.d.ts +10 -1
  142. package/dist/ui/emoji-picker.js +71 -14
  143. package/dist/ui/flow.js +1 -1
  144. package/dist/ui/gradient-editor-controls.d.ts +19 -0
  145. package/dist/ui/gradient-editor-controls.js +75 -0
  146. package/dist/ui/gradient-editor.d.ts +23 -22
  147. package/dist/ui/gradient-editor.js +77 -123
  148. package/dist/ui/icon-picker.d.ts +1 -1
  149. package/dist/ui/icon-picker.js +11 -6
  150. package/dist/ui/markdown-elements.d.ts +3 -1
  151. package/dist/ui/markdown-elements.js +62 -22
  152. package/dist/ui/markdown-heading.d.ts +9 -0
  153. package/dist/ui/markdown-heading.js +25 -0
  154. package/dist/ui/resizable.js +24 -9
  155. package/dist/ui/sidebar-provider.js +3 -12
  156. package/dist/ui/typography.d.ts +1 -0
  157. package/dist/ui/typography.js +12 -3
  158. package/dist/user-ask.js +4 -8
  159. package/package.json +7 -3
  160. package/dist/ui/emoji-icon-picker.d.ts +0 -13
  161. package/dist/ui/emoji-icon-picker.js +0 -50
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
+ import { ScrollArea } from "./scroll-area.js";
3
4
  import { Input } from "./input.js";
4
5
  import { Toolbar } from "@base-ui/react/toolbar";
5
6
  import { createContext, useContext, useRef, useState } from "react";
@@ -62,7 +63,7 @@ function IconPickerSearch({ placeholder = "Search icons…", "aria-label": ariaL
62
63
  }
63
64
  });
64
65
  }
65
- function IconPickerContent({ className, empty = "No icons found.", "aria-label": ariaLabel = "Icons", ...props }) {
66
+ function IconPickerContent({ className, ref, empty = "No icons found.", "aria-label": ariaLabel = "Icons", ...props }) {
66
67
  const picker = useIconPicker();
67
68
  const buttonsRef = useRef(/* @__PURE__ */ new Map());
68
69
  const normalizedSearch = picker.search.trim().toLocaleLowerCase();
@@ -76,12 +77,16 @@ function IconPickerContent({ className, empty = "No icons found.", "aria-label":
76
77
  const nextIndex = Math.max(0, Math.min(filteredItems.length - 1, currentIndex + direction * picker.columns));
77
78
  buttonsRef.current.get(filteredItems[nextIndex].value)?.focus();
78
79
  };
79
- return /* @__PURE__ */ jsx("div", {
80
- "data-control-ui": "icon-picker",
81
- "data-control-family": "icon-picker",
82
- "data-slot": "content",
80
+ return /* @__PURE__ */ jsx(ScrollArea, {
81
+ lockAxis: "x",
83
82
  className,
84
- ...props,
83
+ viewportRef: ref,
84
+ viewportProps: {
85
+ "data-control-ui": "icon-picker",
86
+ "data-control-family": "icon-picker",
87
+ "data-slot": "content",
88
+ ...props
89
+ },
85
90
  children: filteredItems.length === 0 ? /* @__PURE__ */ jsx("div", {
86
91
  "data-control-ui": "icon-picker",
87
92
  "data-control-family": "icon-picker",
@@ -11,6 +11,7 @@ type MarkdownElementProps<Tag extends keyof JSX.IntrinsicElements> = ComponentPr
11
11
  } & {
12
12
  style?: CSSProperties & MarkdownKnobStyle;
13
13
  };
14
+ export declare function MarkdownInput({ type, checked, className, node: _node, ...props }: MarkdownElementProps<"input">): JSX.Element;
14
15
  export declare function MarkdownInlineCode({ className, children, node: _node, ...props }: MarkdownCodeProps): JSX.Element;
15
16
  export declare function MarkdownPre({ children, node: _node }: MarkdownElementProps<"pre">): JSX.Element;
16
17
  export declare function MarkdownCode({ className, children, node: _node, ...props }: MarkdownCodeProps): JSX.Element;
@@ -23,7 +24,7 @@ export declare function MarkdownH6({ className, node: _node, ...props }: Markdow
23
24
  export declare function MarkdownP({ className, node: _node, ...props }: MarkdownElementProps<"p">): JSX.Element;
24
25
  export declare function MarkdownUl({ className, node: _node, ...props }: MarkdownElementProps<"ul">): JSX.Element;
25
26
  export declare function MarkdownOl({ className, node: _node, ...props }: MarkdownElementProps<"ol">): JSX.Element;
26
- export declare function MarkdownLi({ className, node: _node, ...props }: MarkdownElementProps<"li">): JSX.Element;
27
+ export declare function MarkdownLi({ id, className, node: _node, ...props }: MarkdownElementProps<"li">): JSX.Element;
27
28
  export declare function MarkdownA({ className, node: _node, ...props }: MarkdownElementProps<"a">): JSX.Element;
28
29
  export declare function MarkdownBlockquote({ className, node: _node, ...props }: MarkdownElementProps<"blockquote">): JSX.Element;
29
30
  export declare function MarkdownHr({ className, node: _node, ...props }: MarkdownElementProps<"hr">): JSX.Element;
@@ -33,6 +34,7 @@ export declare function MarkdownTable({ className, children, node: _node, ...pro
33
34
  export declare function MarkdownTh({ className, node: _node, ...props }: MarkdownElementProps<"th">): JSX.Element;
34
35
  export declare function MarkdownTd({ className, node: _node, ...props }: MarkdownElementProps<"td">): JSX.Element;
35
36
  export declare const markdownComponents: {
37
+ input: typeof MarkdownInput;
36
38
  code: typeof MarkdownCode;
37
39
  inlineCode: typeof MarkdownInlineCode;
38
40
  h1: typeof MarkdownH1;
@@ -1,9 +1,31 @@
1
+ "use client";
1
2
  import { cn } from "../lib/cn.js";
2
3
  import { ScrollArea } from "./scroll-area.js";
4
+ import { Heading } from "./typography.js";
3
5
  import { Code, CodeActions, CodeContent, CodeCopy, CodeHeader, CodeTitle } from "./code.js";
6
+ import { Checkbox } from "./checkbox.js";
4
7
  import { CodeDiff } from "./code-diff.js";
5
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { markdownHeadingAttributes } from "./markdown-heading.js";
9
+ import { createContext, use, useId } from "react";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
11
  //#region src/ui/markdown-elements.tsx
12
+ const MarkdownTaskLabelContext = createContext(void 0);
13
+ function MarkdownInput({ type, checked, className, node: _node, ...props }) {
14
+ const labelId = use(MarkdownTaskLabelContext);
15
+ if (type !== "checkbox") return /* @__PURE__ */ jsx("input", {
16
+ type,
17
+ checked,
18
+ className,
19
+ ...props
20
+ });
21
+ return /* @__PURE__ */ jsx(Checkbox, {
22
+ checked: Boolean(checked),
23
+ readOnly: true,
24
+ className,
25
+ "aria-label": labelId ? void 0 : "Task item",
26
+ "aria-labelledby": labelId
27
+ });
28
+ }
7
29
  function textValue(children) {
8
30
  return Array.isArray(children) ? children.join("") : String(children ?? "");
9
31
  }
@@ -21,7 +43,7 @@ function MarkdownInlineCode({ className, children, node: _node, ...props }) {
21
43
  });
22
44
  }
23
45
  function MarkdownPre({ children, node: _node }) {
24
- return /* @__PURE__ */ jsx(Fragment, { children });
46
+ return /* @__PURE__ */ jsx(Fragment$1, { children });
25
47
  }
26
48
  function MarkdownCode({ className, children, node: _node, ...props }) {
27
49
  const lang = languageFromClassName(className);
@@ -44,56 +66,68 @@ function MarkdownCode({ className, children, node: _node, ...props }) {
44
66
  })] });
45
67
  }
46
68
  function MarkdownH1({ className, node: _node, ...props }) {
47
- return /* @__PURE__ */ jsx("h1", {
69
+ const { class: headingClass } = markdownHeadingAttributes(1);
70
+ return /* @__PURE__ */ jsx(Heading, {
71
+ level: 1,
48
72
  "data-control-ui": "markdown",
49
73
  "data-control-family": "markdown",
50
74
  "data-slot": "h1",
51
- className,
75
+ className: cn(headingClass, className),
52
76
  ...props
53
77
  });
54
78
  }
55
79
  function MarkdownH2({ className, node: _node, ...props }) {
56
- return /* @__PURE__ */ jsx("h2", {
80
+ const { class: headingClass } = markdownHeadingAttributes(2);
81
+ return /* @__PURE__ */ jsx(Heading, {
82
+ level: 2,
57
83
  "data-control-ui": "markdown",
58
84
  "data-control-family": "markdown",
59
85
  "data-slot": "h2",
60
- className,
86
+ className: cn(headingClass, className),
61
87
  ...props
62
88
  });
63
89
  }
64
90
  function MarkdownH3({ className, node: _node, ...props }) {
65
- return /* @__PURE__ */ jsx("h3", {
91
+ const { class: headingClass } = markdownHeadingAttributes(3);
92
+ return /* @__PURE__ */ jsx(Heading, {
93
+ level: 3,
66
94
  "data-control-ui": "markdown",
67
95
  "data-control-family": "markdown",
68
96
  "data-slot": "h3",
69
- className,
97
+ className: cn(headingClass, className),
70
98
  ...props
71
99
  });
72
100
  }
73
101
  function MarkdownH4({ className, node: _node, ...props }) {
74
- return /* @__PURE__ */ jsx("h4", {
102
+ const { class: headingClass } = markdownHeadingAttributes(4);
103
+ return /* @__PURE__ */ jsx(Heading, {
104
+ level: 4,
75
105
  "data-control-ui": "markdown",
76
106
  "data-control-family": "markdown",
77
107
  "data-slot": "h4",
78
- className,
108
+ className: cn(headingClass, className),
79
109
  ...props
80
110
  });
81
111
  }
82
112
  function MarkdownH5({ className, node: _node, ...props }) {
83
- return /* @__PURE__ */ jsx("h5", {
113
+ const { class: headingClass } = markdownHeadingAttributes(5);
114
+ return /* @__PURE__ */ jsx(Heading, {
115
+ level: 5,
84
116
  "data-control-ui": "markdown",
85
117
  "data-control-family": "markdown",
86
118
  "data-slot": "h5",
87
- className,
119
+ className: cn(headingClass, className),
88
120
  ...props
89
121
  });
90
122
  }
91
123
  function MarkdownH6({ className, node: _node, ...props }) {
92
- return /* @__PURE__ */ jsx("h6", {
124
+ const { class: headingClass } = markdownHeadingAttributes(6);
125
+ return /* @__PURE__ */ jsx(Heading, {
126
+ level: 6,
93
127
  "data-control-ui": "markdown",
94
128
  "data-control-family": "markdown",
95
129
  "data-slot": "h6",
96
- className,
130
+ className: cn(headingClass, className),
97
131
  ...props
98
132
  });
99
133
  }
@@ -124,13 +158,18 @@ function MarkdownOl({ className, node: _node, ...props }) {
124
158
  ...props
125
159
  });
126
160
  }
127
- function MarkdownLi({ className, node: _node, ...props }) {
128
- return /* @__PURE__ */ jsx("li", {
129
- "data-control-ui": "markdown",
130
- "data-control-family": "markdown",
131
- "data-slot": "list-item",
132
- className,
133
- ...props
161
+ function MarkdownLi({ id, className, node: _node, ...props }) {
162
+ const labelId = useId();
163
+ return /* @__PURE__ */ jsx(MarkdownTaskLabelContext, {
164
+ value: id ?? labelId,
165
+ children: /* @__PURE__ */ jsx("li", {
166
+ id: id ?? labelId,
167
+ "data-control-ui": "markdown",
168
+ "data-control-family": "markdown",
169
+ "data-slot": "list-item",
170
+ className,
171
+ ...props
172
+ })
134
173
  });
135
174
  }
136
175
  function MarkdownA({ className, node: _node, ...props }) {
@@ -215,6 +254,7 @@ function MarkdownTd({ className, node: _node, ...props }) {
215
254
  });
216
255
  }
217
256
  const markdownComponents = {
257
+ input: MarkdownInput,
218
258
  code: MarkdownCode,
219
259
  inlineCode: MarkdownInlineCode,
220
260
  h1: MarkdownH1,
@@ -237,4 +277,4 @@ const markdownComponents = {
237
277
  td: MarkdownTd
238
278
  };
239
279
  //#endregion
240
- export { MarkdownA, MarkdownBlockquote, MarkdownCode, MarkdownEm, MarkdownH1, MarkdownH2, MarkdownH3, MarkdownH4, MarkdownH5, MarkdownH6, MarkdownHr, MarkdownInlineCode, MarkdownLi, MarkdownOl, MarkdownP, MarkdownPre, MarkdownStrong, MarkdownTable, MarkdownTd, MarkdownTh, MarkdownUl, markdownComponents };
280
+ export { MarkdownA, MarkdownBlockquote, MarkdownCode, MarkdownEm, MarkdownH1, MarkdownH2, MarkdownH3, MarkdownH4, MarkdownH5, MarkdownH6, MarkdownHr, MarkdownInlineCode, MarkdownInput, MarkdownLi, MarkdownOl, MarkdownP, MarkdownPre, MarkdownStrong, MarkdownTable, MarkdownTd, MarkdownTh, MarkdownUl, markdownComponents };
@@ -0,0 +1,9 @@
1
+ import { HeadingLevel } from "./typography.js";
2
+ //#region src/ui/markdown-heading.d.ts
3
+ export declare function markdownHeadingAttributes(level: HeadingLevel): {
4
+ "data-control-ui": string;
5
+ "data-control-family": string;
6
+ "data-slot": string;
7
+ class: string;
8
+ };
9
+ //#endregion
@@ -0,0 +1,25 @@
1
+ import { headingClassName } from "./typography.js";
2
+ //#region src/ui/markdown-heading.ts
3
+ const headingSizes = {
4
+ 1: "heading-2",
5
+ 2: "heading-3",
6
+ 3: "heading-4",
7
+ 4: "body",
8
+ 5: "body",
9
+ 6: "body"
10
+ };
11
+ function markdownHeadingAttributes(level) {
12
+ return {
13
+ "data-control-ui": "markdown",
14
+ "data-control-family": "markdown",
15
+ "data-slot": `h${level}`,
16
+ class: headingClassName({
17
+ level,
18
+ size: headingSizes[level],
19
+ weight: level >= 4 ? "semibold" : void 0,
20
+ className: level >= 4 ? "leading-tight" : void 0
21
+ })
22
+ };
23
+ }
24
+ //#endregion
25
+ export { markdownHeadingAttributes };
@@ -208,26 +208,41 @@ function ResizableFloatingPanel({ side = "right", size: controlledSize, defaultS
208
208
  }
209
209
  function GripIcon({ className }) {
210
210
  return /* @__PURE__ */ jsxs("svg", {
211
- viewBox: "0 0 4 16",
212
- width: "4",
213
- height: "16",
211
+ viewBox: "0 0 6 10",
212
+ width: "6",
213
+ height: "10",
214
214
  fill: "currentColor",
215
215
  "aria-hidden": "true",
216
216
  className,
217
217
  children: [
218
218
  /* @__PURE__ */ jsx("circle", {
219
- cx: "2",
220
- cy: "3",
219
+ cx: "1",
220
+ cy: "1",
221
221
  r: "1"
222
222
  }),
223
223
  /* @__PURE__ */ jsx("circle", {
224
- cx: "2",
225
- cy: "8",
224
+ cx: "5",
225
+ cy: "1",
226
226
  r: "1"
227
227
  }),
228
228
  /* @__PURE__ */ jsx("circle", {
229
- cx: "2",
230
- cy: "13",
229
+ cx: "1",
230
+ cy: "5",
231
+ r: "1"
232
+ }),
233
+ /* @__PURE__ */ jsx("circle", {
234
+ cx: "5",
235
+ cy: "5",
236
+ r: "1"
237
+ }),
238
+ /* @__PURE__ */ jsx("circle", {
239
+ cx: "1",
240
+ cy: "9",
241
+ r: "1"
242
+ }),
243
+ /* @__PURE__ */ jsx("circle", {
244
+ cx: "5",
245
+ cy: "9",
231
246
  r: "1"
232
247
  })
233
248
  ]
@@ -1,16 +1,13 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
- import { useSkin } from "../skin-provider.js";
4
3
  import { SIDEBAR_COOKIE_NAME } from "../control-props.js";
5
4
  import { TooltipProvider } from "./tooltip.js";
6
5
  import { useIsMobile } from "../hooks/use-mobile.js";
7
- import { createContext, useContext, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
6
+ import { createContext, useContext, useEffect, useEffectEvent, useId, useLayoutEffect, useRef, useState } from "react";
8
7
  import { useRender } from "@base-ui/react/use-render";
9
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
9
  //#region src/ui/sidebar-provider.tsx
11
10
  const SIDEBAR_COOKIE_MAX_AGE = 604800;
12
- const SIDEBAR_WIDTH = "16rem";
13
- const SIDEBAR_WIDTH_ICON = "3rem";
14
11
  const SIDEBAR_KEYBOARD_SHORTCUT = "b";
15
12
  const SIDEBAR_MOBILE_BREAKPOINT = "--breakpoint-lg";
16
13
  const SidebarElementsContext = createContext(null);
@@ -39,7 +36,6 @@ function useSidebar() {
39
36
  return context;
40
37
  }
41
38
  function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, defaultWidth, minWidth = 224, maxWidth = 420, width: widthProp, onWidthChange, persistOpen = true, keyboardShortcut = SIDEBAR_KEYBOARD_SHORTCUT, layout = "viewport", skipLinkLabel = "Skip to content", contentId: contentIdProp, ref, className, style, children, ...props }) {
42
- const skin = useSkin();
43
39
  const isMobile = useIsMobile(SIDEBAR_MOBILE_BREAKPOINT);
44
40
  const [openMobile, setOpenMobile] = useState(false);
45
41
  if (!isMobile && openMobile) setOpenMobile(false);
@@ -88,10 +84,7 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
88
84
  if (persistOpen) document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
89
85
  };
90
86
  const toggleSidebar = () => isMobile ? setOpenMobile((prev) => !prev) : setOpen(!open);
91
- const toggleRef = useRef(toggleSidebar);
92
- useEffect(() => {
93
- toggleRef.current = toggleSidebar;
94
- });
87
+ const toggleSidebarFromShortcut = useEffectEvent(toggleSidebar);
95
88
  useEffect(() => {
96
89
  if (keyboardShortcut === null) return;
97
90
  const shortcut = keyboardShortcut.toLowerCase();
@@ -101,7 +94,7 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
101
94
  const target = event.target;
102
95
  if (target instanceof HTMLElement && (target.isContentEditable || target.closest("input, textarea, select") !== null)) return;
103
96
  event.preventDefault();
104
- toggleRef.current();
97
+ toggleSidebarFromShortcut();
105
98
  };
106
99
  window.addEventListener("keydown", handleKeyDown);
107
100
  return () => window.removeEventListener("keydown", handleKeyDown);
@@ -124,8 +117,6 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
124
117
  contentId
125
118
  };
126
119
  const wrapperStyle = {
127
- "--sidebar-width": skin.sidebarWidth ?? SIDEBAR_WIDTH,
128
- "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
129
120
  ...style,
130
121
  ...width === void 0 ? {} : { "--sidebar-width": `${width}px` }
131
122
  };
@@ -34,6 +34,7 @@ export type HeadingProps = ComponentProps<"h1"> & {
34
34
  weight?: TextWeight;
35
35
  tone?: TypeTone;
36
36
  };
37
+ export declare function headingClassName({ level, size, weight, tone, className }: HeadingProps): string;
37
38
  export declare function Heading({ level, size, weight, tone, className, ...props }: HeadingProps): import("react").JSX.Element;
38
39
  export type TextTag = "p" | "span" | "div" | "small" | "strong" | "em" | "code" | "li" | "dt" | "dd" | "figcaption" | "legend" | "blockquote";
39
40
  export type TextProps = HTMLAttributes<HTMLElement> & {
@@ -33,13 +33,22 @@ const headingSizeByLevel = {
33
33
  5: "heading-4",
34
34
  6: "heading-4"
35
35
  };
36
- function Heading({ level, size = headingSizeByLevel[level], weight, tone = "default", className, ...props }) {
36
+ function headingClassName({ level, size = headingSizeByLevel[level], weight, tone = "default", className }) {
37
+ return cn(sizeClassNames[size], weight ? weightClassNames[weight] : void 0, toneClassNames[tone], className);
38
+ }
39
+ function Heading({ level, size, weight, tone, className, ...props }) {
37
40
  const Tag = `h${level}`;
38
41
  return /* @__PURE__ */ jsx(Tag, {
39
42
  "data-control-ui": "typography",
40
43
  "data-control-family": "typography",
41
44
  "data-slot": "heading",
42
- className: cn(sizeClassNames[size], weight ? weightClassNames[weight] : void 0, toneClassNames[tone], className),
45
+ className: headingClassName({
46
+ level,
47
+ size,
48
+ weight,
49
+ tone,
50
+ className
51
+ }),
43
52
  ...props
44
53
  });
45
54
  }
@@ -58,4 +67,4 @@ function Text({ as: Tag = "span", size = "body", weight, tone = "default", class
58
67
  });
59
68
  }
60
69
  //#endregion
61
- export { Heading, Text };
70
+ export { Heading, Text, headingClassName };
package/dist/user-ask.js CHANGED
@@ -4,7 +4,7 @@ import { Button } from "./ui/button.js";
4
4
  import { LiveStatus } from "./ui/live-status.js";
5
5
  import { useUserAsk } from "./hooks/use-user-ask.js";
6
6
  import { Kbd } from "./ui/kbd.js";
7
- import { createContext, useContext, useEffect, useId, useRef, useState } from "react";
7
+ import { createContext, useContext, useEffect, useId, useRef } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Check, ChevronLeft, ChevronRight, PencilLine } from "lucide-react";
10
10
  //#region src/user-ask.tsx
@@ -30,21 +30,17 @@ function UserAsk({ onComplete, onDismiss, autoFocus = false, questionStatusLabel
30
30
  });
31
31
  const titleId = useId();
32
32
  const panelRef = useRef(null);
33
- const [hasNavigated, setHasNavigated] = useState(false);
34
- const questionStatus = hasNavigated && ask.activeQuestion ? questionStatusLabel(ask.activeIndex + 1, ask.questions.length, ask.activeQuestion.title) : "";
33
+ const questionStatus = ask.hasNavigated && ask.activeQuestion ? questionStatusLabel(ask.activeIndex + 1, ask.questions.length, ask.activeQuestion.title) : "";
35
34
  useEffect(() => {
36
35
  if (autoFocus) panelRef.current?.focus();
37
36
  }, [autoFocus]);
38
- const lastActiveIndex = useRef(ask.activeIndex);
39
37
  useEffect(() => {
40
- if (lastActiveIndex.current === ask.activeIndex) return;
41
- lastActiveIndex.current = ask.activeIndex;
42
- setHasNavigated(true);
38
+ if (!ask.hasNavigated) return;
43
39
  const panel = panelRef.current;
44
40
  const active = document.activeElement;
45
41
  const activeIsUsable = active instanceof HTMLElement && panel?.contains(active) && active.checkVisibility();
46
42
  if (panel && !activeIsUsable) panel.focus();
47
- }, [ask.activeIndex]);
43
+ }, [ask.activeIndex, ask.hasNavigated]);
48
44
  return /* @__PURE__ */ jsx(UserAskContext.Provider, {
49
45
  value: {
50
46
  ...ask,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctrl-ui/react",
3
- "version": "0.8.20",
3
+ "version": "0.9.0",
4
4
  "description": "Control UI components, blocks, and primitives with neutral defaults and consumer-owned themes.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,8 +35,8 @@
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@base-ui/react": "^1.8.0",
38
+ "@tanstack/charts": "^1.1.0",
38
39
  "@tanstack/react-virtual": "^3.14.13",
39
- "@xyflow/react": "^12.12.0",
40
40
  "@tiptap/core": "3.31.4",
41
41
  "@tiptap/extension-image": "3.31.4",
42
42
  "@tiptap/extension-list": "3.31.4",
@@ -46,6 +46,7 @@
46
46
  "@tiptap/pm": "3.31.4",
47
47
  "@tiptap/react": "3.31.4",
48
48
  "@tiptap/starter-kit": "3.31.4",
49
+ "@xyflow/react": "^12.12.0",
49
50
  "class-variance-authority": "^0.7.1",
50
51
  "clsx": "^2.1.1",
51
52
  "cmdk": "^1.1.1",
@@ -71,7 +72,7 @@
71
72
  "zod": "^4.6.5"
72
73
  },
73
74
  "peerDependenciesMeta": {
74
- "@xyflow/react": {
75
+ "@tanstack/charts": {
75
76
  "optional": true
76
77
  },
77
78
  "@tanstack/react-virtual": {
@@ -104,6 +105,9 @@
104
105
  "@tiptap/starter-kit": {
105
106
  "optional": true
106
107
  },
108
+ "@xyflow/react": {
109
+ "optional": true
110
+ },
107
111
  "cmdk": {
108
112
  "optional": true
109
113
  },
@@ -1,13 +0,0 @@
1
- import { EmojiPicker } from "./emoji-picker.js";
2
- import { IconPicker } from "./icon-picker.js";
3
- import { Tabs, TabsList } from "./tabs.js";
4
- import { ComponentProps } from "react";
5
- //#region src/ui/emoji-icon-picker.d.ts
6
- export declare function EmojiIconPicker({ children, defaultValue, ...props }: ComponentProps<typeof Tabs<"emoji" | "icons">>): import("react").JSX.Element;
7
- export declare function EmojiIconPickerTabs({ emojiLabel, iconsLabel, ...props }: Omit<ComponentProps<typeof TabsList>, "children"> & {
8
- emojiLabel?: string;
9
- iconsLabel?: string;
10
- }): import("react").JSX.Element;
11
- export declare function EmojiIconPickerEmoji(props: ComponentProps<typeof EmojiPicker>): import("react").JSX.Element;
12
- export declare function EmojiIconPickerIcons(props: ComponentProps<typeof IconPicker>): import("react").JSX.Element;
13
- //#endregion
@@ -1,50 +0,0 @@
1
- "use client";
2
- import { PopoverViewport } from "./popover.js";
3
- import { EmojiPicker } from "./emoji-picker.js";
4
- import { IconPicker } from "./icon-picker.js";
5
- import { Tabs, TabsList, TabsPanel, TabsTab } from "./tabs.js";
6
- import { jsx, jsxs } from "react/jsx-runtime";
7
- //#region src/ui/emoji-icon-picker.tsx
8
- function EmojiIconPicker({ children, defaultValue = "emoji", ...props }) {
9
- return /* @__PURE__ */ jsx(Tabs, {
10
- "data-control-ui": "emoji-icon-picker",
11
- "data-control-family": "tabs",
12
- "data-slot": "root",
13
- defaultValue,
14
- ...props,
15
- children: /* @__PURE__ */ jsx(PopoverViewport, { children })
16
- });
17
- }
18
- function EmojiIconPickerTabs({ emojiLabel = "Emoji", iconsLabel = "Icons", ...props }) {
19
- return /* @__PURE__ */ jsxs(TabsList, {
20
- size: "xs",
21
- className: "mx-2 mt-2",
22
- "aria-label": "Choose emoji or icon",
23
- ...props,
24
- children: [/* @__PURE__ */ jsx(TabsTab, {
25
- value: "emoji",
26
- children: emojiLabel
27
- }), /* @__PURE__ */ jsx(TabsTab, {
28
- value: "icons",
29
- children: iconsLabel
30
- })]
31
- });
32
- }
33
- function EmojiIconPickerEmoji(props) {
34
- return /* @__PURE__ */ jsx(TabsPanel, {
35
- value: "emoji",
36
- "data-slide": void 0,
37
- className: "mt-0",
38
- children: /* @__PURE__ */ jsx(EmojiPicker, { ...props })
39
- });
40
- }
41
- function EmojiIconPickerIcons(props) {
42
- return /* @__PURE__ */ jsx(TabsPanel, {
43
- value: "icons",
44
- "data-slide": void 0,
45
- className: "mt-0",
46
- children: /* @__PURE__ */ jsx(IconPicker, { ...props })
47
- });
48
- }
49
- //#endregion
50
- export { EmojiIconPicker, EmojiIconPickerEmoji, EmojiIconPickerIcons, EmojiIconPickerTabs };