@optilogic/editor 1.0.0-beta.1 → 1.0.0-beta.3
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/index.cjs +94 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.js +88 -23
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +6 -0
- package/src/slate-editor.tsx +117 -22
package/dist/index.cjs
CHANGED
|
@@ -165,12 +165,15 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
165
165
|
onTagCreate,
|
|
166
166
|
onTagDelete,
|
|
167
167
|
onSubmit,
|
|
168
|
+
clearOnSubmit = false,
|
|
168
169
|
placeholder = "Type something...",
|
|
169
170
|
disabled = false,
|
|
170
171
|
enableTags = true,
|
|
171
172
|
minRows = 3,
|
|
172
173
|
maxRows = 8,
|
|
173
|
-
className
|
|
174
|
+
className,
|
|
175
|
+
decorate,
|
|
176
|
+
renderLeaf: customRenderLeaf
|
|
174
177
|
}, ref) => {
|
|
175
178
|
const editor = React__namespace.useMemo(
|
|
176
179
|
() => withTags(slateHistory.withHistory(slateReact.withReact(slate.createEditor()))),
|
|
@@ -182,16 +185,46 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
182
185
|
const [editorValue, setEditorValue] = React__namespace.useState(
|
|
183
186
|
() => deserializeFromText(value)
|
|
184
187
|
);
|
|
188
|
+
const lastOnChangeValue = React__namespace.useRef(value);
|
|
189
|
+
const getEditableElement = React__namespace.useCallback(() => {
|
|
190
|
+
try {
|
|
191
|
+
return slateReact.ReactEditor.toDOMNode(editor, editor);
|
|
192
|
+
} catch {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}, [editor]);
|
|
196
|
+
const resetEditorContent = React__namespace.useCallback(
|
|
197
|
+
(newContent) => {
|
|
198
|
+
const el = getEditableElement();
|
|
199
|
+
const savedScroll = el ? { top: el.scrollTop, left: el.scrollLeft } : null;
|
|
200
|
+
slate.Editor.withoutNormalizing(editor, () => {
|
|
201
|
+
while (editor.children.length > 0) {
|
|
202
|
+
slate.Transforms.removeNodes(editor, { at: [0] });
|
|
203
|
+
}
|
|
204
|
+
slate.Transforms.insertNodes(editor, newContent, { at: [0] });
|
|
205
|
+
});
|
|
206
|
+
setEditorValue(newContent);
|
|
207
|
+
const point = { path: [0, 0], offset: 0 };
|
|
208
|
+
slate.Transforms.select(editor, { anchor: point, focus: point });
|
|
209
|
+
if (savedScroll && el) {
|
|
210
|
+
requestAnimationFrame(() => {
|
|
211
|
+
el.scrollTop = savedScroll.top;
|
|
212
|
+
el.scrollLeft = savedScroll.left;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
[editor, getEditableElement]
|
|
217
|
+
);
|
|
185
218
|
React__namespace.useEffect(() => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
219
|
+
if (value !== lastOnChangeValue.current) {
|
|
220
|
+
const currentText = serializeToText(editor.children);
|
|
221
|
+
if (currentText !== value) {
|
|
222
|
+
const newValue = deserializeFromText(value);
|
|
223
|
+
resetEditorContent(newValue);
|
|
224
|
+
}
|
|
225
|
+
lastOnChangeValue.current = value;
|
|
193
226
|
}
|
|
194
|
-
}, [value, editor]);
|
|
227
|
+
}, [value, editor, resetEditorContent]);
|
|
195
228
|
React__namespace.useImperativeHandle(
|
|
196
229
|
ref,
|
|
197
230
|
() => ({
|
|
@@ -199,13 +232,13 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
199
232
|
slateReact.ReactEditor.focus(editor);
|
|
200
233
|
},
|
|
201
234
|
clear: () => {
|
|
202
|
-
const
|
|
235
|
+
const emptyValue = [
|
|
203
236
|
{ type: "paragraph", children: [{ text: "" }] }
|
|
204
237
|
];
|
|
205
|
-
|
|
206
|
-
|
|
238
|
+
resetEditorContent(emptyValue);
|
|
239
|
+
onChange?.("");
|
|
207
240
|
},
|
|
208
|
-
getText: () => serializeToText(
|
|
241
|
+
getText: () => serializeToText(editor.children),
|
|
209
242
|
insertText: (text) => {
|
|
210
243
|
slate.Transforms.insertText(editor, text);
|
|
211
244
|
},
|
|
@@ -214,11 +247,10 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
214
247
|
onTagCreate?.(tag);
|
|
215
248
|
}
|
|
216
249
|
}),
|
|
217
|
-
[editor,
|
|
250
|
+
[editor, onTagCreate, resetEditorContent, onChange]
|
|
218
251
|
);
|
|
219
252
|
const handleChange = React__namespace.useCallback(
|
|
220
253
|
(newValue) => {
|
|
221
|
-
setEditorValue(newValue);
|
|
222
254
|
if (isCreatingTag && tagStartPoint) {
|
|
223
255
|
const { selection } = editor;
|
|
224
256
|
if (selection && slate.Range.isCollapsed(selection)) {
|
|
@@ -269,6 +301,7 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
269
301
|
}
|
|
270
302
|
}
|
|
271
303
|
const text = serializeToText(newValue);
|
|
304
|
+
lastOnChangeValue.current = text;
|
|
272
305
|
onChange?.(text);
|
|
273
306
|
},
|
|
274
307
|
[editor, onChange, onTagDelete, isCreatingTag, tagStartPoint]
|
|
@@ -353,9 +386,29 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
353
386
|
}
|
|
354
387
|
if (event.key === "Enter" && !event.shiftKey && !isCreatingTag) {
|
|
355
388
|
event.preventDefault();
|
|
356
|
-
const text = serializeToText(
|
|
389
|
+
const text = serializeToText(editor.children);
|
|
357
390
|
if (text.trim() && onSubmit) {
|
|
358
391
|
onSubmit(text.trim());
|
|
392
|
+
if (clearOnSubmit) {
|
|
393
|
+
const emptyValue = [
|
|
394
|
+
{ type: "paragraph", children: [{ text: "" }] }
|
|
395
|
+
];
|
|
396
|
+
resetEditorContent(emptyValue);
|
|
397
|
+
onChange?.("");
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (event.key === "Enter" && event.shiftKey) {
|
|
403
|
+
event.preventDefault();
|
|
404
|
+
const el = getEditableElement();
|
|
405
|
+
const savedScrollTop = el?.scrollTop ?? 0;
|
|
406
|
+
slate.Transforms.insertText(editor, "\n");
|
|
407
|
+
if (el) {
|
|
408
|
+
el.scrollTop = savedScrollTop;
|
|
409
|
+
requestAnimationFrame(() => {
|
|
410
|
+
el.scrollTop = savedScrollTop;
|
|
411
|
+
});
|
|
359
412
|
}
|
|
360
413
|
return;
|
|
361
414
|
}
|
|
@@ -385,13 +438,16 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
385
438
|
},
|
|
386
439
|
[
|
|
387
440
|
editor,
|
|
388
|
-
editorValue,
|
|
389
441
|
isCreatingTag,
|
|
390
442
|
enableTags,
|
|
391
443
|
completeTag,
|
|
392
444
|
cancelTag,
|
|
393
445
|
onSubmit,
|
|
394
|
-
onTagDelete
|
|
446
|
+
onTagDelete,
|
|
447
|
+
clearOnSubmit,
|
|
448
|
+
resetEditorContent,
|
|
449
|
+
onChange,
|
|
450
|
+
getEditableElement
|
|
395
451
|
]
|
|
396
452
|
);
|
|
397
453
|
const renderElement = React__namespace.useCallback((props) => {
|
|
@@ -408,9 +464,15 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
408
464
|
return /* @__PURE__ */ jsxRuntime.jsx(DefaultElement, { ...props });
|
|
409
465
|
}
|
|
410
466
|
}, []);
|
|
411
|
-
const renderLeaf = React__namespace.useCallback(
|
|
412
|
-
|
|
413
|
-
|
|
467
|
+
const renderLeaf = React__namespace.useCallback(
|
|
468
|
+
(props) => {
|
|
469
|
+
if (customRenderLeaf) {
|
|
470
|
+
return customRenderLeaf(props);
|
|
471
|
+
}
|
|
472
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Leaf, { ...props });
|
|
473
|
+
},
|
|
474
|
+
[customRenderLeaf]
|
|
475
|
+
);
|
|
414
476
|
const lineHeight = 24;
|
|
415
477
|
const minHeight = lineHeight * minRows;
|
|
416
478
|
const maxHeight = lineHeight * maxRows;
|
|
@@ -437,13 +499,15 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
437
499
|
placeholder,
|
|
438
500
|
renderElement,
|
|
439
501
|
renderLeaf,
|
|
502
|
+
decorate,
|
|
440
503
|
onKeyDown: handleKeyDown,
|
|
441
504
|
className: core.cn(
|
|
442
505
|
"w-full outline-none",
|
|
443
506
|
"text-foreground placeholder:text-muted-foreground",
|
|
444
507
|
"leading-6",
|
|
445
508
|
"overflow-y-auto overflow-x-hidden",
|
|
446
|
-
"whitespace-pre-wrap break-words"
|
|
509
|
+
"whitespace-pre-wrap break-words",
|
|
510
|
+
"scrollbar-thin"
|
|
447
511
|
),
|
|
448
512
|
style: {
|
|
449
513
|
minHeight: `${minHeight}px`,
|
|
@@ -480,6 +544,14 @@ var SlateEditor = React__namespace.forwardRef(
|
|
|
480
544
|
);
|
|
481
545
|
SlateEditor.displayName = "SlateEditor";
|
|
482
546
|
|
|
547
|
+
Object.defineProperty(exports, "Range", {
|
|
548
|
+
enumerable: true,
|
|
549
|
+
get: function () { return slate.Range; }
|
|
550
|
+
});
|
|
551
|
+
Object.defineProperty(exports, "Text", {
|
|
552
|
+
enumerable: true,
|
|
553
|
+
get: function () { return slate.Text; }
|
|
554
|
+
});
|
|
483
555
|
exports.SlateEditor = SlateEditor;
|
|
484
556
|
exports.deserializeFromText = deserializeFromText;
|
|
485
557
|
exports.serializeToText = serializeToText;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/slate-editor.tsx"],"names":["Range","Editor","SlateElement","Path","Transforms","Text","jsxs","cn","jsx","React","withHistory","withReact","createEditor","ReactEditor","Node","editor","Slate","Editable"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SlateEditor Component\n *\n * A reusable rich text editor primitive based on Slate.js\n * Provides consistent theming and can be used as an alternative to textarea\n */\n\nimport * as React from \"react\";\nimport {\n createEditor,\n Descendant,\n Editor,\n Transforms,\n Text,\n Element as SlateElement,\n Range,\n Node,\n BaseEditor,\n Path,\n} from \"slate\";\nimport {\n Slate,\n Editable,\n withReact,\n ReactEditor,\n RenderElementProps,\n RenderLeafProps,\n} from \"slate-react\";\nimport { withHistory, HistoryEditor } from \"slate-history\";\nimport { cn } from \"@optilogic/core\";\n\ntype TagElement = {\n type: \"tag\";\n tag: string;\n children: [{ text: \"\" }];\n};\n\ntype ParagraphElement = {\n type: \"paragraph\";\n children: Descendant[];\n};\n\ntype CustomElement = TagElement | ParagraphElement;\ntype CustomText = { text: string };\n\ndeclare module \"slate\" {\n interface CustomTypes {\n Editor: BaseEditor & ReactEditor & HistoryEditor;\n Element: CustomElement;\n Text: CustomText;\n }\n}\n\nconst isTagElement = (element: CustomElement): element is TagElement => {\n return element.type === \"tag\";\n};\n\nexport interface SlateEditorRef {\n /** Focus the editor */\n focus: () => void;\n /** Clear the editor content */\n clear: () => void;\n /** Get plain text content */\n getText: () => string;\n /** Insert text at cursor */\n insertText: (text: string) => void;\n /** Insert a tag element */\n insertTag: (tag: string) => void;\n}\n\nexport interface SlateEditorProps {\n /** Initial plain text value */\n value?: string;\n /** Callback when content changes (plain text) */\n onChange?: (value: string) => void;\n /** Callback when a tag is created */\n onTagCreate?: (tag: string) => void;\n /** Callback when a tag is deleted */\n onTagDelete?: (tag: string) => void;\n /** Callback when Enter is pressed (without Shift) */\n onSubmit?: (text: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the editor is disabled */\n disabled?: boolean;\n /** Whether to enable tag detection (# character) */\n enableTags?: boolean;\n /** Minimum number of rows */\n minRows?: number;\n /** Maximum number of rows before scrolling */\n maxRows?: number;\n /** Additional class names */\n className?: string;\n}\n\nconst withTags = (editor: Editor) => {\n const { isInline, isVoid, deleteBackward, deleteForward } = editor;\n\n editor.isInline = (element) => {\n return element.type === \"tag\" ? true : isInline(element);\n };\n\n editor.isVoid = (element) => {\n return element.type === \"tag\" ? true : isVoid(element);\n };\n\n editor.deleteBackward = (unit) => {\n const { selection } = editor;\n\n if (selection && Range.isCollapsed(selection)) {\n const [tagEntry] = Editor.nodes(editor, {\n match: (n) =>\n !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === \"tag\",\n });\n\n if (tagEntry) {\n const [, path] = tagEntry;\n const after = Editor.after(editor, path);\n if (after && Path.equals(selection.anchor.path, after.path)) {\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n\n const before = Editor.before(editor, selection);\n if (before) {\n const [beforeTagEntry] = Editor.nodes(editor, {\n at: before,\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (beforeTagEntry) {\n const [, path] = beforeTagEntry;\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n }\n\n deleteBackward(unit);\n };\n\n editor.deleteForward = (unit) => {\n const { selection } = editor;\n\n if (selection && Range.isCollapsed(selection)) {\n const after = Editor.after(editor, selection);\n if (after) {\n const [afterTagEntry] = Editor.nodes(editor, {\n at: after,\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (afterTagEntry) {\n const [, path] = afterTagEntry;\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n }\n\n deleteForward(unit);\n };\n\n return editor;\n};\n\n/**\n * Convert Slate content to plain text\n */\nexport function serializeToText(nodes: Descendant[]): string {\n return nodes\n .map((n) => {\n if (Text.isText(n)) {\n return n.text;\n }\n if (SlateElement.isElement(n)) {\n if (n.type === \"tag\") {\n return `#${n.tag}`;\n }\n return serializeToText(n.children);\n }\n return \"\";\n })\n .join(\"\");\n}\n\n/**\n * Convert plain text to Slate nodes (preserving existing tags)\n */\nexport function deserializeFromText(text: string): Descendant[] {\n if (!text) {\n return [{ type: \"paragraph\", children: [{ text: \"\" }] }];\n }\n\n const children: Descendant[] = [];\n const tagRegex = /#([a-zA-Z0-9@#$_-]+(?:--[a-zA-Z0-9_-]+)?)/g;\n let lastIndex = 0;\n let match;\n\n while ((match = tagRegex.exec(text)) !== null) {\n if (match.index > lastIndex) {\n children.push({ text: text.substring(lastIndex, match.index) });\n }\n\n children.push({\n type: \"tag\",\n tag: match[1],\n children: [{ text: \"\" }],\n });\n\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < text.length) {\n children.push({ text: text.substring(lastIndex) });\n }\n\n if (children.length === 0) {\n children.push({ text: \"\" });\n }\n\n return [{ type: \"paragraph\", children }];\n}\n\nconst TagElementRenderer = ({\n attributes,\n children,\n element,\n}: RenderElementProps & { element: TagElement }) => {\n return (\n <span\n {...attributes}\n contentEditable={false}\n className={cn(\n \"inline-flex items-center\",\n \"px-1.5 py-0.5 mx-0.5\",\n \"rounded-md border\",\n \"bg-accent/20 text-accent border-accent/40\",\n \"text-sm font-medium\",\n \"select-none cursor-default\"\n )}\n >\n <span className=\"font-bold\">#</span>\n {element.tag}\n {children}\n </span>\n );\n};\n\nconst DefaultElement = ({ attributes, children }: RenderElementProps) => {\n return <p {...attributes}>{children}</p>;\n};\n\nconst Leaf = ({ attributes, children }: RenderLeafProps) => {\n return <span {...attributes}>{children}</span>;\n};\n\n/**\n * SlateEditor component\n *\n * A rich text editor based on Slate.js with support for inline tags.\n * Can be used as a drop-in replacement for textarea with enhanced features.\n *\n * @example\n * <SlateEditor\n * value={content}\n * onChange={setContent}\n * placeholder=\"Type your message...\"\n * onSubmit={(text) => console.log('Submitted:', text)}\n * />\n */\nexport const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(\n (\n {\n value = \"\",\n onChange,\n onTagCreate,\n onTagDelete,\n onSubmit,\n placeholder = \"Type something...\",\n disabled = false,\n enableTags = true,\n minRows = 3,\n maxRows = 8,\n className,\n },\n ref\n ) => {\n const editor = React.useMemo(\n () => withTags(withHistory(withReact(createEditor()))),\n []\n );\n\n const [isCreatingTag, setIsCreatingTag] = React.useState(false);\n const [tagStartPoint, setTagStartPoint] = React.useState<{\n path: Path;\n offset: number;\n } | null>(null);\n const [currentTagText, setCurrentTagText] = React.useState(\"\");\n\n const [editorValue, setEditorValue] = React.useState<Descendant[]>(() =>\n deserializeFromText(value)\n );\n\n React.useEffect(() => {\n const newValue = deserializeFromText(value);\n const currentText = serializeToText(editorValue);\n if (currentText !== value) {\n setEditorValue(newValue);\n Transforms.removeNodes(editor, { at: [] });\n Transforms.insertNodes(editor, newValue, { at: [0] });\n Transforms.select(editor, Editor.start(editor, []));\n }\n }, [value, editor]);\n\n React.useImperativeHandle(\n ref,\n () => ({\n focus: () => {\n ReactEditor.focus(editor);\n },\n clear: () => {\n const newValue: Descendant[] = [\n { type: \"paragraph\", children: [{ text: \"\" }] },\n ];\n setEditorValue(newValue);\n Transforms.select(editor, Editor.start(editor, []));\n },\n getText: () => serializeToText(editorValue),\n insertText: (text: string) => {\n Transforms.insertText(editor, text);\n },\n insertTag: (tag: string) => {\n insertTag(editor, tag);\n onTagCreate?.(tag);\n },\n }),\n [editor, editorValue, onTagCreate]\n );\n\n const handleChange = React.useCallback(\n (newValue: Descendant[]) => {\n setEditorValue(newValue);\n\n if (isCreatingTag && tagStartPoint) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n const currentPath = selection.anchor.path;\n const currentOffset = selection.anchor.offset;\n\n if (Path.equals(currentPath, tagStartPoint.path)) {\n try {\n const [textNode] = Editor.node(editor, currentPath);\n if (Text.isText(textNode)) {\n const tagText = textNode.text.substring(\n tagStartPoint.offset + 1,\n currentOffset\n );\n setCurrentTagText(tagText);\n }\n } catch {\n // Ignore - node may not exist\n }\n }\n }\n }\n\n const oldTags = new Set<string>();\n const newTags = new Set<string>();\n\n for (const node of Node.descendants(editor, {\n from: [],\n pass: ([n]) => SlateElement.isElement(n) && n.type === \"paragraph\",\n })) {\n const [n] = node;\n if (SlateElement.isElement(n) && n.type === \"tag\") {\n oldTags.add(n.tag);\n }\n }\n\n const extractTags = (nodes: Descendant[]) => {\n for (const node of nodes) {\n if (SlateElement.isElement(node)) {\n if (node.type === \"tag\") {\n newTags.add(node.tag);\n }\n if (\"children\" in node) {\n extractTags(node.children);\n }\n }\n }\n };\n extractTags(newValue);\n\n for (const tag of oldTags) {\n if (!newTags.has(tag)) {\n onTagDelete?.(tag);\n }\n }\n\n const text = serializeToText(newValue);\n onChange?.(text);\n },\n [editor, onChange, onTagDelete, isCreatingTag, tagStartPoint]\n );\n\n const insertTag = (editor: Editor, tag: string) => {\n const tagNode: TagElement = {\n type: \"tag\",\n tag,\n children: [{ text: \"\" }],\n };\n Transforms.insertNodes(editor, tagNode);\n Transforms.move(editor);\n Transforms.insertText(editor, \" \");\n };\n\n const completeTag = React.useCallback(() => {\n if (!isCreatingTag || !tagStartPoint) return;\n\n const { selection } = editor;\n if (!selection || !Range.isCollapsed(selection)) return;\n\n const currentPath = selection.anchor.path;\n const currentOffset = selection.anchor.offset;\n\n if (!Path.equals(currentPath, tagStartPoint.path)) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const [textNode] = Editor.node(editor, currentPath);\n if (!Text.isText(textNode)) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const tagText = textNode.text.substring(\n tagStartPoint.offset + 1,\n currentOffset\n );\n\n if (!tagText.trim()) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const start = { path: currentPath, offset: tagStartPoint.offset };\n const end = { path: currentPath, offset: currentOffset };\n\n Transforms.delete(editor, { at: { anchor: start, focus: end } });\n insertTag(editor, tagText.trim());\n\n onTagCreate?.(tagText.trim());\n\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n }, [editor, isCreatingTag, tagStartPoint, onTagCreate]);\n\n const cancelTag = React.useCallback(() => {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n }, []);\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (isCreatingTag) {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n completeTag();\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n cancelTag();\n return;\n }\n }\n\n if (enableTags && event.key === \"#\" && !isCreatingTag) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n setIsCreatingTag(true);\n setCurrentTagText(\"\");\n setTagStartPoint({\n path: selection.anchor.path,\n offset: selection.anchor.offset,\n });\n }\n }\n\n if (event.key === \"Enter\" && !event.shiftKey && !isCreatingTag) {\n event.preventDefault();\n const text = serializeToText(editorValue);\n if (text.trim() && onSubmit) {\n onSubmit(text.trim());\n }\n return;\n }\n\n if (\n (event.key === \"Backspace\" || event.key === \"Delete\") &&\n event.ctrlKey\n ) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n const direction =\n event.key === \"Backspace\" ? \"backward\" : \"forward\";\n const pointFn =\n direction === \"backward\" ? Editor.before : Editor.after;\n const point = pointFn(editor, selection, { unit: \"word\" });\n\n if (point) {\n const [tagEntry] = Editor.nodes(editor, {\n at:\n direction === \"backward\"\n ? { anchor: point, focus: selection.anchor }\n : { anchor: selection.anchor, focus: point },\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (tagEntry) {\n event.preventDefault();\n const [tagNode, tagPath] = tagEntry;\n if (SlateElement.isElement(tagNode) && tagNode.type === \"tag\") {\n onTagDelete?.(tagNode.tag);\n }\n Transforms.removeNodes(editor, { at: tagPath });\n return;\n }\n }\n }\n }\n },\n [\n editor,\n editorValue,\n isCreatingTag,\n enableTags,\n completeTag,\n cancelTag,\n onSubmit,\n onTagDelete,\n ]\n );\n\n const renderElement = React.useCallback((props: RenderElementProps) => {\n switch (props.element.type) {\n case \"tag\":\n return (\n <TagElementRenderer\n {...props}\n element={props.element as TagElement}\n />\n );\n default:\n return <DefaultElement {...props} />;\n }\n }, []);\n\n const renderLeaf = React.useCallback((props: RenderLeafProps) => {\n return <Leaf {...props} />;\n }, []);\n\n const lineHeight = 24;\n const minHeight = lineHeight * minRows;\n const maxHeight = lineHeight * maxRows;\n\n return (\n <div\n className={cn(\n \"relative w-full rounded-md\",\n \"bg-transparent\",\n disabled && \"opacity-50 cursor-not-allowed\",\n className\n )}\n >\n <Slate\n editor={editor}\n initialValue={editorValue}\n onChange={handleChange}\n >\n <Editable\n readOnly={disabled}\n placeholder={placeholder}\n renderElement={renderElement}\n renderLeaf={renderLeaf}\n onKeyDown={handleKeyDown}\n className={cn(\n \"w-full outline-none\",\n \"text-foreground placeholder:text-muted-foreground\",\n \"leading-6\",\n \"overflow-y-auto overflow-x-hidden\",\n \"whitespace-pre-wrap break-words\"\n )}\n style={{\n minHeight: `${minHeight}px`,\n maxHeight: `${maxHeight}px`,\n wordBreak: \"break-word\",\n overflowWrap: \"break-word\",\n }}\n spellCheck\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n />\n </Slate>\n\n {isCreatingTag && (\n <div className=\"absolute bottom-full left-0 mb-2 flex items-center gap-2.5 animate-in fade-in-0 slide-in-from-bottom-1 duration-150\">\n <div className=\"flex items-center px-2 py-1 rounded-md border shadow-sm bg-accent/20 border-accent/40\">\n <span className=\"font-bold text-sm text-accent\">#</span>\n <span className=\"text-sm font-medium min-w-[2ch] text-accent\">\n {currentTagText || (\n <span className=\"opacity-50 italic\">tag</span>\n )}\n </span>\n </div>\n <span className=\"text-muted-foreground/80 text-[11px]\">\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mr-1\">\n Enter\n </kbd>\n or\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mx-1\">\n Space\n </kbd>\n to add\n <span className=\"mx-1.5 text-muted-foreground/50\">·</span>\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mr-1\">\n Esc\n </kbd>\n to cancel\n </span>\n </div>\n )}\n </div>\n );\n }\n);\n\nSlateEditor.displayName = \"SlateEditor\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/slate-editor.tsx"],"names":["Range","Editor","SlateElement","Path","Transforms","Text","jsxs","cn","jsx","React","withHistory","withReact","createEditor","ReactEditor","Node","editor","Slate","Editable"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SlateEditor Component\n *\n * A reusable rich text editor primitive based on Slate.js\n * Provides consistent theming and can be used as an alternative to textarea\n */\n\nimport * as React from \"react\";\nimport {\n createEditor,\n Descendant,\n Editor,\n Transforms,\n Text,\n Element as SlateElement,\n Range,\n Node,\n BaseEditor,\n Path,\n} from \"slate\";\nimport {\n Slate,\n Editable,\n withReact,\n ReactEditor,\n RenderElementProps,\n RenderLeafProps,\n} from \"slate-react\";\nimport type { NodeEntry } from \"slate\";\nimport { withHistory, HistoryEditor } from \"slate-history\";\nimport { cn } from \"@optilogic/core\";\n\ntype TagElement = {\n type: \"tag\";\n tag: string;\n children: [{ text: \"\" }];\n};\n\ntype ParagraphElement = {\n type: \"paragraph\";\n children: Descendant[];\n};\n\ntype CustomElement = TagElement | ParagraphElement;\ntype CustomText = { text: string; [key: string]: unknown };\n\nexport type DecoratedRange = Range & { [key: string]: unknown };\n\ndeclare module \"slate\" {\n interface CustomTypes {\n Editor: BaseEditor & ReactEditor & HistoryEditor;\n Element: CustomElement;\n Text: CustomText;\n }\n}\n\nconst isTagElement = (element: CustomElement): element is TagElement => {\n return element.type === \"tag\";\n};\n\nexport interface SlateEditorRef {\n /** Focus the editor */\n focus: () => void;\n /** Clear the editor content */\n clear: () => void;\n /** Get plain text content */\n getText: () => string;\n /** Insert text at cursor */\n insertText: (text: string) => void;\n /** Insert a tag element */\n insertTag: (tag: string) => void;\n}\n\nexport interface SlateEditorProps {\n /** Initial plain text value */\n value?: string;\n /** Callback when content changes (plain text) */\n onChange?: (value: string) => void;\n /** Callback when a tag is created */\n onTagCreate?: (tag: string) => void;\n /** Callback when a tag is deleted */\n onTagDelete?: (tag: string) => void;\n /** Callback when Enter is pressed (without Shift) */\n onSubmit?: (text: string) => void;\n /** Automatically clear the editor after onSubmit is called */\n clearOnSubmit?: boolean;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the editor is disabled */\n disabled?: boolean;\n /** Whether to enable tag detection (# character) */\n enableTags?: boolean;\n /** Minimum number of rows */\n minRows?: number;\n /** Maximum number of rows before scrolling */\n maxRows?: number;\n /** Additional class names */\n className?: string;\n /** Custom decoration function for text ranges */\n decorate?: (entry: NodeEntry) => DecoratedRange[];\n /** Custom leaf renderer for decorated text */\n renderLeaf?: (props: RenderLeafProps) => React.ReactElement;\n}\n\nconst withTags = (editor: Editor) => {\n const { isInline, isVoid, deleteBackward, deleteForward } = editor;\n\n editor.isInline = (element) => {\n return element.type === \"tag\" ? true : isInline(element);\n };\n\n editor.isVoid = (element) => {\n return element.type === \"tag\" ? true : isVoid(element);\n };\n\n editor.deleteBackward = (unit) => {\n const { selection } = editor;\n\n if (selection && Range.isCollapsed(selection)) {\n const [tagEntry] = Editor.nodes(editor, {\n match: (n) =>\n !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === \"tag\",\n });\n\n if (tagEntry) {\n const [, path] = tagEntry;\n const after = Editor.after(editor, path);\n if (after && Path.equals(selection.anchor.path, after.path)) {\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n\n const before = Editor.before(editor, selection);\n if (before) {\n const [beforeTagEntry] = Editor.nodes(editor, {\n at: before,\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (beforeTagEntry) {\n const [, path] = beforeTagEntry;\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n }\n\n deleteBackward(unit);\n };\n\n editor.deleteForward = (unit) => {\n const { selection } = editor;\n\n if (selection && Range.isCollapsed(selection)) {\n const after = Editor.after(editor, selection);\n if (after) {\n const [afterTagEntry] = Editor.nodes(editor, {\n at: after,\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (afterTagEntry) {\n const [, path] = afterTagEntry;\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n }\n\n deleteForward(unit);\n };\n\n return editor;\n};\n\n/**\n * Convert Slate content to plain text\n */\nexport function serializeToText(nodes: Descendant[]): string {\n return nodes\n .map((n) => {\n if (Text.isText(n)) {\n return n.text;\n }\n if (SlateElement.isElement(n)) {\n if (n.type === \"tag\") {\n return `#${n.tag}`;\n }\n return serializeToText(n.children);\n }\n return \"\";\n })\n .join(\"\");\n}\n\n/**\n * Convert plain text to Slate nodes (preserving existing tags)\n */\nexport function deserializeFromText(text: string): Descendant[] {\n if (!text) {\n return [{ type: \"paragraph\", children: [{ text: \"\" }] }];\n }\n\n const children: Descendant[] = [];\n const tagRegex = /#([a-zA-Z0-9@#$_-]+(?:--[a-zA-Z0-9_-]+)?)/g;\n let lastIndex = 0;\n let match;\n\n while ((match = tagRegex.exec(text)) !== null) {\n if (match.index > lastIndex) {\n children.push({ text: text.substring(lastIndex, match.index) });\n }\n\n children.push({\n type: \"tag\",\n tag: match[1],\n children: [{ text: \"\" }],\n });\n\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < text.length) {\n children.push({ text: text.substring(lastIndex) });\n }\n\n if (children.length === 0) {\n children.push({ text: \"\" });\n }\n\n return [{ type: \"paragraph\", children }];\n}\n\nconst TagElementRenderer = ({\n attributes,\n children,\n element,\n}: RenderElementProps & { element: TagElement }) => {\n return (\n <span\n {...attributes}\n contentEditable={false}\n className={cn(\n \"inline-flex items-center\",\n \"px-1.5 py-0.5 mx-0.5\",\n \"rounded-md border\",\n \"bg-accent/20 text-accent border-accent/40\",\n \"text-sm font-medium\",\n \"select-none cursor-default\"\n )}\n >\n <span className=\"font-bold\">#</span>\n {element.tag}\n {children}\n </span>\n );\n};\n\nconst DefaultElement = ({ attributes, children }: RenderElementProps) => {\n return <p {...attributes}>{children}</p>;\n};\n\nconst Leaf = ({ attributes, children }: RenderLeafProps) => {\n return <span {...attributes}>{children}</span>;\n};\n\n/**\n * SlateEditor component\n *\n * A rich text editor based on Slate.js with support for inline tags.\n * Can be used as a drop-in replacement for textarea with enhanced features.\n *\n * @example\n * <SlateEditor\n * value={content}\n * onChange={setContent}\n * placeholder=\"Type your message...\"\n * onSubmit={(text) => console.log('Submitted:', text)}\n * />\n */\nexport const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(\n (\n {\n value = \"\",\n onChange,\n onTagCreate,\n onTagDelete,\n onSubmit,\n clearOnSubmit = false,\n placeholder = \"Type something...\",\n disabled = false,\n enableTags = true,\n minRows = 3,\n maxRows = 8,\n className,\n decorate,\n renderLeaf: customRenderLeaf,\n },\n ref\n ) => {\n const editor = React.useMemo(\n () => withTags(withHistory(withReact(createEditor()))),\n []\n );\n\n const [isCreatingTag, setIsCreatingTag] = React.useState(false);\n const [tagStartPoint, setTagStartPoint] = React.useState<{\n path: Path;\n offset: number;\n } | null>(null);\n const [currentTagText, setCurrentTagText] = React.useState(\"\");\n\n const [editorValue, setEditorValue] = React.useState<Descendant[]>(() =>\n deserializeFromText(value)\n );\n\n // Track the last value we sent via onChange to distinguish user input from external prop changes\n const lastOnChangeValue = React.useRef<string>(value);\n\n // Get the editable DOM element from the editor\n const getEditableElement = React.useCallback(() => {\n try {\n return ReactEditor.toDOMNode(editor, editor) as HTMLElement;\n } catch {\n return null;\n }\n }, [editor]);\n\n const resetEditorContent = React.useCallback(\n (newContent: Descendant[]) => {\n // Save scroll position before resetting content\n const el = getEditableElement();\n const savedScroll = el\n ? { top: el.scrollTop, left: el.scrollLeft }\n : null;\n\n Editor.withoutNormalizing(editor, () => {\n // Remove all existing nodes\n while (editor.children.length > 0) {\n Transforms.removeNodes(editor, { at: [0] });\n }\n // Insert new content\n Transforms.insertNodes(editor, newContent, { at: [0] });\n });\n\n setEditorValue(newContent);\n\n // Set selection to start safely\n const point = { path: [0, 0], offset: 0 };\n Transforms.select(editor, { anchor: point, focus: point });\n\n // Restore scroll position after content reset (use requestAnimationFrame to ensure DOM is updated)\n if (savedScroll && el) {\n requestAnimationFrame(() => {\n el.scrollTop = savedScroll.top;\n el.scrollLeft = savedScroll.left;\n });\n }\n },\n [editor, getEditableElement]\n );\n\n React.useEffect(() => {\n // Only reset content if value changed externally (not from our own onChange)\n // This prevents scroll position reset during user typing\n if (value !== lastOnChangeValue.current) {\n const currentText = serializeToText(editor.children as Descendant[]);\n if (currentText !== value) {\n const newValue = deserializeFromText(value);\n resetEditorContent(newValue);\n }\n lastOnChangeValue.current = value;\n }\n }, [value, editor, resetEditorContent]);\n\n React.useImperativeHandle(\n ref,\n () => ({\n focus: () => {\n ReactEditor.focus(editor);\n },\n clear: () => {\n const emptyValue: Descendant[] = [\n { type: \"paragraph\", children: [{ text: \"\" }] },\n ];\n resetEditorContent(emptyValue);\n onChange?.(\"\");\n },\n getText: () => serializeToText(editor.children as Descendant[]),\n insertText: (text: string) => {\n Transforms.insertText(editor, text);\n },\n insertTag: (tag: string) => {\n insertTag(editor, tag);\n onTagCreate?.(tag);\n },\n }),\n [editor, onTagCreate, resetEditorContent, onChange]\n );\n\n const handleChange = React.useCallback(\n (newValue: Descendant[]) => {\n if (isCreatingTag && tagStartPoint) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n const currentPath = selection.anchor.path;\n const currentOffset = selection.anchor.offset;\n\n if (Path.equals(currentPath, tagStartPoint.path)) {\n try {\n const [textNode] = Editor.node(editor, currentPath);\n if (Text.isText(textNode)) {\n const tagText = textNode.text.substring(\n tagStartPoint.offset + 1,\n currentOffset\n );\n setCurrentTagText(tagText);\n }\n } catch {\n // Ignore - node may not exist\n }\n }\n }\n }\n\n const oldTags = new Set<string>();\n const newTags = new Set<string>();\n\n for (const node of Node.descendants(editor, {\n from: [],\n pass: ([n]) => SlateElement.isElement(n) && n.type === \"paragraph\",\n })) {\n const [n] = node;\n if (SlateElement.isElement(n) && n.type === \"tag\") {\n oldTags.add(n.tag);\n }\n }\n\n const extractTags = (nodes: Descendant[]) => {\n for (const node of nodes) {\n if (SlateElement.isElement(node)) {\n if (node.type === \"tag\") {\n newTags.add(node.tag);\n }\n if (\"children\" in node) {\n extractTags(node.children);\n }\n }\n }\n };\n extractTags(newValue);\n\n for (const tag of oldTags) {\n if (!newTags.has(tag)) {\n onTagDelete?.(tag);\n }\n }\n\n const text = serializeToText(newValue);\n lastOnChangeValue.current = text;\n onChange?.(text);\n },\n [editor, onChange, onTagDelete, isCreatingTag, tagStartPoint]\n );\n\n const insertTag = (editor: Editor, tag: string) => {\n const tagNode: TagElement = {\n type: \"tag\",\n tag,\n children: [{ text: \"\" }],\n };\n Transforms.insertNodes(editor, tagNode);\n Transforms.move(editor);\n Transforms.insertText(editor, \" \");\n };\n\n const completeTag = React.useCallback(() => {\n if (!isCreatingTag || !tagStartPoint) return;\n\n const { selection } = editor;\n if (!selection || !Range.isCollapsed(selection)) return;\n\n const currentPath = selection.anchor.path;\n const currentOffset = selection.anchor.offset;\n\n if (!Path.equals(currentPath, tagStartPoint.path)) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const [textNode] = Editor.node(editor, currentPath);\n if (!Text.isText(textNode)) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const tagText = textNode.text.substring(\n tagStartPoint.offset + 1,\n currentOffset\n );\n\n if (!tagText.trim()) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const start = { path: currentPath, offset: tagStartPoint.offset };\n const end = { path: currentPath, offset: currentOffset };\n\n Transforms.delete(editor, { at: { anchor: start, focus: end } });\n insertTag(editor, tagText.trim());\n\n onTagCreate?.(tagText.trim());\n\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n }, [editor, isCreatingTag, tagStartPoint, onTagCreate]);\n\n const cancelTag = React.useCallback(() => {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n }, []);\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (isCreatingTag) {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n completeTag();\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n cancelTag();\n return;\n }\n }\n\n if (enableTags && event.key === \"#\" && !isCreatingTag) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n setIsCreatingTag(true);\n setCurrentTagText(\"\");\n setTagStartPoint({\n path: selection.anchor.path,\n offset: selection.anchor.offset,\n });\n }\n }\n\n if (event.key === \"Enter\" && !event.shiftKey && !isCreatingTag) {\n event.preventDefault();\n const text = serializeToText(editor.children as Descendant[]);\n if (text.trim() && onSubmit) {\n onSubmit(text.trim());\n if (clearOnSubmit) {\n const emptyValue: Descendant[] = [\n { type: \"paragraph\", children: [{ text: \"\" }] },\n ];\n resetEditorContent(emptyValue);\n onChange?.(\"\");\n }\n }\n return;\n }\n\n // Shift+Enter: Insert soft line break (newline character) instead of new paragraph\n if (event.key === \"Enter\" && event.shiftKey) {\n event.preventDefault();\n const el = getEditableElement();\n const savedScrollTop = el?.scrollTop ?? 0;\n\n Transforms.insertText(editor, \"\\n\");\n\n // Restore scroll position immediately and after paint to prevent jump\n if (el) {\n el.scrollTop = savedScrollTop;\n requestAnimationFrame(() => {\n el.scrollTop = savedScrollTop;\n });\n }\n return;\n }\n\n if (\n (event.key === \"Backspace\" || event.key === \"Delete\") &&\n event.ctrlKey\n ) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n const direction =\n event.key === \"Backspace\" ? \"backward\" : \"forward\";\n const pointFn =\n direction === \"backward\" ? Editor.before : Editor.after;\n const point = pointFn(editor, selection, { unit: \"word\" });\n\n if (point) {\n const [tagEntry] = Editor.nodes(editor, {\n at:\n direction === \"backward\"\n ? { anchor: point, focus: selection.anchor }\n : { anchor: selection.anchor, focus: point },\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (tagEntry) {\n event.preventDefault();\n const [tagNode, tagPath] = tagEntry;\n if (SlateElement.isElement(tagNode) && tagNode.type === \"tag\") {\n onTagDelete?.(tagNode.tag);\n }\n Transforms.removeNodes(editor, { at: tagPath });\n return;\n }\n }\n }\n }\n },\n [\n editor,\n isCreatingTag,\n enableTags,\n completeTag,\n cancelTag,\n onSubmit,\n onTagDelete,\n clearOnSubmit,\n resetEditorContent,\n onChange,\n getEditableElement,\n ]\n );\n\n const renderElement = React.useCallback((props: RenderElementProps) => {\n switch (props.element.type) {\n case \"tag\":\n return (\n <TagElementRenderer\n {...props}\n element={props.element as TagElement}\n />\n );\n default:\n return <DefaultElement {...props} />;\n }\n }, []);\n\n const renderLeaf = React.useCallback(\n (props: RenderLeafProps) => {\n if (customRenderLeaf) {\n return customRenderLeaf(props);\n }\n return <Leaf {...props} />;\n },\n [customRenderLeaf]\n );\n\n const lineHeight = 24;\n const minHeight = lineHeight * minRows;\n const maxHeight = lineHeight * maxRows;\n\n return (\n <div\n className={cn(\n \"relative w-full rounded-md\",\n \"bg-transparent\",\n disabled && \"opacity-50 cursor-not-allowed\",\n className\n )}\n >\n <Slate\n editor={editor}\n initialValue={editorValue}\n onChange={handleChange}\n >\n <Editable\n readOnly={disabled}\n placeholder={placeholder}\n renderElement={renderElement}\n renderLeaf={renderLeaf}\n decorate={decorate}\n onKeyDown={handleKeyDown}\n className={cn(\n \"w-full outline-none\",\n \"text-foreground placeholder:text-muted-foreground\",\n \"leading-6\",\n \"overflow-y-auto overflow-x-hidden\",\n \"whitespace-pre-wrap break-words\",\n \"scrollbar-thin\"\n )}\n style={{\n minHeight: `${minHeight}px`,\n maxHeight: `${maxHeight}px`,\n wordBreak: \"break-word\",\n overflowWrap: \"break-word\",\n }}\n spellCheck\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n />\n </Slate>\n\n {isCreatingTag && (\n <div className=\"absolute bottom-full left-0 mb-2 flex items-center gap-2.5 animate-in fade-in-0 slide-in-from-bottom-1 duration-150\">\n <div className=\"flex items-center px-2 py-1 rounded-md border shadow-sm bg-accent/20 border-accent/40\">\n <span className=\"font-bold text-sm text-accent\">#</span>\n <span className=\"text-sm font-medium min-w-[2ch] text-accent\">\n {currentTagText || (\n <span className=\"opacity-50 italic\">tag</span>\n )}\n </span>\n </div>\n <span className=\"text-muted-foreground/80 text-[11px]\">\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mr-1\">\n Enter\n </kbd>\n or\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mx-1\">\n Space\n </kbd>\n to add\n <span className=\"mx-1.5 text-muted-foreground/50\">·</span>\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mr-1\">\n Esc\n </kbd>\n to cancel\n </span>\n </div>\n )}\n </div>\n );\n }\n);\n\nSlateEditor.displayName = \"SlateEditor\";\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { BaseEditor, Descendant } from 'slate';
|
|
3
|
-
|
|
2
|
+
import { BaseEditor, Descendant, NodeEntry, Range } from 'slate';
|
|
3
|
+
export { NodeEntry, Range, Text } from 'slate';
|
|
4
|
+
import { ReactEditor, RenderLeafProps } from 'slate-react';
|
|
5
|
+
export { RenderLeafProps } from 'slate-react';
|
|
4
6
|
import { HistoryEditor } from 'slate-history';
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -24,6 +26,10 @@ type ParagraphElement = {
|
|
|
24
26
|
type CustomElement = TagElement | ParagraphElement;
|
|
25
27
|
type CustomText = {
|
|
26
28
|
text: string;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
type DecoratedRange = Range & {
|
|
32
|
+
[key: string]: unknown;
|
|
27
33
|
};
|
|
28
34
|
declare module "slate" {
|
|
29
35
|
interface CustomTypes {
|
|
@@ -55,6 +61,8 @@ interface SlateEditorProps {
|
|
|
55
61
|
onTagDelete?: (tag: string) => void;
|
|
56
62
|
/** Callback when Enter is pressed (without Shift) */
|
|
57
63
|
onSubmit?: (text: string) => void;
|
|
64
|
+
/** Automatically clear the editor after onSubmit is called */
|
|
65
|
+
clearOnSubmit?: boolean;
|
|
58
66
|
/** Placeholder text */
|
|
59
67
|
placeholder?: string;
|
|
60
68
|
/** Whether the editor is disabled */
|
|
@@ -67,6 +75,10 @@ interface SlateEditorProps {
|
|
|
67
75
|
maxRows?: number;
|
|
68
76
|
/** Additional class names */
|
|
69
77
|
className?: string;
|
|
78
|
+
/** Custom decoration function for text ranges */
|
|
79
|
+
decorate?: (entry: NodeEntry) => DecoratedRange[];
|
|
80
|
+
/** Custom leaf renderer for decorated text */
|
|
81
|
+
renderLeaf?: (props: RenderLeafProps) => React.ReactElement;
|
|
70
82
|
}
|
|
71
83
|
/**
|
|
72
84
|
* Convert Slate content to plain text
|
|
@@ -92,4 +104,4 @@ declare function deserializeFromText(text: string): Descendant[];
|
|
|
92
104
|
*/
|
|
93
105
|
declare const SlateEditor: React.ForwardRefExoticComponent<SlateEditorProps & React.RefAttributes<SlateEditorRef>>;
|
|
94
106
|
|
|
95
|
-
export { SlateEditor, type SlateEditorProps, type SlateEditorRef, deserializeFromText, serializeToText };
|
|
107
|
+
export { type DecoratedRange, SlateEditor, type SlateEditorProps, type SlateEditorRef, deserializeFromText, serializeToText };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { BaseEditor, Descendant } from 'slate';
|
|
3
|
-
|
|
2
|
+
import { BaseEditor, Descendant, NodeEntry, Range } from 'slate';
|
|
3
|
+
export { NodeEntry, Range, Text } from 'slate';
|
|
4
|
+
import { ReactEditor, RenderLeafProps } from 'slate-react';
|
|
5
|
+
export { RenderLeafProps } from 'slate-react';
|
|
4
6
|
import { HistoryEditor } from 'slate-history';
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -24,6 +26,10 @@ type ParagraphElement = {
|
|
|
24
26
|
type CustomElement = TagElement | ParagraphElement;
|
|
25
27
|
type CustomText = {
|
|
26
28
|
text: string;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
type DecoratedRange = Range & {
|
|
32
|
+
[key: string]: unknown;
|
|
27
33
|
};
|
|
28
34
|
declare module "slate" {
|
|
29
35
|
interface CustomTypes {
|
|
@@ -55,6 +61,8 @@ interface SlateEditorProps {
|
|
|
55
61
|
onTagDelete?: (tag: string) => void;
|
|
56
62
|
/** Callback when Enter is pressed (without Shift) */
|
|
57
63
|
onSubmit?: (text: string) => void;
|
|
64
|
+
/** Automatically clear the editor after onSubmit is called */
|
|
65
|
+
clearOnSubmit?: boolean;
|
|
58
66
|
/** Placeholder text */
|
|
59
67
|
placeholder?: string;
|
|
60
68
|
/** Whether the editor is disabled */
|
|
@@ -67,6 +75,10 @@ interface SlateEditorProps {
|
|
|
67
75
|
maxRows?: number;
|
|
68
76
|
/** Additional class names */
|
|
69
77
|
className?: string;
|
|
78
|
+
/** Custom decoration function for text ranges */
|
|
79
|
+
decorate?: (entry: NodeEntry) => DecoratedRange[];
|
|
80
|
+
/** Custom leaf renderer for decorated text */
|
|
81
|
+
renderLeaf?: (props: RenderLeafProps) => React.ReactElement;
|
|
70
82
|
}
|
|
71
83
|
/**
|
|
72
84
|
* Convert Slate content to plain text
|
|
@@ -92,4 +104,4 @@ declare function deserializeFromText(text: string): Descendant[];
|
|
|
92
104
|
*/
|
|
93
105
|
declare const SlateEditor: React.ForwardRefExoticComponent<SlateEditorProps & React.RefAttributes<SlateEditorRef>>;
|
|
94
106
|
|
|
95
|
-
export { SlateEditor, type SlateEditorProps, type SlateEditorRef, deserializeFromText, serializeToText };
|
|
107
|
+
export { type DecoratedRange, SlateEditor, type SlateEditorProps, type SlateEditorRef, deserializeFromText, serializeToText };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { createEditor,
|
|
2
|
+
import { createEditor, Editor, Transforms, Range, Path, Text, Node, Element } from 'slate';
|
|
3
|
+
export { Range, Text } from 'slate';
|
|
3
4
|
import { withReact, ReactEditor, Slate, Editable } from 'slate-react';
|
|
4
5
|
import { withHistory } from 'slate-history';
|
|
5
6
|
import { cn } from '@optilogic/core';
|
|
@@ -143,12 +144,15 @@ var SlateEditor = React.forwardRef(
|
|
|
143
144
|
onTagCreate,
|
|
144
145
|
onTagDelete,
|
|
145
146
|
onSubmit,
|
|
147
|
+
clearOnSubmit = false,
|
|
146
148
|
placeholder = "Type something...",
|
|
147
149
|
disabled = false,
|
|
148
150
|
enableTags = true,
|
|
149
151
|
minRows = 3,
|
|
150
152
|
maxRows = 8,
|
|
151
|
-
className
|
|
153
|
+
className,
|
|
154
|
+
decorate,
|
|
155
|
+
renderLeaf: customRenderLeaf
|
|
152
156
|
}, ref) => {
|
|
153
157
|
const editor = React.useMemo(
|
|
154
158
|
() => withTags(withHistory(withReact(createEditor()))),
|
|
@@ -160,16 +164,46 @@ var SlateEditor = React.forwardRef(
|
|
|
160
164
|
const [editorValue, setEditorValue] = React.useState(
|
|
161
165
|
() => deserializeFromText(value)
|
|
162
166
|
);
|
|
167
|
+
const lastOnChangeValue = React.useRef(value);
|
|
168
|
+
const getEditableElement = React.useCallback(() => {
|
|
169
|
+
try {
|
|
170
|
+
return ReactEditor.toDOMNode(editor, editor);
|
|
171
|
+
} catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}, [editor]);
|
|
175
|
+
const resetEditorContent = React.useCallback(
|
|
176
|
+
(newContent) => {
|
|
177
|
+
const el = getEditableElement();
|
|
178
|
+
const savedScroll = el ? { top: el.scrollTop, left: el.scrollLeft } : null;
|
|
179
|
+
Editor.withoutNormalizing(editor, () => {
|
|
180
|
+
while (editor.children.length > 0) {
|
|
181
|
+
Transforms.removeNodes(editor, { at: [0] });
|
|
182
|
+
}
|
|
183
|
+
Transforms.insertNodes(editor, newContent, { at: [0] });
|
|
184
|
+
});
|
|
185
|
+
setEditorValue(newContent);
|
|
186
|
+
const point = { path: [0, 0], offset: 0 };
|
|
187
|
+
Transforms.select(editor, { anchor: point, focus: point });
|
|
188
|
+
if (savedScroll && el) {
|
|
189
|
+
requestAnimationFrame(() => {
|
|
190
|
+
el.scrollTop = savedScroll.top;
|
|
191
|
+
el.scrollLeft = savedScroll.left;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
[editor, getEditableElement]
|
|
196
|
+
);
|
|
163
197
|
React.useEffect(() => {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
198
|
+
if (value !== lastOnChangeValue.current) {
|
|
199
|
+
const currentText = serializeToText(editor.children);
|
|
200
|
+
if (currentText !== value) {
|
|
201
|
+
const newValue = deserializeFromText(value);
|
|
202
|
+
resetEditorContent(newValue);
|
|
203
|
+
}
|
|
204
|
+
lastOnChangeValue.current = value;
|
|
171
205
|
}
|
|
172
|
-
}, [value, editor]);
|
|
206
|
+
}, [value, editor, resetEditorContent]);
|
|
173
207
|
React.useImperativeHandle(
|
|
174
208
|
ref,
|
|
175
209
|
() => ({
|
|
@@ -177,13 +211,13 @@ var SlateEditor = React.forwardRef(
|
|
|
177
211
|
ReactEditor.focus(editor);
|
|
178
212
|
},
|
|
179
213
|
clear: () => {
|
|
180
|
-
const
|
|
214
|
+
const emptyValue = [
|
|
181
215
|
{ type: "paragraph", children: [{ text: "" }] }
|
|
182
216
|
];
|
|
183
|
-
|
|
184
|
-
|
|
217
|
+
resetEditorContent(emptyValue);
|
|
218
|
+
onChange?.("");
|
|
185
219
|
},
|
|
186
|
-
getText: () => serializeToText(
|
|
220
|
+
getText: () => serializeToText(editor.children),
|
|
187
221
|
insertText: (text) => {
|
|
188
222
|
Transforms.insertText(editor, text);
|
|
189
223
|
},
|
|
@@ -192,11 +226,10 @@ var SlateEditor = React.forwardRef(
|
|
|
192
226
|
onTagCreate?.(tag);
|
|
193
227
|
}
|
|
194
228
|
}),
|
|
195
|
-
[editor,
|
|
229
|
+
[editor, onTagCreate, resetEditorContent, onChange]
|
|
196
230
|
);
|
|
197
231
|
const handleChange = React.useCallback(
|
|
198
232
|
(newValue) => {
|
|
199
|
-
setEditorValue(newValue);
|
|
200
233
|
if (isCreatingTag && tagStartPoint) {
|
|
201
234
|
const { selection } = editor;
|
|
202
235
|
if (selection && Range.isCollapsed(selection)) {
|
|
@@ -247,6 +280,7 @@ var SlateEditor = React.forwardRef(
|
|
|
247
280
|
}
|
|
248
281
|
}
|
|
249
282
|
const text = serializeToText(newValue);
|
|
283
|
+
lastOnChangeValue.current = text;
|
|
250
284
|
onChange?.(text);
|
|
251
285
|
},
|
|
252
286
|
[editor, onChange, onTagDelete, isCreatingTag, tagStartPoint]
|
|
@@ -331,9 +365,29 @@ var SlateEditor = React.forwardRef(
|
|
|
331
365
|
}
|
|
332
366
|
if (event.key === "Enter" && !event.shiftKey && !isCreatingTag) {
|
|
333
367
|
event.preventDefault();
|
|
334
|
-
const text = serializeToText(
|
|
368
|
+
const text = serializeToText(editor.children);
|
|
335
369
|
if (text.trim() && onSubmit) {
|
|
336
370
|
onSubmit(text.trim());
|
|
371
|
+
if (clearOnSubmit) {
|
|
372
|
+
const emptyValue = [
|
|
373
|
+
{ type: "paragraph", children: [{ text: "" }] }
|
|
374
|
+
];
|
|
375
|
+
resetEditorContent(emptyValue);
|
|
376
|
+
onChange?.("");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (event.key === "Enter" && event.shiftKey) {
|
|
382
|
+
event.preventDefault();
|
|
383
|
+
const el = getEditableElement();
|
|
384
|
+
const savedScrollTop = el?.scrollTop ?? 0;
|
|
385
|
+
Transforms.insertText(editor, "\n");
|
|
386
|
+
if (el) {
|
|
387
|
+
el.scrollTop = savedScrollTop;
|
|
388
|
+
requestAnimationFrame(() => {
|
|
389
|
+
el.scrollTop = savedScrollTop;
|
|
390
|
+
});
|
|
337
391
|
}
|
|
338
392
|
return;
|
|
339
393
|
}
|
|
@@ -363,13 +417,16 @@ var SlateEditor = React.forwardRef(
|
|
|
363
417
|
},
|
|
364
418
|
[
|
|
365
419
|
editor,
|
|
366
|
-
editorValue,
|
|
367
420
|
isCreatingTag,
|
|
368
421
|
enableTags,
|
|
369
422
|
completeTag,
|
|
370
423
|
cancelTag,
|
|
371
424
|
onSubmit,
|
|
372
|
-
onTagDelete
|
|
425
|
+
onTagDelete,
|
|
426
|
+
clearOnSubmit,
|
|
427
|
+
resetEditorContent,
|
|
428
|
+
onChange,
|
|
429
|
+
getEditableElement
|
|
373
430
|
]
|
|
374
431
|
);
|
|
375
432
|
const renderElement = React.useCallback((props) => {
|
|
@@ -386,9 +443,15 @@ var SlateEditor = React.forwardRef(
|
|
|
386
443
|
return /* @__PURE__ */ jsx(DefaultElement, { ...props });
|
|
387
444
|
}
|
|
388
445
|
}, []);
|
|
389
|
-
const renderLeaf = React.useCallback(
|
|
390
|
-
|
|
391
|
-
|
|
446
|
+
const renderLeaf = React.useCallback(
|
|
447
|
+
(props) => {
|
|
448
|
+
if (customRenderLeaf) {
|
|
449
|
+
return customRenderLeaf(props);
|
|
450
|
+
}
|
|
451
|
+
return /* @__PURE__ */ jsx(Leaf, { ...props });
|
|
452
|
+
},
|
|
453
|
+
[customRenderLeaf]
|
|
454
|
+
);
|
|
392
455
|
const lineHeight = 24;
|
|
393
456
|
const minHeight = lineHeight * minRows;
|
|
394
457
|
const maxHeight = lineHeight * maxRows;
|
|
@@ -415,13 +478,15 @@ var SlateEditor = React.forwardRef(
|
|
|
415
478
|
placeholder,
|
|
416
479
|
renderElement,
|
|
417
480
|
renderLeaf,
|
|
481
|
+
decorate,
|
|
418
482
|
onKeyDown: handleKeyDown,
|
|
419
483
|
className: cn(
|
|
420
484
|
"w-full outline-none",
|
|
421
485
|
"text-foreground placeholder:text-muted-foreground",
|
|
422
486
|
"leading-6",
|
|
423
487
|
"overflow-y-auto overflow-x-hidden",
|
|
424
|
-
"whitespace-pre-wrap break-words"
|
|
488
|
+
"whitespace-pre-wrap break-words",
|
|
489
|
+
"scrollbar-thin"
|
|
425
490
|
),
|
|
426
491
|
style: {
|
|
427
492
|
minHeight: `${minHeight}px`,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/slate-editor.tsx"],"names":["SlateElement","editor"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * SlateEditor Component\n *\n * A reusable rich text editor primitive based on Slate.js\n * Provides consistent theming and can be used as an alternative to textarea\n */\n\nimport * as React from \"react\";\nimport {\n createEditor,\n Descendant,\n Editor,\n Transforms,\n Text,\n Element as SlateElement,\n Range,\n Node,\n BaseEditor,\n Path,\n} from \"slate\";\nimport {\n Slate,\n Editable,\n withReact,\n ReactEditor,\n RenderElementProps,\n RenderLeafProps,\n} from \"slate-react\";\nimport { withHistory, HistoryEditor } from \"slate-history\";\nimport { cn } from \"@optilogic/core\";\n\ntype TagElement = {\n type: \"tag\";\n tag: string;\n children: [{ text: \"\" }];\n};\n\ntype ParagraphElement = {\n type: \"paragraph\";\n children: Descendant[];\n};\n\ntype CustomElement = TagElement | ParagraphElement;\ntype CustomText = { text: string };\n\ndeclare module \"slate\" {\n interface CustomTypes {\n Editor: BaseEditor & ReactEditor & HistoryEditor;\n Element: CustomElement;\n Text: CustomText;\n }\n}\n\nconst isTagElement = (element: CustomElement): element is TagElement => {\n return element.type === \"tag\";\n};\n\nexport interface SlateEditorRef {\n /** Focus the editor */\n focus: () => void;\n /** Clear the editor content */\n clear: () => void;\n /** Get plain text content */\n getText: () => string;\n /** Insert text at cursor */\n insertText: (text: string) => void;\n /** Insert a tag element */\n insertTag: (tag: string) => void;\n}\n\nexport interface SlateEditorProps {\n /** Initial plain text value */\n value?: string;\n /** Callback when content changes (plain text) */\n onChange?: (value: string) => void;\n /** Callback when a tag is created */\n onTagCreate?: (tag: string) => void;\n /** Callback when a tag is deleted */\n onTagDelete?: (tag: string) => void;\n /** Callback when Enter is pressed (without Shift) */\n onSubmit?: (text: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the editor is disabled */\n disabled?: boolean;\n /** Whether to enable tag detection (# character) */\n enableTags?: boolean;\n /** Minimum number of rows */\n minRows?: number;\n /** Maximum number of rows before scrolling */\n maxRows?: number;\n /** Additional class names */\n className?: string;\n}\n\nconst withTags = (editor: Editor) => {\n const { isInline, isVoid, deleteBackward, deleteForward } = editor;\n\n editor.isInline = (element) => {\n return element.type === \"tag\" ? true : isInline(element);\n };\n\n editor.isVoid = (element) => {\n return element.type === \"tag\" ? true : isVoid(element);\n };\n\n editor.deleteBackward = (unit) => {\n const { selection } = editor;\n\n if (selection && Range.isCollapsed(selection)) {\n const [tagEntry] = Editor.nodes(editor, {\n match: (n) =>\n !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === \"tag\",\n });\n\n if (tagEntry) {\n const [, path] = tagEntry;\n const after = Editor.after(editor, path);\n if (after && Path.equals(selection.anchor.path, after.path)) {\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n\n const before = Editor.before(editor, selection);\n if (before) {\n const [beforeTagEntry] = Editor.nodes(editor, {\n at: before,\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (beforeTagEntry) {\n const [, path] = beforeTagEntry;\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n }\n\n deleteBackward(unit);\n };\n\n editor.deleteForward = (unit) => {\n const { selection } = editor;\n\n if (selection && Range.isCollapsed(selection)) {\n const after = Editor.after(editor, selection);\n if (after) {\n const [afterTagEntry] = Editor.nodes(editor, {\n at: after,\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (afterTagEntry) {\n const [, path] = afterTagEntry;\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n }\n\n deleteForward(unit);\n };\n\n return editor;\n};\n\n/**\n * Convert Slate content to plain text\n */\nexport function serializeToText(nodes: Descendant[]): string {\n return nodes\n .map((n) => {\n if (Text.isText(n)) {\n return n.text;\n }\n if (SlateElement.isElement(n)) {\n if (n.type === \"tag\") {\n return `#${n.tag}`;\n }\n return serializeToText(n.children);\n }\n return \"\";\n })\n .join(\"\");\n}\n\n/**\n * Convert plain text to Slate nodes (preserving existing tags)\n */\nexport function deserializeFromText(text: string): Descendant[] {\n if (!text) {\n return [{ type: \"paragraph\", children: [{ text: \"\" }] }];\n }\n\n const children: Descendant[] = [];\n const tagRegex = /#([a-zA-Z0-9@#$_-]+(?:--[a-zA-Z0-9_-]+)?)/g;\n let lastIndex = 0;\n let match;\n\n while ((match = tagRegex.exec(text)) !== null) {\n if (match.index > lastIndex) {\n children.push({ text: text.substring(lastIndex, match.index) });\n }\n\n children.push({\n type: \"tag\",\n tag: match[1],\n children: [{ text: \"\" }],\n });\n\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < text.length) {\n children.push({ text: text.substring(lastIndex) });\n }\n\n if (children.length === 0) {\n children.push({ text: \"\" });\n }\n\n return [{ type: \"paragraph\", children }];\n}\n\nconst TagElementRenderer = ({\n attributes,\n children,\n element,\n}: RenderElementProps & { element: TagElement }) => {\n return (\n <span\n {...attributes}\n contentEditable={false}\n className={cn(\n \"inline-flex items-center\",\n \"px-1.5 py-0.5 mx-0.5\",\n \"rounded-md border\",\n \"bg-accent/20 text-accent border-accent/40\",\n \"text-sm font-medium\",\n \"select-none cursor-default\"\n )}\n >\n <span className=\"font-bold\">#</span>\n {element.tag}\n {children}\n </span>\n );\n};\n\nconst DefaultElement = ({ attributes, children }: RenderElementProps) => {\n return <p {...attributes}>{children}</p>;\n};\n\nconst Leaf = ({ attributes, children }: RenderLeafProps) => {\n return <span {...attributes}>{children}</span>;\n};\n\n/**\n * SlateEditor component\n *\n * A rich text editor based on Slate.js with support for inline tags.\n * Can be used as a drop-in replacement for textarea with enhanced features.\n *\n * @example\n * <SlateEditor\n * value={content}\n * onChange={setContent}\n * placeholder=\"Type your message...\"\n * onSubmit={(text) => console.log('Submitted:', text)}\n * />\n */\nexport const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(\n (\n {\n value = \"\",\n onChange,\n onTagCreate,\n onTagDelete,\n onSubmit,\n placeholder = \"Type something...\",\n disabled = false,\n enableTags = true,\n minRows = 3,\n maxRows = 8,\n className,\n },\n ref\n ) => {\n const editor = React.useMemo(\n () => withTags(withHistory(withReact(createEditor()))),\n []\n );\n\n const [isCreatingTag, setIsCreatingTag] = React.useState(false);\n const [tagStartPoint, setTagStartPoint] = React.useState<{\n path: Path;\n offset: number;\n } | null>(null);\n const [currentTagText, setCurrentTagText] = React.useState(\"\");\n\n const [editorValue, setEditorValue] = React.useState<Descendant[]>(() =>\n deserializeFromText(value)\n );\n\n React.useEffect(() => {\n const newValue = deserializeFromText(value);\n const currentText = serializeToText(editorValue);\n if (currentText !== value) {\n setEditorValue(newValue);\n Transforms.removeNodes(editor, { at: [] });\n Transforms.insertNodes(editor, newValue, { at: [0] });\n Transforms.select(editor, Editor.start(editor, []));\n }\n }, [value, editor]);\n\n React.useImperativeHandle(\n ref,\n () => ({\n focus: () => {\n ReactEditor.focus(editor);\n },\n clear: () => {\n const newValue: Descendant[] = [\n { type: \"paragraph\", children: [{ text: \"\" }] },\n ];\n setEditorValue(newValue);\n Transforms.select(editor, Editor.start(editor, []));\n },\n getText: () => serializeToText(editorValue),\n insertText: (text: string) => {\n Transforms.insertText(editor, text);\n },\n insertTag: (tag: string) => {\n insertTag(editor, tag);\n onTagCreate?.(tag);\n },\n }),\n [editor, editorValue, onTagCreate]\n );\n\n const handleChange = React.useCallback(\n (newValue: Descendant[]) => {\n setEditorValue(newValue);\n\n if (isCreatingTag && tagStartPoint) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n const currentPath = selection.anchor.path;\n const currentOffset = selection.anchor.offset;\n\n if (Path.equals(currentPath, tagStartPoint.path)) {\n try {\n const [textNode] = Editor.node(editor, currentPath);\n if (Text.isText(textNode)) {\n const tagText = textNode.text.substring(\n tagStartPoint.offset + 1,\n currentOffset\n );\n setCurrentTagText(tagText);\n }\n } catch {\n // Ignore - node may not exist\n }\n }\n }\n }\n\n const oldTags = new Set<string>();\n const newTags = new Set<string>();\n\n for (const node of Node.descendants(editor, {\n from: [],\n pass: ([n]) => SlateElement.isElement(n) && n.type === \"paragraph\",\n })) {\n const [n] = node;\n if (SlateElement.isElement(n) && n.type === \"tag\") {\n oldTags.add(n.tag);\n }\n }\n\n const extractTags = (nodes: Descendant[]) => {\n for (const node of nodes) {\n if (SlateElement.isElement(node)) {\n if (node.type === \"tag\") {\n newTags.add(node.tag);\n }\n if (\"children\" in node) {\n extractTags(node.children);\n }\n }\n }\n };\n extractTags(newValue);\n\n for (const tag of oldTags) {\n if (!newTags.has(tag)) {\n onTagDelete?.(tag);\n }\n }\n\n const text = serializeToText(newValue);\n onChange?.(text);\n },\n [editor, onChange, onTagDelete, isCreatingTag, tagStartPoint]\n );\n\n const insertTag = (editor: Editor, tag: string) => {\n const tagNode: TagElement = {\n type: \"tag\",\n tag,\n children: [{ text: \"\" }],\n };\n Transforms.insertNodes(editor, tagNode);\n Transforms.move(editor);\n Transforms.insertText(editor, \" \");\n };\n\n const completeTag = React.useCallback(() => {\n if (!isCreatingTag || !tagStartPoint) return;\n\n const { selection } = editor;\n if (!selection || !Range.isCollapsed(selection)) return;\n\n const currentPath = selection.anchor.path;\n const currentOffset = selection.anchor.offset;\n\n if (!Path.equals(currentPath, tagStartPoint.path)) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const [textNode] = Editor.node(editor, currentPath);\n if (!Text.isText(textNode)) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const tagText = textNode.text.substring(\n tagStartPoint.offset + 1,\n currentOffset\n );\n\n if (!tagText.trim()) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const start = { path: currentPath, offset: tagStartPoint.offset };\n const end = { path: currentPath, offset: currentOffset };\n\n Transforms.delete(editor, { at: { anchor: start, focus: end } });\n insertTag(editor, tagText.trim());\n\n onTagCreate?.(tagText.trim());\n\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n }, [editor, isCreatingTag, tagStartPoint, onTagCreate]);\n\n const cancelTag = React.useCallback(() => {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n }, []);\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (isCreatingTag) {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n completeTag();\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n cancelTag();\n return;\n }\n }\n\n if (enableTags && event.key === \"#\" && !isCreatingTag) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n setIsCreatingTag(true);\n setCurrentTagText(\"\");\n setTagStartPoint({\n path: selection.anchor.path,\n offset: selection.anchor.offset,\n });\n }\n }\n\n if (event.key === \"Enter\" && !event.shiftKey && !isCreatingTag) {\n event.preventDefault();\n const text = serializeToText(editorValue);\n if (text.trim() && onSubmit) {\n onSubmit(text.trim());\n }\n return;\n }\n\n if (\n (event.key === \"Backspace\" || event.key === \"Delete\") &&\n event.ctrlKey\n ) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n const direction =\n event.key === \"Backspace\" ? \"backward\" : \"forward\";\n const pointFn =\n direction === \"backward\" ? Editor.before : Editor.after;\n const point = pointFn(editor, selection, { unit: \"word\" });\n\n if (point) {\n const [tagEntry] = Editor.nodes(editor, {\n at:\n direction === \"backward\"\n ? { anchor: point, focus: selection.anchor }\n : { anchor: selection.anchor, focus: point },\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (tagEntry) {\n event.preventDefault();\n const [tagNode, tagPath] = tagEntry;\n if (SlateElement.isElement(tagNode) && tagNode.type === \"tag\") {\n onTagDelete?.(tagNode.tag);\n }\n Transforms.removeNodes(editor, { at: tagPath });\n return;\n }\n }\n }\n }\n },\n [\n editor,\n editorValue,\n isCreatingTag,\n enableTags,\n completeTag,\n cancelTag,\n onSubmit,\n onTagDelete,\n ]\n );\n\n const renderElement = React.useCallback((props: RenderElementProps) => {\n switch (props.element.type) {\n case \"tag\":\n return (\n <TagElementRenderer\n {...props}\n element={props.element as TagElement}\n />\n );\n default:\n return <DefaultElement {...props} />;\n }\n }, []);\n\n const renderLeaf = React.useCallback((props: RenderLeafProps) => {\n return <Leaf {...props} />;\n }, []);\n\n const lineHeight = 24;\n const minHeight = lineHeight * minRows;\n const maxHeight = lineHeight * maxRows;\n\n return (\n <div\n className={cn(\n \"relative w-full rounded-md\",\n \"bg-transparent\",\n disabled && \"opacity-50 cursor-not-allowed\",\n className\n )}\n >\n <Slate\n editor={editor}\n initialValue={editorValue}\n onChange={handleChange}\n >\n <Editable\n readOnly={disabled}\n placeholder={placeholder}\n renderElement={renderElement}\n renderLeaf={renderLeaf}\n onKeyDown={handleKeyDown}\n className={cn(\n \"w-full outline-none\",\n \"text-foreground placeholder:text-muted-foreground\",\n \"leading-6\",\n \"overflow-y-auto overflow-x-hidden\",\n \"whitespace-pre-wrap break-words\"\n )}\n style={{\n minHeight: `${minHeight}px`,\n maxHeight: `${maxHeight}px`,\n wordBreak: \"break-word\",\n overflowWrap: \"break-word\",\n }}\n spellCheck\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n />\n </Slate>\n\n {isCreatingTag && (\n <div className=\"absolute bottom-full left-0 mb-2 flex items-center gap-2.5 animate-in fade-in-0 slide-in-from-bottom-1 duration-150\">\n <div className=\"flex items-center px-2 py-1 rounded-md border shadow-sm bg-accent/20 border-accent/40\">\n <span className=\"font-bold text-sm text-accent\">#</span>\n <span className=\"text-sm font-medium min-w-[2ch] text-accent\">\n {currentTagText || (\n <span className=\"opacity-50 italic\">tag</span>\n )}\n </span>\n </div>\n <span className=\"text-muted-foreground/80 text-[11px]\">\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mr-1\">\n Enter\n </kbd>\n or\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mx-1\">\n Space\n </kbd>\n to add\n <span className=\"mx-1.5 text-muted-foreground/50\">·</span>\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mr-1\">\n Esc\n </kbd>\n to cancel\n </span>\n </div>\n )}\n </div>\n );\n }\n);\n\nSlateEditor.displayName = \"SlateEditor\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/slate-editor.tsx"],"names":["SlateElement","editor"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * SlateEditor Component\n *\n * A reusable rich text editor primitive based on Slate.js\n * Provides consistent theming and can be used as an alternative to textarea\n */\n\nimport * as React from \"react\";\nimport {\n createEditor,\n Descendant,\n Editor,\n Transforms,\n Text,\n Element as SlateElement,\n Range,\n Node,\n BaseEditor,\n Path,\n} from \"slate\";\nimport {\n Slate,\n Editable,\n withReact,\n ReactEditor,\n RenderElementProps,\n RenderLeafProps,\n} from \"slate-react\";\nimport type { NodeEntry } from \"slate\";\nimport { withHistory, HistoryEditor } from \"slate-history\";\nimport { cn } from \"@optilogic/core\";\n\ntype TagElement = {\n type: \"tag\";\n tag: string;\n children: [{ text: \"\" }];\n};\n\ntype ParagraphElement = {\n type: \"paragraph\";\n children: Descendant[];\n};\n\ntype CustomElement = TagElement | ParagraphElement;\ntype CustomText = { text: string; [key: string]: unknown };\n\nexport type DecoratedRange = Range & { [key: string]: unknown };\n\ndeclare module \"slate\" {\n interface CustomTypes {\n Editor: BaseEditor & ReactEditor & HistoryEditor;\n Element: CustomElement;\n Text: CustomText;\n }\n}\n\nconst isTagElement = (element: CustomElement): element is TagElement => {\n return element.type === \"tag\";\n};\n\nexport interface SlateEditorRef {\n /** Focus the editor */\n focus: () => void;\n /** Clear the editor content */\n clear: () => void;\n /** Get plain text content */\n getText: () => string;\n /** Insert text at cursor */\n insertText: (text: string) => void;\n /** Insert a tag element */\n insertTag: (tag: string) => void;\n}\n\nexport interface SlateEditorProps {\n /** Initial plain text value */\n value?: string;\n /** Callback when content changes (plain text) */\n onChange?: (value: string) => void;\n /** Callback when a tag is created */\n onTagCreate?: (tag: string) => void;\n /** Callback when a tag is deleted */\n onTagDelete?: (tag: string) => void;\n /** Callback when Enter is pressed (without Shift) */\n onSubmit?: (text: string) => void;\n /** Automatically clear the editor after onSubmit is called */\n clearOnSubmit?: boolean;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the editor is disabled */\n disabled?: boolean;\n /** Whether to enable tag detection (# character) */\n enableTags?: boolean;\n /** Minimum number of rows */\n minRows?: number;\n /** Maximum number of rows before scrolling */\n maxRows?: number;\n /** Additional class names */\n className?: string;\n /** Custom decoration function for text ranges */\n decorate?: (entry: NodeEntry) => DecoratedRange[];\n /** Custom leaf renderer for decorated text */\n renderLeaf?: (props: RenderLeafProps) => React.ReactElement;\n}\n\nconst withTags = (editor: Editor) => {\n const { isInline, isVoid, deleteBackward, deleteForward } = editor;\n\n editor.isInline = (element) => {\n return element.type === \"tag\" ? true : isInline(element);\n };\n\n editor.isVoid = (element) => {\n return element.type === \"tag\" ? true : isVoid(element);\n };\n\n editor.deleteBackward = (unit) => {\n const { selection } = editor;\n\n if (selection && Range.isCollapsed(selection)) {\n const [tagEntry] = Editor.nodes(editor, {\n match: (n) =>\n !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === \"tag\",\n });\n\n if (tagEntry) {\n const [, path] = tagEntry;\n const after = Editor.after(editor, path);\n if (after && Path.equals(selection.anchor.path, after.path)) {\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n\n const before = Editor.before(editor, selection);\n if (before) {\n const [beforeTagEntry] = Editor.nodes(editor, {\n at: before,\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (beforeTagEntry) {\n const [, path] = beforeTagEntry;\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n }\n\n deleteBackward(unit);\n };\n\n editor.deleteForward = (unit) => {\n const { selection } = editor;\n\n if (selection && Range.isCollapsed(selection)) {\n const after = Editor.after(editor, selection);\n if (after) {\n const [afterTagEntry] = Editor.nodes(editor, {\n at: after,\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (afterTagEntry) {\n const [, path] = afterTagEntry;\n Transforms.removeNodes(editor, { at: path });\n return;\n }\n }\n }\n\n deleteForward(unit);\n };\n\n return editor;\n};\n\n/**\n * Convert Slate content to plain text\n */\nexport function serializeToText(nodes: Descendant[]): string {\n return nodes\n .map((n) => {\n if (Text.isText(n)) {\n return n.text;\n }\n if (SlateElement.isElement(n)) {\n if (n.type === \"tag\") {\n return `#${n.tag}`;\n }\n return serializeToText(n.children);\n }\n return \"\";\n })\n .join(\"\");\n}\n\n/**\n * Convert plain text to Slate nodes (preserving existing tags)\n */\nexport function deserializeFromText(text: string): Descendant[] {\n if (!text) {\n return [{ type: \"paragraph\", children: [{ text: \"\" }] }];\n }\n\n const children: Descendant[] = [];\n const tagRegex = /#([a-zA-Z0-9@#$_-]+(?:--[a-zA-Z0-9_-]+)?)/g;\n let lastIndex = 0;\n let match;\n\n while ((match = tagRegex.exec(text)) !== null) {\n if (match.index > lastIndex) {\n children.push({ text: text.substring(lastIndex, match.index) });\n }\n\n children.push({\n type: \"tag\",\n tag: match[1],\n children: [{ text: \"\" }],\n });\n\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < text.length) {\n children.push({ text: text.substring(lastIndex) });\n }\n\n if (children.length === 0) {\n children.push({ text: \"\" });\n }\n\n return [{ type: \"paragraph\", children }];\n}\n\nconst TagElementRenderer = ({\n attributes,\n children,\n element,\n}: RenderElementProps & { element: TagElement }) => {\n return (\n <span\n {...attributes}\n contentEditable={false}\n className={cn(\n \"inline-flex items-center\",\n \"px-1.5 py-0.5 mx-0.5\",\n \"rounded-md border\",\n \"bg-accent/20 text-accent border-accent/40\",\n \"text-sm font-medium\",\n \"select-none cursor-default\"\n )}\n >\n <span className=\"font-bold\">#</span>\n {element.tag}\n {children}\n </span>\n );\n};\n\nconst DefaultElement = ({ attributes, children }: RenderElementProps) => {\n return <p {...attributes}>{children}</p>;\n};\n\nconst Leaf = ({ attributes, children }: RenderLeafProps) => {\n return <span {...attributes}>{children}</span>;\n};\n\n/**\n * SlateEditor component\n *\n * A rich text editor based on Slate.js with support for inline tags.\n * Can be used as a drop-in replacement for textarea with enhanced features.\n *\n * @example\n * <SlateEditor\n * value={content}\n * onChange={setContent}\n * placeholder=\"Type your message...\"\n * onSubmit={(text) => console.log('Submitted:', text)}\n * />\n */\nexport const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(\n (\n {\n value = \"\",\n onChange,\n onTagCreate,\n onTagDelete,\n onSubmit,\n clearOnSubmit = false,\n placeholder = \"Type something...\",\n disabled = false,\n enableTags = true,\n minRows = 3,\n maxRows = 8,\n className,\n decorate,\n renderLeaf: customRenderLeaf,\n },\n ref\n ) => {\n const editor = React.useMemo(\n () => withTags(withHistory(withReact(createEditor()))),\n []\n );\n\n const [isCreatingTag, setIsCreatingTag] = React.useState(false);\n const [tagStartPoint, setTagStartPoint] = React.useState<{\n path: Path;\n offset: number;\n } | null>(null);\n const [currentTagText, setCurrentTagText] = React.useState(\"\");\n\n const [editorValue, setEditorValue] = React.useState<Descendant[]>(() =>\n deserializeFromText(value)\n );\n\n // Track the last value we sent via onChange to distinguish user input from external prop changes\n const lastOnChangeValue = React.useRef<string>(value);\n\n // Get the editable DOM element from the editor\n const getEditableElement = React.useCallback(() => {\n try {\n return ReactEditor.toDOMNode(editor, editor) as HTMLElement;\n } catch {\n return null;\n }\n }, [editor]);\n\n const resetEditorContent = React.useCallback(\n (newContent: Descendant[]) => {\n // Save scroll position before resetting content\n const el = getEditableElement();\n const savedScroll = el\n ? { top: el.scrollTop, left: el.scrollLeft }\n : null;\n\n Editor.withoutNormalizing(editor, () => {\n // Remove all existing nodes\n while (editor.children.length > 0) {\n Transforms.removeNodes(editor, { at: [0] });\n }\n // Insert new content\n Transforms.insertNodes(editor, newContent, { at: [0] });\n });\n\n setEditorValue(newContent);\n\n // Set selection to start safely\n const point = { path: [0, 0], offset: 0 };\n Transforms.select(editor, { anchor: point, focus: point });\n\n // Restore scroll position after content reset (use requestAnimationFrame to ensure DOM is updated)\n if (savedScroll && el) {\n requestAnimationFrame(() => {\n el.scrollTop = savedScroll.top;\n el.scrollLeft = savedScroll.left;\n });\n }\n },\n [editor, getEditableElement]\n );\n\n React.useEffect(() => {\n // Only reset content if value changed externally (not from our own onChange)\n // This prevents scroll position reset during user typing\n if (value !== lastOnChangeValue.current) {\n const currentText = serializeToText(editor.children as Descendant[]);\n if (currentText !== value) {\n const newValue = deserializeFromText(value);\n resetEditorContent(newValue);\n }\n lastOnChangeValue.current = value;\n }\n }, [value, editor, resetEditorContent]);\n\n React.useImperativeHandle(\n ref,\n () => ({\n focus: () => {\n ReactEditor.focus(editor);\n },\n clear: () => {\n const emptyValue: Descendant[] = [\n { type: \"paragraph\", children: [{ text: \"\" }] },\n ];\n resetEditorContent(emptyValue);\n onChange?.(\"\");\n },\n getText: () => serializeToText(editor.children as Descendant[]),\n insertText: (text: string) => {\n Transforms.insertText(editor, text);\n },\n insertTag: (tag: string) => {\n insertTag(editor, tag);\n onTagCreate?.(tag);\n },\n }),\n [editor, onTagCreate, resetEditorContent, onChange]\n );\n\n const handleChange = React.useCallback(\n (newValue: Descendant[]) => {\n if (isCreatingTag && tagStartPoint) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n const currentPath = selection.anchor.path;\n const currentOffset = selection.anchor.offset;\n\n if (Path.equals(currentPath, tagStartPoint.path)) {\n try {\n const [textNode] = Editor.node(editor, currentPath);\n if (Text.isText(textNode)) {\n const tagText = textNode.text.substring(\n tagStartPoint.offset + 1,\n currentOffset\n );\n setCurrentTagText(tagText);\n }\n } catch {\n // Ignore - node may not exist\n }\n }\n }\n }\n\n const oldTags = new Set<string>();\n const newTags = new Set<string>();\n\n for (const node of Node.descendants(editor, {\n from: [],\n pass: ([n]) => SlateElement.isElement(n) && n.type === \"paragraph\",\n })) {\n const [n] = node;\n if (SlateElement.isElement(n) && n.type === \"tag\") {\n oldTags.add(n.tag);\n }\n }\n\n const extractTags = (nodes: Descendant[]) => {\n for (const node of nodes) {\n if (SlateElement.isElement(node)) {\n if (node.type === \"tag\") {\n newTags.add(node.tag);\n }\n if (\"children\" in node) {\n extractTags(node.children);\n }\n }\n }\n };\n extractTags(newValue);\n\n for (const tag of oldTags) {\n if (!newTags.has(tag)) {\n onTagDelete?.(tag);\n }\n }\n\n const text = serializeToText(newValue);\n lastOnChangeValue.current = text;\n onChange?.(text);\n },\n [editor, onChange, onTagDelete, isCreatingTag, tagStartPoint]\n );\n\n const insertTag = (editor: Editor, tag: string) => {\n const tagNode: TagElement = {\n type: \"tag\",\n tag,\n children: [{ text: \"\" }],\n };\n Transforms.insertNodes(editor, tagNode);\n Transforms.move(editor);\n Transforms.insertText(editor, \" \");\n };\n\n const completeTag = React.useCallback(() => {\n if (!isCreatingTag || !tagStartPoint) return;\n\n const { selection } = editor;\n if (!selection || !Range.isCollapsed(selection)) return;\n\n const currentPath = selection.anchor.path;\n const currentOffset = selection.anchor.offset;\n\n if (!Path.equals(currentPath, tagStartPoint.path)) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const [textNode] = Editor.node(editor, currentPath);\n if (!Text.isText(textNode)) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const tagText = textNode.text.substring(\n tagStartPoint.offset + 1,\n currentOffset\n );\n\n if (!tagText.trim()) {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n return;\n }\n\n const start = { path: currentPath, offset: tagStartPoint.offset };\n const end = { path: currentPath, offset: currentOffset };\n\n Transforms.delete(editor, { at: { anchor: start, focus: end } });\n insertTag(editor, tagText.trim());\n\n onTagCreate?.(tagText.trim());\n\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n }, [editor, isCreatingTag, tagStartPoint, onTagCreate]);\n\n const cancelTag = React.useCallback(() => {\n setIsCreatingTag(false);\n setTagStartPoint(null);\n setCurrentTagText(\"\");\n }, []);\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (isCreatingTag) {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n completeTag();\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n cancelTag();\n return;\n }\n }\n\n if (enableTags && event.key === \"#\" && !isCreatingTag) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n setIsCreatingTag(true);\n setCurrentTagText(\"\");\n setTagStartPoint({\n path: selection.anchor.path,\n offset: selection.anchor.offset,\n });\n }\n }\n\n if (event.key === \"Enter\" && !event.shiftKey && !isCreatingTag) {\n event.preventDefault();\n const text = serializeToText(editor.children as Descendant[]);\n if (text.trim() && onSubmit) {\n onSubmit(text.trim());\n if (clearOnSubmit) {\n const emptyValue: Descendant[] = [\n { type: \"paragraph\", children: [{ text: \"\" }] },\n ];\n resetEditorContent(emptyValue);\n onChange?.(\"\");\n }\n }\n return;\n }\n\n // Shift+Enter: Insert soft line break (newline character) instead of new paragraph\n if (event.key === \"Enter\" && event.shiftKey) {\n event.preventDefault();\n const el = getEditableElement();\n const savedScrollTop = el?.scrollTop ?? 0;\n\n Transforms.insertText(editor, \"\\n\");\n\n // Restore scroll position immediately and after paint to prevent jump\n if (el) {\n el.scrollTop = savedScrollTop;\n requestAnimationFrame(() => {\n el.scrollTop = savedScrollTop;\n });\n }\n return;\n }\n\n if (\n (event.key === \"Backspace\" || event.key === \"Delete\") &&\n event.ctrlKey\n ) {\n const { selection } = editor;\n if (selection && Range.isCollapsed(selection)) {\n const direction =\n event.key === \"Backspace\" ? \"backward\" : \"forward\";\n const pointFn =\n direction === \"backward\" ? Editor.before : Editor.after;\n const point = pointFn(editor, selection, { unit: \"word\" });\n\n if (point) {\n const [tagEntry] = Editor.nodes(editor, {\n at:\n direction === \"backward\"\n ? { anchor: point, focus: selection.anchor }\n : { anchor: selection.anchor, focus: point },\n match: (n) =>\n !Editor.isEditor(n) &&\n SlateElement.isElement(n) &&\n n.type === \"tag\",\n });\n\n if (tagEntry) {\n event.preventDefault();\n const [tagNode, tagPath] = tagEntry;\n if (SlateElement.isElement(tagNode) && tagNode.type === \"tag\") {\n onTagDelete?.(tagNode.tag);\n }\n Transforms.removeNodes(editor, { at: tagPath });\n return;\n }\n }\n }\n }\n },\n [\n editor,\n isCreatingTag,\n enableTags,\n completeTag,\n cancelTag,\n onSubmit,\n onTagDelete,\n clearOnSubmit,\n resetEditorContent,\n onChange,\n getEditableElement,\n ]\n );\n\n const renderElement = React.useCallback((props: RenderElementProps) => {\n switch (props.element.type) {\n case \"tag\":\n return (\n <TagElementRenderer\n {...props}\n element={props.element as TagElement}\n />\n );\n default:\n return <DefaultElement {...props} />;\n }\n }, []);\n\n const renderLeaf = React.useCallback(\n (props: RenderLeafProps) => {\n if (customRenderLeaf) {\n return customRenderLeaf(props);\n }\n return <Leaf {...props} />;\n },\n [customRenderLeaf]\n );\n\n const lineHeight = 24;\n const minHeight = lineHeight * minRows;\n const maxHeight = lineHeight * maxRows;\n\n return (\n <div\n className={cn(\n \"relative w-full rounded-md\",\n \"bg-transparent\",\n disabled && \"opacity-50 cursor-not-allowed\",\n className\n )}\n >\n <Slate\n editor={editor}\n initialValue={editorValue}\n onChange={handleChange}\n >\n <Editable\n readOnly={disabled}\n placeholder={placeholder}\n renderElement={renderElement}\n renderLeaf={renderLeaf}\n decorate={decorate}\n onKeyDown={handleKeyDown}\n className={cn(\n \"w-full outline-none\",\n \"text-foreground placeholder:text-muted-foreground\",\n \"leading-6\",\n \"overflow-y-auto overflow-x-hidden\",\n \"whitespace-pre-wrap break-words\",\n \"scrollbar-thin\"\n )}\n style={{\n minHeight: `${minHeight}px`,\n maxHeight: `${maxHeight}px`,\n wordBreak: \"break-word\",\n overflowWrap: \"break-word\",\n }}\n spellCheck\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n />\n </Slate>\n\n {isCreatingTag && (\n <div className=\"absolute bottom-full left-0 mb-2 flex items-center gap-2.5 animate-in fade-in-0 slide-in-from-bottom-1 duration-150\">\n <div className=\"flex items-center px-2 py-1 rounded-md border shadow-sm bg-accent/20 border-accent/40\">\n <span className=\"font-bold text-sm text-accent\">#</span>\n <span className=\"text-sm font-medium min-w-[2ch] text-accent\">\n {currentTagText || (\n <span className=\"opacity-50 italic\">tag</span>\n )}\n </span>\n </div>\n <span className=\"text-muted-foreground/80 text-[11px]\">\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mr-1\">\n Enter\n </kbd>\n or\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mx-1\">\n Space\n </kbd>\n to add\n <span className=\"mx-1.5 text-muted-foreground/50\">·</span>\n <kbd className=\"px-1.5 py-0.5 bg-muted rounded text-[10px] font-mono mr-1\">\n Esc\n </kbd>\n to cancel\n </span>\n </div>\n )}\n </div>\n );\n }\n);\n\nSlateEditor.displayName = \"SlateEditor\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optilogic/editor",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.3",
|
|
4
4
|
"description": "Rich text editor component for Optilogic - SlateEditor built on Slate.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"README.md"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@optilogic/core": "1.0.0-beta.
|
|
27
|
+
"@optilogic/core": "1.0.0-beta.3"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"react": "^18.0.0 || ^19.0.0",
|
package/src/index.ts
CHANGED
|
@@ -4,4 +4,10 @@ export {
|
|
|
4
4
|
deserializeFromText,
|
|
5
5
|
type SlateEditorProps,
|
|
6
6
|
type SlateEditorRef,
|
|
7
|
+
type DecoratedRange,
|
|
7
8
|
} from "./slate-editor";
|
|
9
|
+
|
|
10
|
+
// Re-export Slate types and utilities for convenience
|
|
11
|
+
export { Text, Range } from "slate";
|
|
12
|
+
export type { NodeEntry } from "slate";
|
|
13
|
+
export type { RenderLeafProps } from "slate-react";
|
package/src/slate-editor.tsx
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
RenderElementProps,
|
|
27
27
|
RenderLeafProps,
|
|
28
28
|
} from "slate-react";
|
|
29
|
+
import type { NodeEntry } from "slate";
|
|
29
30
|
import { withHistory, HistoryEditor } from "slate-history";
|
|
30
31
|
import { cn } from "@optilogic/core";
|
|
31
32
|
|
|
@@ -41,7 +42,9 @@ type ParagraphElement = {
|
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
type CustomElement = TagElement | ParagraphElement;
|
|
44
|
-
type CustomText = { text: string };
|
|
45
|
+
type CustomText = { text: string; [key: string]: unknown };
|
|
46
|
+
|
|
47
|
+
export type DecoratedRange = Range & { [key: string]: unknown };
|
|
45
48
|
|
|
46
49
|
declare module "slate" {
|
|
47
50
|
interface CustomTypes {
|
|
@@ -79,6 +82,8 @@ export interface SlateEditorProps {
|
|
|
79
82
|
onTagDelete?: (tag: string) => void;
|
|
80
83
|
/** Callback when Enter is pressed (without Shift) */
|
|
81
84
|
onSubmit?: (text: string) => void;
|
|
85
|
+
/** Automatically clear the editor after onSubmit is called */
|
|
86
|
+
clearOnSubmit?: boolean;
|
|
82
87
|
/** Placeholder text */
|
|
83
88
|
placeholder?: string;
|
|
84
89
|
/** Whether the editor is disabled */
|
|
@@ -91,6 +96,10 @@ export interface SlateEditorProps {
|
|
|
91
96
|
maxRows?: number;
|
|
92
97
|
/** Additional class names */
|
|
93
98
|
className?: string;
|
|
99
|
+
/** Custom decoration function for text ranges */
|
|
100
|
+
decorate?: (entry: NodeEntry) => DecoratedRange[];
|
|
101
|
+
/** Custom leaf renderer for decorated text */
|
|
102
|
+
renderLeaf?: (props: RenderLeafProps) => React.ReactElement;
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
const withTags = (editor: Editor) => {
|
|
@@ -284,12 +293,15 @@ export const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(
|
|
|
284
293
|
onTagCreate,
|
|
285
294
|
onTagDelete,
|
|
286
295
|
onSubmit,
|
|
296
|
+
clearOnSubmit = false,
|
|
287
297
|
placeholder = "Type something...",
|
|
288
298
|
disabled = false,
|
|
289
299
|
enableTags = true,
|
|
290
300
|
minRows = 3,
|
|
291
301
|
maxRows = 8,
|
|
292
302
|
className,
|
|
303
|
+
decorate,
|
|
304
|
+
renderLeaf: customRenderLeaf,
|
|
293
305
|
},
|
|
294
306
|
ref
|
|
295
307
|
) => {
|
|
@@ -309,16 +321,64 @@ export const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(
|
|
|
309
321
|
deserializeFromText(value)
|
|
310
322
|
);
|
|
311
323
|
|
|
324
|
+
// Track the last value we sent via onChange to distinguish user input from external prop changes
|
|
325
|
+
const lastOnChangeValue = React.useRef<string>(value);
|
|
326
|
+
|
|
327
|
+
// Get the editable DOM element from the editor
|
|
328
|
+
const getEditableElement = React.useCallback(() => {
|
|
329
|
+
try {
|
|
330
|
+
return ReactEditor.toDOMNode(editor, editor) as HTMLElement;
|
|
331
|
+
} catch {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
}, [editor]);
|
|
335
|
+
|
|
336
|
+
const resetEditorContent = React.useCallback(
|
|
337
|
+
(newContent: Descendant[]) => {
|
|
338
|
+
// Save scroll position before resetting content
|
|
339
|
+
const el = getEditableElement();
|
|
340
|
+
const savedScroll = el
|
|
341
|
+
? { top: el.scrollTop, left: el.scrollLeft }
|
|
342
|
+
: null;
|
|
343
|
+
|
|
344
|
+
Editor.withoutNormalizing(editor, () => {
|
|
345
|
+
// Remove all existing nodes
|
|
346
|
+
while (editor.children.length > 0) {
|
|
347
|
+
Transforms.removeNodes(editor, { at: [0] });
|
|
348
|
+
}
|
|
349
|
+
// Insert new content
|
|
350
|
+
Transforms.insertNodes(editor, newContent, { at: [0] });
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
setEditorValue(newContent);
|
|
354
|
+
|
|
355
|
+
// Set selection to start safely
|
|
356
|
+
const point = { path: [0, 0], offset: 0 };
|
|
357
|
+
Transforms.select(editor, { anchor: point, focus: point });
|
|
358
|
+
|
|
359
|
+
// Restore scroll position after content reset (use requestAnimationFrame to ensure DOM is updated)
|
|
360
|
+
if (savedScroll && el) {
|
|
361
|
+
requestAnimationFrame(() => {
|
|
362
|
+
el.scrollTop = savedScroll.top;
|
|
363
|
+
el.scrollLeft = savedScroll.left;
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
[editor, getEditableElement]
|
|
368
|
+
);
|
|
369
|
+
|
|
312
370
|
React.useEffect(() => {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
if (
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
371
|
+
// Only reset content if value changed externally (not from our own onChange)
|
|
372
|
+
// This prevents scroll position reset during user typing
|
|
373
|
+
if (value !== lastOnChangeValue.current) {
|
|
374
|
+
const currentText = serializeToText(editor.children as Descendant[]);
|
|
375
|
+
if (currentText !== value) {
|
|
376
|
+
const newValue = deserializeFromText(value);
|
|
377
|
+
resetEditorContent(newValue);
|
|
378
|
+
}
|
|
379
|
+
lastOnChangeValue.current = value;
|
|
320
380
|
}
|
|
321
|
-
}, [value, editor]);
|
|
381
|
+
}, [value, editor, resetEditorContent]);
|
|
322
382
|
|
|
323
383
|
React.useImperativeHandle(
|
|
324
384
|
ref,
|
|
@@ -327,13 +387,13 @@ export const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(
|
|
|
327
387
|
ReactEditor.focus(editor);
|
|
328
388
|
},
|
|
329
389
|
clear: () => {
|
|
330
|
-
const
|
|
390
|
+
const emptyValue: Descendant[] = [
|
|
331
391
|
{ type: "paragraph", children: [{ text: "" }] },
|
|
332
392
|
];
|
|
333
|
-
|
|
334
|
-
|
|
393
|
+
resetEditorContent(emptyValue);
|
|
394
|
+
onChange?.("");
|
|
335
395
|
},
|
|
336
|
-
getText: () => serializeToText(
|
|
396
|
+
getText: () => serializeToText(editor.children as Descendant[]),
|
|
337
397
|
insertText: (text: string) => {
|
|
338
398
|
Transforms.insertText(editor, text);
|
|
339
399
|
},
|
|
@@ -342,13 +402,11 @@ export const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(
|
|
|
342
402
|
onTagCreate?.(tag);
|
|
343
403
|
},
|
|
344
404
|
}),
|
|
345
|
-
[editor,
|
|
405
|
+
[editor, onTagCreate, resetEditorContent, onChange]
|
|
346
406
|
);
|
|
347
407
|
|
|
348
408
|
const handleChange = React.useCallback(
|
|
349
409
|
(newValue: Descendant[]) => {
|
|
350
|
-
setEditorValue(newValue);
|
|
351
|
-
|
|
352
410
|
if (isCreatingTag && tagStartPoint) {
|
|
353
411
|
const { selection } = editor;
|
|
354
412
|
if (selection && Range.isCollapsed(selection)) {
|
|
@@ -406,6 +464,7 @@ export const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(
|
|
|
406
464
|
}
|
|
407
465
|
|
|
408
466
|
const text = serializeToText(newValue);
|
|
467
|
+
lastOnChangeValue.current = text;
|
|
409
468
|
onChange?.(text);
|
|
410
469
|
},
|
|
411
470
|
[editor, onChange, onTagDelete, isCreatingTag, tagStartPoint]
|
|
@@ -507,9 +566,34 @@ export const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(
|
|
|
507
566
|
|
|
508
567
|
if (event.key === "Enter" && !event.shiftKey && !isCreatingTag) {
|
|
509
568
|
event.preventDefault();
|
|
510
|
-
const text = serializeToText(
|
|
569
|
+
const text = serializeToText(editor.children as Descendant[]);
|
|
511
570
|
if (text.trim() && onSubmit) {
|
|
512
571
|
onSubmit(text.trim());
|
|
572
|
+
if (clearOnSubmit) {
|
|
573
|
+
const emptyValue: Descendant[] = [
|
|
574
|
+
{ type: "paragraph", children: [{ text: "" }] },
|
|
575
|
+
];
|
|
576
|
+
resetEditorContent(emptyValue);
|
|
577
|
+
onChange?.("");
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Shift+Enter: Insert soft line break (newline character) instead of new paragraph
|
|
584
|
+
if (event.key === "Enter" && event.shiftKey) {
|
|
585
|
+
event.preventDefault();
|
|
586
|
+
const el = getEditableElement();
|
|
587
|
+
const savedScrollTop = el?.scrollTop ?? 0;
|
|
588
|
+
|
|
589
|
+
Transforms.insertText(editor, "\n");
|
|
590
|
+
|
|
591
|
+
// Restore scroll position immediately and after paint to prevent jump
|
|
592
|
+
if (el) {
|
|
593
|
+
el.scrollTop = savedScrollTop;
|
|
594
|
+
requestAnimationFrame(() => {
|
|
595
|
+
el.scrollTop = savedScrollTop;
|
|
596
|
+
});
|
|
513
597
|
}
|
|
514
598
|
return;
|
|
515
599
|
}
|
|
@@ -553,13 +637,16 @@ export const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(
|
|
|
553
637
|
},
|
|
554
638
|
[
|
|
555
639
|
editor,
|
|
556
|
-
editorValue,
|
|
557
640
|
isCreatingTag,
|
|
558
641
|
enableTags,
|
|
559
642
|
completeTag,
|
|
560
643
|
cancelTag,
|
|
561
644
|
onSubmit,
|
|
562
645
|
onTagDelete,
|
|
646
|
+
clearOnSubmit,
|
|
647
|
+
resetEditorContent,
|
|
648
|
+
onChange,
|
|
649
|
+
getEditableElement,
|
|
563
650
|
]
|
|
564
651
|
);
|
|
565
652
|
|
|
@@ -577,9 +664,15 @@ export const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(
|
|
|
577
664
|
}
|
|
578
665
|
}, []);
|
|
579
666
|
|
|
580
|
-
const renderLeaf = React.useCallback(
|
|
581
|
-
|
|
582
|
-
|
|
667
|
+
const renderLeaf = React.useCallback(
|
|
668
|
+
(props: RenderLeafProps) => {
|
|
669
|
+
if (customRenderLeaf) {
|
|
670
|
+
return customRenderLeaf(props);
|
|
671
|
+
}
|
|
672
|
+
return <Leaf {...props} />;
|
|
673
|
+
},
|
|
674
|
+
[customRenderLeaf]
|
|
675
|
+
);
|
|
583
676
|
|
|
584
677
|
const lineHeight = 24;
|
|
585
678
|
const minHeight = lineHeight * minRows;
|
|
@@ -604,13 +697,15 @@ export const SlateEditor = React.forwardRef<SlateEditorRef, SlateEditorProps>(
|
|
|
604
697
|
placeholder={placeholder}
|
|
605
698
|
renderElement={renderElement}
|
|
606
699
|
renderLeaf={renderLeaf}
|
|
700
|
+
decorate={decorate}
|
|
607
701
|
onKeyDown={handleKeyDown}
|
|
608
702
|
className={cn(
|
|
609
703
|
"w-full outline-none",
|
|
610
704
|
"text-foreground placeholder:text-muted-foreground",
|
|
611
705
|
"leading-6",
|
|
612
706
|
"overflow-y-auto overflow-x-hidden",
|
|
613
|
-
"whitespace-pre-wrap break-words"
|
|
707
|
+
"whitespace-pre-wrap break-words",
|
|
708
|
+
"scrollbar-thin"
|
|
614
709
|
)}
|
|
615
710
|
style={{
|
|
616
711
|
minHeight: `${minHeight}px`,
|