@ctrl-ui/react 0.9.16 → 0.9.18

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 (66) hide show
  1. package/dist/action-bar.d.ts +2 -2
  2. package/dist/action-bar.js +34 -15
  3. package/dist/activity.d.ts +1 -1
  4. package/dist/activity.js +1 -1
  5. package/dist/audio-device-select.js +1 -1
  6. package/dist/audio-recorder.js +1 -1
  7. package/dist/blocks/agent-run-sidebar.js +1 -1
  8. package/dist/blocks/agent-run.js +1 -1
  9. package/dist/blocks/coding-agent.js +1 -1
  10. package/dist/blocks/design-canvas-inspector.js +1 -1
  11. package/dist/blocks/design-canvas.js +1 -1
  12. package/dist/blocks/discussion.js +1 -1
  13. package/dist/blocks/file-explorer.js +1 -1
  14. package/dist/blocks/settings.js +1 -1
  15. package/dist/blocks/theme-toggle.js +1 -1
  16. package/dist/chat-composer-attachment.js +1 -1
  17. package/dist/chat-composer.js +1 -1
  18. package/dist/chat-layout.js +1 -1
  19. package/dist/context.js +1 -1
  20. package/dist/filter-bar/parts.js +1 -1
  21. package/dist/inline-citation.js +1 -1
  22. package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
  23. package/dist/knob-contracts/sidebar-knobs.js +7 -0
  24. package/dist/markdown-editor/context.d.ts +2 -0
  25. package/dist/markdown-editor/drag-handle.js +1 -1
  26. package/dist/markdown-editor/extensions.d.ts +14 -4
  27. package/dist/markdown-editor/extensions.js +39 -34
  28. package/dist/markdown-editor/suggestions.js +4 -5
  29. package/dist/markdown-editor/toolbar.d.ts +1 -1
  30. package/dist/markdown-editor/toolbar.js +5 -6
  31. package/dist/markdown-editor.d.ts +7 -1
  32. package/dist/markdown-editor.js +16 -6
  33. package/dist/source-badge.js +1 -1
  34. package/dist/styles/index.css +1 -0
  35. package/dist/styles/recipes/action-bar.css +12 -3
  36. package/dist/styles/recipes/popup-controls.css +3 -3
  37. package/dist/styles/recipes/resizable.css +15 -0
  38. package/dist/styles/recipes/sidebar-panes.css +192 -0
  39. package/dist/styles/recipes/sidebar-parts.css +61 -3
  40. package/dist/task-list.js +1 -1
  41. package/dist/tool-approval.js +1 -1
  42. package/dist/ui/accordion.js +1 -1
  43. package/dist/ui/breadcrumb.js +1 -1
  44. package/dist/ui/code.js +1 -1
  45. package/dist/ui/dropzone.js +1 -1
  46. package/dist/ui/emoji-picker.js +1 -1
  47. package/dist/ui/flow.js +1 -1
  48. package/dist/ui/hover-card.d.ts +3 -1
  49. package/dist/ui/hover-card.js +2 -2
  50. package/dist/ui/infinite-canvas.js +1 -1
  51. package/dist/ui/pagination.js +1 -1
  52. package/dist/ui/resizable.d.ts +3 -1
  53. package/dist/ui/resizable.js +3 -1
  54. package/dist/ui/rich-tooltip.js +1 -1
  55. package/dist/ui/sidebar-menu.js +6 -6
  56. package/dist/ui/sidebar-mobile.js +1 -1
  57. package/dist/ui/sidebar-provider.d.ts +2 -0
  58. package/dist/ui/sidebar-provider.js +7 -1
  59. package/dist/ui/sidebar.d.ts +12 -0
  60. package/dist/ui/sidebar.js +34 -9
  61. package/dist/ui/spinner.js +1 -1
  62. package/dist/ui/stepper.js +1 -1
  63. package/dist/ui/toast.js +1 -1
  64. package/dist/ui/tree.js +1 -1
  65. package/dist/user-ask.js +1 -1
  66. package/package.json +1 -1
@@ -6,15 +6,14 @@ import { ChatComposerAttachment, ChatComposerAttachments } from "../chat-compose
6
6
  import { Popover, PopoverContent, PopoverTitle, PopoverTrigger } from "../ui/popover.js";
7
7
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip.js";
8
8
  import { useMarkdownEditor } from "./context.js";
9
- import { isEditorUrl } from "./extensions.js";
10
9
  import { markdownImageTypes } from "./uploads.js";
11
10
  import { Input } from "../ui/input.js";
12
11
  import { Toolbar, ToolbarButton, ToolbarSeparator } from "../ui/toolbar.js";
13
12
  import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from "../ui/dropdown-menu.js";
14
13
  import { Label } from "../ui/label.js";
14
+ import { BoldIcon, ChevronDownIcon, CodeIcon, ImageIcon, ItalicIcon, LinkIcon, ListChecksIcon, ListIcon, ListOrderedIcon, QuoteIcon, RedoIcon, SquareCodeIcon, StrikethroughIcon, UndoIcon } from "lucide-react";
15
15
  import { useId, useRef, useState } from "react";
