@ctrl-ui/react 0.8.5 → 0.8.7

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 (152) hide show
  1. package/dist/action-bar.js +1 -1
  2. package/dist/activity.js +1 -1
  3. package/dist/blocks/coding-agent.js +16 -19
  4. package/dist/blocks/design-canvas-data.d.ts +32 -0
  5. package/dist/blocks/design-canvas-data.js +100 -0
  6. package/dist/blocks/design-canvas-inspector.d.ts +8 -0
  7. package/dist/blocks/design-canvas-inspector.js +238 -0
  8. package/dist/blocks/design-canvas.d.ts +17 -0
  9. package/dist/blocks/design-canvas.js +346 -0
  10. package/dist/blocks/file-explorer.js +2 -2
  11. package/dist/blocks/settings.js +2 -2
  12. package/dist/chat-composer-attachment.d.ts +9 -3
  13. package/dist/chat-composer-attachment.js +27 -10
  14. package/dist/chat-composer-editor.js +20 -4
  15. package/dist/chat-composer.d.ts +1 -1
  16. package/dist/chat-composer.js +4 -3
  17. package/dist/chat-layout.js +32 -19
  18. package/dist/context.js +1 -1
  19. package/dist/dynamic-notification.js +1 -1
  20. package/dist/environment-variables.js +1 -1
  21. package/dist/filter-bar/context.d.ts +32 -0
  22. package/dist/filter-bar/context.js +11 -0
  23. package/dist/filter-bar/editor.d.ts +14 -0
  24. package/dist/filter-bar/editor.js +204 -0
  25. package/dist/filter-bar/model.d.ts +9 -0
  26. package/dist/filter-bar/model.js +48 -0
  27. package/dist/filter-bar/motion.d.ts +10 -0
  28. package/dist/filter-bar/motion.js +84 -0
  29. package/dist/filter-bar/parts.d.ts +19 -0
  30. package/dist/filter-bar/parts.js +233 -0
  31. package/dist/filter-bar/types.d.ts +53 -0
  32. package/dist/filter-bar/types.js +0 -0
  33. package/dist/filter-bar.d.ts +27 -0
  34. package/dist/filter-bar.js +304 -0
  35. package/dist/hooks/use-chat-composer.d.ts +3 -1
  36. package/dist/hooks/use-chat-composer.js +2 -2
  37. package/dist/hooks/use-dropzone.d.ts +7 -4
  38. package/dist/hooks/use-dropzone.js +34 -3
  39. package/dist/inline-attachment.js +8 -14
  40. package/dist/inline-citation.js +1 -1
  41. package/dist/knob-contracts/chat-layout-knobs.d.ts +1 -1
  42. package/dist/knob-contracts/chat-layout-knobs.js +2 -1
  43. package/dist/knob-contracts/choice-knobs.d.ts +1 -1
  44. package/dist/knob-contracts/choice-knobs.js +1 -0
  45. package/dist/knob-contracts/collapsible-knobs.d.ts +1 -1
  46. package/dist/knob-contracts/collapsible-knobs.js +1 -1
  47. package/dist/knob-contracts/filter-bar-knobs.d.ts +4 -0
  48. package/dist/knob-contracts/filter-bar-knobs.js +16 -0
  49. package/dist/knob-contracts/infinite-canvas-knobs.d.ts +1 -1
  50. package/dist/knob-contracts/infinite-canvas-knobs.js +3 -0
  51. package/dist/knob-contracts/page-layout-knobs.d.ts +1 -1
  52. package/dist/knob-contracts/page-layout-knobs.js +4 -1
  53. package/dist/knob-contracts/popup-knobs.d.ts +1 -1
  54. package/dist/knob-contracts/popup-knobs.js +1 -0
  55. package/dist/knob-contracts/table-of-contents-knobs.d.ts +1 -1
  56. package/dist/knob-contracts/table-of-contents-knobs.js +3 -5
  57. package/dist/lib/phone-input-format.js +1 -1
  58. package/dist/markdown-block.js +11 -7
  59. package/dist/scripts/contrast-eval.js +5 -4
  60. package/dist/styles/index.css +5 -4
  61. package/dist/styles/recipes/button-group.css +1 -1
  62. package/dist/styles/recipes/button.css +2 -2
  63. package/dist/styles/recipes/chat-composer.css +14 -6
  64. package/dist/styles/recipes/chat-layout.css +29 -2
  65. package/dist/styles/recipes/choice.css +10 -3
  66. package/dist/styles/recipes/code-diff.css +16 -4
  67. package/dist/styles/recipes/code.css +11 -5
  68. package/dist/styles/recipes/collapsible.css +37 -0
  69. package/dist/styles/recipes/color-picker.css +12 -2
  70. package/dist/styles/recipes/dockable-panel.css +11 -3
  71. package/dist/styles/recipes/field-parts.css +62 -0
  72. package/dist/styles/recipes/field.css +28 -6
  73. package/dist/styles/recipes/filter-bar.css +174 -0
  74. package/dist/styles/recipes/infinite-canvas.css +51 -3
  75. package/dist/styles/recipes/inline-attachment.css +6 -1
  76. package/dist/styles/recipes/page-layout.css +36 -2
  77. package/dist/styles/recipes/pagination.css +1 -1
  78. package/dist/styles/recipes/popup-controls.css +16 -0
  79. package/dist/styles/recipes/popup-drawer.css +34 -32
  80. package/dist/styles/recipes/popup-lists.css +11 -2
  81. package/dist/styles/recipes/popup.css +10 -12
  82. package/dist/styles/recipes/range.css +1 -1
  83. package/dist/styles/recipes/resizable.css +34 -0
  84. package/dist/styles/recipes/spinner.css +4 -0
  85. package/dist/styles/recipes/table-of-contents.css +42 -42
  86. package/dist/styles/recipes/tabs.css +21 -0
  87. package/dist/styles/recipes/track-highlight.css +2 -1
  88. package/dist/styles/recipes/transcript-divider.css +2 -2
  89. package/dist/styles/theme.css +250 -91
  90. package/dist/ui/alert-dialog.js +1 -1
  91. package/dist/ui/autocomplete.js +5 -1
  92. package/dist/ui/button.js +2 -2
  93. package/dist/ui/checkbox-group.js +1 -1
  94. package/dist/ui/code-diff.js +1 -1
  95. package/dist/ui/code.js +3 -3
  96. package/dist/ui/collapsible.js +1 -1
  97. package/dist/ui/color-picker.js +2 -2
  98. package/dist/ui/combobox-disabled-selection.d.ts +1 -1
  99. package/dist/ui/combobox-disabled-selection.js +2 -1
  100. package/dist/ui/combobox.d.ts +5 -23
  101. package/dist/ui/combobox.js +26 -14
  102. package/dist/ui/command.js +9 -1
  103. package/dist/ui/context-menu.js +1 -1
  104. package/dist/ui/dialog.js +1 -1
  105. package/dist/ui/dockable-panel.js +18 -10
  106. package/dist/ui/drawer.d.ts +7 -4
  107. package/dist/ui/drawer.js +36 -23
  108. package/dist/ui/dropdown-menu.js +1 -1
  109. package/dist/ui/dropzone.d.ts +3 -1
  110. package/dist/ui/dropzone.js +3 -1
  111. package/dist/ui/field.js +1 -1
  112. package/dist/ui/hover-card.js +1 -1
  113. package/dist/ui/infinite-canvas.d.ts +11 -0
  114. package/dist/ui/infinite-canvas.js +82 -7
  115. package/dist/ui/input-group.d.ts +2 -1
  116. package/dist/ui/input-group.js +12 -3
  117. package/dist/ui/input.js +9 -0
  118. package/dist/ui/item.js +1 -1
  119. package/dist/ui/markdown-elements.js +11 -8
  120. package/dist/ui/menubar.js +1 -1
  121. package/dist/ui/morphing-panel.js +1 -1
  122. package/dist/ui/navigation-menu.js +1 -1
  123. package/dist/ui/number-field.d.ts +1 -1
  124. package/dist/ui/number-field.js +13 -2
  125. package/dist/ui/phone-input.js +2 -2
  126. package/dist/ui/popover.js +1 -1
  127. package/dist/ui/radio-group.d.ts +1 -0
  128. package/dist/ui/radio-group.js +11 -1
  129. package/dist/ui/resizable.d.ts +18 -1
  130. package/dist/ui/resizable.js +127 -7
  131. package/dist/ui/responsive-dialog.js +6 -3
  132. package/dist/ui/rich-tooltip.js +1 -1
  133. package/dist/ui/scroll-area.d.ts +4 -1
  134. package/dist/ui/scroll-area.js +2 -1
  135. package/dist/ui/select.d.ts +2 -1
  136. package/dist/ui/select.js +58 -33
  137. package/dist/ui/sheet.js +1 -1
  138. package/dist/ui/sidebar-menu.js +1 -1
  139. package/dist/ui/sidebar-provider.js +2 -2
  140. package/dist/ui/sidebar-resize-rail.js +1 -1
  141. package/dist/ui/sidebar.js +1 -1
  142. package/dist/ui/table-of-contents.d.ts +4 -3
  143. package/dist/ui/table-of-contents.js +126 -47
  144. package/dist/ui/table.js +11 -7
  145. package/dist/ui/toast.js +1 -1
  146. package/dist/ui/toggle.d.ts +1 -1
  147. package/dist/ui/toggle.js +2 -1
  148. package/dist/ui/tooltip.js +1 -1
  149. package/dist/ui/tree.js +1 -1
  150. package/dist/ui/trigger-menu.js +7 -3
  151. package/dist/user-ask.js +1 -1
  152. package/package.json +1 -1
