@ctrl-ui/react 0.8.19 → 0.8.21
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 +306 -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/dist/chat-message.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "./lib/cn.js";
|
|
3
|
+
import { LiveStatus } from "./ui/live-status.js";
|
|
4
|
+
import { ActionBar, ActionBarCopy, ActionBarEdit, ActionBarItem } from "./action-bar.js";
|
|
3
5
|
import { ChatMessageStateProvider, chatAuthorLabels, chatMessageStatusLabels, chatMessageTransition, useChatMessage, useChatMessageContext, useChatThreadAnnounce } from "./hooks/use-chat-message.js";
|
|
4
6
|
import { ChatMessageReaction, ChatMessageReactions, ChatMessageReplies, ChatMessageReplySummary, ChatTypingIndicator } from "./chat-message/social.js";
|
|
5
|
-
import { useEffect, useRef } from "react";
|
|
6
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
8
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
9
|
//#region src/chat-message.tsx
|
|
8
10
|
function ChatMessage({ from, state = "idle", density = "comfortable", layout = "bubble", continuation = false, authorLabel = chatAuthorLabels[from], statusLabels, className, children, ...props }) {
|
|
9
11
|
const message = useChatMessage({
|
|
@@ -137,6 +139,199 @@ function ChatMessageContent({ className, ...props }) {
|
|
|
137
139
|
...props
|
|
138
140
|
});
|
|
139
141
|
}
|
|
142
|
+
function useMessageEditor({ value, onSave, onSaveError }) {
|
|
143
|
+
const [editing, setEditing] = useState(false);
|
|
144
|
+
const [draft, setDraft] = useState(value);
|
|
145
|
+
const [originalValue, setOriginalValue] = useState(value);
|
|
146
|
+
const [saving, setSaving] = useState(false);
|
|
147
|
+
const [failed, setFailed] = useState(false);
|
|
148
|
+
const inputRef = useRef(null);
|
|
149
|
+
const triggerRef = useRef(null);
|
|
150
|
+
const savingRef = useRef(false);
|
|
151
|
+
const mountedRef = useRef(false);
|
|
152
|
+
const errorId = useId();
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
mountedRef.current = true;
|
|
155
|
+
return () => {
|
|
156
|
+
mountedRef.current = false;
|
|
157
|
+
};
|
|
158
|
+
}, []);
|
|
159
|
+
useLayoutEffect(() => {
|
|
160
|
+
if (editing) {
|
|
161
|
+
const input = inputRef.current;
|
|
162
|
+
input?.focus({ preventScroll: true });
|
|
163
|
+
input?.setSelectionRange(input.value.length, input.value.length);
|
|
164
|
+
} else if (triggerRef.current) {
|
|
165
|
+
triggerRef.current.focus({ preventScroll: true });
|
|
166
|
+
triggerRef.current = null;
|
|
167
|
+
}
|
|
168
|
+
}, [editing]);
|
|
169
|
+
function startEditing() {
|
|
170
|
+
if (savingRef.current) return;
|
|
171
|
+
triggerRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
172
|
+
setDraft(value);
|
|
173
|
+
setOriginalValue(value);
|
|
174
|
+
setFailed(false);
|
|
175
|
+
setEditing(true);
|
|
176
|
+
}
|
|
177
|
+
function cancelEditing() {
|
|
178
|
+
if (savingRef.current) return;
|
|
179
|
+
setFailed(false);
|
|
180
|
+
setEditing(false);
|
|
181
|
+
}
|
|
182
|
+
async function save() {
|
|
183
|
+
if (!editing || savingRef.current || !draft.trim()) return;
|
|
184
|
+
if (draft === value) {
|
|
185
|
+
cancelEditing();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
savingRef.current = true;
|
|
189
|
+
setSaving(true);
|
|
190
|
+
setFailed(false);
|
|
191
|
+
try {
|
|
192
|
+
await onSave(draft);
|
|
193
|
+
if (mountedRef.current) setEditing(false);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if (mountedRef.current) {
|
|
196
|
+
setFailed(true);
|
|
197
|
+
onSaveError?.(error);
|
|
198
|
+
}
|
|
199
|
+
} finally {
|
|
200
|
+
savingRef.current = false;
|
|
201
|
+
if (mountedRef.current) setSaving(false);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
editing,
|
|
206
|
+
draft,
|
|
207
|
+
setDraft,
|
|
208
|
+
saving,
|
|
209
|
+
failed,
|
|
210
|
+
inputRef,
|
|
211
|
+
errorId,
|
|
212
|
+
startEditing,
|
|
213
|
+
cancelEditing,
|
|
214
|
+
save,
|
|
215
|
+
displayValue: editing ? originalValue : value
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/** Plain-text editing in the message surface. Children replace the default Copy/Edit actions. */
|
|
219
|
+
function ChatMessageEditable({ value, onSave, onSaveError, editorLabel = "Edit message", saveLabel = "Save", cancelLabel = "Cancel", savingLabel = "Saving…", saveErrorLabel = "Couldn't save your message. Try again.", children, className, ...props }) {
|
|
220
|
+
const message = useChatMessageContext();
|
|
221
|
+
const { editing, draft, setDraft, saving, failed, inputRef, errorId, startEditing, cancelEditing, save, displayValue } = useMessageEditor({
|
|
222
|
+
value,
|
|
223
|
+
onSave,
|
|
224
|
+
onSaveError
|
|
225
|
+
});
|
|
226
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
227
|
+
...props,
|
|
228
|
+
"data-control-ui": "chat-message",
|
|
229
|
+
"data-control-family": "chat-message",
|
|
230
|
+
"data-slot": "editable",
|
|
231
|
+
"data-editing": editing ? "" : void 0,
|
|
232
|
+
className: cn("min-w-0", className),
|
|
233
|
+
children: [
|
|
234
|
+
/* @__PURE__ */ jsxs(ChatMessageContent, {
|
|
235
|
+
"data-editable": "",
|
|
236
|
+
children: [
|
|
237
|
+
/* @__PURE__ */ jsx("span", {
|
|
238
|
+
"data-control-ui": "chat-message",
|
|
239
|
+
"data-control-family": "chat-message",
|
|
240
|
+
"data-slot": "edit-value",
|
|
241
|
+
"aria-hidden": editing,
|
|
242
|
+
children: displayValue || ""
|
|
243
|
+
}),
|
|
244
|
+
/* @__PURE__ */ jsx("span", {
|
|
245
|
+
"data-control-ui": "chat-message",
|
|
246
|
+
"data-control-family": "chat-message",
|
|
247
|
+
"data-slot": "edit-sizer",
|
|
248
|
+
"aria-hidden": "true",
|
|
249
|
+
children: `${draft}\u200b`
|
|
250
|
+
}),
|
|
251
|
+
/* @__PURE__ */ jsx("textarea", {
|
|
252
|
+
ref: inputRef,
|
|
253
|
+
"data-control-ui": "chat-message",
|
|
254
|
+
"data-control-family": "chat-message",
|
|
255
|
+
"data-slot": "edit-input",
|
|
256
|
+
"aria-keyshortcuts": "Control+Enter Meta+Enter Escape",
|
|
257
|
+
"aria-label": editorLabel,
|
|
258
|
+
"aria-describedby": failed ? errorId : void 0,
|
|
259
|
+
"aria-hidden": !editing,
|
|
260
|
+
"aria-busy": saving,
|
|
261
|
+
tabIndex: editing ? 0 : -1,
|
|
262
|
+
readOnly: !editing || saving,
|
|
263
|
+
value: editing ? draft : value,
|
|
264
|
+
rows: 1,
|
|
265
|
+
onChange: (event) => setDraft(event.currentTarget.value),
|
|
266
|
+
onKeyDown: (event) => {
|
|
267
|
+
if (event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) return;
|
|
268
|
+
if (event.key === "Escape") {
|
|
269
|
+
event.preventDefault();
|
|
270
|
+
event.stopPropagation();
|
|
271
|
+
cancelEditing();
|
|
272
|
+
} else if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
|
|
273
|
+
event.preventDefault();
|
|
274
|
+
save();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
})
|
|
278
|
+
]
|
|
279
|
+
}),
|
|
280
|
+
/* @__PURE__ */ jsxs("div", {
|
|
281
|
+
"data-control-ui": "chat-message",
|
|
282
|
+
"data-control-family": "chat-message",
|
|
283
|
+
"data-slot": "edit-toolbars",
|
|
284
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
285
|
+
"data-control-ui": "chat-message",
|
|
286
|
+
"data-control-family": "chat-message",
|
|
287
|
+
"data-slot": "edit-toolbar",
|
|
288
|
+
"data-active": !editing ? "" : void 0,
|
|
289
|
+
inert: editing,
|
|
290
|
+
"aria-hidden": editing,
|
|
291
|
+
children: /* @__PURE__ */ jsx(ActionBar, {
|
|
292
|
+
align: message.isEndAligned ? "end" : "start",
|
|
293
|
+
copyValue: value,
|
|
294
|
+
onEdit: startEditing,
|
|
295
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ActionBarCopy, {}), /* @__PURE__ */ jsx(ActionBarEdit, {})] })
|
|
296
|
+
})
|
|
297
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
298
|
+
"data-control-ui": "chat-message",
|
|
299
|
+
"data-control-family": "chat-message",
|
|
300
|
+
"data-slot": "edit-toolbar",
|
|
301
|
+
"data-active": editing ? "" : void 0,
|
|
302
|
+
inert: !editing,
|
|
303
|
+
"aria-hidden": !editing,
|
|
304
|
+
children: /* @__PURE__ */ jsxs(ActionBar, {
|
|
305
|
+
align: message.isEndAligned ? "end" : "start",
|
|
306
|
+
label: "Edit actions",
|
|
307
|
+
"aria-busy": saving,
|
|
308
|
+
children: [/* @__PURE__ */ jsx(ActionBarItem, {
|
|
309
|
+
type: "button",
|
|
310
|
+
disabled: saving || !draft.trim(),
|
|
311
|
+
onClick: () => void save(),
|
|
312
|
+
children: saveLabel
|
|
313
|
+
}), /* @__PURE__ */ jsx(ActionBarItem, {
|
|
314
|
+
type: "button",
|
|
315
|
+
disabled: saving,
|
|
316
|
+
onClick: cancelEditing,
|
|
317
|
+
children: cancelLabel
|
|
318
|
+
})]
|
|
319
|
+
})
|
|
320
|
+
})]
|
|
321
|
+
}),
|
|
322
|
+
/* @__PURE__ */ jsx(LiveStatus, { message: saving ? savingLabel : "" }),
|
|
323
|
+
/* @__PURE__ */ jsx("span", {
|
|
324
|
+
id: errorId,
|
|
325
|
+
role: "alert",
|
|
326
|
+
"data-control-ui": "chat-message",
|
|
327
|
+
"data-control-family": "chat-message",
|
|
328
|
+
"data-slot": "edit-error",
|
|
329
|
+
hidden: !failed,
|
|
330
|
+
children: failed ? saveErrorLabel : ""
|
|
331
|
+
})
|
|
332
|
+
]
|
|
333
|
+
});
|
|
334
|
+
}
|
|
140
335
|
/** Visual only: the pending transition is announced by `ChatMessage` through the thread's status region. */
|
|
141
336
|
function ChatMessagePending({ className, ...props }) {
|
|
142
337
|
if (!useChatMessageContext().isPending) return null;
|
|
@@ -190,4 +385,4 @@ function ChatMessageActions({ className, children, ...props }) {
|
|
|
190
385
|
});
|
|
191
386
|
}
|
|
192
387
|
//#endregion
|
|
193
|
-
export { ChatMessage, ChatMessageActions, ChatMessageAuthor, ChatMessageAvatar, ChatMessageBody, ChatMessageContent, ChatMessageFooter, ChatMessageHeader, ChatMessagePending, ChatMessageReaction, ChatMessageReactions, ChatMessageReplies, ChatMessageReplySummary, ChatMessageRow, ChatMessageTime, ChatTypingIndicator };
|
|
388
|
+
export { ChatMessage, ChatMessageActions, ChatMessageAuthor, ChatMessageAvatar, ChatMessageBody, ChatMessageContent, ChatMessageEditable, ChatMessageFooter, ChatMessageHeader, ChatMessagePending, ChatMessageReaction, ChatMessageReactions, ChatMessageReplies, ChatMessageReplySummary, ChatMessageRow, ChatMessageTime, ChatTypingIndicator };
|
|
@@ -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 { useFilterBarContext } from "./context.js";
|
|
4
5
|
import { allowsCustomValue, fieldOperators, fieldOptions, parseCustomValue } from "./model.js";
|
|
5
6
|
import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList } from "../ui/combobox.js";
|
|
@@ -75,9 +76,11 @@ function handleEditorKeyDown(context, draft, event) {
|
|
|
75
76
|
return true;
|
|
76
77
|
}
|
|
77
78
|
function EditorOptions({ field, invalidNumber, owner }) {
|
|
78
|
-
if (field?.loading || field?.error) return /* @__PURE__ */ jsx(
|
|
79
|
+
if (field?.loading || field?.error) return /* @__PURE__ */ jsx(Text, {
|
|
80
|
+
as: "div",
|
|
81
|
+
size: "caption",
|
|
79
82
|
id: statusId(owner),
|
|
80
|
-
className: "p-3
|
|
83
|
+
className: "p-3",
|
|
81
84
|
children: field.error ?? "Loading values…"
|
|
82
85
|
});
|
|
83
86
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ComboboxEmpty, { children: invalidNumber ? "Enter a number, like 42 or 3.5." : "No matching options." }), /* @__PURE__ */ jsx(ComboboxList, { children: (choice) => /* @__PURE__ */ jsx(ComboboxItem, {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
//#region src/knob-contracts/flow-knobs.d.ts
|
|
2
|
+
export declare const flowKnobs: readonly ["--cui-flow-background", "--cui-flow-grid-dot-color", "--cui-flow-edge-stroke", "--cui-flow-selected-edge-stroke", "--cui-flow-edge-size", "--cui-flow-node-background", "--cui-flow-node-foreground", "--cui-flow-node-border-color", "--cui-flow-node-hover-border-color", "--cui-flow-node-selected-border-color", "--cui-flow-node-border-width", "--cui-flow-node-radius", "--cui-flow-node-shadow", "--cui-flow-handle-size", "--cui-flow-handle-background", "--cui-flow-handle-border-color", "--cui-flow-handle-border-width", "--cui-flow-edge-label-background", "--cui-flow-edge-label-foreground", "--cui-flow-edge-label-border-color", "--cui-flow-edge-label-border-width", "--cui-flow-controls-item-radius", "--cui-flow-controls-padding", "--cui-flow-controls-radius", "--cui-flow-controls-background", "--cui-flow-controls-border-color", "--cui-flow-controls-shadow"];
|
|
3
|
+
export type FlowKnobStyle = Partial<Record<(typeof flowKnobs)[number], string>>;
|
|
4
|
+
//#endregion
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/knob-contracts/flow-knobs.ts
|
|
2
|
+
const flowKnobs = [
|
|
3
|
+
"--cui-flow-background",
|
|
4
|
+
"--cui-flow-grid-dot-color",
|
|
5
|
+
"--cui-flow-edge-stroke",
|
|
6
|
+
"--cui-flow-selected-edge-stroke",
|
|
7
|
+
"--cui-flow-edge-size",
|
|
8
|
+
"--cui-flow-node-background",
|
|
9
|
+
"--cui-flow-node-foreground",
|
|
10
|
+
"--cui-flow-node-border-color",
|
|
11
|
+
"--cui-flow-node-hover-border-color",
|
|
12
|
+
"--cui-flow-node-selected-border-color",
|
|
13
|
+
"--cui-flow-node-border-width",
|
|
14
|
+
"--cui-flow-node-radius",
|
|
15
|
+
"--cui-flow-node-shadow",
|
|
16
|
+
"--cui-flow-handle-size",
|
|
17
|
+
"--cui-flow-handle-background",
|
|
18
|
+
"--cui-flow-handle-border-color",
|
|
19
|
+
"--cui-flow-handle-border-width",
|
|
20
|
+
"--cui-flow-edge-label-background",
|
|
21
|
+
"--cui-flow-edge-label-foreground",
|
|
22
|
+
"--cui-flow-edge-label-border-color",
|
|
23
|
+
"--cui-flow-edge-label-border-width",
|
|
24
|
+
"--cui-flow-controls-item-radius",
|
|
25
|
+
"--cui-flow-controls-padding",
|
|
26
|
+
"--cui-flow-controls-radius",
|
|
27
|
+
"--cui-flow-controls-background",
|
|
28
|
+
"--cui-flow-controls-border-color",
|
|
29
|
+
"--cui-flow-controls-shadow"
|
|
30
|
+
];
|
|
31
|
+
//#endregion
|
|
32
|
+
export { flowKnobs };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
//#region src/knob-contracts/item-knobs.d.ts
|
|
2
|
-
export declare const itemKnobs: readonly ["--cui-item-radius", "--cui-item-hover-background", "--cui-item-hover-border-color", "--cui-item-border-width", "--cui-item-active-scale"];
|
|
2
|
+
export declare const itemKnobs: readonly ["--cui-item-radius", "--cui-item-hover-background", "--cui-item-hover-border-color", "--cui-item-border-width", "--cui-item-active-scale", "--cui-item-gap", "--cui-item-padding-block", "--cui-item-padding-inline"];
|
|
3
3
|
export type ItemKnobStyle = Partial<Record<(typeof itemKnobs)[number], string>>;
|
|
4
4
|
//#endregion
|
|
@@ -4,7 +4,10 @@ const itemKnobs = [
|
|
|
4
4
|
"--cui-item-hover-background",
|
|
5
5
|
"--cui-item-hover-border-color",
|
|
6
6
|
"--cui-item-border-width",
|
|
7
|
-
"--cui-item-active-scale"
|
|
7
|
+
"--cui-item-active-scale",
|
|
8
|
+
"--cui-item-gap",
|
|
9
|
+
"--cui-item-padding-block",
|
|
10
|
+
"--cui-item-padding-inline"
|
|
8
11
|
];
|
|
9
12
|
//#endregion
|
|
10
13
|
export { itemKnobs };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
//#region src/knob-contracts/markdown-editor-knobs.d.ts
|
|
2
|
-
export declare const markdownEditorKnobs: readonly ["--cui-markdown-editor-background", "--cui-markdown-editor-foreground", "--cui-markdown-editor-border-color", "--cui-markdown-editor-radius", "--cui-markdown-editor-padding", "--cui-markdown-editor-min-height", "--cui-markdown-editor-max-height", "--cui-markdown-editor-gap", "--cui-markdown-editor-muted-foreground", "--cui-markdown-editor-code-background", "--cui-markdown-editor-border-width"];
|
|
2
|
+
export declare const markdownEditorKnobs: readonly ["--cui-markdown-editor-background", "--cui-markdown-editor-foreground", "--cui-markdown-editor-border-color", "--cui-markdown-editor-radius", "--cui-markdown-editor-padding", "--cui-markdown-editor-gutter-size", "--cui-markdown-editor-min-height", "--cui-markdown-editor-max-height", "--cui-markdown-editor-gap", "--cui-markdown-editor-muted-foreground", "--cui-markdown-editor-code-background", "--cui-markdown-editor-border-width"];
|
|
3
3
|
export type MarkdownEditorKnobStyle = Partial<Record<(typeof markdownEditorKnobs)[number], string>>;
|
|
4
4
|
//#endregion
|
|
@@ -5,6 +5,7 @@ const markdownEditorKnobs = [
|
|
|
5
5
|
"--cui-markdown-editor-border-color",
|
|
6
6
|
"--cui-markdown-editor-radius",
|
|
7
7
|
"--cui-markdown-editor-padding",
|
|
8
|
+
"--cui-markdown-editor-gutter-size",
|
|
8
9
|
"--cui-markdown-editor-min-height",
|
|
9
10
|
"--cui-markdown-editor-max-height",
|
|
10
11
|
"--cui-markdown-editor-gap",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
//#region src/knob-contracts/morphing-panel-knobs.d.ts
|
|
2
|
-
export declare const morphingPanelKnobs: readonly ["--cui-morphing-panel-radius", "--cui-morphing-panel-background", "--cui-morphing-panel-foreground", "--cui-morphing-panel-border-color", "--cui-morphing-panel-shadow", "--cui-morphing-panel-trigger-hover-background"];
|
|
2
|
+
export declare const morphingPanelKnobs: readonly ["--cui-morphing-panel-radius", "--cui-morphing-panel-background", "--cui-morphing-panel-foreground", "--cui-morphing-panel-border-color", "--cui-morphing-panel-shadow", "--cui-morphing-panel-trigger-hover-background", "--cui-morphing-panel-border-width"];
|
|
3
3
|
export type MorphingPanelKnobStyle = Partial<Record<(typeof morphingPanelKnobs)[number], string>>;
|
|
4
4
|
//#endregion
|
|
@@ -5,7 +5,8 @@ const morphingPanelKnobs = [
|
|
|
5
5
|
"--cui-morphing-panel-foreground",
|
|
6
6
|
"--cui-morphing-panel-border-color",
|
|
7
7
|
"--cui-morphing-panel-shadow",
|
|
8
|
-
"--cui-morphing-panel-trigger-hover-background"
|
|
8
|
+
"--cui-morphing-panel-trigger-hover-background",
|
|
9
|
+
"--cui-morphing-panel-border-width"
|
|
9
10
|
];
|
|
10
11
|
//#endregion
|
|
11
12
|
export { morphingPanelKnobs };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
//#region src/knob-contracts/resize-handle-knobs.d.ts
|
|
2
|
+
export declare const resizeHandleKnobs: readonly ["--cui-resize-handle-size", "--cui-resize-handle-hit-size", "--cui-resize-handle-background", "--cui-resize-handle-hover-background", "--cui-resize-handle-border-color", "--cui-resize-handle-border-width", "--cui-resize-handle-radius"];
|
|
3
|
+
export type ResizeHandleKnobStyle = Partial<Record<(typeof resizeHandleKnobs)[number], string>>;
|
|
4
|
+
//#endregion
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/knob-contracts/resize-handle-knobs.ts
|
|
2
|
+
const resizeHandleKnobs = [
|
|
3
|
+
"--cui-resize-handle-size",
|
|
4
|
+
"--cui-resize-handle-hit-size",
|
|
5
|
+
"--cui-resize-handle-background",
|
|
6
|
+
"--cui-resize-handle-hover-background",
|
|
7
|
+
"--cui-resize-handle-border-color",
|
|
8
|
+
"--cui-resize-handle-border-width",
|
|
9
|
+
"--cui-resize-handle-radius"
|
|
10
|
+
];
|
|
11
|
+
//#endregion
|
|
12
|
+
export { resizeHandleKnobs };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
//#region src/knob-contracts/sidebar-knobs.d.ts
|
|
2
|
-
export declare const sidebarKnobs: readonly ["--cui-sidebar-menu-badge-height", "--cui-sidebar-menu-badge-background", "--cui-sidebar-menu-badge-foreground", "--cui-sidebar-rail-divider-background", "--cui-sidebar-wrapper-background", "--cui-sidebar-wrapper-background-image", "--cui-sidebar-inner-background", "--cui-sidebar-inner-border-color", "--cui-sidebar-inner-background-image", "--cui-sidebar-inner-backdrop-filter", "--cui-sidebar-inner-border-width", "--cui-sidebar-inner-radius", "--cui-sidebar-inner-shadow", "--cui-sidebar-header-background", "--cui-sidebar-header-shadow", "--cui-sidebar-inset-background", "--cui-sidebar-inset-background-image", "--cui-sidebar-inset-shadow", "--cui-sidebar-inset-border-color", "--cui-sidebar-inset-border-width", "--cui-sidebar-inset-radius", "--cui-sidebar-inset-inset", "--cui-sidebar-menu-button-radius", "--cui-sidebar-group-label-foreground", "--cui-sidebar-menu-button-foreground", "--cui-sidebar-menu-button-hover-background", "--cui-sidebar-menu-button-hover-foreground", "--cui-sidebar-menu-button-hover-shadow", "--cui-sidebar-menu-button-active-background", "--cui-sidebar-menu-button-active-foreground", "--cui-sidebar-menu-button-active-shadow", "--cui-sidebar-menu-button-track-active-foreground", "--cui-sidebar-menu-button-height", "--cui-sidebar-menu-button-padding-block", "--cui-sidebar-menu-button-padding-inline", "--cui-sidebar-menu-button-font-size", "--cui-sidebar-menu-button-font-weight", "--cui-sidebar-menu-button-active-font-weight", "--cui-sidebar-group-label-font-size", "--cui-sidebar-group-label-font-weight", "--cui-sidebar-group-label-letter-spacing", "--cui-sidebar-group-label-text-transform", "--cui-sidebar-group-label-padding", "--cui-sidebar-skip-link-background", "--cui-sidebar-skip-link-foreground", "--cui-sidebar-skip-link-radius", "--cui-sidebar-skip-link-shadow"];
|
|
2
|
+
export declare const sidebarKnobs: readonly ["--cui-sidebar-nav-height", "--cui-sidebar-nav-background", "--cui-sidebar-nav-foreground", "--cui-sidebar-nav-border-color", "--cui-sidebar-nav-border-width", "--cui-sidebar-nav-shadow", "--cui-sidebar-nav-item-radius", "--cui-sidebar-nav-item-active-background", "--cui-sidebar-nav-item-active-foreground", "--cui-sidebar-nav-gap", "--cui-sidebar-menu-badge-height", "--cui-sidebar-menu-badge-background", "--cui-sidebar-menu-badge-foreground", "--cui-sidebar-rail-divider-background", "--cui-sidebar-wrapper-background", "--cui-sidebar-wrapper-background-image", "--cui-sidebar-inner-background", "--cui-sidebar-inner-border-color", "--cui-sidebar-inner-background-image", "--cui-sidebar-inner-backdrop-filter", "--cui-sidebar-inner-border-width", "--cui-sidebar-inner-radius", "--cui-sidebar-inner-shadow", "--cui-sidebar-header-background", "--cui-sidebar-header-shadow", "--cui-sidebar-inset-background", "--cui-sidebar-inset-background-image", "--cui-sidebar-inset-shadow", "--cui-sidebar-inset-border-color", "--cui-sidebar-inset-border-width", "--cui-sidebar-inset-radius", "--cui-sidebar-inset-inset", "--cui-sidebar-menu-button-radius", "--cui-sidebar-group-label-foreground", "--cui-sidebar-menu-button-foreground", "--cui-sidebar-menu-button-hover-background", "--cui-sidebar-menu-button-hover-foreground", "--cui-sidebar-menu-button-hover-shadow", "--cui-sidebar-menu-button-active-background", "--cui-sidebar-menu-button-active-foreground", "--cui-sidebar-menu-button-active-shadow", "--cui-sidebar-menu-button-track-active-foreground", "--cui-sidebar-menu-button-height", "--cui-sidebar-menu-button-padding-block", "--cui-sidebar-menu-button-padding-inline", "--cui-sidebar-menu-button-font-size", "--cui-sidebar-menu-button-font-weight", "--cui-sidebar-menu-button-active-font-weight", "--cui-sidebar-group-label-font-size", "--cui-sidebar-group-label-font-weight", "--cui-sidebar-group-label-letter-spacing", "--cui-sidebar-group-label-text-transform", "--cui-sidebar-group-label-padding", "--cui-sidebar-skip-link-background", "--cui-sidebar-skip-link-foreground", "--cui-sidebar-skip-link-radius", "--cui-sidebar-skip-link-shadow"];
|
|
3
3
|
export type SidebarKnobStyle = Partial<Record<(typeof sidebarKnobs)[number], string>>;
|
|
4
4
|
//#endregion
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
//#region src/knob-contracts/sidebar-knobs.ts
|
|
2
2
|
const sidebarKnobs = [
|
|
3
|
+
"--cui-sidebar-nav-height",
|
|
4
|
+
"--cui-sidebar-nav-background",
|
|
5
|
+
"--cui-sidebar-nav-foreground",
|
|
6
|
+
"--cui-sidebar-nav-border-color",
|
|
7
|
+
"--cui-sidebar-nav-border-width",
|
|
8
|
+
"--cui-sidebar-nav-shadow",
|
|
9
|
+
"--cui-sidebar-nav-item-radius",
|
|
10
|
+
"--cui-sidebar-nav-item-active-background",
|
|
11
|
+
"--cui-sidebar-nav-item-active-foreground",
|
|
12
|
+
"--cui-sidebar-nav-gap",
|
|
3
13
|
"--cui-sidebar-menu-badge-height",
|
|
4
14
|
"--cui-sidebar-menu-badge-background",
|
|
5
15
|
"--cui-sidebar-menu-badge-foreground",
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Button } from "../ui/button.js";
|
|
3
|
+
import { LiveStatus } from "../ui/live-status.js";
|
|
4
|
+
import { useMarkdownEditor } from "./context.js";
|
|
5
|
+
import { useEffect, useRef, useState } from "react";
|
|
6
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { GripVerticalIcon } from "lucide-react";
|
|
8
|
+
import { NodeSelection } from "@tiptap/pm/state";
|
|
9
|
+
import { closeHistory } from "@tiptap/pm/history";
|
|
10
|
+
//#region src/markdown-editor/drag-handle.tsx
|
|
11
|
+
function MarkdownEditorDragHandle({ container }) {
|
|
12
|
+
const { editor, disabled, source } = useMarkdownEditor();
|
|
13
|
+
const [block, setBlock] = useState(null);
|
|
14
|
+
const [announcement, setAnnouncement] = useState("");
|
|
15
|
+
const button = useRef(null);
|
|
16
|
+
const dragging = useRef(false);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const surface = container.current;
|
|
19
|
+
if (!editor || !surface || disabled || source) return;
|
|
20
|
+
function show(blockPosition) {
|
|
21
|
+
if (!editor || !surface) return;
|
|
22
|
+
const node = editor.view.nodeDOM(blockPosition);
|
|
23
|
+
if (!(node instanceof HTMLElement)) return;
|
|
24
|
+
const top = node.getBoundingClientRect().top - surface.getBoundingClientRect().top + surface.scrollTop;
|
|
25
|
+
setBlock((current) => current?.position === blockPosition && current.top === top ? current : {
|
|
26
|
+
position: blockPosition,
|
|
27
|
+
top
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function track(event) {
|
|
31
|
+
if (!editor || dragging.current || button.current?.contains(event.target instanceof Node ? event.target : null)) return;
|
|
32
|
+
const rect = editor.view.dom.getBoundingClientRect();
|
|
33
|
+
const padding = Number.parseFloat(getComputedStyle(editor.view.dom).paddingInlineStart);
|
|
34
|
+
const hit = editor.view.posAtCoords({
|
|
35
|
+
left: Math.max(event.clientX, rect.left + padding),
|
|
36
|
+
top: event.clientY
|
|
37
|
+
});
|
|
38
|
+
if (!hit) return;
|
|
39
|
+
const resolved = editor.state.doc.resolve(hit.pos);
|
|
40
|
+
show(resolved.depth > 0 ? resolved.before(1) : hit.pos);
|
|
41
|
+
}
|
|
42
|
+
function selectionChanged() {
|
|
43
|
+
if (!editor || dragging.current) return;
|
|
44
|
+
const { $from } = editor.state.selection;
|
|
45
|
+
show($from.depth > 0 ? $from.before(1) : $from.pos);
|
|
46
|
+
}
|
|
47
|
+
function hide() {
|
|
48
|
+
if (!dragging.current && document.activeElement !== button.current) setBlock(null);
|
|
49
|
+
}
|
|
50
|
+
surface.addEventListener("mousemove", track);
|
|
51
|
+
surface.addEventListener("mouseleave", hide);
|
|
52
|
+
editor.on("transaction", selectionChanged).on("focus", selectionChanged);
|
|
53
|
+
return () => {
|
|
54
|
+
surface.removeEventListener("mousemove", track);
|
|
55
|
+
surface.removeEventListener("mouseleave", hide);
|
|
56
|
+
editor.off("transaction", selectionChanged).off("focus", selectionChanged);
|
|
57
|
+
editor.view.dragging = null;
|
|
58
|
+
};
|
|
59
|
+
}, [
|
|
60
|
+
editor,
|
|
61
|
+
container,
|
|
62
|
+
disabled,
|
|
63
|
+
source
|
|
64
|
+
]);
|
|
65
|
+
if (!editor || disabled || source) return null;
|
|
66
|
+
const selected = editor.state.selection.$from;
|
|
67
|
+
const position = block?.position ?? (selected.depth > 0 ? selected.before(1) : selected.pos);
|
|
68
|
+
function move(direction) {
|
|
69
|
+
if (!editor) return;
|
|
70
|
+
const { doc, tr } = editor.state;
|
|
71
|
+
const node = doc.nodeAt(position);
|
|
72
|
+
if (!node) return;
|
|
73
|
+
const adjacent = direction === -1 ? doc.resolve(position).nodeBefore : doc.nodeAt(position + node.nodeSize);
|
|
74
|
+
if (!adjacent) return;
|
|
75
|
+
const target = direction === -1 ? position - adjacent.nodeSize : position + adjacent.nodeSize;
|
|
76
|
+
tr.delete(position, position + node.nodeSize).insert(target, node);
|
|
77
|
+
tr.setSelection(NodeSelection.create(tr.doc, target));
|
|
78
|
+
editor.view.dispatch(closeHistory(tr).scrollIntoView());
|
|
79
|
+
setAnnouncement(`Block moved ${direction === -1 ? "up" : "down"}.`);
|
|
80
|
+
}
|
|
81
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
|
|
82
|
+
ref: button,
|
|
83
|
+
type: "button",
|
|
84
|
+
variant: "ghost",
|
|
85
|
+
size: "xs",
|
|
86
|
+
iconOnly: true,
|
|
87
|
+
"data-markdown-drag-handle": "",
|
|
88
|
+
"data-visible": block ? "" : void 0,
|
|
89
|
+
"aria-label": "Drag to reorder block",
|
|
90
|
+
"aria-description": "Drag this block, or use Alt+ArrowUp and Alt+ArrowDown to move it.",
|
|
91
|
+
title: "Drag to reorder · Alt+↑/↓ to move",
|
|
92
|
+
draggable: true,
|
|
93
|
+
style: { top: block?.top },
|
|
94
|
+
onClick: () => editor.commands.setNodeSelection(position),
|
|
95
|
+
onKeyDown: (event) => {
|
|
96
|
+
if (!event.altKey || !["ArrowUp", "ArrowDown"].includes(event.key)) return;
|
|
97
|
+
event.preventDefault();
|
|
98
|
+
move(event.key === "ArrowUp" ? -1 : 1);
|
|
99
|
+
},
|
|
100
|
+
onDragStart: (event) => {
|
|
101
|
+
const { view } = editor;
|
|
102
|
+
const selection = NodeSelection.create(view.state.doc, position);
|
|
103
|
+
const node = view.nodeDOM(position);
|
|
104
|
+
view.dispatch(view.state.tr.setSelection(selection));
|
|
105
|
+
const { dom, text, slice } = view.serializeForClipboard(selection.content());
|
|
106
|
+
event.dataTransfer.clearData();
|
|
107
|
+
event.dataTransfer.setData("text/html", dom.innerHTML);
|
|
108
|
+
event.dataTransfer.setData("text/plain", text);
|
|
109
|
+
event.dataTransfer.effectAllowed = "copyMove";
|
|
110
|
+
if (node instanceof HTMLElement) event.dataTransfer.setDragImage(node, 0, 0);
|
|
111
|
+
view.dragging = {
|
|
112
|
+
slice,
|
|
113
|
+
move: true
|
|
114
|
+
};
|
|
115
|
+
dragging.current = true;
|
|
116
|
+
},
|
|
117
|
+
onDragEnd: () => {
|
|
118
|
+
editor.view.dragging = null;
|
|
119
|
+
dragging.current = false;
|
|
120
|
+
setBlock(null);
|
|
121
|
+
},
|
|
122
|
+
children: /* @__PURE__ */ jsx(GripVerticalIcon, { "aria-hidden": "true" })
|
|
123
|
+
}), /* @__PURE__ */ jsx(LiveStatus, { message: announcement })] });
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
126
|
+
export { MarkdownEditorDragHandle };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TriggerMenuItemData } from "../hooks/use-trigger-menu.js";
|
|
2
|
+
//#region src/markdown-editor/suggestions.d.ts
|
|
3
|
+
export type MarkdownEditorMention = TriggerMenuItemData & {
|
|
4
|
+
href: string;
|
|
5
|
+
};
|
|
6
|
+
export type MarkdownEditorSuggestionsProps = {
|
|
7
|
+
/** The application supplies people and their persistent profile URLs. */
|
|
8
|
+
mentions?: readonly MarkdownEditorMention[] | ((query: string) => readonly MarkdownEditorMention[]);
|
|
9
|
+
onMentionSelect?: (mention: MarkdownEditorMention) => void;
|
|
10
|
+
};
|
|
11
|
+
export declare function MarkdownEditorSuggestions({ mentions, onMentionSelect }: MarkdownEditorSuggestionsProps): import("react").JSX.Element;
|
|
12
|
+
//#endregion
|