16
16
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
17
- import { BoldIcon, ChevronDownIcon, CodeIcon, ImageIcon, ItalicIcon, LinkIcon, ListChecksIcon, ListIcon, ListOrderedIcon, QuoteIcon, RedoIcon, SquareCodeIcon, StrikethroughIcon, UndoIcon } from "lucide-react";
18
17
  import { useEditorState } from "@tiptap/react";
19
18
  //#region src/markdown-editor/toolbar.tsx
20
19
  function useMarkdownEditorFormatActions() {
@@ -221,11 +220,11 @@ function MarkdownEditorHeading() {
221
220
  })] });
222
221
  }
223
222
  function MarkdownEditorLink() {
224
- const { editor, disabled, source } = useMarkdownEditor();
223
+ const { editor, disabled, source, isUrlAllowed } = useMarkdownEditor();
225
224
  const [open, setOpen] = useState(false);
226
225
  const [url, setUrl] = useState("");
227
226
  const inputId = useId();
228
- const valid = isEditorUrl(url.trim());
227
+ const valid = isUrlAllowed(url.trim(), "link");
229
228
  function apply() {
230
229
  if (!valid || disabled || source) return;
231
230
  editor?.chain().focus().extendMarkRange("link").setLink({ href: url.trim() }).run();
@@ -291,14 +290,14 @@ function MarkdownEditorLink() {
291
290
  });
292
291
  }