@@ -1,9 +1,9 @@
1
1
  import { DropzoneFileRejection, DropzonePolicy } from "../lib/dropzone-validation.js";
2
- import { ChangeEvent, ComponentProps, DragEvent, RefObject } from "react";
2
+ import { ChangeEvent, ClipboardEvent, ComponentProps, DragEvent, RefObject } from "react";
3
3
  //#region src/hooks/use-dropzone.d.ts
4
4
  export type DropzoneVisualState = "idle" | "accept" | "reject" | "unknown" | "processing";
5
- export type DropzoneValueChangeReason = "drop" | "input" | "remove" | "clear";
6
- export type DropzoneEvent = DragEvent<HTMLElement> | ChangeEvent<HTMLInputElement>;
5
+ export type DropzoneValueChangeReason = "drop" | "input" | "paste" | "remove" | "clear";
6
+ export type DropzoneEvent = DragEvent<HTMLElement> | ClipboardEvent<HTMLElement> | ChangeEvent<HTMLInputElement>;
7
7
  export type DropzoneGetFilesFromEvent = (event: DropzoneEvent, signal: AbortSignal) => readonly File[] | Promise<readonly File[]>;
8
8
  export type DropzoneValueChangeDetails = {
9
9
  reason: DropzoneValueChangeReason;
@@ -22,6 +22,7 @@ export type UseDropzoneOptions = {
22
22
  policy?: DropzonePolicy;
23
23
  disabled?: boolean;
24
24
  drag?: boolean;
25
+ paste?: boolean;
25
26
  preventDropOnDocument?: boolean;
26
27
  trackDocumentDrag?: boolean;
27
28
  getFilesFromEvent?: DropzoneGetFilesFromEvent;
@@ -35,6 +36,7 @@ export type UseDropzoneReturn = {
35
36
  multiple: boolean;
36
37
  disabled: boolean;
37
38
  dragEnabled: boolean;
39
+ pasteEnabled: boolean;
38
40
  visualState: DropzoneVisualState;
39
41
  isDragActive: boolean;
40
42
  isDragAccept: boolean;
@@ -48,11 +50,12 @@ export type UseDropzoneReturn = {
48
50
  open: () => void;
49
51
  removeFile: (file: File) => void;
50
52
  clearFiles: () => void;
53
+ removeRejection: (file: File) => void;
51
54
  clearRejections: () => void;
52
55
  reset: () => void;
53
56
  getRootProps: (props?: ComponentProps<"div">) => ComponentProps<"div">;
54
57
  getInputProps: (props?: ComponentProps<"input">) => ComponentProps<"input">;
55
58
  };
56
- export declare function useDropzone({ value: controlledValue, defaultValue, onValueChange, policy, disabled, drag, preventDropOnDocument, trackDocumentDrag, getFilesFromEvent, onDrop, onError }?: UseDropzoneOptions): UseDropzoneReturn;
59
+ export declare function useDropzone({ value: controlledValue, defaultValue, onValueChange, policy, disabled, drag, paste, preventDropOnDocument, trackDocumentDrag, getFilesFromEvent, onDrop, onError }?: UseDropzoneOptions): UseDropzoneReturn;
57
60
  export declare function defaultGetFilesFromEvent(event: DropzoneEvent): readonly File[];
58
61
  //#endregion
@@ -4,7 +4,7 @@ import { useEffect, useLayoutEffect, useRef, useState } from "react";
4
4
  //#region src/hooks/use-dropzone.ts
5
5
  const registeredDropzoneRoots = /* @__PURE__ */ new WeakSet();
6
6
  const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
7
- function useDropzone({ value: controlledValue, defaultValue = [], onValueChange, policy, disabled = false, drag = true, preventDropOnDocument = true, trackDocumentDrag = false, getFilesFromEvent, onDrop, onError } = {}) {
7
+ function useDropzone({ value: controlledValue, defaultValue = [], onValueChange, policy, disabled = false, drag = true, paste = true, preventDropOnDocument = true, trackDocumentDrag = false, getFilesFromEvent, onDrop, onError } = {}) {
8
8
  const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
9
9
  const [fileRejections, setFileRejections] = useState([]);
10
10
  const [isDragActive, setIsDragActive] = useState(false);
@@ -25,12 +25,15 @@ function useDropzone({ value: controlledValue, defaultValue = [], onValueChange,
25
25
  const disabledRef = useRef(disabled);
26
26
  const dragEnabled = drag && !disabled;
27
27
  const dragEnabledRef = useRef(dragEnabled);
28
+ const pasteEnabled = paste && !disabled;
29
+ const pasteEnabledRef = useRef(pasteEnabled);
28
30
  const policyRef = useRef(policy);
29
31
  const customExtractionRef = useRef(Boolean(getFilesFromEvent));
30
32
  useIsomorphicLayoutEffect(() => {
31
33
  currentValueRef.current = currentValue;
32
34
  disabledRef.current = disabled;
33
35
  dragEnabledRef.current = dragEnabled;
36
+ pasteEnabledRef.current = pasteEnabled;
34
37
  policyRef.current = policy;
35
38
  customExtractionRef.current = Boolean(getFilesFromEvent);
36
39
  });
@@ -136,6 +139,10 @@ function useDropzone({ value: controlledValue, defaultValue = [], onValueChange,
136
139
  removedFiles
137
140
  });
138
141
  }
142
+ function removeRejection(file) {
143
+ if (disabledRef.current || processingRef.current) return;
144
+ setFileRejections((current) => current.filter((rejection) => rejection.file !== file));
145
+ }
139
146
  function clearRejections() {
140
147
  if (disabledRef.current || processingRef.current || fileRejections.length === 0) return;
141
148
  setFileRejections([]);
@@ -153,7 +160,7 @@ function useDropzone({ value: controlledValue, defaultValue = [], onValueChange,
153
160
  if (fileRejections.length > 0) setFileRejections([]);
154
161
  }
155
162
  function getRootProps(props = {}) {
156
- const { onDragEnter, onDragOver, onDragLeave, onDragEnd, onDrop: callerOnDrop, ref, ...rootProps } = props;
163
+ const { onDragEnter, onDragOver, onDragLeave, onDragEnd, onDrop: callerOnDrop, onPaste, ref, ...rootProps } = props;
157
164
  return {
158
165
  ...rootProps,
159
166
  ref: (node) => {
@@ -207,6 +214,14 @@ function useDropzone({ value: controlledValue, defaultValue = [], onValueChange,
207
214
  if (event.defaultPrevented || !dragEnabledRef.current) return;
208
215
  event.preventDefault();
209
216
  intake(event, "drop");
217
+ },
218
+ onPaste: (event) => {
219
+ onPaste?.(event);
220
+ if (!isFilePaste(event.clipboardData)) return;
221
+ event.stopPropagation();
222
+ if (event.defaultPrevented || !pasteEnabledRef.current) return;
223
+ event.preventDefault();
224
+ intake(event, "paste");
210
225
  }
211
226
  };
212
227
  }
@@ -326,6 +341,7 @@ function useDropzone({ value: controlledValue, defaultValue = [], onValueChange,
326
341
  multiple: policy?.multiple ?? true,
327
342
  disabled,
328
343
  dragEnabled,
344
+ pasteEnabled,
329
345
  visualState,
330
346
  isDragActive,
331
347
  isDragAccept: visualState === "accept",
@@ -339,6 +355,7 @@ function useDropzone({ value: controlledValue, defaultValue = [], onValueChange,
339
355
  open,
340
356
  removeFile,
341
357
  clearFiles,
358
+ removeRejection,
342
359
  clearRejections,
343
360
  reset,
344
361
  getRootProps,
@@ -346,11 +363,25 @@ function useDropzone({ value: controlledValue, defaultValue = [], onValueChange,
346
363
  };
347
364
  }
348
365
  function defaultGetFilesFromEvent(event) {
349
- return "dataTransfer" in event ? Array.from(event.dataTransfer.files) : Array.from(event.currentTarget.files ?? []);
366
+ if ("clipboardData" in event) return getClipboardFiles(event.clipboardData);
367
+ if ("dataTransfer" in event) return Array.from(event.dataTransfer.files);
368
+ return Array.from(event.currentTarget.files ?? []);
369
+ }
370
+ /** Safari exposes a pasted screenshot through `items` only, so `files` alone loses it. */
371
+ function getClipboardFiles(clipboardData) {
372
+ const files = Array.from(clipboardData.files);
373
+ if (files.length > 0) return files;
374
+ return Array.from(clipboardData.items).filter((item) => item.kind === "file").map((item) => item.getAsFile()).filter((file) => file !== null);
350
375
  }
351
376
  function isFileDrag(dataTransfer) {
352
377
  return dataTransfer ? Array.from(dataTransfer.types).includes("Files") : false;
353
378
  }
379
+ /** Clipboards that also carry text belong to the focused editor: only a text-free paste is an attachment. */
380
+ function isFilePaste(clipboardData) {
381
+ if (!clipboardData) return false;
382
+ const types = Array.from(clipboardData.types);
383
+ return types.includes("Files") && !types.includes("text/plain");
384
+ }
354
385
  function getRegisteredDropzoneRoot(event) {
355
386
  for (const target of event.composedPath()) if (target && registeredDropzoneRoots.has(target)) return target;
356
387
  }
@@ -47,7 +47,7 @@ function GeneratingPlaceholder() {
47
47
  "data-control-ui": "inline-attachment",
48
48
  "data-control-family": "inline-attachment",
49
49
  "data-slot": "placeholder",
50
- className: cn("size-full", "halftone")
50
+ className: "size-full halftone"
51
51
  });
52
52
  }
53
53
  function DocumentPlaceholder() {
@@ -65,8 +65,7 @@ function DocumentPlaceholder() {
65
65
  /* @__PURE__ */ jsx("div", {
66
66
  "data-control-ui": "inline-attachment",
67
67
  "data-control-family": "inline-attachment",
68
- "data-slot": "document-heading",
69
- className: ""
68
+ "data-slot": "document-heading"
70
69
  }),
71
70
  /* @__PURE__ */ jsxs("div", {
72
71
  className: "grid",
@@ -75,37 +74,32 @@ function DocumentPlaceholder() {
75
74
  "data-control-ui": "inline-attachment",
76
75
  "data-control-family": "inline-attachment",
77
76
  "data-slot": "document-line",
78
- "data-width": "long",
79
- className: ""
77
+ "data-width": "long"
80
78
  }),
81
79
  /* @__PURE__ */ jsx("div", {
82
80
  "data-control-ui": "inline-attachment",
83
81
  "data-control-family": "inline-attachment",
84
82
  "data-slot": "document-line",
85
- "data-width": "medium",
86
- className: ""
83
+ "data-width": "medium"
87
84
  }),
88
85
  /* @__PURE__ */ jsx("div", {
89
86
  "data-control-ui": "inline-attachment",
90
87
  "data-control-family": "inline-attachment",
91
88
  "data-slot": "document-line",
92
- "data-width": "longest",
93
- className: ""
89
+ "data-width": "longest"
94
90
  }),
95
91
  /* @__PURE__ */ jsx("div", {
96
92
  "data-control-ui": "inline-attachment",
97
93
  "data-control-family": "inline-attachment",
98
94
  "data-slot": "document-line",
99
- "data-width": "short",
100
- className: ""
95
+ "data-width": "short"
101
96
  })
102
97
  ]
103
98
  }),
104
99
  /* @__PURE__ */ jsx("div", {
105
100
  "data-control-ui": "inline-attachment",
106
101
  "data-control-family": "inline-attachment",
107
- "data-slot": "document-stamp",
108
- className: ""
102
+ "data-slot": "document-stamp"
109
103
  })
110
104
  ]
111
105
  })
@@ -184,7 +178,7 @@ function InlineAttachmentAction({ className, ...props }) {
184
178
  "data-control-ui": "inline-attachment",
185
179
  "data-control-family": "inline-attachment",
186
180
  "data-slot": "action",
187
- className: cn(className),
181
+ className,
188
182
  ...props
189
183
  });
190
184
  }
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "./lib/cn.js";
3
3
  import { Button } from "./ui/button.js";
4
- import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover.js";
5
4
  import { SourceFavicon, sourceHostname } from "./source-badge.js";
5
+ import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover.js";
6
6
  import { createContext, useContext, useRef, useState } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { ArrowLeft, ArrowRight, ExternalLink } from "lucide-react";
@@ -1,4 +1,4 @@
1
1
  //#region src/knob-contracts/chat-layout-knobs.d.ts
2
- export declare const chatLayoutKnobs: readonly ["--cui-chat-layout-radius", "--cui-chat-layout-background", "--cui-chat-layout-border-color", "--cui-chat-layout-border-width", "--cui-chat-layout-shadow", "--cui-chat-layout-scroll-button-gap"];
2
+ export declare const chatLayoutKnobs: readonly ["--cui-chat-layout-radius", "--cui-chat-layout-background", "--cui-chat-layout-border-color", "--cui-chat-layout-border-width", "--cui-chat-layout-shadow", "--cui-chat-layout-scroll-button-gap", "--cui-chat-layout-turn-gap"];
3
3
  export type ChatLayoutKnobStyle = Partial<Record<(typeof chatLayoutKnobs)[number], string>>;
4
4
  //#endregion
@@ -5,7 +5,8 @@ const chatLayoutKnobs = [
5
5
  "--cui-chat-layout-border-color",
6
6
  "--cui-chat-layout-border-width",
7
7
  "--cui-chat-layout-shadow",
8
- "--cui-chat-layout-scroll-button-gap"
8
+ "--cui-chat-layout-scroll-button-gap",
9
+ "--cui-chat-layout-turn-gap"
9
10
  ];
10
11
  //#endregion
11
12
  export { chatLayoutKnobs };
@@ -1,4 +1,4 @@
1
1
  //#region src/knob-contracts/choice-knobs.d.ts
2
- export declare const choiceKnobs: readonly ["--cui-choice-radius", "--cui-choice-border-color", "--cui-choice-checked-background", "--cui-choice-checked-border-color", "--cui-choice-shadow"];
2
+ export declare const choiceKnobs: readonly ["--cui-choice-radius", "--cui-choice-border-color", "--cui-choice-border-width", "--cui-choice-checked-background", "--cui-choice-checked-border-color", "--cui-choice-shadow"];
3
3
  export type ChoiceKnobStyle = Partial<Record<(typeof choiceKnobs)[number], string>>;
4
4
  //#endregion
@@ -2,6 +2,7 @@
2
2
  const choiceKnobs = [
3
3
  "--cui-choice-radius",
4
4
  "--cui-choice-border-color",
5
+ "--cui-choice-border-width",
5
6
  "--cui-choice-checked-background",
6
7
  "--cui-choice-checked-border-color",
7
8
  "--cui-choice-shadow"
@@ -1,4 +1,4 @@
1
1
  //#region src/knob-contracts/collapsible-knobs.d.ts
2
- export declare const collapsibleKnobs: readonly [];
2
+ export declare const collapsibleKnobs: readonly ["--cui-collapsible-trigger-radius", "--cui-collapsible-trigger-hover-background"];
3
3
  export type CollapsibleKnobStyle = Partial<Record<(typeof collapsibleKnobs)[number], string>>;
4
4
  //#endregion
@@ -1,4 +1,4 @@
1
1
  //#region src/knob-contracts/collapsible-knobs.ts
2
- const collapsibleKnobs = [];
2
+ const collapsibleKnobs = ["--cui-collapsible-trigger-radius", "--cui-collapsible-trigger-hover-background"];
3
3
  //#endregion
4
4
  export { collapsibleKnobs };
@@ -0,0 +1,4 @@
1
+ //#region src/knob-contracts/filter-bar-knobs.d.ts
2
+ export declare const filterBarKnobs: readonly ["--cui-filter-bar-background", "--cui-filter-bar-foreground", "--cui-filter-bar-border-color", "--cui-filter-bar-border-width", "--cui-filter-bar-radius", "--cui-filter-bar-height", "--cui-filter-bar-gap", "--cui-filter-bar-padding-inline", "--cui-filter-bar-font-size", "--cui-filter-bar-hover-background", "--cui-filter-bar-focus-ring-color"];
3
+ export type FilterBarKnobStyle = Partial<Record<(typeof filterBarKnobs)[number], string>>;
4
+ //#endregion
@@ -0,0 +1,16 @@
1
+ //#region src/knob-contracts/filter-bar-knobs.ts
2
+ const filterBarKnobs = [
3
+ "--cui-filter-bar-background",
4
+ "--cui-filter-bar-foreground",
5
+ "--cui-filter-bar-border-color",
6
+ "--cui-filter-bar-border-width",
7
+ "--cui-filter-bar-radius",
8
+ "--cui-filter-bar-height",
9
+ "--cui-filter-bar-gap",
10
+ "--cui-filter-bar-padding-inline",
11
+ "--cui-filter-bar-font-size",
12
+ "--cui-filter-bar-hover-background",
13
+ "--cui-filter-bar-focus-ring-color"
14
+ ];
15
+ //#endregion
16
+ export { filterBarKnobs };
@@ -1,4 +1,4 @@
1
1
  //#region src/knob-contracts/infinite-canvas-knobs.d.ts
2
- export declare const infiniteCanvasKnobs: readonly ["--cui-infinite-canvas-radius", "--cui-infinite-canvas-background", "--cui-infinite-canvas-grid-dot-color", "--cui-infinite-canvas-border-color", "--cui-infinite-canvas-controls-radius", "--cui-infinite-canvas-controls-background", "--cui-infinite-canvas-controls-border-color", "--cui-infinite-canvas-controls-shadow"];
2
+ export declare const infiniteCanvasKnobs: readonly ["--cui-infinite-canvas-radius", "--cui-infinite-canvas-background", "--cui-infinite-canvas-grid-dot-color", "--cui-infinite-canvas-border-color", "--cui-infinite-canvas-padding", "--cui-infinite-canvas-controls-item-radius", "--cui-infinite-canvas-controls-padding", "--cui-infinite-canvas-controls-radius", "--cui-infinite-canvas-controls-background", "--cui-infinite-canvas-controls-border-color", "--cui-infinite-canvas-controls-shadow"];
3
3
  export type InfiniteCanvasKnobStyle = Partial<Record<(typeof infiniteCanvasKnobs)[number], string>>;
4
4
  //#endregion
@@ -4,6 +4,9 @@ const infiniteCanvasKnobs = [
4
4
  "--cui-infinite-canvas-background",
5
5
  "--cui-infinite-canvas-grid-dot-color",
6
6
  "--cui-infinite-canvas-border-color",
7
+ "--cui-infinite-canvas-padding",
8
+ "--cui-infinite-canvas-controls-item-radius",
9
+ "--cui-infinite-canvas-controls-padding",
7
10
  "--cui-infinite-canvas-controls-radius",
8
11
  "--cui-infinite-canvas-controls-background",
9
12
  "--cui-infinite-canvas-controls-border-color",
@@ -1,4 +1,4 @@
1
1
  //#region src/knob-contracts/page-layout-knobs.d.ts
2
- export declare const pageLayoutKnobs: readonly ["--cui-page-layout-article-size", "--cui-page-layout-aside-size", "--cui-page-layout-padding-inline", "--cui-page-layout-padding-block", "--cui-page-layout-column-gap", "--cui-page-layout-header-gap", "--cui-page-layout-header-column-gap", "--cui-page-layout-header-row-gap", "--cui-page-layout-size", "--cui-page-layout-sticky-gap"];
2
+ export declare const pageLayoutKnobs: readonly ["--cui-page-layout-article-size", "--cui-page-layout-aside-size", "--cui-page-layout-padding-inline", "--cui-page-layout-padding-block", "--cui-page-layout-column-gap", "--cui-page-layout-header-start-gap", "--cui-page-layout-header-gap", "--cui-page-layout-header-column-gap", "--cui-page-layout-header-row-gap", "--cui-page-layout-size", "--cui-page-layout-sticky-gap", "--cui-page-layout-background", "--cui-page-layout-sticky-header-background"];
3
3
  export type PageLayoutKnobStyle = Partial<Record<(typeof pageLayoutKnobs)[number], string>>;
4
4
  //#endregion
@@ -5,11 +5,14 @@ const pageLayoutKnobs = [
5
5
  "--cui-page-layout-padding-inline",
6
6
  "--cui-page-layout-padding-block",
7
7
  "--cui-page-layout-column-gap",
8
+ "--cui-page-layout-header-start-gap",
8
9
  "--cui-page-layout-header-gap",
9
10
  "--cui-page-layout-header-column-gap",
10
11
  "--cui-page-layout-header-row-gap",
11
12
  "--cui-page-layout-size",
12
- "--cui-page-layout-sticky-gap"
13
+ "--cui-page-layout-sticky-gap",
14
+ "--cui-page-layout-background",
15
+ "--cui-page-layout-sticky-header-background"
13
16
  ];
14
17
  //#endregion
15
18
  export { pageLayoutKnobs };
@@ -1,4 +1,4 @@
1
1
  //#region src/knob-contracts/popup-knobs.d.ts
2
- export declare const popupKnobs: readonly ["--cui-popup-radius", "--cui-popup-background", "--cui-popup-foreground", "--cui-popup-border-color", "--cui-popup-border-width", "--cui-popup-shadow", "--cui-popup-backdrop-filter", "--cui-popup-backdrop-background", "--cui-popup-item-radius", "--cui-popup-item-foreground", "--cui-popup-item-highlight-background", "--cui-popup-item-highlight-foreground", "--cui-popup-item-highlight-muted-foreground", "--cui-popup-item-disabled-opacity", "--cui-popup-separator-color", "--cui-popup-shortcut-foreground"];
2
+ export declare const popupKnobs: readonly ["--cui-popup-radius", "--cui-popup-background", "--cui-popup-foreground", "--cui-popup-border-color", "--cui-popup-border-width", "--cui-popup-shadow", "--cui-popup-backdrop-filter", "--cui-popup-backdrop-background", "--cui-popup-backdrop-blur", "--cui-popup-item-radius", "--cui-popup-item-foreground", "--cui-popup-item-highlight-background", "--cui-popup-item-highlight-foreground", "--cui-popup-item-highlight-muted-foreground", "--cui-popup-item-disabled-opacity", "--cui-popup-separator-color", "--cui-popup-shortcut-foreground"];
3
3
  export type PopupKnobStyle = Partial<Record<(typeof popupKnobs)[number], string>>;
4
4
  //#endregion
@@ -8,6 +8,7 @@ const popupKnobs = [
8
8
  "--cui-popup-shadow",
9
9
  "--cui-popup-backdrop-filter",
10
10
  "--cui-popup-backdrop-background",
11
+ "--cui-popup-backdrop-blur",
11
12
  "--cui-popup-item-radius",
12
13
  "--cui-popup-item-foreground",
13
14
  "--cui-popup-item-highlight-background",
@@ -1,4 +1,4 @@
1
1
  //#region src/knob-contracts/table-of-contents-knobs.d.ts
2
- export declare const tableOfContentsKnobs: readonly ["--cui-table-of-contents-background", "--cui-table-of-contents-border-color", "--cui-table-of-contents-border-width", "--cui-table-of-contents-radius", "--cui-table-of-contents-shadow", "--cui-table-of-contents-backdrop-filter", "--cui-table-of-contents-padding", "--cui-table-of-contents-label-foreground", "--cui-table-of-contents-label-font-size", "--cui-table-of-contents-label-font-weight", "--cui-table-of-contents-label-gap", "--cui-table-of-contents-item-foreground", "--cui-table-of-contents-item-hover-foreground", "--cui-table-of-contents-item-active-foreground", "--cui-table-of-contents-item-font-size", "--cui-table-of-contents-item-line-height", "--cui-table-of-contents-item-font-weight", "--cui-table-of-contents-item-root-font-weight", "--cui-table-of-contents-item-padding-block", "--cui-table-of-contents-item-padding-inline", "--cui-table-of-contents-item-indent-size", "--cui-table-of-contents-rail-background", "--cui-table-of-contents-rail-size", "--cui-table-of-contents-trail-background", "--cui-table-of-contents-trail-size", "--cui-table-of-contents-trail-radius", "--cui-table-of-contents-highlight-radius", "--cui-table-of-contents-highlight-background"];
2
+ export declare const tableOfContentsKnobs: readonly ["--cui-table-of-contents-background", "--cui-table-of-contents-border-color", "--cui-table-of-contents-border-width", "--cui-table-of-contents-radius", "--cui-table-of-contents-shadow", "--cui-table-of-contents-backdrop-filter", "--cui-table-of-contents-padding", "--cui-table-of-contents-label-foreground", "--cui-table-of-contents-label-font-size", "--cui-table-of-contents-label-font-weight", "--cui-table-of-contents-label-gap", "--cui-table-of-contents-item-foreground", "--cui-table-of-contents-item-hover-foreground", "--cui-table-of-contents-item-active-foreground", "--cui-table-of-contents-item-font-size", "--cui-table-of-contents-item-line-height", "--cui-table-of-contents-item-font-weight", "--cui-table-of-contents-item-root-font-weight", "--cui-table-of-contents-item-padding-block", "--cui-table-of-contents-item-padding-inline", "--cui-table-of-contents-item-indent-size", "--cui-table-of-contents-rail-stroke", "--cui-table-of-contents-rail-size", "--cui-table-of-contents-trail-stroke", "--cui-table-of-contents-trail-size", "--cui-table-of-contents-indicator-foreground"];
3
3
  export type TableOfContentsKnobStyle = Partial<Record<(typeof tableOfContentsKnobs)[number], string>>;
4
4
  //#endregion
@@ -21,13 +21,11 @@ const tableOfContentsKnobs = [
21
21
  "--cui-table-of-contents-item-padding-block",
22
22
  "--cui-table-of-contents-item-padding-inline",
23
23
  "--cui-table-of-contents-item-indent-size",
24
- "--cui-table-of-contents-rail-background",
24
+ "--cui-table-of-contents-rail-stroke",
25
25
  "--cui-table-of-contents-rail-size",
26
- "--cui-table-of-contents-trail-background",
26
+ "--cui-table-of-contents-trail-stroke",
27
27
  "--cui-table-of-contents-trail-size",
28
- "--cui-table-of-contents-trail-radius",
29
- "--cui-table-of-contents-highlight-radius",
30
- "--cui-table-of-contents-highlight-background"
28
+ "--cui-table-of-contents-indicator-foreground"
31
29
  ];
32
30
  //#endregion
33
31
  export { tableOfContentsKnobs };
@@ -1,5 +1,5 @@
1
- import { AsYouType } from "libphonenumber-js/max";
2
1
  import { getCountryCallingCode } from "react-phone-number-input/max";
2
+ import { AsYouType } from "libphonenumber-js/max";
3
3
  //#region src/lib/phone-input-format.ts
4
4
  function normalizePhoneInputText(value, country) {
5
5
  if (!country) return value;
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { cn } from "./lib/cn.js";
3
+ import { ScrollArea } from "./ui/scroll-area.js";
3
4
  import { CodeCopy } from "./ui/code.js";
4
5
  import { Markdown } from "./ui/markdown.js";
5
6
  import { createContext, useContext } from "react";
@@ -64,13 +65,16 @@ function MarkdownBlockCopy({ "aria-label": ariaLabel = "Copy markdown", ...props
64
65
  }
65
66
  function MarkdownBlockContent({ children, className, ...props }) {
66
67
  const code = useMarkdownBlockContext();
67
- return /* @__PURE__ */ jsx("div", {
68
- "data-control-ui": "markdown-block",
69
- "data-control-family": "markdown-block",
70
- "data-slot": "content",
71
- className: cn("max-h-[420px] overflow-auto mask-b-from-[calc(100%_-_var(--scroll-fade-size))]", className),
72
- ...props,
73
- children: children ?? /* @__PURE__ */ jsx(Markdown, { content: code })
68
+ return /* @__PURE__ */ jsx(ScrollArea, {
69
+ maxHeight: "420px",
70
+ children: /* @__PURE__ */ jsx("div", {
71
+ "data-control-ui": "markdown-block",
72
+ "data-control-family": "markdown-block",
73
+ "data-slot": "content",
74
+ className,
75
+ ...props,
76
+ children: children ?? /* @__PURE__ */ jsx(Markdown, { content: code })
77
+ })
74
78
  });
75
79
  }
76
80
  //#endregion
@@ -169,13 +169,13 @@ function splitTopLevel(text) {
169
169
  }
170
170
  const unresolved = (reason) => ({ unresolved: reason });
171
171
  const isUnresolved = (result) => Boolean(result?.unresolved);
172
- function evaluateCalc(expression, base, tokens, seen, depth) {
172
+ function evaluateCalc(expression, keyword, base, tokens, seen, depth) {
173
173
  const inner = expression.slice(5, -1).trim();
174
174
  const match = /^(\S+)\s*([+\-*])\s*(\S+)$/.exec(inner);
175
175
  if (!match) return null;
176
176
  const [, leftText, operator, rightText] = match;
177
177
  const operand = (text) => {
178
- if (text === "l" || text === "alpha") return base;
178
+ if (text === keyword) return base;
179
179
  const number = scalar(text);
180
180
  if (number !== null) return number;
181
181
  const nested = resolveScalar(text, tokens, seen, depth + 1);
@@ -204,10 +204,11 @@ function resolveScalar(value, tokens, seen, depth) {
204
204
  const literalChannel = (text, allowPercent) => allowPercent || !text.endsWith("%") ? scalar(text) : null;
205
205
  const channelValue = (text, keyword, base, tokens, seen, depth) => {
206
206
  if (text === keyword) return base;
207
- if (text.startsWith("calc(")) return evaluateCalc(text, base, tokens, seen, depth);
207
+ if (text.startsWith("calc(")) return evaluateCalc(text, keyword, base, tokens, seen, depth);
208
+ if (text.startsWith("var(")) return resolveScalar(text, tokens, seen, depth);
208
209
  return literalChannel(text, keyword === "l");
209
210
  };
210
- const alphaValue = (text, base, tokens, seen, depth) => text.startsWith("calc(") ? evaluateCalc(text, base, tokens, seen, depth) : resolveScalar(text, tokens, seen, depth);
211
+ const alphaValue = (text, base, tokens, seen, depth) => text.startsWith("calc(") ? evaluateCalc(text, "alpha", base, tokens, seen, depth) : resolveScalar(text, tokens, seen, depth);
211
212
  const CHANNEL_KEYWORDS = [
212
213
  "l",
213
214
  "c",
@@ -39,18 +39,20 @@
39
39
  @import "./recipes/color-picker-values.css";
40
40
  @import "./recipes/empty.css";
41
41
  @import "./recipes/context.css";
42
+ @import "./recipes/infinite-canvas.css";
43
+ @import "./recipes/resizable.css";
44
+ @import "./recipes/separator.css";
45
+ @import "./recipes/toolbar.css";
42
46
  @import "./recipes/popup-drawer.css";
43
47
  @import "./recipes/dockable-panel.css";
44
- @import "./recipes/separator.css";
45
48
  @import "./recipes/item.css";
46
49
  @import "./recipes/dropzone.css";
47
50
  @import "./recipes/dynamic-notification.css";
48
51
  @import "./recipes/dynamic-notification-input.css";
49
52
  @import "./recipes/dynamic-notification-motion.css";
50
53
  @import "./recipes/environment-variables.css";
51
- @import "./recipes/resizable.css";
54
+ @import "./recipes/filter-bar.css";
52
55
  @import "./recipes/gradient-editor.css";
53
- @import "./recipes/infinite-canvas.css";
54
56
  @import "./recipes/inline-attachment.css";
55
57
  @import "./recipes/source-badge.css";
56
58
  @import "./recipes/inline-citation.css";
@@ -73,7 +75,6 @@
73
75
  @import "./recipes/thread-rail.css";
74
76
  @import "./recipes/timeline.css";
75
77
  @import "./recipes/popup-toast.css";
76
- @import "./recipes/toolbar.css";
77
78
  @import "./recipes/transcript-divider.css";
78
79
  @import "./recipes/tree.css";
79
80
  @import "./type-scale.css";
@@ -1,7 +1,7 @@
1
1
  @layer components {
2
2
  :where([data-control-family="button-group"][data-slot="root"]) {
3
3
  --cui-button-group-text-radius: var(--radius-control);
4
- --cui-button-group-text-background: oklch(from var(--card) l c h / 0.72);
4
+ --cui-button-group-text-background: var(--control-fill);
5
5
  --cui-button-group-text-foreground: var(--muted-foreground);
6
6
  --cui-button-group-separator-background: var(--border);
7
7
  }
@@ -47,7 +47,7 @@
47
47
  --cui-button-open-background: var(--cui-button-hover-background);
48
48
  --cui-button-open-foreground: var(--cui-button-hover-foreground);
49
49
  --cui-button-open-shadow: var(--cui-button-shadow);
50
- border-radius: var(--cui-button-radius);
50
+ border-radius: var(--nest-radius, var(--cui-button-radius));
51
51
  background-color: var(--cui-button-background);
52
52
  background-image: var(--cui-button-background-image);
53
53
  box-shadow: var(--cui-button-shadow);
@@ -142,7 +142,7 @@
142
142
  }
143
143
 
144
144
  :where([data-control-family="button"][data-variant="surface"]) {
145
- --cui-button-background: oklch(from var(--card) l c h / 0.72);
145
+ --cui-button-background: var(--control-fill);
146
146
  --cui-button-foreground: var(--foreground);
147
147
  --cui-button-hover-background: oklch(from var(--foreground) l c h / 0.05);
148
148
  --cui-button-hover-foreground: var(--foreground);
@@ -6,7 +6,7 @@
6
6
  --cui-chat-composer-shell-backdrop-filter: none;
7
7
  --cui-chat-composer-shell-border-color: var(--border);
8
8
  --cui-chat-composer-shell-border-width: var(--control-rim-width);
9
- --cui-chat-composer-shell-radius: var(--radius-field);
9
+ --cui-chat-composer-shell-radius: var(--radius-composer);
10
10
  --cui-chat-composer-shell-shadow: var(--shadow-md);
11
11
  --cui-chat-composer-input-foreground: var(--card-foreground);
12
12
  --cui-chat-composer-input-placeholder-foreground: var(--muted-foreground);
@@ -15,8 +15,8 @@
15
15
  --cui-chat-composer-mention-border-color: transparent;
16
16
  --cui-chat-composer-mention-border-width: 0px;
17
17
  --cui-chat-composer-mention-background: oklch(from var(--primary) l c h / 0.1);
18
- padding-inline: calc(var(--spacing) * 2);
19
- padding-block: calc(var(--spacing) * 1) calc(var(--spacing) * 2);
18
+ padding-inline: var(--composer-padding);
19
+ padding-block: calc(var(--spacing) * 1) var(--composer-padding);
20
20
  background: var(--cui-chat-composer-root-background);
21
21
  }
22
22
 
@@ -41,6 +41,10 @@
41
41
  outline-offset: var(--focus-ring-offset);
42
42
  }
43
43
 
44
+ :where([data-control-family="chat-composer"][data-slot="shell"] [data-control-family="dropzone"][data-slot="overlay"]) {
45
+ --cui-dropzone-surface-radius: max(0px, calc(var(--cui-chat-composer-shell-radius) - var(--cui-chat-composer-shell-border-width)));
46
+ }
47
+
44
48
  :where([data-control-family="chat-composer"][data-slot="accent"]) {
45
49
  block-size: 1px;
46
50
  background-image: linear-gradient(to right, transparent, oklch(from var(--foreground) l c h / 0.2), transparent);
@@ -76,11 +80,15 @@
76
80
  }
77
81
 
78
82
  :where([data-control-family="chat-composer"][data-slot="toolbar"]) {
79
- min-block-size: calc(var(--spacing) * 10);
83
+ --nest-radius: max(
84
+ 0px,
85
+ calc(var(--cui-chat-composer-shell-radius) - var(--cui-chat-composer-shell-border-width) - var(--composer-padding))
86
+ );
87
+ min-block-size: calc(var(--control-h-xs) + var(--composer-padding) + var(--spacing) * 0.5);
80
88
  gap: calc(var(--spacing) * 2);
81
89
  flex-wrap: wrap;
82
- padding-inline: calc(var(--spacing) * 2.5);
83
- padding-block-end: calc(var(--spacing) * 2);
90
+ padding-inline: var(--composer-padding);
91
+ padding-block-end: var(--composer-padding);
84
92
  }
85
93
 
86
94
  :where([data-control-family="chat-composer"][data-slot="tools"]) {
@@ -6,27 +6,48 @@
6
6
  --cui-chat-layout-border-width: var(--control-rim-width);
7
7
  --cui-chat-layout-shadow: var(--shadow-md);
8
8
  --cui-chat-layout-scroll-button-gap: calc(var(--spacing) * 3);
9
- background: var(--cui-chat-layout-background);
9
+ --cui-chat-layout-turn-gap: calc(var(--spacing) * 2);
10
+ container: chat-layout / inline-size;
11
+ }
12
+
13
+ :where(
14
+ [data-control-family="chat-layout"][data-slot="root"][data-chrome="panel"]:has([data-control-family="chat-layout"][data-slot="dock"])
15
+ ) {
16
+ --cui-chat-layout-radius: max(
17
+ var(--radius-scene),
18
+ calc(var(--radius-composer) + var(--composer-padding) + var(--cui-chat-layout-border-width))
19
+ );
10
20
  }
11
21
 
12
22
  :where([data-control-family="chat-layout"][data-slot="root"][data-chrome="panel"]) {
23
+ background: var(--cui-chat-layout-background);
13
24
  border: var(--cui-chat-layout-border-width) solid var(--cui-chat-layout-border-color);
14
25
  border-radius: var(--cui-chat-layout-radius);
15
26
  box-shadow: var(--cui-chat-layout-shadow);
16
27
  }
17
28
 
29
+ :where([data-popup-part="surface"] [data-control-family="chat-layout"][data-slot="root"][data-chrome="embedded"]) {
30
+ --cui-chat-layout-background: var(--cui-popup-background);
31
+ --cui-chat-layout-radius: var(--cui-popup-radius);
32
+ border-radius: var(--cui-chat-layout-radius);
33
+ }
34
+
18
35
  :where([data-control-family="chat-layout"][data-slot="thread-content"]) {
19
36
  gap: calc(var(--spacing) * 8);
20
37
  padding-block: calc(var(--spacing) * 6);
21
38
  padding-inline: calc(var(--spacing) * 4);
22
39
  }
23
40
 
24
- @media (width >= 40rem) {
41
+ @container chat-layout (width >= 40rem) {
25
42
  :where([data-control-family="chat-layout"][data-slot="thread-content"]) {
26
43
  padding-inline: calc(var(--spacing) * 8);
27
44
  }
28
45
  }
29
46
 
47
+ :where([data-control-family="chat-layout"][data-slot="turn"]) {
48
+ gap: var(--cui-chat-layout-turn-gap);
49
+ }
50
+
30
51
  :where([data-control-family="chat-layout"][data-slot="dock"])::before {
31
52
  content: "";
32
53
  position: absolute;
@@ -89,3 +110,9 @@
89
110
  inherits: true;
90
111
  initial-value: 0px;
91
112
  }
113
+
114
+ @property --cui-chat-layout-turn-gap {
115
+ syntax: "<length>";
116
+ inherits: true;
117
+ initial-value: 0px;
118
+ }