@ctrl-ui/react 0.8.19 → 0.8.20
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/README.md +7 -0
- package/dist/action-bar.js +2 -2
- package/dist/audio-device-select.js +5 -2
- package/dist/blocks/coding-agent.js +22 -12
- package/dist/blocks/design-canvas-inspector.js +6 -3
- package/dist/blocks/design-canvas.js +17 -11
- package/dist/blocks/discussion-markdown-input.d.ts +3 -1
- package/dist/blocks/discussion-markdown-input.js +3 -1
- package/dist/blocks/discussion.d.ts +3 -1
- package/dist/blocks/discussion.js +9 -4
- package/dist/blocks/file-explorer.js +47 -25
- package/dist/blocks/settings.js +8 -6
- package/dist/chat-composer-editor/extensions/mention.d.ts +1 -1
- package/dist/chat-message.d.ts +13 -0
- package/dist/chat-message.js +198 -3
- package/dist/filter-bar/editor.js +5 -2
- package/dist/knob-contracts/flow-knobs.d.ts +4 -0
- package/dist/knob-contracts/flow-knobs.js +32 -0
- package/dist/knob-contracts/item-knobs.d.ts +1 -1
- package/dist/knob-contracts/item-knobs.js +4 -1
- package/dist/knob-contracts/markdown-editor-knobs.d.ts +1 -1
- package/dist/knob-contracts/markdown-editor-knobs.js +1 -0
- package/dist/knob-contracts/morphing-panel-knobs.d.ts +1 -1
- package/dist/knob-contracts/morphing-panel-knobs.js +2 -1
- package/dist/knob-contracts/resize-handle-knobs.d.ts +4 -0
- package/dist/knob-contracts/resize-handle-knobs.js +12 -0
- package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
- package/dist/knob-contracts/sidebar-knobs.js +10 -0
- package/dist/lib/canvas-grid.d.ts +4 -0
- package/dist/lib/canvas-grid.js +5 -0
- package/dist/markdown-editor/drag-handle.d.ts +6 -0
- package/dist/markdown-editor/drag-handle.js +126 -0
- package/dist/markdown-editor/suggestions.d.ts +12 -0
- package/dist/markdown-editor/suggestions.js +235 -0
- package/dist/markdown-editor/toolbar.js +6 -3
- package/dist/markdown-editor.js +14 -4
- package/dist/styles/index.css +6 -3
- package/dist/styles/recipes/chat-message-edit.css +105 -0
- package/dist/styles/recipes/flow.css +304 -0
- package/dist/styles/recipes/infinite-canvas.css +1 -1
- package/dist/styles/recipes/item.css +39 -2
- package/dist/styles/recipes/markdown-editor.css +44 -6
- package/dist/styles/recipes/morphing-panel.css +53 -12
- package/dist/styles/recipes/page-layout.css +11 -1
- package/dist/styles/recipes/resize-handle.css +126 -0
- package/dist/styles/recipes/sidebar-mobile.css +171 -0
- package/dist/styles/recipes/toolbar.css +8 -1
- package/dist/styles/theme.css +1 -0
- package/dist/ui/app-shell.js +1 -1
- package/dist/ui/color-picker.js +1 -1
- package/dist/ui/combobox.d.ts +1 -1
- package/dist/ui/command.js +1 -1
- package/dist/ui/dockable-panel.js +1 -1
- package/dist/ui/flow.d.ts +51 -0
- package/dist/ui/flow.js +153 -0
- package/dist/ui/infinite-canvas.js +3 -3
- package/dist/ui/item.d.ts +5 -3
- package/dist/ui/item.js +2 -1
- package/dist/ui/morphing-panel.d.ts +21 -4
- package/dist/ui/morphing-panel.js +152 -36
- package/dist/ui/resize-handle.d.ts +11 -0
- package/dist/ui/resize-handle.js +26 -0
- package/dist/ui/responsive-dialog.js +1 -1
- package/dist/ui/sidebar-menu.js +1 -1
- package/dist/ui/sidebar-mobile.d.ts +17 -0
- package/dist/ui/sidebar-mobile.js +70 -0
- package/dist/ui/sidebar-provider.d.ts +1 -0
- package/dist/ui/sidebar-provider.js +3 -0
- package/dist/ui/sidebar.d.ts +3 -1
- package/dist/ui/sidebar.js +100 -48
- package/dist/ui/toolbar.d.ts +3 -1
- package/dist/ui/toolbar.js +2 -1
- package/dist/ui/typography.d.ts +5 -2
- package/dist/ui/typography.js +5 -3
- package/package.json +5 -1
- package/dist/environment-variables.d.ts +0 -125
- package/dist/environment-variables.js +0 -512
- package/dist/hooks/use-environment-variables.d.ts +0 -50
- package/dist/hooks/use-environment-variables.js +0 -188
- package/dist/knob-contracts/environment-variables-knobs.d.ts +0 -4
- package/dist/knob-contracts/environment-variables-knobs.js +0 -12
- package/dist/lib/env-file.d.ts +0 -27
- package/dist/lib/env-file.js +0 -218
- package/dist/styles/recipes/environment-variables.css +0 -170
package/README.md
CHANGED
|
@@ -73,8 +73,15 @@ Install a peer only when you import the component that needs it.
|
|
|
73
73
|
| `ui/calendar` | `react-day-picker` |
|
|
74
74
|
| `ui/code`, `ui/code-diff` | `@tanstack/react-virtual`, `diff`, `shiki` |
|
|
75
75
|
| `ui/command` | `cmdk` |
|
|
76
|
+
| `ui/flow` | `@xyflow/react` |
|
|
76
77
|
| `ui/markdown` | `streamdown` |
|
|
77
78
|
| `ui/phone-input` | `react-phone-number-input`, `libphonenumber-js`, `zod` |
|
|
78
79
|
| `ui/resizable` | `react-resizable-panels` |
|
|
79
80
|
| `chat-composer` | `prosemirror-*` |
|
|
80
81
|
| `email/email`, `email/templates` | `react-email` |
|
|
82
|
+
|
|
83
|
+
`ui/flow` also needs the React Flow structural stylesheet, loaded under the recipes:
|
|
84
|
+
|
|
85
|
+
```css
|
|
86
|
+
@import "@xyflow/react/dist/base.css" layer(base);
|
|
87
|
+
```
|
package/dist/action-bar.js
CHANGED
|
@@ -92,14 +92,14 @@ function ActionBarEdit({ value, children = "Edit", disabled, onClick, ...props }
|
|
|
92
92
|
if (event.defaultPrevented || !onEdit) return;
|
|
93
93
|
try {
|
|
94
94
|
const nextValue = await resolveCopyValue(editValue);
|
|
95
|
-
if (
|
|
95
|
+
if (nextValue === void 0) return;
|
|
96
96
|
onEdit(nextValue);
|
|
97
97
|
} catch (error) {
|
|
98
98
|
onEditError?.(error);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
return /* @__PURE__ */ jsx(ActionBarItem, {
|
|
102
|
-
disabled: disabled ?? (
|
|
102
|
+
disabled: disabled ?? (editValue === void 0 || !onEdit),
|
|
103
103
|
onClick: handleClick,
|
|
104
104
|
...props,
|
|
105
105
|
children
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { cn } from "./lib/cn.js";
|
|
3
3
|
import { Button } from "./ui/button.js";
|
|
4
4
|
import { Select, SelectContent, SelectItem, SelectTrigger } from "./ui/select.js";
|
|
5
|
+
import { Text } from "./ui/typography.js";
|
|
5
6
|
import { createContext, use, useState } from "react";
|
|
6
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
import { MicIcon } from "lucide-react";
|
|
@@ -118,8 +119,10 @@ function AudioDeviceSelectContent({ children, ...props }) {
|
|
|
118
119
|
children: [/* @__PURE__ */ jsx("span", {
|
|
119
120
|
className: "min-w-0 flex-1 truncate",
|
|
120
121
|
children: deviceLabel(device, index)
|
|
121
|
-
}), device.isDefault || device.deviceId === "default" ? /* @__PURE__ */ jsx(
|
|
122
|
-
|
|
122
|
+
}), device.isDefault || device.deviceId === "default" ? /* @__PURE__ */ jsx(Text, {
|
|
123
|
+
size: "caption",
|
|
124
|
+
tone: "muted",
|
|
125
|
+
className: "ms-3",
|
|
123
126
|
children: "Default"
|
|
124
127
|
}) : null]
|
|
125
128
|
}, device.deviceId)),
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
3
|
import { Button } from "../ui/button.js";
|
|
4
4
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../ui/collapsible.js";
|
|
5
|
+
import { Heading, Text } from "../ui/typography.js";
|
|
5
6
|
import { ChatLayout, ChatThread } from "../chat-layout.js";
|
|
6
7
|
import { SidebarProvider, useSidebar } from "../ui/sidebar-provider.js";
|
|
7
8
|
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "../ui/sidebar-menu.js";
|
|
@@ -10,7 +11,6 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
10
11
|
import { BotIcon, ChevronRightIcon, CircleIcon, FolderIcon, PlusIcon, SearchIcon } from "lucide-react";
|
|
11
12
|
//#region src/blocks/coding-agent.tsx
|
|
12
13
|
function CodingAgentBlock({ appName = "Agent", brand, sidebarTop, navigation = [], projects, activeTaskId, activeTaskTitle = "New task", onNavigationSelect, onTaskSelect, onNewTask, onSearch, headerActions, sidebarFooter, children, layout = "viewport", className, style, ...props }) {
|
|
13
|
-
const Heading = layout === "contained" ? "h2" : "h1";
|
|
14
14
|
const providerStyle = {
|
|
15
15
|
"--sidebar-width": "17.5rem",
|
|
16
16
|
...style
|
|
@@ -46,7 +46,10 @@ function CodingAgentBlock({ appName = "Agent", brand, sidebarTop, navigation = [
|
|
|
46
46
|
"aria-hidden": "true"
|
|
47
47
|
}),
|
|
48
48
|
/* @__PURE__ */ jsx(Heading, {
|
|
49
|
-
|
|
49
|
+
level: layout === "contained" ? 2 : 1,
|
|
50
|
+
size: "label",
|
|
51
|
+
weight: "medium",
|
|
52
|
+
className: "min-w-0 flex-1 truncate",
|
|
50
53
|
title: activeTaskTitle,
|
|
51
54
|
children: activeTaskTitle
|
|
52
55
|
}),
|
|
@@ -88,8 +91,10 @@ function CodingAgentSidebar({ appName, brand, sidebarTop, navigation, projects,
|
|
|
88
91
|
className: "size-3.5",
|
|
89
92
|
"aria-hidden": "true"
|
|
90
93
|
})
|
|
91
|
-
}), /* @__PURE__ */ jsx(
|
|
92
|
-
|
|
94
|
+
}), /* @__PURE__ */ jsx(Text, {
|
|
95
|
+
size: "label",
|
|
96
|
+
weight: "semibold",
|
|
97
|
+
className: "truncate",
|
|
93
98
|
title: appName,
|
|
94
99
|
children: appName
|
|
95
100
|
})]
|
|
@@ -214,12 +219,14 @@ function CodingAgentEmptyState({ title = "What should we build?", description, i
|
|
|
214
219
|
"aria-hidden": "true"
|
|
215
220
|
})
|
|
216
221
|
}),
|
|
217
|
-
/* @__PURE__ */ jsx(
|
|
218
|
-
|
|
222
|
+
/* @__PURE__ */ jsx(Heading, {
|
|
223
|
+
level: 2,
|
|
219
224
|
children: title
|
|
220
225
|
}),
|
|
221
|
-
description ? /* @__PURE__ */ jsx(
|
|
222
|
-
|
|
226
|
+
description ? /* @__PURE__ */ jsx(Text, {
|
|
227
|
+
as: "p",
|
|
228
|
+
tone: "muted",
|
|
229
|
+
className: "mt-2 max-w-xl text-pretty",
|
|
223
230
|
children: description
|
|
224
231
|
}) : null,
|
|
225
232
|
suggestions.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
@@ -236,12 +243,15 @@ function CodingAgentEmptyState({ title = "What should we build?", description, i
|
|
|
236
243
|
className: "text-primary-text",
|
|
237
244
|
children: suggestion.icon
|
|
238
245
|
}),
|
|
239
|
-
/* @__PURE__ */ jsx(
|
|
240
|
-
|
|
246
|
+
/* @__PURE__ */ jsx(Text, {
|
|
247
|
+
weight: "medium",
|
|
248
|
+
tone: "foreground",
|
|
241
249
|
children: suggestion.title
|
|
242
250
|
}),
|
|
243
|
-
suggestion.description ? /* @__PURE__ */ jsx(
|
|
244
|
-
|
|
251
|
+
suggestion.description ? /* @__PURE__ */ jsx(Text, {
|
|
252
|
+
size: "caption",
|
|
253
|
+
tone: "muted",
|
|
254
|
+
className: "leading-5",
|
|
245
255
|
children: suggestion.description
|
|
246
256
|
}) : null
|
|
247
257
|
]
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Button } from "../ui/button.js";
|
|
3
|
+
import { Heading } from "../ui/typography.js";
|
|
4
|
+
import { resizeDesignCanvasLayer } from "./design-canvas-data.js";
|
|
3
5
|
import { InputGroup, InputGroupAddon } from "../ui/input-group.js";
|
|
4
6
|
import { NumberField, NumberFieldGroup, NumberFieldInput, NumberFieldScrubArea } from "../ui/number-field.js";
|
|
5
7
|
import { ColorPicker, ColorPickerArea, ColorPickerContent, ColorPickerEyeDropper, ColorPickerHue, ColorPickerInput, ColorPickerTrigger } from "../ui/color-picker.js";
|
|
6
8
|
import { Empty, EmptyDescription, EmptyHeader, EmptyTitle } from "../ui/empty.js";
|
|
7
9
|
import { Separator } from "../ui/separator.js";
|
|
8
10
|
import { Toggle } from "../ui/toggle.js";
|
|
9
|
-
import { resizeDesignCanvasLayer } from "./design-canvas-data.js";
|
|
10
11
|
import { useState } from "react";
|
|
11
12
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
12
13
|
import { BlendIcon, EyeIcon, EyeOffIcon, Link2Icon, MinusIcon, PlusIcon, RotateCwIcon, SquareRoundCornerIcon, Unlink2Icon } from "lucide-react";
|
|
@@ -136,8 +137,10 @@ function InspectorSection({ title, action, children }) {
|
|
|
136
137
|
className: "flex flex-col gap-2 border-b px-3 py-3",
|
|
137
138
|
children: [/* @__PURE__ */ jsxs("header", {
|
|
138
139
|
className: "flex h-6 items-center justify-between",
|
|
139
|
-
children: [/* @__PURE__ */ jsx(
|
|
140
|
-
|
|
140
|
+
children: [/* @__PURE__ */ jsx(Heading, {
|
|
141
|
+
level: 3,
|
|
142
|
+
size: "caption",
|
|
143
|
+
weight: "medium",
|
|
141
144
|
children: title
|
|
142
145
|
}), action]
|
|
143
146
|
}), /* @__PURE__ */ jsx("div", {
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
3
|
import { Button } from "../ui/button.js";
|
|
4
4
|
import { ScrollArea } from "../ui/scroll-area.js";
|
|
5
|
+
import { Heading, Text } from "../ui/typography.js";
|
|
5
6
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip.js";
|
|
6
|
-
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator } from "../ui/toolbar.js";
|
|
7
7
|
import { Drawer, DrawerContent, DrawerTitle } from "../ui/drawer.js";
|
|
8
|
-
import { InfiniteCanvas, InfiniteCanvasContent, InfiniteCanvasControls, InfiniteCanvasItem } from "../ui/infinite-canvas.js";
|
|
9
|
-
import { ResizableFloatingPanel } from "../ui/resizable.js";
|
|
10
|
-
import { Text } from "../ui/typography.js";
|
|
11
8
|
import { createDesignCanvasLayer, designCanvasFillColor, drawnDesignCanvasBounds } from "./design-canvas-data.js";
|
|
12
9
|
import { DesignCanvasInspector } from "./design-canvas-inspector.js";
|
|
10
|
+
import { InfiniteCanvas, InfiniteCanvasContent, InfiniteCanvasControls, InfiniteCanvasItem } from "../ui/infinite-canvas.js";
|
|
11
|
+
import { ResizableFloatingPanel } from "../ui/resizable.js";
|
|
12
|
+
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator } from "../ui/toolbar.js";
|
|
13
13
|
import { useRef, useState } from "react";
|
|
14
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
15
|
import { CircleIcon, FrameIcon, LayersIcon, MousePointer2Icon, SlidersHorizontalIcon, SquareIcon, TypeIcon } from "lucide-react";
|
|
@@ -345,7 +345,7 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
|
|
|
345
345
|
});
|
|
346
346
|
}
|
|
347
347
|
function DesignCanvasPanel({ label, title, inDrawer = false, children }) {
|
|
348
|
-
const titleClassName = "flex h-11 shrink-0 items-center border-b px-3
|
|
348
|
+
const titleClassName = "flex h-11 shrink-0 items-center border-b px-3";
|
|
349
349
|
const titleText = /* @__PURE__ */ jsx("span", {
|
|
350
350
|
className: "truncate",
|
|
351
351
|
title,
|
|
@@ -355,9 +355,12 @@ function DesignCanvasPanel({ label, title, inDrawer = false, children }) {
|
|
|
355
355
|
"aria-label": label,
|
|
356
356
|
className: "flex min-h-0 flex-1 flex-col",
|
|
357
357
|
children: [inDrawer ? /* @__PURE__ */ jsx(DrawerTitle, {
|
|
358
|
-
className: titleClassName
|
|
358
|
+
className: `${titleClassName} text-caption font-medium`,
|
|
359
359
|
children: titleText
|
|
360
|
-
}) : /* @__PURE__ */ jsx(
|
|
360
|
+
}) : /* @__PURE__ */ jsx(Heading, {
|
|
361
|
+
level: 2,
|
|
362
|
+
size: "caption",
|
|
363
|
+
weight: "medium",
|
|
361
364
|
className: titleClassName,
|
|
362
365
|
children: titleText
|
|
363
366
|
}), /* @__PURE__ */ jsx(ScrollArea, {
|
|
@@ -411,8 +414,10 @@ function DesignCanvasLayerNode({ layer, selected, onSelect, onKeyDown, onLayerCh
|
|
|
411
414
|
y: Math.round(position.y)
|
|
412
415
|
})),
|
|
413
416
|
children: [
|
|
414
|
-
layer.kind === "frame" ? /* @__PURE__ */ jsx(
|
|
415
|
-
|
|
417
|
+
layer.kind === "frame" ? /* @__PURE__ */ jsx(Text, {
|
|
418
|
+
size: "caption",
|
|
419
|
+
tone: "muted",
|
|
420
|
+
className: "absolute start-0 bottom-full mb-1 whitespace-nowrap",
|
|
416
421
|
children: layer.name
|
|
417
422
|
}) : null,
|
|
418
423
|
layer.kind === "text" ? /* @__PURE__ */ jsx(Text, {
|
|
@@ -429,8 +434,9 @@ function DesignCanvasLayerNode({ layer, selected, onSelect, onKeyDown, onLayerCh
|
|
|
429
434
|
borderRadius: layer.kind === "ellipse" ? "50%" : layer.cornerRadius
|
|
430
435
|
}
|
|
431
436
|
}),
|
|
432
|
-
selected ? /* @__PURE__ */ jsxs(
|
|
433
|
-
|
|
437
|
+
selected ? /* @__PURE__ */ jsxs(Text, {
|
|
438
|
+
size: "micro",
|
|
439
|
+
className: "absolute inset-x-0 top-full mx-auto mt-1.5 w-max rounded-sm bg-primary px-1 whitespace-nowrap text-primary-foreground tabular-nums",
|
|
434
440
|
children: [
|
|
435
441
|
layer.width,
|
|
436
442
|
" × ",
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { MarkdownImageUploader } from "../markdown-editor/uploads.js";
|
|
2
2
|
import { MarkdownEditorStatus } from "../markdown-editor.js";
|
|
3
|
+
import { MarkdownEditorMention } from "../markdown-editor/suggestions.js";
|
|
3
4
|
//#region src/blocks/discussion-markdown-input.d.ts
|
|
4
|
-
export default function DiscussionMarkdownInput({ label, placeholder, autoFocus, onUploadImage, onStatusChange, blocked }: {
|
|
5
|
+
export default function DiscussionMarkdownInput({ label, placeholder, autoFocus, onUploadImage, mentions, onStatusChange, blocked }: {
|
|
5
6
|
label: string;
|
|
6
7
|
placeholder?: string;
|
|
7
8
|
autoFocus?: boolean;
|
|
8
9
|
onUploadImage?: MarkdownImageUploader;
|
|
10
|
+
mentions?: readonly MarkdownEditorMention[];
|
|
9
11
|
onStatusChange: (status: MarkdownEditorStatus) => void;
|
|
10
12
|
blocked: boolean;
|
|
11
13
|
}): import("react").JSX.Element;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useChatComposerContext } from "../chat-composer.js";
|
|
3
3
|
import { MarkdownEditor, MarkdownEditorContent } from "../markdown-editor.js";
|
|
4
|
+
import { MarkdownEditorSuggestions } from "../markdown-editor/suggestions.js";
|
|
4
5
|
import { MarkdownEditorToolbar, MarkdownEditorUploads } from "../markdown-editor/toolbar.js";
|
|
5
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
7
|
//#region src/blocks/discussion-markdown-input.tsx
|
|
7
|
-
function DiscussionMarkdownInput({ label, placeholder, autoFocus, onUploadImage, onStatusChange, blocked }) {
|
|
8
|
+
function DiscussionMarkdownInput({ label, placeholder, autoFocus, onUploadImage, mentions, onStatusChange, blocked }) {
|
|
8
9
|
const composer = useChatComposerContext();
|
|
9
10
|
return /* @__PURE__ */ jsxs(MarkdownEditor, {
|
|
10
11
|
value: composer.value,
|
|
@@ -26,6 +27,7 @@ function DiscussionMarkdownInput({ label, placeholder, autoFocus, onUploadImage,
|
|
|
26
27
|
placeholder,
|
|
27
28
|
autoFocus
|
|
28
29
|
}),
|
|
30
|
+
/* @__PURE__ */ jsx(MarkdownEditorSuggestions, { mentions }),
|
|
29
31
|
/* @__PURE__ */ jsx(MarkdownEditorUploads, {})
|
|
30
32
|
]
|
|
31
33
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MarkdownImageUploader } from "../markdown-editor/uploads.js";
|
|
2
|
+
import { MarkdownEditorMention } from "../markdown-editor/suggestions.js";
|
|
2
3
|
import { ChatComposer } from "../chat-composer.js";
|
|
3
4
|
import { ChatMessage } from "../chat-message.js";
|
|
4
5
|
import { ComponentProps, ReactNode } from "react";
|
|
@@ -12,8 +13,9 @@ export type DiscussionComposerProps = Omit<ComponentProps<typeof ChatComposer>,
|
|
|
12
13
|
autoFocus?: boolean;
|
|
13
14
|
format?: "plain" | "markdown";
|
|
14
15
|
onUploadImage?: MarkdownImageUploader;
|
|
16
|
+
mentions?: readonly MarkdownEditorMention[];
|
|
15
17
|
};
|
|
16
|
-
export declare function DiscussionComposer({ label, placeholder, submitLabel, secondaryAction, hint, autoFocus, format, onUploadImage, onSubmit, ...props }: DiscussionComposerProps): import("react").JSX.Element;
|
|
18
|
+
export declare function DiscussionComposer({ label, placeholder, submitLabel, secondaryAction, hint, autoFocus, format, onUploadImage, mentions, onSubmit, ...props }: DiscussionComposerProps): import("react").JSX.Element;
|
|
17
19
|
export type DiscussionCommentProps = Omit<ComponentProps<typeof ChatMessage>, "from" | "layout" | "authorLabel" | "children"> & {
|
|
18
20
|
author: string;
|
|
19
21
|
avatar?: ReactNode;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Button } from "../ui/button.js";
|
|
3
|
+
import { Text } from "../ui/typography.js";
|
|
3
4
|
import { ChatComposer, ChatComposerShell, ChatComposerSubmit, ChatComposerTextarea, ChatComposerToolbar } from "../chat-composer.js";
|
|
4
5
|
import { ChatMessageReplies } from "../chat-message/social.js";
|
|
5
6
|
import { ChatMessage, ChatMessageActions, ChatMessageAuthor, ChatMessageAvatar, ChatMessageBody, ChatMessageContent, ChatMessageFooter, ChatMessageHeader, ChatMessageRow, ChatMessageTime } from "../chat-message.js";
|
|
@@ -10,7 +11,7 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
|
10
11
|
import { CornerDownRightIcon } from "lucide-react";
|
|
11
12
|
//#region src/blocks/discussion.tsx
|
|
12
13
|
const DiscussionMarkdownInput = lazy(() => import("./discussion-markdown-input.js"));
|
|
13
|
-
function DiscussionComposer({ label, placeholder, submitLabel = "Post", secondaryAction, hint = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(KbdGroup, { children: [/* @__PURE__ */ jsx(Kbd, { children: "⌘" }), /* @__PURE__ */ jsx(Kbd, { children: "Enter" })] }), /* @__PURE__ */ jsx("span", { children: "to post" })] }), autoFocus, format = "plain", onUploadImage, onSubmit, ...props }) {
|
|
14
|
+
function DiscussionComposer({ label, placeholder, submitLabel = "Post", secondaryAction, hint = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(KbdGroup, { children: [/* @__PURE__ */ jsx(Kbd, { children: "⌘" }), /* @__PURE__ */ jsx(Kbd, { children: "Enter" })] }), /* @__PURE__ */ jsx("span", { children: "to post" })] }), autoFocus, format = "plain", onUploadImage, mentions, onSubmit, ...props }) {
|
|
14
15
|
const [draft, setDraft] = useState(props.defaultValue ?? "");
|
|
15
16
|
const value = props.value ?? draft;
|
|
16
17
|
const [status, setStatus] = useState({
|
|
@@ -56,6 +57,7 @@ function DiscussionComposer({ label, placeholder, submitLabel = "Post", secondar
|
|
|
56
57
|
placeholder,
|
|
57
58
|
autoFocus,
|
|
58
59
|
onUploadImage,
|
|
60
|
+
mentions,
|
|
59
61
|
onStatusChange: setStatus,
|
|
60
62
|
blocked
|
|
61
63
|
})
|
|
@@ -65,13 +67,16 @@ function DiscussionComposer({ label, placeholder, submitLabel = "Post", secondar
|
|
|
65
67
|
autoFocus,
|
|
66
68
|
"aria-keyshortcuts": "Meta+Enter Control+Enter"
|
|
67
69
|
}),
|
|
68
|
-
error ? /* @__PURE__ */ jsx(
|
|
70
|
+
error ? /* @__PURE__ */ jsx(Text, {
|
|
71
|
+
as: "p",
|
|
69
72
|
role: "alert",
|
|
70
73
|
className: "px-3",
|
|
71
74
|
children: error
|
|
72
75
|
}) : null,
|
|
73
|
-
/* @__PURE__ */ jsxs(ChatComposerToolbar, { children: [/* @__PURE__ */ jsx(
|
|
74
|
-
|
|
76
|
+
/* @__PURE__ */ jsxs(ChatComposerToolbar, { children: [/* @__PURE__ */ jsx(Text, {
|
|
77
|
+
size: "caption",
|
|
78
|
+
tone: "muted",
|
|
79
|
+
className: "flex min-w-0 items-center gap-1.5",
|
|
75
80
|
children: hint
|
|
76
81
|
}), /* @__PURE__ */ jsxs("span", {
|
|
77
82
|
className: "flex items-center gap-2",
|
|
@@ -3,17 +3,18 @@ import { cn } from "../lib/cn.js";
|
|
|
3
3
|
import { Button } from "../ui/button.js";
|
|
4
4
|
import { LiveStatus } from "../ui/live-status.js";
|
|
5
5
|
import { ScrollArea } from "../ui/scroll-area.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { Heading, Text } from "../ui/typography.js";
|
|
7
|
+
import { Drawer, DrawerBody, DrawerContent, DrawerTitle, DrawerTrigger } from "../ui/drawer.js";
|
|
8
8
|
import { SidebarProvider, useSidebar } from "../ui/sidebar-provider.js";
|
|
9
9
|
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "../ui/sidebar-menu.js";
|
|
10
10
|
import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarInset, SidebarRail, SidebarTrigger } from "../ui/sidebar.js";
|
|
11
|
-
import {
|
|
11
|
+
import { InputGroup, InputGroupAddon } from "../ui/input-group.js";
|
|
12
|
+
import { Input } from "../ui/input.js";
|
|
12
13
|
import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "../ui/empty.js";
|
|
13
|
-
import { Drawer, DrawerBody, DrawerContent, DrawerTitle, DrawerTrigger } from "../ui/drawer.js";
|
|
14
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "../ui/dropdown-menu.js";
|
|
15
14
|
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "../ui/resizable.js";
|
|
16
15
|
import { groupFileExplorerItems, orderFileExplorerEntries, resolveFileExplorer, searchFileExplorer } from "./file-explorer-data.js";
|
|
16
|
+
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "../ui/breadcrumb.js";
|
|
17
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "../ui/dropdown-menu.js";
|
|
17
18
|
import { Fragment, useEffect, useId, useRef, useState } from "react";
|
|
18
19
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
19
20
|
import { ChevronLeftIcon, ChevronRightIcon, FileIcon, FolderIcon, MoreHorizontalIcon, SearchIcon, XIcon } from "lucide-react";
|
|
@@ -81,7 +82,7 @@ function FileExplorerBlock({ locations, activeLocationId, defaultActiveLocationI
|
|
|
81
82
|
children: [
|
|
82
83
|
/* @__PURE__ */ jsx(FileExplorerHeader, {
|
|
83
84
|
location: activeLocation,
|
|
84
|
-
|
|
85
|
+
headingLevel: contained ? 2 : 1,
|
|
85
86
|
breadcrumbs: resolution.breadcrumbs,
|
|
86
87
|
query,
|
|
87
88
|
searchPlaceholder,
|
|
@@ -110,7 +111,7 @@ function FileExplorerBlock({ locations, activeLocationId, defaultActiveLocationI
|
|
|
110
111
|
columns: resolution.columns,
|
|
111
112
|
selectedEntry: resolution.selectedEntry,
|
|
112
113
|
selectedPath: resolution.validPath,
|
|
113
|
-
|
|
114
|
+
headingLevel: contained ? 3 : 2,
|
|
114
115
|
backLabel,
|
|
115
116
|
detailsLabel,
|
|
116
117
|
onNavigate: changePath,
|
|
@@ -164,7 +165,7 @@ function FileExplorerSidebar({ locations, activeLocationId, sidebarTop, sidebarF
|
|
|
164
165
|
]
|
|
165
166
|
});
|
|
166
167
|
}
|
|
167
|
-
function FileExplorerHeader({ location,
|
|
168
|
+
function FileExplorerHeader({ location, headingLevel, breadcrumbs, query, searchPlaceholder, searchLabel, clearSearchLabel, backLabel, moreActionsLabel, canGoBack, headerActions, headerMenuItems, onBack, onBreadcrumbSelect, onQueryChange }) {
|
|
168
169
|
return /* @__PURE__ */ jsxs("header", {
|
|
169
170
|
className: "shrink-0 border-b border-border/70 bg-card/35",
|
|
170
171
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -184,7 +185,10 @@ function FileExplorerHeader({ location, headingAs: Heading, breadcrumbs, query,
|
|
|
184
185
|
})
|
|
185
186
|
}),
|
|
186
187
|
/* @__PURE__ */ jsx(Heading, {
|
|
187
|
-
|
|
188
|
+
level: headingLevel,
|
|
189
|
+
size: "label",
|
|
190
|
+
weight: "semibold",
|
|
191
|
+
className: "min-w-0 flex-1 truncate",
|
|
188
192
|
title: location.label,
|
|
189
193
|
children: location.label
|
|
190
194
|
}),
|
|
@@ -245,7 +249,7 @@ function FileExplorerHeader({ location, headingAs: Heading, breadcrumbs, query,
|
|
|
245
249
|
})]
|
|
246
250
|
});
|
|
247
251
|
}
|
|
248
|
-
function FileExplorerColumns({ columns, selectedEntry, selectedPath,
|
|
252
|
+
function FileExplorerColumns({ columns, selectedEntry, selectedPath, headingLevel, backLabel, detailsLabel, onNavigate, onOpen }) {
|
|
249
253
|
const rootRef = useRef(null);
|
|
250
254
|
const optionElements = useRef(/* @__PURE__ */ new Map());
|
|
251
255
|
const pendingFocus = useRef(null);
|
|
@@ -381,8 +385,10 @@ function FileExplorerColumns({ columns, selectedEntry, selectedPath, headingAs,
|
|
|
381
385
|
className: "truncate",
|
|
382
386
|
children: parentColumn.label
|
|
383
387
|
})]
|
|
384
|
-
}) : /* @__PURE__ */ jsx(
|
|
385
|
-
|
|
388
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
389
|
+
size: "label",
|
|
390
|
+
weight: "medium",
|
|
391
|
+
className: "min-w-0 truncate px-1",
|
|
386
392
|
children: activeColumn?.label
|
|
387
393
|
}), /* @__PURE__ */ jsxs(Drawer, { children: [/* @__PURE__ */ jsx(DrawerTrigger, {
|
|
388
394
|
render: /* @__PURE__ */ jsx(Button, {
|
|
@@ -418,7 +424,7 @@ function FileExplorerColumns({ columns, selectedEntry, selectedPath, headingAs,
|
|
|
418
424
|
minSize: "20%",
|
|
419
425
|
children: /* @__PURE__ */ jsx(FileExplorerPreview, {
|
|
420
426
|
entry: selectedEntry,
|
|
421
|
-
|
|
427
|
+
headingLevel
|
|
422
428
|
})
|
|
423
429
|
})]
|
|
424
430
|
}) : null
|
|
@@ -502,10 +508,14 @@ function FileExplorerColumnView({ column, optionRef, onSelect, onOpen, onOptionK
|
|
|
502
508
|
role: "group",
|
|
503
509
|
"aria-labelledby": labelId,
|
|
504
510
|
className: "grid min-w-0 gap-0.5",
|
|
505
|
-
children: [/* @__PURE__ */ jsx(
|
|
511
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
506
512
|
role: "presentation",
|
|
507
513
|
id: labelId,
|
|
508
|
-
|
|
514
|
+
as: "div",
|
|
515
|
+
size: "caption",
|
|
516
|
+
weight: "semibold",
|
|
517
|
+
tone: "muted",
|
|
518
|
+
className: "mb-1 px-2",
|
|
509
519
|
children: group.label
|
|
510
520
|
}), options]
|
|
511
521
|
}, group.label) : /* @__PURE__ */ jsx("div", {
|
|
@@ -517,7 +527,7 @@ function FileExplorerColumnView({ column, optionRef, onSelect, onOpen, onOptionK
|
|
|
517
527
|
})
|
|
518
528
|
});
|
|
519
529
|
}
|
|
520
|
-
function FileExplorerPreview({ entry,
|
|
530
|
+
function FileExplorerPreview({ entry, headingLevel }) {
|
|
521
531
|
if (!entry) return /* @__PURE__ */ jsx(Empty, {
|
|
522
532
|
className: "h-full rounded-none bg-background/45",
|
|
523
533
|
children: /* @__PURE__ */ jsxs(EmptyHeader, { children: [
|
|
@@ -533,7 +543,9 @@ function FileExplorerPreview({ entry, headingAs: Heading }) {
|
|
|
533
543
|
entry,
|
|
534
544
|
className: "px-6 py-10",
|
|
535
545
|
title: /* @__PURE__ */ jsx(Heading, {
|
|
536
|
-
|
|
546
|
+
level: headingLevel,
|
|
547
|
+
size: "heading-4",
|
|
548
|
+
className: "mt-4 max-w-full truncate",
|
|
537
549
|
title: entry.name,
|
|
538
550
|
children: entry.name
|
|
539
551
|
})
|
|
@@ -549,8 +561,11 @@ function FileExplorerPreviewContent({ entry, title, className }) {
|
|
|
549
561
|
children: /* @__PURE__ */ jsx(FileExplorerEntryIcon, { entry })
|
|
550
562
|
}),
|
|
551
563
|
title,
|
|
552
|
-
entry.description ? /* @__PURE__ */ jsx(
|
|
553
|
-
|
|
564
|
+
entry.description ? /* @__PURE__ */ jsx(Text, {
|
|
565
|
+
as: "div",
|
|
566
|
+
size: "caption",
|
|
567
|
+
tone: "muted",
|
|
568
|
+
className: "mt-1",
|
|
554
569
|
children: entry.description
|
|
555
570
|
}) : null,
|
|
556
571
|
entry.details && entry.details.length > 0 ? /* @__PURE__ */ jsx("dl", {
|
|
@@ -613,8 +628,11 @@ function FileExplorerSearchResults({ label, status, clearSearchLabel, results, o
|
|
|
613
628
|
lockAxis: "x",
|
|
614
629
|
children: /* @__PURE__ */ jsxs("div", {
|
|
615
630
|
className: "mx-auto grid w-full max-w-3xl gap-1 p-4",
|
|
616
|
-
children: [/* @__PURE__ */ jsx(
|
|
617
|
-
|
|
631
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
632
|
+
as: "div",
|
|
633
|
+
size: "caption",
|
|
634
|
+
tone: "muted",
|
|
635
|
+
className: "mb-2 px-2 tabular-nums",
|
|
618
636
|
children: status
|
|
619
637
|
}), /* @__PURE__ */ jsx("div", {
|
|
620
638
|
role: "listbox",
|
|
@@ -639,11 +657,15 @@ function FileExplorerSearchResults({ label, status, clearSearchLabel, results, o
|
|
|
639
657
|
children: /* @__PURE__ */ jsx(FileExplorerEntryIcon, { entry: result.entry })
|
|
640
658
|
}), /* @__PURE__ */ jsxs("span", {
|
|
641
659
|
className: "min-w-0 flex-1",
|
|
642
|
-
children: [/* @__PURE__ */ jsx(
|
|
643
|
-
|
|
660
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
661
|
+
size: "label",
|
|
662
|
+
tone: "foreground",
|
|
663
|
+
className: "block truncate",
|
|
644
664
|
children: result.entry.name
|
|
645
|
-
}), /* @__PURE__ */ jsx(
|
|
646
|
-
|
|
665
|
+
}), /* @__PURE__ */ jsx(Text, {
|
|
666
|
+
size: "caption",
|
|
667
|
+
tone: "muted",
|
|
668
|
+
className: "block truncate",
|
|
647
669
|
children: result.parents.join(" / ") || "Top level"
|
|
648
670
|
})]
|
|
649
671
|
})]
|
package/dist/blocks/settings.js
CHANGED
|
@@ -3,16 +3,16 @@ import { cn } from "../lib/cn.js";
|
|
|
3
3
|
import { Button } from "../ui/button.js";
|
|
4
4
|
import { LiveStatus } from "../ui/live-status.js";
|
|
5
5
|
import { ScrollArea } from "../ui/scroll-area.js";
|
|
6
|
+
import { Heading, Text } from "../ui/typography.js";
|
|
6
7
|
import { prefersReducedMotion } from "../lib/motion.js";
|
|
7
|
-
import { InputGroup, InputGroupAddon } from "../ui/input-group.js";
|
|
8
|
-
import { Input } from "../ui/input.js";
|
|
9
8
|
import { SidebarProvider, useSidebar } from "../ui/sidebar-provider.js";
|
|
10
9
|
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "../ui/sidebar-menu.js";
|
|
11
10
|
import { Sidebar, SidebarContent, SidebarHeader, SidebarInset, SidebarTrigger } from "../ui/sidebar.js";
|
|
11
|
+
import { InputGroup, InputGroupAddon } from "../ui/input-group.js";
|
|
12
|
+
import { Input } from "../ui/input.js";
|
|
12
13
|
import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "../ui/empty.js";
|
|
13
|
-
import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet } from "../ui/field.js";
|
|
14
|
-
import { Heading } from "../ui/typography.js";
|
|
15
14
|
import { searchSettings } from "./settings-data.js";
|
|
15
|
+
import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet } from "../ui/field.js";
|
|
16
16
|
import { useEffect, useId, useState } from "react";
|
|
17
17
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
18
18
|
import { ArrowLeftIcon, SearchIcon, XIcon } from "lucide-react";
|
|
@@ -119,8 +119,10 @@ function SettingsShell({ pages, currentPage, query, results, backAction, searchP
|
|
|
119
119
|
className: "h-full min-h-0 min-w-0",
|
|
120
120
|
children: [/* @__PURE__ */ jsxs("header", {
|
|
121
121
|
className: "flex h-12 shrink-0 items-center gap-2 border-b px-3 lg:hidden",
|
|
122
|
-
children: [/* @__PURE__ */ jsx(SidebarTrigger, {}), /* @__PURE__ */ jsx(
|
|
123
|
-
|
|
122
|
+
children: [/* @__PURE__ */ jsx(SidebarTrigger, {}), /* @__PURE__ */ jsx(Text, {
|
|
123
|
+
size: "label",
|
|
124
|
+
weight: "medium",
|
|
125
|
+
className: "truncate",
|
|
124
126
|
title: currentPage?.title,
|
|
125
127
|
children: currentPage?.title ?? "Settings"
|
|
126
128
|
})]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ChatComposerEditorExtension } from "../types.js";
|
|
2
1
|
import { TriggerConfig, TriggerMenuItemData } from "../../hooks/use-trigger-menu.js";
|
|
2
|
+
import { ChatComposerEditorExtension } from "../types.js";
|
|
3
3
|
import { Command } from "prosemirror-state";
|
|
4
4
|
//#region src/chat-composer-editor/extensions/mention.d.ts
|
|
5
5
|
export declare const deleteMentionBackward: Command;
|
package/dist/chat-message.d.ts
CHANGED
|
@@ -23,6 +23,19 @@ export type ChatMessageTimeProps = ChatMessagePartProps<"time"> & {
|
|
|
23
23
|
export declare function ChatMessageTime({ className, ...props }: ChatMessageTimeProps): JSX.Element;
|
|
24
24
|
export type ChatMessageContentProps = ChatMessagePartProps<"div">;
|
|
25
25
|
export declare function ChatMessageContent({ className, ...props }: ChatMessageContentProps): JSX.Element;
|
|
26
|
+
export type ChatMessageEditableProps = Omit<ChatMessagePartProps<"div">, "onError"> & {
|
|
27
|
+
value: string;
|
|
28
|
+
/** Persist the text in the host. Reject to keep the draft open for retry. */
|
|
29
|
+
onSave: (value: string) => void | Promise<void>;
|
|
30
|
+
onSaveError?: (error: unknown) => void;
|
|
31
|
+
editorLabel?: string;
|
|
32
|
+
saveLabel?: string;
|
|
33
|
+
cancelLabel?: string;
|
|
34
|
+
savingLabel?: string;
|
|
35
|
+
saveErrorLabel?: string;
|
|
36
|
+
};
|
|
37
|
+
/** Plain-text editing in the message surface. Children replace the default Copy/Edit actions. */
|
|
38
|
+
export declare function ChatMessageEditable({ value, onSave, onSaveError, editorLabel, saveLabel, cancelLabel, savingLabel, saveErrorLabel, children, className, ...props }: ChatMessageEditableProps): JSX.Element;
|
|
26
39
|
export type ChatMessagePendingProps = Omit<ChatMessagePartProps<"div">, "children">;
|
|
27
40
|
/** Visual only: the pending transition is announced by `ChatMessage` through the thread's status region. */
|
|
28
41
|
export declare function ChatMessagePending({ className, ...props }: ChatMessagePendingProps): JSX.Element | null;
|