293
292
  function MarkdownEditorImage() {
294
- const { editor, disabled, source, canUpload, upload } = useMarkdownEditor();
293
+ const { editor, disabled, source, canUpload, upload, isUrlAllowed } = useMarkdownEditor();
295
294
  const [open, setOpen] = useState(false);
296
295
  const [url, setUrl] = useState("");
297
296
  const [alt, setAlt] = useState("");
298
297
  const inputId = useId();
299
298
  const altId = useId();
300
299
  const fileInput = useRef(null);
301
- const valid = isEditorUrl(url.trim(), true);
300
+ const valid = isUrlAllowed(url.trim(), "image");
302
301
  function insert() {
303
302
  if (!valid || disabled || source) return;
304
303
  editor?.chain().focus().setImage({
@@ -1,6 +1,8 @@
1
1
  import { MarkdownEditorKnobStyle } from "./knob-contracts/markdown-editor-knobs.js";
2
+ import { MarkdownUrlPolicy } from "./markdown-editor/extensions.js";
2
3
  import { MarkdownImageUploader } from "./markdown-editor/uploads.js";
3
4
  import { CSSProperties, ComponentProps } from "react";
5
+ import { Extensions } from "@tiptap/core";
4
6
  //#region src/markdown-editor.d.ts
5
7
  export type MarkdownEditorStatus = {
6
8
  isEmpty: boolean;
@@ -14,9 +16,13 @@ export type MarkdownEditorProps = Omit<ComponentProps<"div">, "defaultValue" | "
14
16
  onUploadImage?: MarkdownImageUploader;
15
17
  maxImageBytes?: number;
16
18
  onStatusChange?: (status: MarkdownEditorStatus) => void;
19
+ /** Extra TipTap extensions, applied after the built-in Markdown set. Read once, when the editor mounts. */
20
+ extensions?: Extensions;
21
+ /** Which link and image URLs the editor keeps; defaults to URLs that survive a reload. Read once, when the editor mounts. */
22
+ isUrlAllowed?: MarkdownUrlPolicy;
17
23
  style?: CSSProperties & MarkdownEditorKnobStyle;
18
24
  };
19
- export declare function MarkdownEditor({ value, defaultValue, onValueChange, disabled, onUploadImage, maxImageBytes, onStatusChange, children, className, ...props }: MarkdownEditorProps): import("react").JSX.Element;
25
+ export declare function MarkdownEditor({ value, defaultValue, onValueChange, disabled, onUploadImage, maxImageBytes, onStatusChange, extensions: extraExtensions, isUrlAllowed: urlPolicy, children, className, ...props }: MarkdownEditorProps): import("react").JSX.Element;
20
26
  export type MarkdownEditorContentProps = {
21
27
  label: string;
22
28
  placeholder?: string;
@@ -3,7 +3,7 @@ import { cn } from "./lib/cn.js";
3
3
  import { Textarea } from "./ui/textarea.js";
4
4
  import { MarkdownEditorContext, useMarkdownEditor } from "./markdown-editor/context.js";
5
5
  import { MarkdownEditorDragHandle } from "./markdown-editor/drag-handle.js";
6
- import { createMarkdownCodec, hasMarkdownContent, markdownExtensions, requiresMarkdownSource } from "./markdown-editor/extensions.js";
6
+ import { createMarkdownCodec, hasMarkdownContent, markdownExtensions, persistentUrlPolicy, requiresMarkdownSource } from "./markdown-editor/extensions.js";
7
7
  import { useImageUploads } from "./markdown-editor/use-image-uploads.js";
8
8
  import { useEffect, useMemo, useRef, useState } from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -11,7 +11,7 @@ import { Slice } from "@tiptap/pm/model";
11
11
  import { EditorState } from "@tiptap/pm/state";
12
12
  import { EditorContent, useEditor } from "@tiptap/react";
13
13
  //#region src/markdown-editor.tsx
14
- function MarkdownEditor({ value, defaultValue = "", onValueChange, disabled = false, onUploadImage, maxImageBytes = 10485760, onStatusChange, children, className, ...props }) {
14
+ function MarkdownEditor({ value, defaultValue = "", onValueChange, disabled = false, onUploadImage, maxImageBytes = 10485760, onStatusChange, extensions: extraExtensions, isUrlAllowed: urlPolicy = persistentUrlPolicy, children, className, ...props }) {
15
15
  const [internalValue, setInternalValue] = useState(defaultValue);
16
16
  const markdown = value ?? internalValue;
17
17
  const [sourceMode, setSourceMode] = useState(false);
@@ -19,11 +19,20 @@ function MarkdownEditor({ value, defaultValue = "", onValueChange, disabled = fa
19
19
  role: "textbox",
20
20
  "aria-multiline": "true"
21
21
  });
22
- const [codec] = useState(createMarkdownCodec);
23
- const sourceRequired = useMemo(() => requiresMarkdownSource(markdown, codec), [markdown, codec]);
22
+ const [isUrlAllowed] = useState(() => urlPolicy);
23
+ const [extensionOptions] = useState(() => ({
24
+ extensions: extraExtensions,
25
+ isUrlAllowed
26
+ }));
27
+ const [codec] = useState(() => createMarkdownCodec(extensionOptions));
28
+ const sourceRequired = useMemo(() => requiresMarkdownSource(markdown, codec, isUrlAllowed), [
29
+ markdown,
30
+ codec,
31
+ isUrlAllowed
32
+ ]);
24
33
  const source = sourceMode || sourceRequired;
25
34
  const lastValue = useRef(markdown);
26
- const [extensions] = useState(markdownExtensions);
35
+ const [extensions] = useState(() => markdownExtensions(extensionOptions));
27
36
  const handlers = useRef(null);
28
37
  function setMarkdown(next) {
29
38
  lastValue.current = next;
@@ -49,7 +58,7 @@ function MarkdownEditor({ value, defaultValue = "", onValueChange, disabled = fa
49
58
  return true;
50
59
  }
51
60
  const text = event.clipboardData?.getData("text/plain");
52
- if (!text || event.clipboardData?.getData("text/html") || requiresMarkdownSource(text, codec)) return false;
61
+ if (!text || event.clipboardData?.getData("text/html") || requiresMarkdownSource(text, codec, isUrlAllowed)) return false;
53
62
  const document = view.state.schema.nodeFromJSON(codec.parse(text));
54
63
  event.preventDefault();
55
64
  view.dispatch(view.state.tr.replaceSelection(Slice.maxOpen(document.content)).scrollIntoView());
@@ -127,6 +136,7 @@ function MarkdownEditor({ value, defaultValue = "", onValueChange, disabled = fa
127
136
  setMarkdown,
128
137
  setContentAttributes,
129
138
  canUpload: Boolean(onUploadImage),
139
+ isUrlAllowed,
130
140
  ...imageUploads
131
141
  },
132
142
  children: /* @__PURE__ */ jsx("div", {
@@ -2,8 +2,8 @@
2
2
  import { cn } from "./lib/cn.js";
3
3
  import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar.js";
4
4
  import { Badge } from "./ui/badge.js";
5
- import { jsx, jsxs } from "react/jsx-runtime";
6
5
  import { Globe } from "lucide-react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region src/source-badge.tsx
8
8
  function sourceHostname(href) {
9
9
  try {
@@ -20,6 +20,7 @@
20
20
  @import "./recipes/sidebar.css";
21
21
  @import "./recipes/sidebar-menu.css";
22
22
  @import "./recipes/sidebar-mobile.css";
23
+ @import "./recipes/sidebar-panes.css";
23
24
  @import "./recipes/sidebar-parts.css";
24
25
  @import "./recipes/timeline.css";
25
26
  @import "./recipes/alert.css";
@@ -12,16 +12,25 @@
12
12
  }
13
13
 
14
14
  @media (hover: hover) and (pointer: fine) {
15
- :where([data-control-family="chat-layout"][data-slot="turn"] [data-control-family="action-bar"][data-slot="root"]) {
15
+ :where(
16
+ :is([data-control-family="chat-layout"][data-slot="turn"], [data-control-family="chat-message"][data-slot="editable"])
17
+ [data-control-family="action-bar"][data-slot="root"]
18
+ ) {
16
19
  opacity: var(--cui-action-bar-hidden-opacity);
17
20
  }
18
21
 
19
- :where([data-control-family="chat-layout"][data-slot="turn"]:hover [data-control-family="action-bar"][data-slot="root"]) {
22
+ :where(
23
+ :is([data-control-family="chat-layout"][data-slot="turn"], [data-control-family="chat-message"][data-slot="editable"]):hover
24
+ [data-control-family="action-bar"][data-slot="root"]
25
+ ) {
20
26
  opacity: var(--cui-action-bar-visible-opacity);
21
27
  }
22
28
  }
23
29
 
24
- :where([data-control-family="chat-layout"][data-slot="turn"]:focus-within [data-control-family="action-bar"][data-slot="root"]) {
30
+ :where(
31
+ :is([data-control-family="chat-layout"][data-slot="turn"], [data-control-family="chat-message"][data-slot="editable"]):focus-within
32
+ [data-control-family="action-bar"][data-slot="root"]
33
+ ) {
25
34
  opacity: var(--cui-action-bar-visible-opacity);
26
35
  }
27
36
  }
@@ -166,7 +166,7 @@
166
166
  border-block-end: 1px solid var(--cui-popup-separator-color);
167
167
  }
168
168
 
169
- :where([data-control-family="popup"][data-popup-kind="hover-card"][data-slot="trigger"]:is(a)) {
169
+ :where([data-popup-kind="hover-card"][data-slot="trigger"]:is(a)) {
170
170
  border-radius: var(--radius-sm);
171
171
  color: var(--foreground);
172
172
  font-weight: var(--font-weight-medium);
@@ -178,12 +178,12 @@
178
178
  transition: text-decoration-color var(--duration-fast) var(--ease-standard);
179
179
  }
180
180
 
181
- :where([data-control-family="popup"][data-popup-kind="hover-card"][data-slot="trigger"]:is(a)[data-popup-open]) {
181
+ :where([data-popup-kind="hover-card"][data-slot="trigger"]:is(a)[data-popup-open]) {
182
182
  text-decoration-color: var(--foreground);
183
183
  }
184
184
 
185
185
  @media (hover: hover) {
186
- :where([data-control-family="popup"][data-popup-kind="hover-card"][data-slot="trigger"]:is(a):hover) {
186
+ :where([data-popup-kind="hover-card"][data-slot="trigger"]:is(a):hover) {
187
187
  text-decoration-color: var(--foreground);
188
188
  }
189
189
  }
@@ -25,6 +25,21 @@
25
25
  --cui-resizable-group-radius: 0px;
26
26
  }
27
27
 
28
+ /* biome-ignore-start lint/complexity/noImportantStyles: react-resizable-panels sets inline display on the group and panels. */
29
+ :where([data-control-family="resizable"][data-slot="panel-group"][data-layout="contents"]) {
30
+ display: contents !important;
31
+ }
32
+
33
+ :where([data-control-family="resizable"][data-slot="panel-group"]:not([data-layout="resizable"]) > [data-slot="panel"]),
34
+ :where([data-control-family="resizable"][data-slot="panel-group"]:not([data-layout="resizable"]) > [data-slot="panel"] > div) {
35
+ display: contents !important;
36
+ }
37
+
38
+ :where([data-control-family="resizable"][data-slot="panel-group"]:not([data-layout="resizable"]) > [data-slot="handle"]) {
39
+ display: none !important;
40
+ }
41
+ /* biome-ignore-end lint/complexity/noImportantStyles: react-resizable-panels sets inline display on the group and panels. */
42
+
28
43
  :where([data-control-family="resizable"][data-slot="handle"]) {
29
44
  --_resizable-gradient-color: var(--cui-resizable-handle-hover-background);
30
45
  background-color: var(--cui-resizable-handle-background);
@@ -0,0 +1,192 @@
1
+ @layer components {
2
+ :where([data-control-family="sidebar"][data-slot="root"]) {
3
+ --cui-sidebar-icon-rail-border-width: 1px;
4
+ --cui-sidebar-icon-rail-border-color: var(--sidebar-border);
5
+ --cui-sidebar-raised-background: var(--cui-sidebar-inset-background);
6
+ --cui-sidebar-raised-border-width: var(--cui-sidebar-inset-border-width);
7
+ --cui-sidebar-raised-border-color: var(--cui-sidebar-inset-border-color);
8
+ --cui-sidebar-raised-radius: var(--cui-sidebar-inset-radius);
9
+ --cui-sidebar-raised-shadow: var(--cui-sidebar-inset-shadow);
10
+ }
11
+
12
+ :where([data-control-family="sidebar"][data-slot="root"]:is([data-variant="page"], [data-variant="inset"])[data-state]),
13
+ :where([data-control-family="sidebar"][data-slot="root"][data-state="collapsed"]) {
14
+ --cui-sidebar-icon-rail-border-width: 0px;
15
+ }
16
+
17
+ :where(
18
+ [data-control-family="sidebar"][data-slot="root"][data-variant="sidebar"][data-state="expanded"]:has(
19
+ [data-control-family="sidebar"][data-slot="panel"][data-layer="content"]
20
+ )
21
+ ) {
22
+ --cui-sidebar-container-border-width: 0px;
23
+ }
24
+
25
+ :where([data-control-family="sidebar"]:is([data-slot="root"], [data-slot="inner"])) {
26
+ flex-direction: column;
27
+ }
28
+
29
+ :where([data-control-family="sidebar"]:is([data-slot="root"], [data-slot="inner"]):has(> [data-slot="panel"])) {
30
+ flex-direction: row;
31
+ }
32
+
33
+ :where([data-control-family="sidebar"][data-slot="root"][data-side="right"]:has(> [data-slot="panel"])),
34
+ :where(
35
+ [data-control-family="sidebar"][data-slot="root"][data-side="right"]
36
+ [data-control-family="sidebar"][data-slot="inner"]:has(> [data-slot="panel"])
37
+ ) {
38
+ flex-direction: row-reverse;
39
+ }
40
+
41
+ :where([data-control-family="sidebar"][data-slot="icon-rail"]) {
42
+ flex: none;
43
+ inline-size: var(--sidebar-width-icon);
44
+ }
45
+
46
+ :where([data-control-family="sidebar"][data-slot="root"][data-side="left"] [data-control-family="sidebar"][data-slot="icon-rail"]) {
47
+ border-inline-end: var(--cui-sidebar-icon-rail-border-width) solid var(--cui-sidebar-icon-rail-border-color);
48
+ }
49
+
50
+ :where([data-control-family="sidebar"][data-slot="root"][data-side="right"] [data-control-family="sidebar"][data-slot="icon-rail"]) {
51
+ border-inline-start: var(--cui-sidebar-icon-rail-border-width) solid var(--cui-sidebar-icon-rail-border-color);
52
+ }
53
+
54
+ :where([data-control-family="sidebar"][data-slot="panel"]) {
55
+ flex: 1 1 0;
56
+ }
57
+
58
+ :where([data-control-family="sidebar"][data-slot="root"][data-collapsible="icon"] [data-control-family="sidebar"][data-slot="panel"]) {
59
+ visibility: hidden;
60
+ }
61
+
62
+ :where([data-control-family="sidebar"][data-slot="icon-rail"][data-layer="raised"]),
63
+ :where([data-control-family="sidebar"][data-slot="panel"][data-layer="raised"]) {
64
+ background-color: var(--cui-sidebar-raised-background);
65
+ }
66
+
67
+ :where([data-control-family="sidebar"][data-slot="panel"][data-layer="content"]) {
68
+ background-color: var(--cui-sidebar-inset-background);
69
+ background-image: var(--cui-sidebar-inset-background-image);
70
+ }
71
+
72
+ :where(
73
+ [data-control-family="sidebar"][data-slot="root"][data-variant="floating"][data-state]
74
+ [data-control-family="sidebar"][data-slot="inner"]:has(> [data-slot="panel"])
75
+ ) {
76
+ overflow: clip;
77
+ }
78
+
79
+ :where(
80
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"]
81
+ [data-control-family="sidebar"][data-slot="inner"]:has(> [data-layer="raised"])
82
+ ) {
83
+ column-gap: var(--cui-sidebar-inset-inset);
84
+ }
85
+
86
+ :where(
87
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state]
88
+ [data-control-family="sidebar"][data-slot="icon-rail"][data-layer="raised"]
89
+ ),
90
+ :where(
91
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state]
92
+ [data-control-family="sidebar"][data-slot="panel"][data-layer="raised"]
93
+ ) {
94
+ margin-block: calc(var(--cui-sidebar-inset-inset) - var(--spacing) * 2);
95
+ border: var(--cui-sidebar-raised-border-width) solid var(--cui-sidebar-raised-border-color);
96
+ border-radius: var(--cui-sidebar-raised-radius);
97
+ box-shadow: var(--cui-sidebar-raised-shadow);
98
+ }
99
+
100
+ :where(
101
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"]
102
+ [data-control-family="sidebar"][data-slot="panel"][data-layer="content"]
103
+ ) {
104
+ margin-block: calc(var(--cui-sidebar-inset-inset) - var(--spacing) * 2);
105
+ border: var(--cui-sidebar-inset-border-width) solid var(--cui-sidebar-inset-border-color);
106
+ border-radius: var(--cui-sidebar-inset-radius);
107
+ box-shadow: var(--cui-sidebar-inset-shadow);
108
+ }
109
+
110
+ :where(
111
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="left"]
112
+ [data-control-family="sidebar"][data-slot="panel"][data-layer="content"]
113
+ ) {
114
+ margin-inline-end: calc(var(--spacing) * -2 - var(--control-rim-width) * 2);
115
+ border-inline-end-width: 0;
116
+ border-start-end-radius: 0;
117
+ border-end-end-radius: 0;
118
+ }
119
+
120
+ :where(
121
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="right"]
122
+ [data-control-family="sidebar"][data-slot="panel"][data-layer="content"]
123
+ ) {
124
+ margin-inline-start: calc(var(--spacing) * -2 - var(--control-rim-width) * 2);
125
+ border-inline-start-width: 0;
126
+ border-start-start-radius: 0;
127
+ border-end-start-radius: 0;
128
+ }
129
+
130
+ :where(
131
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="left"]:dir(ltr)
132
+ [data-control-family="sidebar"][data-slot="panel"][data-layer="content"]
133
+ ),
134
+ :where(
135
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="right"]:dir(rtl)
136
+ [data-control-family="sidebar"][data-slot="panel"][data-layer="content"]
137
+ ) {
138
+ clip-path: inset(-100vmax var(--control-rim-width) -100vmax -100vmax);
139
+ }
140
+
141
+ :where(
142
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="left"]:dir(rtl)
143
+ [data-control-family="sidebar"][data-slot="panel"][data-layer="content"]
144
+ ),
145
+ :where(
146
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="right"]:dir(ltr)
147
+ [data-control-family="sidebar"][data-slot="panel"][data-layer="content"]
148
+ ) {
149
+ clip-path: inset(-100vmax -100vmax -100vmax var(--control-rim-width));
150
+ }
151
+ }
152
+
153
+ @property --cui-sidebar-icon-rail-border-width {
154
+ syntax: "<length>";
155
+ inherits: true;
156
+ initial-value: 0px;
157
+ }
158
+
159
+ @property --cui-sidebar-icon-rail-border-color {
160
+ syntax: "<color>";
161
+ inherits: true;
162
+ initial-value: transparent;
163
+ }
164
+
165
+ @property --cui-sidebar-raised-background {
166
+ syntax: "<color>";
167
+ inherits: true;
168
+ initial-value: transparent;
169
+ }
170
+
171
+ @property --cui-sidebar-raised-border-width {
172
+ syntax: "<length>";
173
+ inherits: true;
174
+ initial-value: 0px;
175
+ }
176
+
177
+ @property --cui-sidebar-raised-border-color {
178
+ syntax: "<color>";
179
+ inherits: true;
180
+ initial-value: transparent;
181
+ }
182
+
183
+ @property --cui-sidebar-raised-radius {
184
+ syntax: "<length-percentage>";
185
+ inherits: true;
186
+ initial-value: 0px;
187
+ }
188
+
189
+ @property --cui-sidebar-raised-shadow {
190
+ syntax: "*";
191
+ inherits: true;
192
+ }
@@ -100,17 +100,75 @@
100
100
  ~ [data-control-family="sidebar"][data-slot="inset"]
101
101
  ) {
102
102
  margin: var(--cui-sidebar-inset-inset);
103
- margin-inline-start: 0;
104
103
  border: var(--cui-sidebar-inset-border-width) solid var(--cui-sidebar-inset-border-color);
105
104
  border-radius: var(--cui-sidebar-inset-radius);
106
105
  box-shadow: var(--cui-sidebar-inset-shadow);
107
106
  }
108
107
 
109
108
  :where(
110
- [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="collapsed"]
109
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="left"]
110
+ ~ [data-control-family="sidebar"][data-slot="inset"]
111
+ ) {
112
+ margin-inline-start: 0;
113
+ }
114
+
115
+ :where(
116
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="right"]
117
+ ~ [data-control-family="sidebar"][data-slot="inset"]
118
+ ) {
119
+ margin-inline-end: 0;
120
+ }
121
+
122
+ :where(
123
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="left"]:has(
124
+ [data-slot="panel"][data-layer="content"]
125
+ )
126
+ ~ [data-control-family="sidebar"][data-slot="inset"]
127
+ ) {
128
+ border-inline-start-width: 0;
129
+ border-start-start-radius: 0;
130
+ border-end-start-radius: 0;
131
+ }
132
+
133
+ :where(
134
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="right"]:has(
135
+ [data-slot="panel"][data-layer="content"]
136
+ )
137
+ ~ [data-control-family="sidebar"][data-slot="inset"]
138
+ ) {
139
+ border-inline-end-width: 0;
140
+ border-start-end-radius: 0;
141
+ border-end-end-radius: 0;
142
+ }
143
+
144
+ :where(
145
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="left"]:dir(ltr):has(
146
+ [data-slot="panel"][data-layer="content"]
147
+ )
148
+ ~ [data-control-family="sidebar"][data-slot="inset"]
149
+ ),
150
+ :where(
151
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="right"]:dir(rtl):has(
152
+ [data-slot="panel"][data-layer="content"]
153
+ )
154
+ ~ [data-control-family="sidebar"][data-slot="inset"]
155
+ ) {
156
+ clip-path: inset(-100vmax -100vmax -100vmax 0);
157
+ }
158
+
159
+ :where(
160
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="left"]:dir(rtl):has(
161
+ [data-slot="panel"][data-layer="content"]
162
+ )
163
+ ~ [data-control-family="sidebar"][data-slot="inset"]
164
+ ),
165
+ :where(
166
+ [data-control-family="sidebar"][data-slot="root"][data-variant="inset"][data-state="expanded"][data-side="right"]:dir(ltr):has(
167
+ [data-slot="panel"][data-layer="content"]
168
+ )
111
169
  ~ [data-control-family="sidebar"][data-slot="inset"]
112
170
  ) {
113
- margin-inline-start: var(--cui-sidebar-inset-inset);
171
+ clip-path: inset(-100vmax 0 -100vmax -100vmax);
114
172
  }
115
173
  }
