@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.
Files changed (35) hide show
  1. package/dist/esm/index.js +5 -0
  2. package/dist/esm/src/components/Autocomplete/Autocomplete.js +5 -0
  3. package/dist/esm/src/components/InputFile/InputFile.js +5 -0
  4. package/dist/esm/src/components/PromptComposer/PromptComposer.helpers.js +44 -0
  5. package/dist/esm/src/components/PromptComposer/PromptComposer.js +35 -0
  6. package/dist/esm/src/components/PromptComposer/PromptComposer.styl.js +7 -0
  7. package/dist/esm/src/components/PromptComposer/promptComposerDoc.js +17 -0
  8. package/dist/esm/src/components/PromptComposer/promptComposerInsert.js +101 -0
  9. package/dist/esm/src/components/PromptComposer/usePromptComposerEditor.js +192 -0
  10. package/dist/esm/src/components/Slider/Slider.styl.js +1 -1
  11. package/dist/esm/src/tiptap/slash-mention/SlashSuggestionList.js +57 -0
  12. package/dist/esm/src/tiptap/slash-mention/SlashSuggestionList.styl.js +7 -0
  13. package/dist/esm/src/tiptap/slash-mention/createSlashMentionExtension.js +202 -0
  14. package/dist/esm/src/tiptap/slash-mention/defaultChatSlashItems.js +12 -0
  15. package/dist/esm/types/node_modules/@tiptap/pm/state/index.d.ts +1 -0
  16. package/dist/esm/types/src/components/PromptComposer/PromptComposer.d.ts +13 -0
  17. package/dist/esm/types/src/components/PromptComposer/PromptComposer.helpers.d.ts +8 -0
  18. package/dist/esm/types/src/components/PromptComposer/PromptComposer.types.d.ts +19 -0
  19. package/dist/esm/types/src/components/PromptComposer/index.d.ts +7 -0
  20. package/dist/esm/types/src/components/PromptComposer/promptComposerDoc.d.ts +3 -0
  21. package/dist/esm/types/src/components/PromptComposer/promptComposerInsert.d.ts +42 -0
  22. package/dist/esm/types/src/components/PromptComposer/usePromptComposerEditor.d.ts +19 -0
  23. package/dist/esm/types/src/components/index.d.ts +1 -0
  24. package/dist/esm/types/src/index.d.ts +1 -0
  25. package/dist/esm/types/src/tiptap/slash-mention/SlashSuggestionList.d.ts +11 -0
  26. package/dist/esm/types/src/tiptap/slash-mention/createSlashMentionExtension.d.ts +21 -0
  27. package/dist/esm/types/src/tiptap/slash-mention/defaultChatSlashItems.d.ts +4 -0
  28. package/dist/esm/types/src/tiptap/slash-mention/index.d.ts +5 -0
  29. package/dist/esm/types/src/tiptap/slash-mention/types.d.ts +28 -0
  30. package/package.json +8 -1
  31. package/.cursor/debug-8c6f78.log +0 -44
  32. package/.cursor/debug-a8590a.log +0 -26
  33. package/.cursor/debug-cdef6d.log +0 -694
  34. package/.cursor/debug-e1fd63.log +0 -83
  35. 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('<', '&lt;')
14
+ .replaceAll('>', '&gt;')
15
+ .replaceAll('"', '&quot;');
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:var(--marker-size);position:relative;width:100%}.Slider_markerWrap__6hLJN{pointer-events:auto;position:absolute;top:50%;transform:translate(-50%,-50%)}.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;width:var(--marker-size)}.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-m__Dj7LT{--track-height:8px;--thumb-size:16px;--ghost-size:16px;--marker-size:8px;font-size:16px}.Slider_size-l__Qi6tI{--track-height:12px;--thumb-size:20px;--ghost-size:20px;--marker-size:10px;font-size:18px}.Slider_size-xl__85Gcz{--track-height:16px;--thumb-size:24px;--ghost-size:24px;--marker-size:12px;font-size:20px}";
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 };