@homecode/ui 5.1.17 → 5.3.0
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/esm/index.js +5 -0
- package/dist/esm/src/components/Autocomplete/Autocomplete.js +5 -0
- package/dist/esm/src/components/InputFile/InputFile.js +5 -0
- package/dist/esm/src/components/PromptComposer/PromptComposer.helpers.js +44 -0
- package/dist/esm/src/components/PromptComposer/PromptComposer.js +35 -0
- package/dist/esm/src/components/PromptComposer/PromptComposer.styl.js +7 -0
- package/dist/esm/src/components/PromptComposer/promptComposerDoc.js +17 -0
- package/dist/esm/src/components/PromptComposer/promptComposerInsert.js +101 -0
- package/dist/esm/src/components/PromptComposer/usePromptComposerEditor.js +192 -0
- package/dist/esm/src/components/Slider/Slider.styl.js +1 -1
- package/dist/esm/src/tiptap/slash-mention/SlashSuggestionList.js +57 -0
- package/dist/esm/src/tiptap/slash-mention/SlashSuggestionList.styl.js +7 -0
- package/dist/esm/src/tiptap/slash-mention/createSlashMentionExtension.js +202 -0
- package/dist/esm/src/tiptap/slash-mention/defaultChatSlashItems.js +12 -0
- package/dist/esm/types/node_modules/@tiptap/pm/state/index.d.ts +1 -0
- package/dist/esm/types/src/components/PromptComposer/PromptComposer.d.ts +13 -0
- package/dist/esm/types/src/components/PromptComposer/PromptComposer.helpers.d.ts +8 -0
- package/dist/esm/types/src/components/PromptComposer/PromptComposer.types.d.ts +19 -0
- package/dist/esm/types/src/components/PromptComposer/index.d.ts +7 -0
- package/dist/esm/types/src/components/PromptComposer/promptComposerDoc.d.ts +3 -0
- package/dist/esm/types/src/components/PromptComposer/promptComposerInsert.d.ts +42 -0
- package/dist/esm/types/src/components/PromptComposer/usePromptComposerEditor.d.ts +19 -0
- package/dist/esm/types/src/components/index.d.ts +1 -0
- package/dist/esm/types/src/index.d.ts +1 -0
- package/dist/esm/types/src/tiptap/slash-mention/SlashSuggestionList.d.ts +11 -0
- package/dist/esm/types/src/tiptap/slash-mention/createSlashMentionExtension.d.ts +21 -0
- package/dist/esm/types/src/tiptap/slash-mention/defaultChatSlashItems.d.ts +4 -0
- package/dist/esm/types/src/tiptap/slash-mention/index.d.ts +5 -0
- package/dist/esm/types/src/tiptap/slash-mention/types.d.ts +28 -0
- package/package.json +8 -1
- package/.cursor/debug-8c6f78.log +0 -44
- package/.cursor/debug-a8590a.log +0 -26
- package/.cursor/debug-cdef6d.log +0 -694
- package/.cursor/debug-e1fd63.log +0 -83
- package/.cursor/debug.log +0 -207
package/dist/esm/index.js
CHANGED
|
@@ -33,6 +33,9 @@ export { Portal } from './src/components/Portal/Portal.js';
|
|
|
33
33
|
export { PopupMenu } from './src/components/PopupMenu/PopupMenu.js';
|
|
34
34
|
export { Progress } from './src/components/Progress/Progress.js';
|
|
35
35
|
export { ProgressCircular } from './src/components/ProgressCircular/ProgressCircular.js';
|
|
36
|
+
export { PromptComposer } from './src/components/PromptComposer/PromptComposer.js';
|
|
37
|
+
export { usePromptComposerEditor } from './src/components/PromptComposer/usePromptComposerEditor.js';
|
|
38
|
+
export { PROMPT_COMPOSER_COMMAND_CHIP_CLASS, createPromptComposerHandle, getPromptComposerTokenRangeBeforePos, insertPromptComposerContentAtCaret, promptComposerChipHtml, promptComposerMentionNode } from './src/components/PromptComposer/promptComposerInsert.js';
|
|
36
39
|
export { RadioButton } from './src/components/RadioButton/RadioButton.js';
|
|
37
40
|
export { RadioGroup } from './src/components/RadioGroup/RadioGroup.js';
|
|
38
41
|
export { Router, RouterContext, RouterStore } from './src/components/Router/Router.js';
|
|
@@ -57,6 +60,8 @@ export { default as VirtualizedListScroll } from './src/components/Virtualized/L
|
|
|
57
60
|
import * as Virtualized_types from './src/components/Virtualized/Virtualized.types.js';
|
|
58
61
|
export { Virtualized_types as VirtualizedTypes };
|
|
59
62
|
export { Toggle } from './src/components/Toggle/Toggle.js';
|
|
63
|
+
export { DEFAULT_CHAT_SLASH_ITEMS, filterSlashItems } from './src/tiptap/slash-mention/defaultChatSlashItems.js';
|
|
64
|
+
export { createSlashMentionExtension, slashMentionSuggestionRender } from './src/tiptap/slash-mention/createSlashMentionExtension.js';
|
|
60
65
|
import * as i18n from './src/services/i18n.js';
|
|
61
66
|
export { i18n };
|
|
62
67
|
import * as env from './src/tools/env.js';
|
|
@@ -46,6 +46,7 @@ import '../Gallery/Gallery.styl.js';
|
|
|
46
46
|
import '../Heading/Heading.js';
|
|
47
47
|
import '../InputFile/InputFile.styl.js';
|
|
48
48
|
import '../InputFile/Item/Item.styl.js';
|
|
49
|
+
import '../../tiptap/slash-mention/createSlashMentionExtension.js';
|
|
49
50
|
import '../../services/i18n.js';
|
|
50
51
|
import '../Portal/Portal.js';
|
|
51
52
|
import '../Paranja/Paranja.styl.js';
|
|
@@ -56,6 +57,10 @@ import '../Notifications/Notifications.styl.js';
|
|
|
56
57
|
import '../PopupMenu/PopupMenu.styl.js';
|
|
57
58
|
import '../Progress/Progress.styl.js';
|
|
58
59
|
import '../ProgressCircular/ProgressCircular.styl.js';
|
|
60
|
+
import '../PromptComposer/PromptComposer.js';
|
|
61
|
+
import '@tiptap/extensions';
|
|
62
|
+
import '@tiptap/react';
|
|
63
|
+
import '@tiptap/starter-kit';
|
|
59
64
|
import '../RadioGroup/RadioGroupContext.js';
|
|
60
65
|
import '../RadioButton/RadioButton.styl.js';
|
|
61
66
|
import '../RadioGroup/RadioGroup.styl.js';
|
|
@@ -55,6 +55,11 @@ import '../Notifications/Notifications.styl.js';
|
|
|
55
55
|
import '../PopupMenu/PopupMenu.styl.js';
|
|
56
56
|
import '../Progress/Progress.styl.js';
|
|
57
57
|
import '../ProgressCircular/ProgressCircular.styl.js';
|
|
58
|
+
import '../PromptComposer/PromptComposer.js';
|
|
59
|
+
import '@tiptap/extensions';
|
|
60
|
+
import '@tiptap/react';
|
|
61
|
+
import '@tiptap/starter-kit';
|
|
62
|
+
import '../../tiptap/slash-mention/createSlashMentionExtension.js';
|
|
58
63
|
import '../RadioGroup/RadioGroupContext.js';
|
|
59
64
|
import '../RadioButton/RadioButton.styl.js';
|
|
60
65
|
import '../RadioGroup/RadioGroup.styl.js';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Keep in sync with `PromptComposer.styl` max/min heights. */
|
|
2
|
+
const PROMPT_COMPOSER_MAX_HEIGHT_PX = 200;
|
|
3
|
+
const PROMPT_COMPOSER_MIN_HEIGHT_PX = 40;
|
|
4
|
+
function promptComposerSafeEditorDom(editor) {
|
|
5
|
+
if (!editor || editor.isDestroyed)
|
|
6
|
+
return null;
|
|
7
|
+
try {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
const dom = editor.view?.dom;
|
|
10
|
+
return dom instanceof HTMLElement ? dom : null;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function promptComposerFloorPx(cs) {
|
|
17
|
+
const padY = (Number.parseFloat(cs.paddingTop) || 0) +
|
|
18
|
+
(Number.parseFloat(cs.paddingBottom) || 0);
|
|
19
|
+
const fs = Number.parseFloat(cs.fontSize) || 14;
|
|
20
|
+
const linePx = cs.lineHeight === 'normal'
|
|
21
|
+
? fs * 1.25
|
|
22
|
+
: Number.parseFloat(cs.lineHeight) || fs * 1.25;
|
|
23
|
+
return Math.max(PROMPT_COMPOSER_MIN_HEIGHT_PX, Math.ceil(linePx + padY));
|
|
24
|
+
}
|
|
25
|
+
/** Autosize `.ProseMirror` root: empty -> floor, text -> measured height with clamp. */
|
|
26
|
+
function syncPromptComposerHeight(el, text) {
|
|
27
|
+
const floor = promptComposerFloorPx(getComputedStyle(el));
|
|
28
|
+
el.style.overflowY = 'hidden';
|
|
29
|
+
let contentHeight;
|
|
30
|
+
const empty = text.trim() === '';
|
|
31
|
+
if (empty) {
|
|
32
|
+
contentHeight = floor;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
el.style.height = '0';
|
|
36
|
+
contentHeight = el.scrollHeight;
|
|
37
|
+
}
|
|
38
|
+
const h = Math.min(Math.max(contentHeight, floor), PROMPT_COMPOSER_MAX_HEIGHT_PX);
|
|
39
|
+
el.style.height = `${h}px`;
|
|
40
|
+
el.style.overflowY =
|
|
41
|
+
contentHeight > PROMPT_COMPOSER_MAX_HEIGHT_PX ? 'auto' : 'hidden';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { PROMPT_COMPOSER_MAX_HEIGHT_PX, PROMPT_COMPOSER_MIN_HEIGHT_PX, promptComposerSafeEditorDom, syncPromptComposerHeight };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import { forwardRef, useMemo, useImperativeHandle } from 'react';
|
|
4
|
+
import { EditorContent } from '@tiptap/react';
|
|
5
|
+
import S from './PromptComposer.styl.js';
|
|
6
|
+
import { createPromptComposerHandle } from './promptComposerInsert.js';
|
|
7
|
+
import { usePromptComposerEditor } from './usePromptComposerEditor.js';
|
|
8
|
+
|
|
9
|
+
const PromptComposer = forwardRef(function PromptComposer({ disabled = false, placeholder, className, slashCommandItems, onSlashItemCommand, prefillMessage, attachmentsCount = 0, allowEnterSubmit = true, onSubmit, onChange, }, ref) {
|
|
10
|
+
const { editor } = usePromptComposerEditor({
|
|
11
|
+
disabled,
|
|
12
|
+
placeholder,
|
|
13
|
+
slashCommandItems,
|
|
14
|
+
onSlashItemCommand,
|
|
15
|
+
prefillMessage,
|
|
16
|
+
attachmentsCount,
|
|
17
|
+
allowEnterSubmit,
|
|
18
|
+
onSubmit,
|
|
19
|
+
onChange,
|
|
20
|
+
});
|
|
21
|
+
const unavailableHandle = useMemo(() => ({
|
|
22
|
+
insertAtCaret: () => undefined,
|
|
23
|
+
focus: () => undefined,
|
|
24
|
+
reset: () => undefined,
|
|
25
|
+
setContent: () => undefined,
|
|
26
|
+
getText: () => '',
|
|
27
|
+
getEditor: () => {
|
|
28
|
+
throw new Error('PromptComposer editor is not ready yet');
|
|
29
|
+
},
|
|
30
|
+
}), []);
|
|
31
|
+
useImperativeHandle(ref, () => (editor ? createPromptComposerHandle(editor) : unavailableHandle), [editor, unavailableHandle]);
|
|
32
|
+
return (jsx("div", { className: cn(S.root, className), "data-disabled": disabled ? 'true' : 'false', children: jsx(EditorContent, { editor: editor, className: S.editorMount }) }));
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export { PromptComposer };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
|
|
2
|
+
|
|
3
|
+
var css_248z = ".PromptComposer_root__gfdXN{width:100%}.PromptComposer_editorMount__B9G-o{background:transparent;border:none;border-radius:0!important;box-shadow:none!important;display:flex;flex:1;flex-direction:column;max-height:200px;min-height:40px;min-width:0;padding:0!important}.PromptComposer_editorMount__B9G-o:focus-within{box-shadow:none!important}.PromptComposer_editorMount__B9G-o .promptComposerEditor{border:none!important;box-shadow:none!important;flex:1;margin:0;max-height:200px!important;min-height:40px!important;outline:none!important;overflow-x:hidden!important;overflow-y:auto!important;padding:var(--p-2) 0 0!important;resize:none!important;white-space:pre-wrap;word-break:break-word}.PromptComposer_editorMount__B9G-o .promptComposerEmptyEditor .promptComposerEmptyNode:before{color:var(--muted-foreground);content:attr(data-placeholder);float:left;height:0;pointer-events:none}";
|
|
4
|
+
var S = {"root":"PromptComposer_root__gfdXN","editorMount":"PromptComposer_editorMount__B9G-o"};
|
|
5
|
+
styleInject(css_248z);
|
|
6
|
+
|
|
7
|
+
export { S as default };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const PROMPT_COMPOSER_EMPTY_DOC = {
|
|
2
|
+
type: 'doc',
|
|
3
|
+
content: [{ type: 'paragraph' }],
|
|
4
|
+
};
|
|
5
|
+
function promptComposerParagraphDoc(text) {
|
|
6
|
+
return {
|
|
7
|
+
type: 'doc',
|
|
8
|
+
content: [
|
|
9
|
+
{
|
|
10
|
+
type: 'paragraph',
|
|
11
|
+
content: text ? [{ type: 'text', text }] : [],
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { PROMPT_COMPOSER_EMPTY_DOC, promptComposerParagraphDoc };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { promptComposerParagraphDoc } from './promptComposerDoc.js';
|
|
2
|
+
|
|
3
|
+
const PROMPT_COMPOSER_COMMAND_CHIP_CLASS = 'prompt-composer-command-chip';
|
|
4
|
+
function getPromptComposerTokenRangeBeforePos(editor, pos) {
|
|
5
|
+
const $pos = editor.state.doc.resolve(pos);
|
|
6
|
+
const textBefore = $pos.parent.textBetween(0, $pos.parentOffset, undefined, '\ufffc');
|
|
7
|
+
const token = textBefore.match(/[^\s]*$/)?.[0] ?? '';
|
|
8
|
+
return { from: pos - token.length, to: pos };
|
|
9
|
+
}
|
|
10
|
+
function escapeHtml(text) {
|
|
11
|
+
return text
|
|
12
|
+
.replaceAll('&', '&')
|
|
13
|
+
.replaceAll('<', '<')
|
|
14
|
+
.replaceAll('>', '>')
|
|
15
|
+
.replaceAll('"', '"');
|
|
16
|
+
}
|
|
17
|
+
function promptComposerChipHtml(text, className = PROMPT_COMPOSER_COMMAND_CHIP_CLASS) {
|
|
18
|
+
const cls = className ? ` class="${className}"` : '';
|
|
19
|
+
return `<span${cls} data-prompt-composer-chip="true">${escapeHtml(text)}</span>`;
|
|
20
|
+
}
|
|
21
|
+
function promptComposerMentionNode(input) {
|
|
22
|
+
const { id, label = id, className = null, color = null, slashChar = '/', } = input;
|
|
23
|
+
return {
|
|
24
|
+
type: 'mention',
|
|
25
|
+
attrs: {
|
|
26
|
+
id,
|
|
27
|
+
label,
|
|
28
|
+
mentionSuggestionChar: slashChar,
|
|
29
|
+
className,
|
|
30
|
+
color,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function insertPromptComposerContentAtCaret(editor, content, options) {
|
|
35
|
+
if (editor.isDestroyed)
|
|
36
|
+
return;
|
|
37
|
+
const { replaceRange, replaceTriggerToken = true, trailingSpace = true, } = options ?? {};
|
|
38
|
+
const { from: selFrom, to: selTo } = editor.state.selection;
|
|
39
|
+
let from;
|
|
40
|
+
let to;
|
|
41
|
+
if (replaceRange) {
|
|
42
|
+
from = replaceRange.from;
|
|
43
|
+
to = replaceRange.to;
|
|
44
|
+
}
|
|
45
|
+
else if (replaceTriggerToken) {
|
|
46
|
+
({ from, to } = getPromptComposerTokenRangeBeforePos(editor, selFrom));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
from = selFrom;
|
|
50
|
+
to = selTo;
|
|
51
|
+
}
|
|
52
|
+
const chain = editor.chain().focus().deleteRange({ from, to });
|
|
53
|
+
if (typeof content === 'string') {
|
|
54
|
+
chain.insertContentAt(from, trailingSpace ? `${content} ` : content);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
chain.insertContentAt(from, content);
|
|
58
|
+
if (trailingSpace) {
|
|
59
|
+
chain.insertContent(' ');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
chain.run();
|
|
63
|
+
queueMicrotask(() => {
|
|
64
|
+
editor.view.dom.ownerDocument?.defaultView
|
|
65
|
+
?.getSelection?.()
|
|
66
|
+
?.collapseToEnd();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function setPromptComposerEditorText(editor, text, options) {
|
|
70
|
+
if (editor.isDestroyed)
|
|
71
|
+
return;
|
|
72
|
+
editor.commands.setContent(promptComposerParagraphDoc(text));
|
|
73
|
+
if (options?.focus) {
|
|
74
|
+
editor.commands.focus(options.atEnd === false ? 'start' : 'end');
|
|
75
|
+
}
|
|
76
|
+
else if (options?.atEnd !== false) {
|
|
77
|
+
queueMicrotask(() => {
|
|
78
|
+
editor.view.dom.ownerDocument?.defaultView
|
|
79
|
+
?.getSelection?.()
|
|
80
|
+
?.collapseToEnd();
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function createPromptComposerHandle(editor) {
|
|
85
|
+
return {
|
|
86
|
+
insertAtCaret: (content, options) => insertPromptComposerContentAtCaret(editor, content, options),
|
|
87
|
+
focus: () => {
|
|
88
|
+
editor.commands.focus();
|
|
89
|
+
},
|
|
90
|
+
reset: () => {
|
|
91
|
+
editor.chain().clearContent().focus().run();
|
|
92
|
+
},
|
|
93
|
+
getText: () => editor.getText(),
|
|
94
|
+
setContent: (text, options) => {
|
|
95
|
+
setPromptComposerEditorText(editor, text, options);
|
|
96
|
+
},
|
|
97
|
+
getEditor: () => editor,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { PROMPT_COMPOSER_COMMAND_CHIP_CLASS, createPromptComposerHandle, getPromptComposerTokenRangeBeforePos, insertPromptComposerContentAtCaret, promptComposerChipHtml, promptComposerMentionNode };
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { useRef, useCallback, useMemo, useState, useEffect, useLayoutEffect } from 'react';
|
|
2
|
+
import { Placeholder } from '@tiptap/extensions';
|
|
3
|
+
import { useEditor } from '@tiptap/react';
|
|
4
|
+
import StarterKit from '@tiptap/starter-kit';
|
|
5
|
+
import { DEFAULT_CHAT_SLASH_ITEMS } from '../../tiptap/slash-mention/defaultChatSlashItems.js';
|
|
6
|
+
import { createSlashMentionExtension } from '../../tiptap/slash-mention/createSlashMentionExtension.js';
|
|
7
|
+
import { promptComposerSafeEditorDom, syncPromptComposerHeight } from './PromptComposer.helpers.js';
|
|
8
|
+
import { PROMPT_COMPOSER_EMPTY_DOC, promptComposerParagraphDoc } from './promptComposerDoc.js';
|
|
9
|
+
|
|
10
|
+
const PROMPT_COMPOSER_EDITOR_CLASS = 'promptComposerEditor';
|
|
11
|
+
const PROMPT_COMPOSER_EMPTY_EDITOR_CLASS = 'promptComposerEmptyEditor';
|
|
12
|
+
const PROMPT_COMPOSER_EMPTY_NODE_CLASS = 'promptComposerEmptyNode';
|
|
13
|
+
function usePromptComposerEditor({ disabled, placeholder, slashCommandItems, onSlashItemCommand, prefillMessage, attachmentsCount = 0, allowEnterSubmit, onSubmit, onChange, }) {
|
|
14
|
+
const slashOpenRef = useRef(false);
|
|
15
|
+
const onSlashItemCommandRef = useRef(onSlashItemCommand);
|
|
16
|
+
onSlashItemCommandRef.current = onSlashItemCommand;
|
|
17
|
+
const onSubmitRef = useRef(onSubmit);
|
|
18
|
+
onSubmitRef.current = onSubmit;
|
|
19
|
+
const onChangeRef = useRef(onChange);
|
|
20
|
+
onChangeRef.current = onChange;
|
|
21
|
+
const editorRef = useRef(null);
|
|
22
|
+
const suggestionActiveUpdater = useCallback((active) => {
|
|
23
|
+
slashOpenRef.current = active;
|
|
24
|
+
}, []);
|
|
25
|
+
const slashItemsFingerprint = JSON.stringify(slashCommandItems ?? null);
|
|
26
|
+
const slashItemsStable = useMemo(() => slashCommandItems ?? DEFAULT_CHAT_SLASH_ITEMS, [slashCommandItems, slashItemsFingerprint]);
|
|
27
|
+
const placeholderText = useMemo(() => {
|
|
28
|
+
if (placeholder === undefined || placeholder === null) {
|
|
29
|
+
return 'Type a message...';
|
|
30
|
+
}
|
|
31
|
+
const text = String(placeholder).trim();
|
|
32
|
+
return text === '' ? 'Type a message...' : text;
|
|
33
|
+
}, [placeholder]);
|
|
34
|
+
const ariaLabelComposer = useMemo(() => {
|
|
35
|
+
if (placeholder === undefined || placeholder === null)
|
|
36
|
+
return 'Message';
|
|
37
|
+
const text = String(placeholder).trim();
|
|
38
|
+
return text === '' ? 'Message' : text;
|
|
39
|
+
}, [placeholder]);
|
|
40
|
+
const extensions = useMemo(() => {
|
|
41
|
+
const exts = [
|
|
42
|
+
StarterKit.configure({
|
|
43
|
+
heading: false,
|
|
44
|
+
bulletList: false,
|
|
45
|
+
orderedList: false,
|
|
46
|
+
blockquote: false,
|
|
47
|
+
codeBlock: false,
|
|
48
|
+
horizontalRule: false,
|
|
49
|
+
}),
|
|
50
|
+
Placeholder.configure({
|
|
51
|
+
placeholder: placeholderText,
|
|
52
|
+
showOnlyWhenEditable: true,
|
|
53
|
+
emptyEditorClass: PROMPT_COMPOSER_EMPTY_EDITOR_CLASS,
|
|
54
|
+
emptyNodeClass: PROMPT_COMPOSER_EMPTY_NODE_CLASS,
|
|
55
|
+
}),
|
|
56
|
+
];
|
|
57
|
+
if (slashItemsStable.length > 0) {
|
|
58
|
+
exts.push(createSlashMentionExtension({
|
|
59
|
+
items: slashItemsStable,
|
|
60
|
+
suggestionPlacement: 'above',
|
|
61
|
+
onSuggestionUiActiveChange: suggestionActiveUpdater,
|
|
62
|
+
onItemCommand: ctx => onSlashItemCommandRef.current?.(ctx) === true,
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
return exts;
|
|
66
|
+
}, [placeholderText, slashItemsStable, suggestionActiveUpdater]);
|
|
67
|
+
const [text, setText] = useState('');
|
|
68
|
+
const editorDomRef = useRef(null);
|
|
69
|
+
const bindEditorDom = useCallback(({ editor }) => {
|
|
70
|
+
const nextText = editor.getText();
|
|
71
|
+
setText(nextText);
|
|
72
|
+
queueMicrotask(() => {
|
|
73
|
+
const dom = promptComposerSafeEditorDom(editor);
|
|
74
|
+
if (!dom)
|
|
75
|
+
return;
|
|
76
|
+
editorDomRef.current = dom;
|
|
77
|
+
syncPromptComposerHeight(dom, nextText);
|
|
78
|
+
});
|
|
79
|
+
}, []);
|
|
80
|
+
const trimmedText = text.trim();
|
|
81
|
+
const trimmedTextRef = useRef(trimmedText);
|
|
82
|
+
trimmedTextRef.current = trimmedText;
|
|
83
|
+
const attachmentsCountRef = useRef(attachmentsCount);
|
|
84
|
+
attachmentsCountRef.current = attachmentsCount;
|
|
85
|
+
const allowEnterSubmitRef = useRef(allowEnterSubmit);
|
|
86
|
+
allowEnterSubmitRef.current = allowEnterSubmit;
|
|
87
|
+
const handleEditorKeyDown = useCallback((_view, event) => {
|
|
88
|
+
if (!(event.key === 'Enter' &&
|
|
89
|
+
!event.shiftKey &&
|
|
90
|
+
!event.metaKey &&
|
|
91
|
+
!event.ctrlKey)) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
if (!allowEnterSubmitRef.current)
|
|
95
|
+
return false;
|
|
96
|
+
if (slashOpenRef.current)
|
|
97
|
+
return false;
|
|
98
|
+
if (!trimmedTextRef.current && attachmentsCountRef.current === 0) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
const activeEditor = editorRef.current;
|
|
103
|
+
if (!activeEditor)
|
|
104
|
+
return true;
|
|
105
|
+
onSubmitRef.current?.(activeEditor.getText(), activeEditor);
|
|
106
|
+
return true;
|
|
107
|
+
}, []);
|
|
108
|
+
const editor = useEditor({
|
|
109
|
+
extensions,
|
|
110
|
+
content: PROMPT_COMPOSER_EMPTY_DOC,
|
|
111
|
+
editable: !disabled,
|
|
112
|
+
immediatelyRender: true,
|
|
113
|
+
editorProps: {
|
|
114
|
+
attributes: {
|
|
115
|
+
spellcheck: 'true',
|
|
116
|
+
'aria-label': ariaLabelComposer,
|
|
117
|
+
class: PROMPT_COMPOSER_EDITOR_CLASS,
|
|
118
|
+
},
|
|
119
|
+
handleKeyDown: handleEditorKeyDown,
|
|
120
|
+
},
|
|
121
|
+
onTransaction: ({ editor: activeEditor }) => {
|
|
122
|
+
const dom = promptComposerSafeEditorDom(activeEditor);
|
|
123
|
+
const nextText = activeEditor.getText();
|
|
124
|
+
if (dom) {
|
|
125
|
+
syncPromptComposerHeight(dom, nextText);
|
|
126
|
+
}
|
|
127
|
+
setText(nextText);
|
|
128
|
+
onChangeRef.current?.(nextText, activeEditor);
|
|
129
|
+
},
|
|
130
|
+
onCreate: bindEditorDom,
|
|
131
|
+
}, [extensions, bindEditorDom, ariaLabelComposer, handleEditorKeyDown]);
|
|
132
|
+
editorRef.current = editor;
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (!editor)
|
|
135
|
+
return;
|
|
136
|
+
editor.setEditable(!disabled);
|
|
137
|
+
}, [editor, disabled]);
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if (!editor)
|
|
140
|
+
return;
|
|
141
|
+
const bind = () => {
|
|
142
|
+
editorDomRef.current = promptComposerSafeEditorDom(editor);
|
|
143
|
+
};
|
|
144
|
+
bind();
|
|
145
|
+
let rafId = null;
|
|
146
|
+
if (typeof window !== 'undefined') {
|
|
147
|
+
rafId = window.requestAnimationFrame(bind);
|
|
148
|
+
}
|
|
149
|
+
return () => {
|
|
150
|
+
if (rafId != null)
|
|
151
|
+
cancelAnimationFrame(rafId);
|
|
152
|
+
};
|
|
153
|
+
}, [editor]);
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
if (!editor || prefillMessage == null)
|
|
156
|
+
return;
|
|
157
|
+
const current = editor.getText();
|
|
158
|
+
const next = prefillMessage;
|
|
159
|
+
if (current === next)
|
|
160
|
+
return;
|
|
161
|
+
if (next === '') {
|
|
162
|
+
editor.commands.setContent(PROMPT_COMPOSER_EMPTY_DOC);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
editor.commands.setContent(promptComposerParagraphDoc(next));
|
|
166
|
+
}
|
|
167
|
+
setText(editor.getText());
|
|
168
|
+
queueMicrotask(() => {
|
|
169
|
+
const dom = promptComposerSafeEditorDom(editor);
|
|
170
|
+
if (dom)
|
|
171
|
+
syncPromptComposerHeight(dom, editor.getText());
|
|
172
|
+
if (!disabled && !editor.isDestroyed) {
|
|
173
|
+
editor.chain().focus('end').run();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}, [editor, prefillMessage, disabled]);
|
|
177
|
+
useLayoutEffect(() => {
|
|
178
|
+
if (!editor)
|
|
179
|
+
return;
|
|
180
|
+
const dom = promptComposerSafeEditorDom(editor);
|
|
181
|
+
if (!dom)
|
|
182
|
+
return;
|
|
183
|
+
syncPromptComposerHeight(dom, text);
|
|
184
|
+
}, [editor, text]);
|
|
185
|
+
return {
|
|
186
|
+
editor,
|
|
187
|
+
text,
|
|
188
|
+
trimmedText,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export { usePromptComposerEditor };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
|
|
2
2
|
|
|
3
|
-
var css_248z = ".Slider_root__hLZtd{color:var(--accent-color);position:relative;width:100%}.Slider_disabled__jz0lx{opacity:.4;pointer-events:none}.Slider_disabled__jz0lx .Slider_control__vtxup[disabled]{opacity:1}.Slider_hasLabel__Epyqi{align-items:center;display:flex;gap:var(--p-2)}.Slider_label__Gi7GI{color:inherit;font-size:inherit;white-space:nowrap}.Slider_trackWrap__PX861{display:flex;flex:1;flex-direction:column;min-width:0;position:relative}.Slider_hasMarkers__YfnMG{gap:var(--p-1)}.Slider_trackRow__hbQdR{align-items:center;display:flex;position:relative;width:100%}.Slider_markersRow__l-yga{flex-shrink:0;height:
|
|
3
|
+
var css_248z = ".Slider_root__hLZtd{color:var(--accent-color);position:relative;width:100%}.Slider_disabled__jz0lx{opacity:.4;pointer-events:none}.Slider_disabled__jz0lx .Slider_control__vtxup[disabled]{opacity:1}.Slider_hasLabel__Epyqi{align-items:center;display:flex;gap:var(--p-2)}.Slider_label__Gi7GI{color:inherit;font-size:inherit;white-space:nowrap}.Slider_trackWrap__PX861{display:flex;flex:1;flex-direction:column;min-width:0;position:relative}.Slider_hasMarkers__YfnMG{gap:var(--p-1)}.Slider_trackRow__hbQdR{align-items:center;display:flex;position:relative;width:100%}.Slider_markersRow__l-yga{flex-shrink:0;height:0;position:absolute;width:100%;z-index:2}.Slider_markerWrap__6hLJN{pointer-events:auto;position:absolute;top:-3px}.Slider_marker__vtOv9{background:var(--accent-color);border:none;border-radius:50%;box-shadow:0 0 0 1px var(--decent-color-alpha-800);cursor:pointer;display:block;height:var(--marker-size);margin:0;padding:0;position:relative;width:var(--marker-size)}.Slider_marker__vtOv9:before{border-radius:50%;content:\"\";display:block;height:40px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:40px}.Slider_marker__vtOv9:hover{background:var(--active-color)}.Slider_marker__vtOv9:disabled{cursor:default;opacity:.5}.Slider_control__vtxup{--track-radius:50px;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;box-shadow:inset 0 0 0 2px none;box-sizing:border-box;cursor:pointer;height:var(--thumb-size);margin:0;padding:0;position:relative;transition:.2s ease-out;transition-property:background-color,box-shadow,opacity;width:100%;z-index:2}.Slider_control__vtxup:focus,.Slider_control__vtxup:hover{background-color:var(--active-color-alpha-100)}.Slider_control__vtxup[disabled]{background-color:var(--accent-color-alpha-100);opacity:.4;pointer-events:none}.Slider_control__vtxup:focus,.Slider_control__vtxup:hover{background:transparent!important}.Slider_control__vtxup:focus{box-shadow:inset 0 0 0 2px none}.Slider_control__vtxup::-webkit-slider-runnable-track{background:linear-gradient(to right,var(--active-color) 0,var(--active-color) var(--progress),var(--accent-color-alpha-100) var(--progress),var(--accent-color-alpha-100) 100%);border-radius:var(--track-radius);height:var(--track-height)}.Slider_control__vtxup::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background:var(--active-color);border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.2);cursor:pointer;height:var(--thumb-size);margin-top:calc((var(--track-height) - var(--thumb-size))/2);width:var(--thumb-size)}.Slider_control__vtxup::-moz-range-track{background:var(--accent-color-alpha-100);border-radius:var(--track-radius);height:var(--track-height)}.Slider_control__vtxup::-moz-range-progress{background:var(--active-color);border-radius:var(--track-radius);height:var(--track-height)}.Slider_control__vtxup::-moz-range-thumb{background:var(--active-color);border:none;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.2);cursor:pointer;height:var(--thumb-size);width:var(--thumb-size)}.Slider_ghost__tfPtm{background:var(--accent-color);border-radius:50%;height:var(--ghost-size);left:0;opacity:.45;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);width:var(--ghost-size);z-index:2}.Slider_size-xs__v6UDK{--track-height:1px;--thumb-size:10px;--ghost-size:10px;--marker-size:6px;font-size:12px}.Slider_size-s__8hGSO{--track-height:2px;--thumb-size:12px;--ghost-size:12px;--marker-size:7px;font-size:14px}.Slider_size-s__8hGSO .Slider_markersRow__l-yga{top:-1px}.Slider_size-m__Dj7LT{--track-height:8px;--thumb-size:16px;--ghost-size:16px;--marker-size:12px;font-size:16px}.Slider_size-m__Dj7LT .Slider_markersRow__l-yga{top:1px}.Slider_size-l__Qi6tI{--track-height:12px;--thumb-size:20px;--ghost-size:20px;--marker-size:16px;font-size:18px}.Slider_size-l__Qi6tI .Slider_markersRow__l-yga{top:4px}.Slider_size-xl__85Gcz{--track-height:16px;--thumb-size:24px;--ghost-size:24px;--marker-size:20px;font-size:20px}.Slider_size-xl__85Gcz .Slider_markersRow__l-yga{top:5px}";
|
|
4
4
|
var S = {"root":"Slider_root__hLZtd","disabled":"Slider_disabled__jz0lx","control":"Slider_control__vtxup","hasLabel":"Slider_hasLabel__Epyqi","label":"Slider_label__Gi7GI","trackWrap":"Slider_trackWrap__PX861","hasMarkers":"Slider_hasMarkers__YfnMG","trackRow":"Slider_trackRow__hbQdR","markersRow":"Slider_markersRow__l-yga","markerWrap":"Slider_markerWrap__6hLJN","marker":"Slider_marker__vtOv9","ghost":"Slider_ghost__tfPtm","size-xs":"Slider_size-xs__v6UDK","size-s":"Slider_size-s__8hGSO","size-m":"Slider_size-m__Dj7LT","size-l":"Slider_size-l__Qi6tI","size-xl":"Slider_size-xl__85Gcz"};
|
|
5
5
|
styleInject(css_248z);
|
|
6
6
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import { useState, useEffect, useCallback, useImperativeHandle } from 'react';
|
|
4
|
+
import { Menu } from '../../components/Menu/Menu.js';
|
|
5
|
+
import S from './SlashSuggestionList.styl.js';
|
|
6
|
+
|
|
7
|
+
function SlashSuggestionListInner({ items, command, listHandleRef, }) {
|
|
8
|
+
const [selected, setSelected] = useState(0);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
setSelected(s => Math.min(s, Math.max(items.length - 1, 0)));
|
|
11
|
+
}, [items.length]);
|
|
12
|
+
const safeSel = Math.min(selected, Math.max(items.length - 1, 0));
|
|
13
|
+
const onPick = useCallback((index) => {
|
|
14
|
+
const item = items[index];
|
|
15
|
+
if (!item)
|
|
16
|
+
return;
|
|
17
|
+
command(item);
|
|
18
|
+
}, [command, items]);
|
|
19
|
+
const onKeyboardEvent = useCallback((event) => {
|
|
20
|
+
if (items.length === 0)
|
|
21
|
+
return false;
|
|
22
|
+
if (event.key === 'ArrowDown') {
|
|
23
|
+
event.preventDefault();
|
|
24
|
+
setSelected(s => Math.min(s + 1, items.length - 1));
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
if (event.key === 'ArrowUp') {
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
setSelected(s => Math.max(s - 1, 0));
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
if (event.key === 'Enter') {
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
const max = Math.max(items.length - 1, 0);
|
|
35
|
+
const idx = Math.min(selected, max);
|
|
36
|
+
const item = items[idx];
|
|
37
|
+
if (item)
|
|
38
|
+
command(item);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
if (event.key === 'Escape') {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}, [command, items, selected]);
|
|
46
|
+
useImperativeHandle(listHandleRef, () => ({ onKeyboardEvent }), [
|
|
47
|
+
onKeyboardEvent,
|
|
48
|
+
]);
|
|
49
|
+
return (jsx("div", { className: S.root, children: jsx(Menu, { className: S.menu, role: "listbox", "aria-label": "Slash commands", children: items.map((item, idx) => (jsxs(Menu.Item, { role: "option", "aria-selected": idx === safeSel, className: cn(S.item, idx === safeSel && S.itemHighlighted), onMouseDown: e => e.preventDefault(), onMouseEnter: () => setSelected(idx), onClick: () => onPick(idx), textOverflow: true, children: [jsxs("span", { className: S.itemLabel, children: ["/", item.label] }), item.description ? (jsx("span", { className: S.itemDesc, children: item.description })) : null] }, `${item.id}-${idx}`))) }) }));
|
|
50
|
+
}
|
|
51
|
+
function SlashSuggestionList(props) {
|
|
52
|
+
if (props.items.length === 0)
|
|
53
|
+
return null;
|
|
54
|
+
return (jsx(SlashSuggestionListInner, { items: props.items, command: props.command, listHandleRef: props.listHandleRef }));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { SlashSuggestionList };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
|
|
2
|
+
|
|
3
|
+
var css_248z = ".SlashSuggestionList_root__9KCb1{background-color:var(--decent-color);border-radius:8px;border-radius:var(--radius-lg,8px);box-shadow:inset 0 0 0 1px var(--accent-color-alpha-50),0 8px 24px rgba(0,0,0,.2);color:var(--foreground);max-width:90vw;min-width:220px;overflow:hidden;position:relative}.SlashSuggestionList_root__9KCb1:before{background-color:var(--accent-color-alpha-50);bottom:0;content:\"\";left:0;pointer-events:none;position:absolute;right:0;top:0}.dark .SlashSuggestionList_root__9KCb1{box-shadow:inset 0 0 0 1px var(--accent-color-alpha-50),0 8px 24px rgba(0,0,0,.5)}.SlashSuggestionList_menu__s-jK3{margin:0;max-height:40vh}.SlashSuggestionList_item__9JBeY{align-items:flex-start;border-radius:var(--p-2);display:flex;flex-direction:column;height:auto!important;justify-content:center;min-height:0;overflow:visible!important;padding:var(--p-1) var(--p-2)!important;position:relative;text-overflow:clip!important;white-space:normal!important;width:100%}.SlashSuggestionList_itemHighlighted__cStZr,.SlashSuggestionList_item__9JBeY:hover{box-shadow:inset 100vw 0 0 0 var(--accent-color-alpha-200)}.SlashSuggestionList_itemLabel__OMaov{font-weight:600}.SlashSuggestionList_itemDesc__fAdcA{color:var(--muted-foreground);font-size:80%;white-space:normal}.SlashSuggestionList_mention__aT45p{align-items:center;background:var(--muted);border-radius:var(--p-1);display:inline-flex;line-height:1.4;margin:0 var(--p-1);padding:0 var(--p-1);-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:baseline;white-space:nowrap}";
|
|
4
|
+
var S = {"root":"SlashSuggestionList_root__9KCb1","menu":"SlashSuggestionList_menu__s-jK3","item":"SlashSuggestionList_item__9JBeY","itemHighlighted":"SlashSuggestionList_itemHighlighted__cStZr","itemLabel":"SlashSuggestionList_itemLabel__OMaov","itemDesc":"SlashSuggestionList_itemDesc__fAdcA","mention":"SlashSuggestionList_mention__aT45p"};
|
|
5
|
+
styleInject(css_248z);
|
|
6
|
+
|
|
7
|
+
export { S as default };
|