@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.
- package/dist/action-bar.js +1 -1
- package/dist/activity.js +1 -1
- package/dist/blocks/coding-agent.js +16 -19
- package/dist/blocks/design-canvas-data.d.ts +32 -0
- package/dist/blocks/design-canvas-data.js +100 -0
- package/dist/blocks/design-canvas-inspector.d.ts +8 -0
- package/dist/blocks/design-canvas-inspector.js +238 -0
- package/dist/blocks/design-canvas.d.ts +17 -0
- package/dist/blocks/design-canvas.js +346 -0
- package/dist/blocks/file-explorer.js +2 -2
- package/dist/blocks/settings.js +2 -2
- package/dist/chat-composer-attachment.d.ts +9 -3
- package/dist/chat-composer-attachment.js +27 -10
- package/dist/chat-composer-editor.js +20 -4
- package/dist/chat-composer.d.ts +1 -1
- package/dist/chat-composer.js +4 -3
- package/dist/chat-layout.js +32 -19
- package/dist/context.js +1 -1
- package/dist/dynamic-notification.js +1 -1
- package/dist/environment-variables.js +1 -1
- package/dist/filter-bar/context.d.ts +32 -0
- package/dist/filter-bar/context.js +11 -0
- package/dist/filter-bar/editor.d.ts +14 -0
- package/dist/filter-bar/editor.js +204 -0
- package/dist/filter-bar/model.d.ts +9 -0
- package/dist/filter-bar/model.js +48 -0
- package/dist/filter-bar/motion.d.ts +10 -0
- package/dist/filter-bar/motion.js +84 -0
- package/dist/filter-bar/parts.d.ts +19 -0
- package/dist/filter-bar/parts.js +233 -0
- package/dist/filter-bar/types.d.ts +53 -0
- package/dist/filter-bar/types.js +0 -0
- package/dist/filter-bar.d.ts +27 -0
- package/dist/filter-bar.js +304 -0
- package/dist/hooks/use-chat-composer.d.ts +3 -1
- package/dist/hooks/use-chat-composer.js +2 -2
- package/dist/hooks/use-dropzone.d.ts +7 -4
- package/dist/hooks/use-dropzone.js +34 -3
- package/dist/inline-attachment.js +8 -14
- package/dist/inline-citation.js +1 -1
- package/dist/knob-contracts/chat-layout-knobs.d.ts +1 -1
- package/dist/knob-contracts/chat-layout-knobs.js +2 -1
- package/dist/knob-contracts/choice-knobs.d.ts +1 -1
- package/dist/knob-contracts/choice-knobs.js +1 -0
- package/dist/knob-contracts/collapsible-knobs.d.ts +1 -1
- package/dist/knob-contracts/collapsible-knobs.js +1 -1
- package/dist/knob-contracts/filter-bar-knobs.d.ts +4 -0
- package/dist/knob-contracts/filter-bar-knobs.js +16 -0
- package/dist/knob-contracts/infinite-canvas-knobs.d.ts +1 -1
- package/dist/knob-contracts/infinite-canvas-knobs.js +3 -0
- package/dist/knob-contracts/page-layout-knobs.d.ts +1 -1
- package/dist/knob-contracts/page-layout-knobs.js +4 -1
- package/dist/knob-contracts/popup-knobs.d.ts +1 -1
- package/dist/knob-contracts/popup-knobs.js +1 -0
- package/dist/knob-contracts/table-of-contents-knobs.d.ts +1 -1
- package/dist/knob-contracts/table-of-contents-knobs.js +3 -5
- package/dist/lib/phone-input-format.js +1 -1
- package/dist/markdown-block.js +11 -7
- package/dist/scripts/contrast-eval.js +5 -4
- package/dist/styles/index.css +5 -4
- package/dist/styles/recipes/button-group.css +1 -1
- package/dist/styles/recipes/button.css +2 -2
- package/dist/styles/recipes/chat-composer.css +14 -6
- package/dist/styles/recipes/chat-layout.css +29 -2
- package/dist/styles/recipes/choice.css +10 -3
- package/dist/styles/recipes/code-diff.css +16 -4
- package/dist/styles/recipes/code.css +11 -5
- package/dist/styles/recipes/collapsible.css +37 -0
- package/dist/styles/recipes/color-picker.css +12 -2
- package/dist/styles/recipes/dockable-panel.css +11 -3
- package/dist/styles/recipes/field-parts.css +62 -0
- package/dist/styles/recipes/field.css +28 -6
- package/dist/styles/recipes/filter-bar.css +174 -0
- package/dist/styles/recipes/infinite-canvas.css +51 -3
- package/dist/styles/recipes/inline-attachment.css +6 -1
- package/dist/styles/recipes/page-layout.css +36 -2
- package/dist/styles/recipes/pagination.css +1 -1
- package/dist/styles/recipes/popup-controls.css +16 -0
- package/dist/styles/recipes/popup-drawer.css +34 -32
- package/dist/styles/recipes/popup-lists.css +11 -2
- package/dist/styles/recipes/popup.css +10 -12
- package/dist/styles/recipes/range.css +1 -1
- package/dist/styles/recipes/resizable.css +34 -0
- package/dist/styles/recipes/spinner.css +4 -0
- package/dist/styles/recipes/table-of-contents.css +42 -42
- package/dist/styles/recipes/tabs.css +21 -0
- package/dist/styles/recipes/track-highlight.css +2 -1
- package/dist/styles/recipes/transcript-divider.css +2 -2
- package/dist/styles/theme.css +250 -91
- package/dist/ui/alert-dialog.js +1 -1
- package/dist/ui/autocomplete.js +5 -1
- package/dist/ui/button.js +2 -2
- package/dist/ui/checkbox-group.js +1 -1
- package/dist/ui/code-diff.js +1 -1
- package/dist/ui/code.js +3 -3
- package/dist/ui/collapsible.js +1 -1
- package/dist/ui/color-picker.js +2 -2
- package/dist/ui/combobox-disabled-selection.d.ts +1 -1
- package/dist/ui/combobox-disabled-selection.js +2 -1
- package/dist/ui/combobox.d.ts +5 -23
- package/dist/ui/combobox.js +26 -14
- package/dist/ui/command.js +9 -1
- package/dist/ui/context-menu.js +1 -1
- package/dist/ui/dialog.js +1 -1
- package/dist/ui/dockable-panel.js +18 -10
- package/dist/ui/drawer.d.ts +7 -4
- package/dist/ui/drawer.js +36 -23
- package/dist/ui/dropdown-menu.js +1 -1
- package/dist/ui/dropzone.d.ts +3 -1
- package/dist/ui/dropzone.js +3 -1
- package/dist/ui/field.js +1 -1
- package/dist/ui/hover-card.js +1 -1
- package/dist/ui/infinite-canvas.d.ts +11 -0
- package/dist/ui/infinite-canvas.js +82 -7
- package/dist/ui/input-group.d.ts +2 -1
- package/dist/ui/input-group.js +12 -3
- package/dist/ui/input.js +9 -0
- package/dist/ui/item.js +1 -1
- package/dist/ui/markdown-elements.js +11 -8
- package/dist/ui/menubar.js +1 -1
- package/dist/ui/morphing-panel.js +1 -1
- package/dist/ui/navigation-menu.js +1 -1
- package/dist/ui/number-field.d.ts +1 -1
- package/dist/ui/number-field.js +13 -2
- package/dist/ui/phone-input.js +2 -2
- package/dist/ui/popover.js +1 -1
- package/dist/ui/radio-group.d.ts +1 -0
- package/dist/ui/radio-group.js +11 -1
- package/dist/ui/resizable.d.ts +18 -1
- package/dist/ui/resizable.js +127 -7
- package/dist/ui/responsive-dialog.js +6 -3
- package/dist/ui/rich-tooltip.js +1 -1
- package/dist/ui/scroll-area.d.ts +4 -1
- package/dist/ui/scroll-area.js +2 -1
- package/dist/ui/select.d.ts +2 -1
- package/dist/ui/select.js +58 -33
- package/dist/ui/sheet.js +1 -1
- package/dist/ui/sidebar-menu.js +1 -1
- package/dist/ui/sidebar-provider.js +2 -2
- package/dist/ui/sidebar-resize-rail.js +1 -1
- package/dist/ui/sidebar.js +1 -1
- package/dist/ui/table-of-contents.d.ts +4 -3
- package/dist/ui/table-of-contents.js +126 -47
- package/dist/ui/table.js +11 -7
- package/dist/ui/toast.js +1 -1
- package/dist/ui/toggle.d.ts +1 -1
- package/dist/ui/toggle.js +2 -1
- package/dist/ui/tooltip.js +1 -1
- package/dist/ui/tree.js +1 -1
- package/dist/ui/trigger-menu.js +7 -3
- package/dist/user-ask.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { Button } from "../ui/button.js";
|
|
4
|
+
import { ScrollArea } from "../ui/scroll-area.js";
|
|
5
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip.js";
|
|
6
|
+
import { InfiniteCanvas, InfiniteCanvasContent, InfiniteCanvasControls, InfiniteCanvasItem } from "../ui/infinite-canvas.js";
|
|
7
|
+
import { ResizableFloatingPanel } from "../ui/resizable.js";
|
|
8
|
+
import { Toolbar, ToolbarButton, ToolbarGroup } from "../ui/toolbar.js";
|
|
9
|
+
import { createDesignCanvasLayer, designCanvasFillColor, drawnDesignCanvasBounds } from "./design-canvas-data.js";
|
|
10
|
+
import { DesignCanvasInspector } from "./design-canvas-inspector.js";
|
|
11
|
+
import { useRef, useState } from "react";
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { CircleIcon, FrameIcon, MousePointer2Icon, SquareIcon, TypeIcon } from "lucide-react";
|
|
14
|
+
//#region src/blocks/design-canvas.tsx
|
|
15
|
+
const TOOLS = [
|
|
16
|
+
{
|
|
17
|
+
tool: "move",
|
|
18
|
+
label: "Move",
|
|
19
|
+
shortcut: "V",
|
|
20
|
+
icon: /* @__PURE__ */ jsx(MousePointer2Icon, {})
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
tool: "frame",
|
|
24
|
+
label: "Frame",
|
|
25
|
+
shortcut: "F",
|
|
26
|
+
icon: /* @__PURE__ */ jsx(FrameIcon, {})
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
tool: "rectangle",
|
|
30
|
+
label: "Rectangle",
|
|
31
|
+
shortcut: "R",
|
|
32
|
+
icon: /* @__PURE__ */ jsx(SquareIcon, {})
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
tool: "ellipse",
|
|
36
|
+
label: "Ellipse",
|
|
37
|
+
shortcut: "O",
|
|
38
|
+
icon: /* @__PURE__ */ jsx(CircleIcon, {})
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
tool: "text",
|
|
42
|
+
label: "Text",
|
|
43
|
+
shortcut: "T",
|
|
44
|
+
icon: /* @__PURE__ */ jsx(TypeIcon, {})
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
const LAYER_ICONS = {
|
|
48
|
+
frame: /* @__PURE__ */ jsx(FrameIcon, {}),
|
|
49
|
+
rectangle: /* @__PURE__ */ jsx(SquareIcon, {}),
|
|
50
|
+
ellipse: /* @__PURE__ */ jsx(CircleIcon, {}),
|
|
51
|
+
text: /* @__PURE__ */ jsx(TypeIcon, {})
|
|
52
|
+
};
|
|
53
|
+
const NUDGE_DIRECTIONS = {
|
|
54
|
+
ArrowLeft: {
|
|
55
|
+
x: -1,
|
|
56
|
+
y: 0
|
|
57
|
+
},
|
|
58
|
+
ArrowRight: {
|
|
59
|
+
x: 1,
|
|
60
|
+
y: 0
|
|
61
|
+
},
|
|
62
|
+
ArrowUp: {
|
|
63
|
+
x: 0,
|
|
64
|
+
y: -1
|
|
65
|
+
},
|
|
66
|
+
ArrowDown: {
|
|
67
|
+
x: 0,
|
|
68
|
+
y: 1
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const DEFAULT_TRANSFORM = {
|
|
72
|
+
x: 0,
|
|
73
|
+
y: 0,
|
|
74
|
+
scale: 1
|
|
75
|
+
};
|
|
76
|
+
const CLICK_TOLERANCE_PX = 4;
|
|
77
|
+
function newLayerId(kind) {
|
|
78
|
+
return `${kind}-${Math.random().toString(36).slice(2, 8)}`;
|
|
79
|
+
}
|
|
80
|
+
function toolForShortcut(key) {
|
|
81
|
+
return TOOLS.find((entry) => entry.shortcut === key.toUpperCase())?.tool;
|
|
82
|
+
}
|
|
83
|
+
function layerFromDraft(draft, id) {
|
|
84
|
+
return createDesignCanvasLayer(draft.kind, drawnDesignCanvasBounds(draft.kind, draft.start, draft.end, draft.clickTolerance), id);
|
|
85
|
+
}
|
|
86
|
+
function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selectedLayerId, defaultSelectedLayerId = null, onSelectedLayerIdChange, defaultTransform = DEFAULT_TRANSFORM, layout = "viewport", className, ...props }) {
|
|
87
|
+
const [internalLayers, setInternalLayers] = useState(defaultLayers);
|
|
88
|
+
const [internalSelectedLayerId, setInternalSelectedLayerId] = useState(defaultSelectedLayerId);
|
|
89
|
+
const transformRef = useRef(defaultTransform);
|
|
90
|
+
const [tool, setTool] = useState("move");
|
|
91
|
+
const [draft, setDraft] = useState(null);
|
|
92
|
+
const currentLayers = layers ?? internalLayers;
|
|
93
|
+
const currentSelectedLayerId = selectedLayerId === void 0 ? internalSelectedLayerId : selectedLayerId;
|
|
94
|
+
const selectedLayer = currentLayers.find((layer) => layer.id === currentSelectedLayerId);
|
|
95
|
+
function changeLayers(next) {
|
|
96
|
+
if (layers === void 0) setInternalLayers(next);
|
|
97
|
+
onLayersChange?.(next);
|
|
98
|
+
}
|
|
99
|
+
function selectLayer(layerId) {
|
|
100
|
+
if (selectedLayerId === void 0) setInternalSelectedLayerId(layerId);
|
|
101
|
+
onSelectedLayerIdChange?.(layerId);
|
|
102
|
+
}
|
|
103
|
+
function replaceLayer(next) {
|
|
104
|
+
changeLayers(currentLayers.map((layer) => layer.id === next.id ? next : layer));
|
|
105
|
+
}
|
|
106
|
+
function worldPointAt(event) {
|
|
107
|
+
const bounds = event.currentTarget.getBoundingClientRect();
|
|
108
|
+
const { x, y, scale } = transformRef.current;
|
|
109
|
+
return {
|
|
110
|
+
x: (event.clientX - bounds.left - x) / scale,
|
|
111
|
+
y: (event.clientY - bounds.top - y) / scale
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function beginDrawOrDeselect(event) {
|
|
115
|
+
if (event.defaultPrevented || event.target !== event.currentTarget) return;
|
|
116
|
+
if (tool === "move") {
|
|
117
|
+
selectLayer(null);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (!event.isPrimary || event.button !== 0) return;
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
123
|
+
const point = worldPointAt(event);
|
|
124
|
+
setDraft({
|
|
125
|
+
kind: tool,
|
|
126
|
+
pointerId: event.pointerId,
|
|
127
|
+
start: point,
|
|
128
|
+
end: point,
|
|
129
|
+
clickTolerance: CLICK_TOLERANCE_PX / transformRef.current.scale
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function resizeDraft(event) {
|
|
133
|
+
if (draft?.pointerId !== event.pointerId) return;
|
|
134
|
+
setDraft({
|
|
135
|
+
...draft,
|
|
136
|
+
end: worldPointAt(event)
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function commitDraft(event) {
|
|
140
|
+
if (draft?.pointerId !== event.pointerId) return;
|
|
141
|
+
const layer = layerFromDraft(draft, newLayerId(draft.kind));
|
|
142
|
+
setDraft(null);
|
|
143
|
+
changeLayers([...currentLayers, layer]);
|
|
144
|
+
selectLayer(layer.id);
|
|
145
|
+
setTool("move");
|
|
146
|
+
}
|
|
147
|
+
function cancelDraft(event) {
|
|
148
|
+
if (draft?.pointerId === event.pointerId) setDraft(null);
|
|
149
|
+
}
|
|
150
|
+
function editSelectedLayerWithKey(event) {
|
|
151
|
+
if (!selectedLayer) return false;
|
|
152
|
+
const nudge = NUDGE_DIRECTIONS[event.key];
|
|
153
|
+
if (event.key === "Delete" || event.key === "Backspace") {
|
|
154
|
+
changeLayers(currentLayers.filter((layer) => layer.id !== selectedLayer.id));
|
|
155
|
+
selectLayer(null);
|
|
156
|
+
} else if (nudge) {
|
|
157
|
+
const distance = event.shiftKey ? 10 : 1;
|
|
158
|
+
replaceLayer({
|
|
159
|
+
...selectedLayer,
|
|
160
|
+
x: selectedLayer.x + nudge.x * distance,
|
|
161
|
+
y: selectedLayer.y + nudge.y * distance
|
|
162
|
+
});
|
|
163
|
+
} else return false;
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
function handleShortcut(event) {
|
|
167
|
+
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
168
|
+
const shortcutTool = toolForShortcut(event.key);
|
|
169
|
+
if (shortcutTool) setTool(shortcutTool);
|
|
170
|
+
else if (event.key === "Escape") {
|
|
171
|
+
setDraft(null);
|
|
172
|
+
setTool("move");
|
|
173
|
+
selectLayer(null);
|
|
174
|
+
} else if (!editSelectedLayerWithKey(event)) return;
|
|
175
|
+
event.preventDefault();
|
|
176
|
+
}
|
|
177
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
178
|
+
className: cn("@container/design-canvas relative isolate overflow-hidden bg-background text-foreground", layout === "contained" ? "h-full min-h-0" : "h-svh", className),
|
|
179
|
+
...props,
|
|
180
|
+
children: [
|
|
181
|
+
/* @__PURE__ */ jsxs(InfiniteCanvas, {
|
|
182
|
+
"aria-label": "Design canvas",
|
|
183
|
+
defaultTransform,
|
|
184
|
+
onTransformChange: (next) => {
|
|
185
|
+
transformRef.current = next;
|
|
186
|
+
},
|
|
187
|
+
"data-tool": tool,
|
|
188
|
+
className: cn("size-full", tool !== "move" && "cursor-crosshair"),
|
|
189
|
+
style: {
|
|
190
|
+
"--cui-infinite-canvas-radius": "0px",
|
|
191
|
+
"--cui-infinite-canvas-border-color": "transparent",
|
|
192
|
+
"--cui-infinite-canvas-background": "var(--muted)"
|
|
193
|
+
},
|
|
194
|
+
onPointerDown: beginDrawOrDeselect,
|
|
195
|
+
onPointerMove: resizeDraft,
|
|
196
|
+
onPointerUp: commitDraft,
|
|
197
|
+
onPointerCancel: cancelDraft,
|
|
198
|
+
onKeyDown: handleShortcut,
|
|
199
|
+
children: [/* @__PURE__ */ jsxs(InfiniteCanvasContent, {
|
|
200
|
+
className: cn(tool !== "move" && "[&>*]:pointer-events-none"),
|
|
201
|
+
children: [currentLayers.map((layer) => /* @__PURE__ */ jsx(DesignCanvasLayerNode, {
|
|
202
|
+
layer,
|
|
203
|
+
selected: layer.id === currentSelectedLayerId,
|
|
204
|
+
onSelect: () => selectLayer(layer.id),
|
|
205
|
+
onLayerChange: replaceLayer
|
|
206
|
+
}, layer.id)), draft ? /* @__PURE__ */ jsx(DesignCanvasLayerNode, {
|
|
207
|
+
layer: layerFromDraft(draft, "draft"),
|
|
208
|
+
selected: true
|
|
209
|
+
}) : null]
|
|
210
|
+
}), /* @__PURE__ */ jsx(InfiniteCanvasControls, { className: "top-3 right-auto bottom-auto left-3 @4xl/design-canvas:left-1/2 @4xl/design-canvas:-translate-x-1/2" })]
|
|
211
|
+
}),
|
|
212
|
+
/* @__PURE__ */ jsx(ResizableFloatingPanel, {
|
|
213
|
+
side: "left",
|
|
214
|
+
defaultSize: 224,
|
|
215
|
+
minSize: 180,
|
|
216
|
+
maxSize: 360,
|
|
217
|
+
className: "hidden @4xl/design-canvas:flex",
|
|
218
|
+
children: /* @__PURE__ */ jsxs("aside", {
|
|
219
|
+
"aria-label": "Layers",
|
|
220
|
+
className: "flex min-h-0 flex-1 flex-col",
|
|
221
|
+
children: [/* @__PURE__ */ jsx("h2", {
|
|
222
|
+
className: "flex h-11 shrink-0 items-center border-b px-3 text-caption font-medium",
|
|
223
|
+
children: "Layers"
|
|
224
|
+
}), /* @__PURE__ */ jsx(ScrollArea, {
|
|
225
|
+
className: "min-h-0 flex-1",
|
|
226
|
+
children: /* @__PURE__ */ jsx("ul", {
|
|
227
|
+
className: "flex flex-col gap-0.5 p-2",
|
|
228
|
+
children: currentLayers.toReversed().map((layer) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Button, {
|
|
229
|
+
variant: "ghost",
|
|
230
|
+
size: "sm",
|
|
231
|
+
active: layer.id === currentSelectedLayerId,
|
|
232
|
+
"aria-pressed": layer.id === currentSelectedLayerId,
|
|
233
|
+
className: "w-full justify-start [&_svg]:size-3.5 [&_svg]:text-muted-foreground",
|
|
234
|
+
onClick: () => selectLayer(layer.id),
|
|
235
|
+
children: [LAYER_ICONS[layer.kind], /* @__PURE__ */ jsx("span", {
|
|
236
|
+
className: "truncate",
|
|
237
|
+
children: layer.name
|
|
238
|
+
})]
|
|
239
|
+
}) }, layer.id))
|
|
240
|
+
})
|
|
241
|
+
})]
|
|
242
|
+
})
|
|
243
|
+
}),
|
|
244
|
+
/* @__PURE__ */ jsx(ResizableFloatingPanel, {
|
|
245
|
+
defaultSize: 280,
|
|
246
|
+
minSize: 256,
|
|
247
|
+
maxSize: 440,
|
|
248
|
+
className: "hidden @xl/design-canvas:flex",
|
|
249
|
+
children: /* @__PURE__ */ jsxs("aside", {
|
|
250
|
+
"aria-label": "Properties",
|
|
251
|
+
className: "flex min-h-0 flex-1 flex-col",
|
|
252
|
+
children: [/* @__PURE__ */ jsx("h2", {
|
|
253
|
+
className: "flex h-11 shrink-0 items-center border-b px-3 text-caption font-medium",
|
|
254
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
255
|
+
className: "truncate",
|
|
256
|
+
children: selectedLayer?.name ?? "Design"
|
|
257
|
+
})
|
|
258
|
+
}), /* @__PURE__ */ jsx(ScrollArea, {
|
|
259
|
+
className: "min-h-0 flex-1",
|
|
260
|
+
children: /* @__PURE__ */ jsx(DesignCanvasInspector, {
|
|
261
|
+
layer: selectedLayer,
|
|
262
|
+
onLayerChange: replaceLayer
|
|
263
|
+
})
|
|
264
|
+
})]
|
|
265
|
+
})
|
|
266
|
+
}),
|
|
267
|
+
/* @__PURE__ */ jsx(DesignCanvasToolbar, {
|
|
268
|
+
tool,
|
|
269
|
+
onToolChange: setTool
|
|
270
|
+
})
|
|
271
|
+
]
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
function DesignCanvasLayerNode({ layer, selected, onSelect, onLayerChange }) {
|
|
275
|
+
const fillColor = designCanvasFillColor(layer.fill);
|
|
276
|
+
return /* @__PURE__ */ jsxs(InfiniteCanvasItem, {
|
|
277
|
+
x: layer.x,
|
|
278
|
+
y: layer.y,
|
|
279
|
+
"aria-label": layer.name,
|
|
280
|
+
"data-selected": selected || void 0,
|
|
281
|
+
className: "outline-primary data-selected:outline-2",
|
|
282
|
+
style: {
|
|
283
|
+
width: layer.width,
|
|
284
|
+
height: layer.height,
|
|
285
|
+
rotate: `${layer.rotation}deg`,
|
|
286
|
+
opacity: layer.opacity / 100
|
|
287
|
+
},
|
|
288
|
+
onPointerDown: onSelect,
|
|
289
|
+
onPositionChange: onLayerChange && ((position) => onLayerChange({
|
|
290
|
+
...layer,
|
|
291
|
+
x: Math.round(position.x),
|
|
292
|
+
y: Math.round(position.y)
|
|
293
|
+
})),
|
|
294
|
+
children: [
|
|
295
|
+
layer.kind === "frame" ? /* @__PURE__ */ jsx("span", {
|
|
296
|
+
className: "absolute bottom-full left-0 mb-1 whitespace-nowrap text-caption text-muted-foreground",
|
|
297
|
+
children: layer.name
|
|
298
|
+
}) : null,
|
|
299
|
+
layer.kind === "text" ? /* @__PURE__ */ jsx("p", {
|
|
300
|
+
className: "size-full overflow-hidden text-2xl leading-8 whitespace-nowrap",
|
|
301
|
+
style: { color: fillColor },
|
|
302
|
+
children: layer.text
|
|
303
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
304
|
+
className: "size-full",
|
|
305
|
+
style: {
|
|
306
|
+
background: fillColor,
|
|
307
|
+
borderRadius: layer.kind === "ellipse" ? "50%" : layer.cornerRadius
|
|
308
|
+
}
|
|
309
|
+
}),
|
|
310
|
+
selected ? /* @__PURE__ */ jsxs("span", {
|
|
311
|
+
className: "absolute top-full left-1/2 mt-1.5 -translate-x-1/2 rounded-sm bg-primary px-1 text-[10px] leading-4 whitespace-nowrap text-primary-foreground tabular-nums",
|
|
312
|
+
children: [
|
|
313
|
+
layer.width,
|
|
314
|
+
" × ",
|
|
315
|
+
layer.height
|
|
316
|
+
]
|
|
317
|
+
}) : null
|
|
318
|
+
]
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
function DesignCanvasToolbar({ tool, onToolChange }) {
|
|
322
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(Toolbar, {
|
|
323
|
+
variant: "floating",
|
|
324
|
+
"aria-label": "Design tools",
|
|
325
|
+
className: "absolute bottom-4 left-4 w-max @4xl/design-canvas:left-1/2 @4xl/design-canvas:-translate-x-1/2",
|
|
326
|
+
children: /* @__PURE__ */ jsx(ToolbarGroup, {
|
|
327
|
+
"aria-label": "Tools",
|
|
328
|
+
children: TOOLS.map((entry) => /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
329
|
+
render: /* @__PURE__ */ jsx(ToolbarButton, {
|
|
330
|
+
"aria-label": entry.label,
|
|
331
|
+
iconOnly: true,
|
|
332
|
+
"aria-pressed": tool === entry.tool,
|
|
333
|
+
"data-pressed": tool === entry.tool ? "" : void 0,
|
|
334
|
+
onClick: () => onToolChange(entry.tool)
|
|
335
|
+
}),
|
|
336
|
+
children: entry.icon
|
|
337
|
+
}), /* @__PURE__ */ jsxs(TooltipContent, { children: [
|
|
338
|
+
entry.label,
|
|
339
|
+
" · ",
|
|
340
|
+
entry.shortcut
|
|
341
|
+
] })] }, entry.tool))
|
|
342
|
+
})
|
|
343
|
+
}) });
|
|
344
|
+
}
|
|
345
|
+
//#endregion
|
|
346
|
+
export { DesignCanvasBlock };
|
|
@@ -3,12 +3,12 @@ import { cn } from "../lib/cn.js";
|
|
|
3
3
|
import { Button } from "../ui/button.js";
|
|
4
4
|
import { ScrollArea } from "../ui/scroll-area.js";
|
|
5
5
|
import { InputGroup, InputGroupAddon, InputGroupInput } from "../ui/input-group.js";
|
|
6
|
+
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "../ui/empty.js";
|
|
6
7
|
import { SidebarProvider, useSidebar } from "../ui/sidebar-provider.js";
|
|
7
8
|
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "../ui/sidebar-menu.js";
|
|
8
9
|
import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarInset, SidebarRail, SidebarTrigger } from "../ui/sidebar.js";
|
|
9
|
-
import { groupFileExplorerItems, resolveFileExplorer, searchFileExplorer } from "./file-explorer-data.js";
|
|
10
|
-
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "../ui/empty.js";
|
|
11
10
|
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "../ui/resizable.js";
|
|
11
|
+
import { groupFileExplorerItems, resolveFileExplorer, searchFileExplorer } from "./file-explorer-data.js";
|
|
12
12
|
import { useState } from "react";
|
|
13
13
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
14
14
|
import { ChevronRightIcon, FileIcon, FolderIcon, SearchIcon, XIcon } from "lucide-react";
|
package/dist/blocks/settings.js
CHANGED
|
@@ -3,12 +3,12 @@ import { cn } from "../lib/cn.js";
|
|
|
3
3
|
import { Button } from "../ui/button.js";
|
|
4
4
|
import { ScrollArea } from "../ui/scroll-area.js";
|
|
5
5
|
import { InputGroup, InputGroupAddon, InputGroupInput } from "../ui/input-group.js";
|
|
6
|
+
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "../ui/empty.js";
|
|
7
|
+
import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet } from "../ui/field.js";
|
|
6
8
|
import { SidebarProvider, useSidebar } from "../ui/sidebar-provider.js";
|
|
7
9
|
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "../ui/sidebar-menu.js";
|
|
8
10
|
import { Sidebar, SidebarContent, SidebarHeader, SidebarInset, SidebarTrigger } from "../ui/sidebar.js";
|
|
9
|
-
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "../ui/empty.js";
|
|
10
11
|
import { searchSettings } from "./settings-data.js";
|
|
11
|
-
import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet } from "../ui/field.js";
|
|
12
12
|
import { useEffect, useId, useState } from "react";
|
|
13
13
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
14
14
|
import { ArrowLeftIcon, SearchIcon, XIcon } from "lucide-react";
|
|
@@ -13,8 +13,14 @@ export type ChatComposerAttachmentsProps = ComponentProps<"div"> & {
|
|
|
13
13
|
style?: CSSProperties & ChatComposerAttachmentKnobStyle;
|
|
14
14
|
};
|
|
15
15
|
export declare function ChatComposerAttachments({ label, className, viewportClassName, children, ...props }: ChatComposerAttachmentsProps): import("react").JSX.Element;
|
|
16
|
-
|
|
16
|
+
type ChatComposerAttachmentSource = {
|
|
17
|
+
file: File;
|
|
18
|
+
name?: string;
|
|
19
|
+
} | {
|
|
20
|
+
file?: undefined;
|
|
17
21
|
name: string;
|
|
22
|
+
};
|
|
23
|
+
export type ChatComposerAttachmentProps = Omit<ComponentProps<"li">, "style"> & ChatComposerAttachmentSource & {
|
|
18
24
|
type?: string;
|
|
19
25
|
description?: ReactNode;
|
|
20
26
|
status?: ChatComposerAttachmentStatus;
|
|
@@ -26,7 +32,7 @@ export type ChatComposerAttachmentProps = Omit<ComponentProps<"li">, "style"> &
|
|
|
26
32
|
removeLabel?: string;
|
|
27
33
|
style?: CSSProperties & ChatComposerAttachmentKnobStyle;
|
|
28
34
|
};
|
|
29
|
-
export declare function ChatComposerAttachment({ name, type, description, status, progress: progressInput, previewUrl, kind, variant, onRemove, removeLabel, className, children,
|
|
35
|
+
export declare function ChatComposerAttachment({ file, name: nameInput, type: typeInput, description, status, progress: progressInput, previewUrl: previewUrlInput, kind, variant, onRemove, removeLabel, className, children, "aria-label": ariaLabel, ...props }: ChatComposerAttachmentProps): import("react").JSX.Element;
|
|
30
36
|
export type ChatComposerAttachmentPreviewProps = Omit<ComponentProps<"div">, "style"> & {
|
|
31
37
|
style?: CSSProperties & ChatComposerAttachmentKnobStyle;
|
|
32
38
|
};
|
|
@@ -50,5 +56,5 @@ export declare function ChatComposerAttachmentRemove({ className, onClick, child
|
|
|
50
56
|
export type ChatComposerAttachmentProgressProps = Omit<ComponentProps<"div">, "style"> & {
|
|
51
57
|
style?: CSSProperties & ChatComposerAttachmentKnobStyle;
|
|
52
58
|
};
|
|
53
|
-
export declare function ChatComposerAttachmentProgress({ className, children,
|
|
59
|
+
export declare function ChatComposerAttachmentProgress({ className, children, ...props }: ChatComposerAttachmentProgressProps): import("react").JSX.Element | null;
|
|
54
60
|
//#endregion
|
|
@@ -3,7 +3,7 @@ import { cn } from "./lib/cn.js";
|
|
|
3
3
|
import { Button } from "./ui/button.js";
|
|
4
4
|
import { ScrollArea } from "./ui/scroll-area.js";
|
|
5
5
|
import { Spinner } from "./ui/spinner.js";
|
|
6
|
-
import { createContext, useContext } from "react";
|
|
6
|
+
import { createContext, useContext, useLayoutEffect, useState } from "react";
|
|
7
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { XIcon } from "lucide-react";
|
|
9
9
|
//#region src/chat-composer-attachment.tsx
|
|
@@ -67,6 +67,24 @@ function kindFromAttachment(type, name) {
|
|
|
67
67
|
].includes(extension)) return "document";
|
|
68
68
|
return "file";
|
|
69
69
|
}
|
|
70
|
+
function resolveVariant(variant, kind, status, previewUrl) {
|
|
71
|
+
if (variant !== "auto") return variant;
|
|
72
|
+
if (status === "error") return "file";
|
|
73
|
+
return previewUrl || kind === "image" ? "preview" : "file";
|
|
74
|
+
}
|
|
75
|
+
function useObjectUrl(blob) {
|
|
76
|
+
const [objectUrl, setObjectUrl] = useState();
|
|
77
|
+
useLayoutEffect(() => {
|
|
78
|
+
if (!blob) return;
|
|
79
|
+
const url = URL.createObjectURL(blob);
|
|
80
|
+
setObjectUrl({
|
|
81
|
+
blob,
|
|
82
|
+
url
|
|
83
|
+
});
|
|
84
|
+
return () => URL.revokeObjectURL(url);
|
|
85
|
+
}, [blob]);
|
|
86
|
+
return blob && objectUrl?.blob === blob ? objectUrl.url : void 0;
|
|
87
|
+
}
|
|
70
88
|
function progressValue(progress) {
|
|
71
89
|
if (typeof progress !== "number" || Number.isNaN(progress)) return void 0;
|
|
72
90
|
return Math.min(100, Math.max(0, progress));
|
|
@@ -104,7 +122,6 @@ function ChatComposerAttachments({ label = "Attachments", className, viewportCla
|
|
|
104
122
|
"aria-label": label,
|
|
105
123
|
lockAxis: "y",
|
|
106
124
|
mask: true,
|
|
107
|
-
scrollbarVisibility: "hover",
|
|
108
125
|
className: "w-full",
|
|
109
126
|
viewportClassName,
|
|
110
127
|
children: /* @__PURE__ */ jsx("ul", {
|
|
@@ -117,11 +134,13 @@ function ChatComposerAttachments({ label = "Attachments", className, viewportCla
|
|
|
117
134
|
})
|
|
118
135
|
});
|
|
119
136
|
}
|
|
120
|
-
function ChatComposerAttachment({ name, type, description, status = "idle", progress: progressInput, previewUrl, kind, variant = "auto", onRemove, removeLabel, className, children,
|
|
137
|
+
function ChatComposerAttachment({ file, name: nameInput, type: typeInput, description, status = "idle", progress: progressInput, previewUrl: previewUrlInput, kind, variant = "auto", onRemove, removeLabel, className, children, "aria-label": ariaLabel, ...props }) {
|
|
138
|
+
const name = nameInput ?? file?.name ?? "";
|
|
139
|
+
const type = typeInput ?? file?.type;
|
|
121
140
|
const resolvedKind = kind ?? kindFromAttachment(type, name);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
const resolvedVariant = resolveVariant(variant, resolvedKind, status, previewUrlInput);
|
|
142
|
+
const filePreviewUrl = useObjectUrl(resolvedVariant === "preview" && !previewUrlInput ? file : void 0);
|
|
143
|
+
const previewUrl = previewUrlInput ?? filePreviewUrl;
|
|
125
144
|
const extension = extensionFromName(name);
|
|
126
145
|
const progress = progressValue(progressInput);
|
|
127
146
|
return /* @__PURE__ */ jsx(ChatComposerAttachmentContext.Provider, {
|
|
@@ -139,7 +158,6 @@ function ChatComposerAttachment({ name, type, description, status = "idle", prog
|
|
|
139
158
|
removeLabel
|
|
140
159
|
},
|
|
141
160
|
children: /* @__PURE__ */ jsx("li", {
|
|
142
|
-
role,
|
|
143
161
|
"aria-label": ariaLabel ?? name,
|
|
144
162
|
"data-control-ui": "chat-composer-attachment",
|
|
145
163
|
"data-control-family": "chat-composer-attachment",
|
|
@@ -166,7 +184,7 @@ function ChatComposerAttachmentPreview({ className, children, ...props }) {
|
|
|
166
184
|
"data-control-ui": "chat-composer-attachment",
|
|
167
185
|
"data-control-family": "chat-composer-attachment",
|
|
168
186
|
"data-slot": "preview",
|
|
169
|
-
className: cn("relative
|
|
187
|
+
className: cn("relative flex shrink-0 items-center justify-center overflow-hidden", className),
|
|
170
188
|
...props,
|
|
171
189
|
children: children ?? (context.previewUrl ? /* @__PURE__ */ jsx("img", {
|
|
172
190
|
src: context.previewUrl,
|
|
@@ -239,7 +257,7 @@ function ChatComposerAttachmentRemove({ className, onClick, children, "aria-labe
|
|
|
239
257
|
})
|
|
240
258
|
});
|
|
241
259
|
}
|
|
242
|
-
function ChatComposerAttachmentProgress({ className, children,
|
|
260
|
+
function ChatComposerAttachmentProgress({ className, children, ...props }) {
|
|
243
261
|
const { name, status, progress } = useChatComposerAttachmentContext();
|
|
244
262
|
if (status !== "uploading") return null;
|
|
245
263
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -252,7 +270,6 @@ function ChatComposerAttachmentProgress({ className, children, style, ...props }
|
|
|
252
270
|
"data-control-family": "chat-composer-attachment",
|
|
253
271
|
"data-slot": "progress",
|
|
254
272
|
className: cn("pointer-events-none absolute inset-0 z-1 grid place-items-center", className),
|
|
255
|
-
style,
|
|
256
273
|
...props,
|
|
257
274
|
children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
258
275
|
"data-control-ui": "chat-composer-attachment",
|
|
@@ -13,6 +13,19 @@ import { EditorState, Plugin } from "prosemirror-state";
|
|
|
13
13
|
import { EditorView } from "prosemirror-view";
|
|
14
14
|
//#region src/chat-composer-editor.tsx
|
|
15
15
|
const SUBMIT_KEY = "Enter";
|
|
16
|
+
function releaseFileDrag(_view, event) {
|
|
17
|
+
return event.dataTransfer ? Array.from(event.dataTransfer.types).includes("Files") : false;
|
|
18
|
+
}
|
|
19
|
+
/** ProseMirror claims every drag and paste over the editor. A transfer it cannot insert is not editor input, so it has to reach the surrounding drop zone with its default intact. */
|
|
20
|
+
const fileTransferPassthrough = {
|
|
21
|
+
dragenter: releaseFileDrag,
|
|
22
|
+
dragover: releaseFileDrag,
|
|
23
|
+
drop: releaseFileDrag,
|
|
24
|
+
paste: (_view, event) => {
|
|
25
|
+
const types = event.clipboardData ? Array.from(event.clipboardData.types) : [];
|
|
26
|
+
return types.includes("Files") && !types.includes("text/plain");
|
|
27
|
+
}
|
|
28
|
+
};
|
|
16
29
|
function ChatComposerEditor({ className, placeholder, style, extensions = [] }) {
|
|
17
30
|
const input = useChatComposerContext();
|
|
18
31
|
const mountRef = useRef(null);
|
|
@@ -59,10 +72,13 @@ function ChatComposerEditor({ className, placeholder, style, extensions = [] })
|
|
|
59
72
|
schema,
|
|
60
73
|
doc: docFromText(schema, inputRef.current.value),
|
|
61
74
|
plugins: [
|
|
62
|
-
new Plugin({ props: {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
new Plugin({ props: {
|
|
76
|
+
handleKeyDown: (_view, event) => {
|
|
77
|
+
for (const handler of keyHandlersRef.current) if (handler(event)) return true;
|
|
78
|
+
return false;
|
|
79
|
+
},
|
|
80
|
+
handleDOMEvents: fileTransferPassthrough
|
|
81
|
+
} }),
|
|
66
82
|
...extensionPlugins,
|
|
67
83
|
history(),
|
|
68
84
|
keymap(extensionKeymap),
|
package/dist/chat-composer.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export declare function useChatComposerContext(): {
|
|
|
29
29
|
preventDefault: () => void;
|
|
30
30
|
}) => void;
|
|
31
31
|
};
|
|
32
|
-
export declare function ChatComposer({ value, defaultValue, onValueChange, onSubmit, state, density, disabled, className, children, ...props }: ChatComposerProps): import("react").JSX.Element;
|
|
32
|
+
export declare function ChatComposer({ value, defaultValue, onValueChange, onSubmit, state, density, disabled, allowEmptySubmit, className, children, ...props }: ChatComposerProps): import("react").JSX.Element;
|
|
33
33
|
export type ChatComposerShellProps = Omit<ComponentProps<"div">, "style"> & {
|
|
34
34
|
style?: CSSProperties & ChatComposerKnobStyle;
|
|
35
35
|
};
|
package/dist/chat-composer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { cn } from "./lib/cn.js";
|
|
3
2
|
import { hasSkinAdornment, skinAdornment } from "./skin.js";
|
|
3
|
+
import { cn } from "./lib/cn.js";
|
|
4
4
|
import { useSkin } from "./skin-provider.js";
|
|
5
5
|
import { Button } from "./ui/button.js";
|
|
6
6
|
import { useChatComposer } from "./hooks/use-chat-composer.js";
|
|
@@ -14,7 +14,7 @@ function useChatComposerContext() {
|
|
|
14
14
|
if (!context) throw new Error("ChatComposer compound components must be rendered inside <ChatComposer>.");
|
|
15
15
|
return context;
|
|
16
16
|
}
|
|
17
|
-
function ChatComposer({ value, defaultValue, onValueChange, onSubmit, state = "idle", density = "comfortable", disabled = false, className, children, ...props }) {
|
|
17
|
+
function ChatComposer({ value, defaultValue, onValueChange, onSubmit, state = "idle", density = "comfortable", disabled = false, allowEmptySubmit = false, className, children, ...props }) {
|
|
18
18
|
const skin = useSkin();
|
|
19
19
|
const input = useChatComposer({
|
|
20
20
|
value,
|
|
@@ -24,6 +24,7 @@ function ChatComposer({ value, defaultValue, onValueChange, onSubmit, state = "i
|
|
|
24
24
|
state,
|
|
25
25
|
density,
|
|
26
26
|
disabled,
|
|
27
|
+
allowEmptySubmit,
|
|
27
28
|
trackSends: hasSkinAdornment(skin, "chat-composer", "send-layer")
|
|
28
29
|
});
|
|
29
30
|
const sendLayer = skinAdornment(skin, "chat-composer", "send-layer", { sendCount: input.sendCount });
|
|
@@ -117,7 +118,7 @@ function ChatComposerFooter({ className, ...props }) {
|
|
|
117
118
|
"data-control-ui": "chat-composer",
|
|
118
119
|
"data-control-family": "chat-composer",
|
|
119
120
|
"data-slot": "footer",
|
|
120
|
-
className
|
|
121
|
+
className,
|
|
121
122
|
...props
|
|
122
123
|
});
|
|
123
124
|
}
|
package/dist/chat-layout.js
CHANGED
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
import { cn } from "./lib/cn.js";
|
|
3
3
|
import { SkinAdornment } from "./skin-provider.js";
|
|
4
4
|
import { Button } from "./ui/button.js";
|
|
5
|
+
import { ScrollArea } from "./ui/scroll-area.js";
|
|
5
6
|
import { useChatThreadScroll } from "./hooks/use-chat-thread-scroll.js";
|
|
6
7
|
import { createContext, useContext } from "react";
|
|
7
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
import { ArrowDown } from "lucide-react";
|
|
9
10
|
//#region src/chat-layout.tsx
|
|
11
|
+
const chromeSizing = {
|
|
12
|
+
panel: "mx-auto min-h-[640px] max-w-3xl",
|
|
13
|
+
embedded: "h-full min-h-0 flex-1"
|
|
14
|
+
};
|
|
10
15
|
function ChatLayout({ children, chrome = "panel", className, ...props }) {
|
|
11
16
|
return /* @__PURE__ */ jsxs("section", {
|
|
12
17
|
"data-control-ui": "chat-layout",
|
|
@@ -14,7 +19,7 @@ function ChatLayout({ children, chrome = "panel", className, ...props }) {
|
|
|
14
19
|
"data-slot": "root",
|
|
15
20
|
"data-chrome": chrome,
|
|
16
21
|
"data-surface": chrome === "panel" ? "panel" : void 0,
|
|
17
|
-
className: cn("relative
|
|
22
|
+
className: cn("relative flex w-full flex-col overflow-hidden", chromeSizing[chrome], className),
|
|
18
23
|
...props,
|
|
19
24
|
children: [chrome === "panel" ? /* @__PURE__ */ jsx(SkinAdornment, {
|
|
20
25
|
scope: "chat-layout",
|
|
@@ -32,30 +37,38 @@ function ChatThread({ children, composer, className, ...props }) {
|
|
|
32
37
|
scrollToBottom
|
|
33
38
|
},
|
|
34
39
|
children: /* @__PURE__ */ jsx("div", {
|
|
35
|
-
ref: viewportRef,
|
|
36
40
|
"data-control-ui": "chat-thread",
|
|
37
41
|
"data-control-family": "chat-layout",
|
|
38
42
|
"data-chat-layout-kind": "thread",
|
|
39
43
|
"data-slot": "root",
|
|
40
44
|
"data-at-bottom": atBottom ? "" : void 0,
|
|
41
|
-
className: cn("min-h-0 min-w-0 flex-1
|
|
45
|
+
className: cn("flex min-h-0 min-w-0 flex-1 flex-col", className),
|
|
42
46
|
...props,
|
|
43
|
-
children: /* @__PURE__ */
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
children: /* @__PURE__ */ jsx(ScrollArea, {
|
|
48
|
+
className: "flex min-h-0 flex-1 flex-col",
|
|
49
|
+
viewportClassName: "min-h-0 flex-1",
|
|
50
|
+
contentClassName: "flex min-h-full flex-col",
|
|
51
|
+
viewportRef,
|
|
52
|
+
lockAxis: "x",
|
|
53
|
+
mask: false,
|
|
54
|
+
blur: false,
|
|
55
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
56
|
+
ref: contentRef,
|
|
57
|
+
className: "relative flex min-w-0 flex-1 flex-col",
|
|
58
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
59
|
+
"data-control-ui": "chat-thread",
|
|
60
|
+
"data-control-family": "chat-layout",
|
|
61
|
+
"data-slot": "thread-content",
|
|
62
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
63
|
+
children
|
|
64
|
+
}), composer ? /* @__PURE__ */ jsx("div", {
|
|
65
|
+
"data-control-ui": "chat-thread",
|
|
66
|
+
"data-control-family": "chat-layout",
|
|
67
|
+
"data-slot": "dock",
|
|
68
|
+
className: "sticky bottom-0 z-10 shrink-0",
|
|
69
|
+
children: composer
|
|
70
|
+
}) : null]
|
|
71
|
+
})
|
|
59
72
|
})
|
|
60
73
|
})
|
|
61
74
|
});
|