116
174
 
package/dist/task-list.js CHANGED
@@ -2,9 +2,9 @@
2
2
  import { cn } from "./lib/cn.js";
3
3
  import { LiveStatus } from "./ui/live-status.js";
4
4
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./ui/collapsible.js";
5
+ import { ChevronRight, CircleCheck, CircleDashed, Loader2 } from "lucide-react";
5
6
  import { createContext, useContext, useEffect, useId, useState } from "react";
6
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
- import { ChevronRight, CircleCheck, CircleDashed, Loader2 } from "lucide-react";
8
8
  //#region src/task-list.tsx
9
9
  const taskStatusLabels = {
10
10
  pending: "Pending",
@@ -4,10 +4,10 @@ import { Button } from "./ui/button.js";
4
4
  import { LiveStatus } from "./ui/live-status.js";
5
5
  import { Badge } from "./ui/badge.js";
6
6
  import { Kbd } from "./ui/kbd.js";
7
+ import { Check, ShieldAlert, X } from "lucide-react";
7
8
  import { createContext, useContext, useEffect, useId, useRef } from "react";
8
9
  import { useRender } from "@base-ui/react/use-render";
9
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
- import { Check, ShieldAlert, X } from "lucide-react";
11
11
  //#region src/tool-approval.tsx
12
12
  const ToolApprovalContext = createContext(null);
13
13
  function useToolApprovalContext() {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
- import { jsx, jsxs } from "react/jsx-runtime";
4
3
  import { ChevronDown } from "lucide-react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { Accordion as Accordion$1 } from "@base-ui/react/accordion";
6
6
  //#region src/ui/accordion.tsx
7
7
  function Accordion({ className, ...props }) {
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
+ import { ChevronRight, MoreHorizontal } from "lucide-react";
3
4
  import { useRender } from "@base-ui/react/use-render";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
- import { ChevronRight, MoreHorizontal } from "lucide-react";
6
6
  //#region src/ui/breadcrumb.tsx
7
7
  function Breadcrumb({ className, ...props }) {
8
8
  return /* @__PURE__ */ jsx("nav", {
package/dist/ui/code.js CHANGED
@@ -7,9 +7,9 @@ import { Swap, SwapItem } from "./swap.js";
7
7
  import { ScrollArea } from "./scroll-area.js";
8
8
  import { highlightToTokens } from "../lib/code-tokens.js";
9
9
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.js";
10
+ import { CheckIcon, CopyIcon } from "lucide-react";
10
11
  import { Children, createContext, isValidElement, useContext, useEffect, useMemo, useRef, useState } from "react";
11
12
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
- import { CheckIcon, CopyIcon } from "lucide-react";
13
13
  import { useVirtualizer } from "@tanstack/react-virtual";
14
14
  //#region src/ui/code.tsx
15
15
  const MAX_STATIC_CODE_LINES = 1e3;
@@ -4,9 +4,9 @@ import { Button } from "./button.js";
4
4
  import { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle } from "./item.js";
5
5
  import { DropzoneErrorCode, formatDropzoneFileSize } from "../lib/dropzone-validation.js";
6
6
  import { useDropzone } from "../hooks/use-dropzone.js";
7
+ import { CircleAlertIcon, CloudUpload, FileIcon, LoaderCircle, Search, XIcon } from "lucide-react";
7
8
  import { createContext, useContext, useEffect, useState } from "react";
8
9
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { CircleAlertIcon, CloudUpload, FileIcon, LoaderCircle, Search, XIcon } from "lucide-react";
10
10
  //#region src/ui/dropzone.tsx
11
11
  const DropzoneContext = createContext(null);
12
12
  const DropzoneFocusContext = createContext(null);
@@ -6,9 +6,9 @@ import { PopoverViewport } from "./popover.js";
6
6
  import { IconPicker } from "./icon-picker.js";
7
7
  import { Tabs, TabsList, TabsPanel, TabsTab } from "./tabs.js";
8
8
  import { Toolbar } from "@base-ui/react/toolbar";
9
+ import { FlagIcon, HandIcon, HashIcon, HeartIcon, LeafIcon, LightbulbIcon, PizzaIcon, PlaneIcon, SearchIcon, SmileIcon, VolleyballIcon } from "lucide-react";
9
10
  import { createContext, useContext, useImperativeHandle, useRef, useState } from "react";
10
11
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
- import { FlagIcon, HandIcon, HashIcon, HeartIcon, LeafIcon, LightbulbIcon, PizzaIcon, PlaneIcon, SearchIcon, SmileIcon, VolleyballIcon } from "lucide-react";
12
12
  import { EmojiPicker as EmojiPicker$1, defaultEmojiDataResolver } from "frimousse";
13
13
  //#region src/ui/emoji-picker.tsx
14
14
  const EmojiPickerContext = createContext(null);
package/dist/ui/flow.js CHANGED
@@ -3,8 +3,8 @@ import { cn } from "../lib/cn.js";
3
3
  import { Button } from "./button.js";
4
4
  import { prefersReducedMotion, readDurationMs } from "../lib/motion.js";
5
5
  import "../lib/canvas-grid.js";
6
- import { jsx, jsxs } from "react/jsx-runtime";
7
6
  import { MaximizeIcon, MinusIcon, PlusIcon } from "lucide-react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { Background, BackgroundVariant, BaseEdge, EdgeLabelRenderer, Handle, Panel, ReactFlow, useReactFlow, useStore } from "@xyflow/react";
9
9
  //#region src/ui/flow.tsx
10
10
  function viewportTransitionMs(element) {
@@ -13,6 +13,8 @@ export type HoverCardContentProps = Omit<ComponentProps<"div"> & {
13
13
  side?: "top" | "bottom" | "left" | "right";
14
14
  align?: "start" | "center" | "end";
15
15
  sideOffset?: number;
16
+ /** Positions the card against this element instead of the trigger, for hover targets React does not render. */
17
+ anchor?: ComponentProps<typeof PreviewCard.Positioner>["anchor"];
16
18
  }, "style"> & {
17
19
  style?: CSSProperties & PopupKnobStyle;
18
20
  };
@@ -20,5 +22,5 @@ export declare function HoverCard(props: HoverCardProps): import("react").JSX.El
20
22
  export declare function HoverCardTrigger({ className, ...props }: ComponentProps<typeof PreviewCard.Trigger> & {
21
23
  style?: CSSProperties & PopupKnobStyle;
22
24
  }): import("react").JSX.Element;
23
- export declare function HoverCardContent({ className, children, side, align, sideOffset, ...props }: HoverCardContentProps): import("react").JSX.Element;
25
+ export declare function HoverCardContent({ className, children, side, align, sideOffset, anchor, ...props }: HoverCardContentProps): import("react").JSX.Element;
24
26
  //#endregion
@@ -11,14 +11,13 @@ function HoverCard(props) {
11
11
  function HoverCardTrigger({ className, ...props }) {
12
12
  return /* @__PURE__ */ jsx(PreviewCard.Trigger, {
13
13
  "data-control-ui": "hover-card",
14
- "data-control-family": "popup",
15
14
  "data-popup-kind": "hover-card",
16
15
  "data-slot": "trigger",
17
16
  className,
18
17
  ...props
19
18
  });
20
19
  }
21
- function HoverCardContent({ className, children, side = "bottom", align = "center", sideOffset = 8, ...props }) {
20
+ function HoverCardContent({ className, children, side = "bottom", align = "center", sideOffset = 8, anchor, ...props }) {
22
21
  const skin = useSkin();
23
22
  return /* @__PURE__ */ jsx(PreviewCard.Portal, { children: /* @__PURE__ */ jsx(PreviewCard.Positioner, {
24
23
  "data-control-ui": "hover-card",
@@ -30,6 +29,7 @@ function HoverCardContent({ className, children, side = "bottom", align = "cente
30
29
  side,
31
30
  align,
32
31
  sideOffset,
32
+ anchor,
33
33
  className: "z-(--z-popup)",
34
34
  children: /* @__PURE__ */ jsx(PreviewCard.Popup, {
35
35
  "data-control-ui": "hover-card",
@@ -4,10 +4,10 @@ import { Button } from "./button.js";
4
4
  import { createInfiniteCanvasCamera, infiniteCanvasGridStyle, infiniteCanvasTransformCss } from "../lib/infinite-canvas-camera-store.js";
5
5
  import { ARROW_KEY_DIRECTIONS, INFINITE_CANVAS_KEY_SHORTCUTS, attachInfiniteCanvasNavigation, keyboardStep, runInfiniteCanvasKeyCommand } from "../lib/infinite-canvas-navigation.js";
6
6
  import { Toolbar, ToolbarButton, ToolbarSeparator } from "./toolbar.js";
7
+ import { GripVerticalIcon, MaximizeIcon, MinusIcon, PlusIcon } from "lucide-react";
7
8
  import { createContext, use, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
8
9
  import { useRender } from "@base-ui/react/use-render";
9
10
  import { jsx, jsxs } from "react/jsx-runtime";
10
- import { GripVerticalIcon, MaximizeIcon, MinusIcon, PlusIcon } from "lucide-react";
11
11
  //#region src/ui/infinite-canvas.tsx
12
12
  const DEFAULT_TRANSFORM = {
13
13
  x: 0,