@haklex/rich-ext-code-snippet 0.0.82 → 0.0.83

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.mjs CHANGED
@@ -1,416 +1,476 @@
1
- import { A as modalTitlebar, C as fileName, D as modalIconButton, E as modalEditor, M as semanticClassNames, N as sidebarAddButton, O as modalSidebar, P as sidebarHeader, S as fileList, T as modalBody, _ as editorContainer, a as _defineProperty, b as fileIcon, c as breadcrumb, f as codeSnippetDialogPopup, g as editOverlay, h as editLabel, i as CodeSnippetNode, j as renameInput, k as modalTitle, m as editContainer, n as $createCodeSnippetNode, o as CodeSnippetRenderer, p as dragOverlay, r as $isCodeSnippetNode, s as getLanguageFromFilename, t as CODE_SNIPPET_BLOCK_TRANSFORMER, u as breadcrumbLeft, w as modal, x as fileItem, y as fileDragHandle } from "./transformer-CCg3Ky-e.js";
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ import { g as getLanguageFromFilename, m as modal, s as semanticClassNames, a as modalTitlebar, b as modalTitle, c as modalIconButton, d as modalBody, e as modalSidebar, f as sidebarHeader, h as sidebarAddButton, i as fileList, j as dragOverlay, k as fileIcon, l as fileName, n as fileItem, o as modalEditor, p as breadcrumb, q as breadcrumbLeft, r as breadcrumbName, t as breadcrumbLang, u as editorContainer, v as fileDragHandle, w as renameInput, x as fileDelete, y as codeSnippetDialogPopup, z as editContainer, C as CodeSnippetRenderer, A as editOverlay, B as editLabel, $ as $isCodeSnippetNode, D as CodeSnippetNode } from "./CodeSnippetNode-BmRM_Ma7.js";
5
+ import { E } from "./CodeSnippetNode-BmRM_Ma7.js";
6
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
7
  import { useColorScheme } from "@haklex/rich-editor";
3
8
  import { presentDialog } from "@haklex/rich-editor-ui";
4
9
  import { usePortalTheme } from "@haklex/rich-style-token";
5
- import { FileCode, GripVertical, Pencil, Plus, Trash2, X } from "lucide-react";
6
- import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
7
- import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
10
+ import { X, Plus, GripVertical, Trash2, Pencil, FileCode } from "lucide-react";
11
+ import { useState, useRef, useEffect, useCallback, useMemo, useContext, createContext, createElement } from "react";
12
+ import { history, defaultKeymap, historyKeymap, indentWithTab } from "@codemirror/commands";
8
13
  import { Compartment, EditorState } from "@codemirror/state";
9
14
  import { EditorView, keymap, lineNumbers } from "@codemirror/view";
10
- import { DndContext, DragOverlay, PointerSensor, closestCenter, useSensor, useSensors } from "@dnd-kit/core";
11
- import { SortableContext, arrayMove, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
15
+ import { useSensors, useSensor, PointerSensor, DndContext, closestCenter, DragOverlay } from "@dnd-kit/core";
16
+ import { arrayMove, SortableContext, verticalListSortingStrategy, useSortable } from "@dnd-kit/sortable";
12
17
  import { CSS } from "@dnd-kit/utilities";
13
18
  import { getThemeExtensions, loadLanguageExtension } from "@haklex/cm-editor";
14
19
  import { normalizeLanguage } from "@haklex/rich-renderer-codeblock/constants";
15
20
  import { FileIcon } from "@haklex/rich-renderer-codeblock/icons";
16
21
  import { createPortal } from "react-dom";
17
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
18
22
  import { $getNodeByKey, $insertNodes } from "lexical";
19
- //#region src/CodeEditorModal.tsx
20
- var SortableFileItem = ({ file, isActive, isEditing, editValue, canDelete, onSelect, onStartRename, onEditChange, onCommitRename, onCancelRename, onDelete }) => {
21
- const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: file.filename });
22
- const style = {
23
- transform: CSS.Transform.toString(transform),
24
- transition
25
- };
26
- return /* @__PURE__ */ jsxs("div", {
27
- className: `${fileItem({
28
- active: isActive,
29
- dragging: isDragging
30
- })} ${semanticClassNames.fileItem} ${isActive ? semanticClassNames.fileItemActive : ""} ${isDragging ? semanticClassNames.fileItemDragging : ""}`.trim(),
31
- ref: setNodeRef,
32
- style,
33
- onClick: onSelect,
34
- onDoubleClick: onStartRename,
35
- children: [
36
- /* @__PURE__ */ jsx("span", {
37
- className: `${fileDragHandle} ${semanticClassNames.fileDragHandle}`,
38
- ...attributes,
39
- ...listeners,
40
- onClick: (e) => e.stopPropagation(),
41
- children: /* @__PURE__ */ jsx(GripVertical, { size: 12 })
42
- }),
43
- /* @__PURE__ */ jsx(FileIcon, {
44
- className: `${fileIcon} ${semanticClassNames.fileIcon}`,
45
- filename: file.filename,
46
- size: 14
47
- }),
48
- isEditing ? /* @__PURE__ */ jsx("input", {
49
- autoFocus: true,
50
- className: `${renameInput} ${semanticClassNames.renameInput}`,
51
- value: editValue,
52
- onBlur: onCommitRename,
53
- onChange: (e) => onEditChange(e.target.value),
54
- onClick: (e) => e.stopPropagation(),
55
- onKeyDown: (e) => {
56
- if (e.key === "Enter") onCommitRename();
57
- if (e.key === "Escape") onCancelRename();
58
- }
59
- }) : /* @__PURE__ */ jsx("span", {
60
- className: `${fileName} ${semanticClassNames.fileName}`,
61
- children: file.filename
62
- }),
63
- canDelete && /* @__PURE__ */ jsx("button", {
64
- "aria-label": `Delete ${file.filename}`,
65
- className: `hjkryc11 ${semanticClassNames.fileDelete}`,
66
- type: "button",
67
- onClick: (e) => {
68
- e.stopPropagation();
69
- onDelete();
70
- },
71
- children: /* @__PURE__ */ jsx(Trash2, { size: 12 })
72
- })
73
- ]
74
- });
23
+ import { CODE_SNIPPET_BLOCK_TRANSFORMER } from "@haklex/rich-headless/transformers";
24
+ const SortableFileItem = ({
25
+ file,
26
+ isActive,
27
+ isEditing,
28
+ editValue,
29
+ canDelete,
30
+ onSelect,
31
+ onStartRename,
32
+ onEditChange,
33
+ onCommitRename,
34
+ onCancelRename,
35
+ onDelete
36
+ }) => {
37
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
38
+ id: file.filename
39
+ });
40
+ const style = {
41
+ transform: CSS.Transform.toString(transform),
42
+ transition
43
+ };
44
+ return /* @__PURE__ */ jsxs(
45
+ "div",
46
+ {
47
+ className: `${fileItem({ active: isActive, dragging: isDragging })} ${semanticClassNames.fileItem} ${isActive ? semanticClassNames.fileItemActive : ""} ${isDragging ? semanticClassNames.fileItemDragging : ""}`.trim(),
48
+ ref: setNodeRef,
49
+ style,
50
+ onClick: onSelect,
51
+ onDoubleClick: onStartRename,
52
+ children: [
53
+ /* @__PURE__ */ jsx(
54
+ "span",
55
+ {
56
+ className: `${fileDragHandle} ${semanticClassNames.fileDragHandle}`,
57
+ ...attributes,
58
+ ...listeners,
59
+ onClick: (e) => e.stopPropagation(),
60
+ children: /* @__PURE__ */ jsx(GripVertical, { size: 12 })
61
+ }
62
+ ),
63
+ /* @__PURE__ */ jsx(
64
+ FileIcon,
65
+ {
66
+ className: `${fileIcon} ${semanticClassNames.fileIcon}`,
67
+ filename: file.filename,
68
+ size: 14
69
+ }
70
+ ),
71
+ isEditing ? /* @__PURE__ */ jsx(
72
+ "input",
73
+ {
74
+ autoFocus: true,
75
+ className: `${renameInput} ${semanticClassNames.renameInput}`,
76
+ value: editValue,
77
+ onBlur: onCommitRename,
78
+ onChange: (e) => onEditChange(e.target.value),
79
+ onClick: (e) => e.stopPropagation(),
80
+ onKeyDown: (e) => {
81
+ if (e.key === "Enter") onCommitRename();
82
+ if (e.key === "Escape") onCancelRename();
83
+ }
84
+ }
85
+ ) : /* @__PURE__ */ jsx("span", { className: `${fileName} ${semanticClassNames.fileName}`, children: file.filename }),
86
+ canDelete && /* @__PURE__ */ jsx(
87
+ "button",
88
+ {
89
+ "aria-label": `Delete ${file.filename}`,
90
+ className: `${fileDelete} ${semanticClassNames.fileDelete}`,
91
+ type: "button",
92
+ onClick: (e) => {
93
+ e.stopPropagation();
94
+ onDelete();
95
+ },
96
+ children: /* @__PURE__ */ jsx(Trash2, { size: 12 })
97
+ }
98
+ )
99
+ ]
100
+ }
101
+ );
75
102
  };
76
- var CodeEditorModal = ({ files: initialFiles, onFilesChange, dismiss, colorScheme }) => {
77
- const [editFiles, setEditFiles] = useState(() => initialFiles.map((f) => ({ ...f })));
78
- const [activeFilename, setActiveFilename] = useState(initialFiles[0]?.filename ?? "");
79
- const [editingFilename, setEditingFilename] = useState(null);
80
- const [newFilenameInput, setNewFilenameInput] = useState("");
81
- const [dragActiveId, setDragActiveId] = useState(null);
82
- const containerRef = useRef(null);
83
- const editorRef = useRef(null);
84
- const languageCompartmentRef = useRef(null);
85
- const themeCompartmentRef = useRef(null);
86
- if (!languageCompartmentRef.current) languageCompartmentRef.current = new Compartment();
87
- if (!themeCompartmentRef.current) themeCompartmentRef.current = new Compartment();
88
- const onCodeChangeRef = useRef(void 0);
89
- const editFilesRef = useRef(editFiles);
90
- editFilesRef.current = editFiles;
91
- const activeFile = editFiles.find((f) => f.filename === activeFilename) ?? editFiles[0];
92
- onCodeChangeRef.current = (code) => {
93
- setEditFiles((prev) => prev.map((f) => f.filename === activeFilename ? {
94
- ...f,
95
- code
96
- } : f));
97
- };
98
- useEffect(() => {
99
- const container = containerRef.current;
100
- if (!container) return;
101
- const file = editFilesRef.current.find((f) => f.filename === activeFilename);
102
- if (!file) return;
103
- let cancelled = false;
104
- const lang = normalizeLanguage(file.language ?? getLanguageFromFilename(file.filename));
105
- const editor = new EditorView({
106
- parent: container,
107
- state: EditorState.create({
108
- doc: file.code,
109
- extensions: [
110
- history(),
111
- keymap.of([
112
- ...defaultKeymap,
113
- ...historyKeymap,
114
- indentWithTab
115
- ]),
116
- EditorView.updateListener.of((update) => {
117
- if (!update.docChanged) return;
118
- onCodeChangeRef.current?.(update.state.doc.toString());
119
- }),
120
- lineNumbers(),
121
- themeCompartmentRef.current.of(getThemeExtensions(colorScheme)),
122
- languageCompartmentRef.current.of([])
123
- ]
124
- })
125
- });
126
- editorRef.current = editor;
127
- (async () => {
128
- const extension = await loadLanguageExtension(lang);
129
- if (cancelled) return;
130
- editor.dispatch({ effects: languageCompartmentRef.current.reconfigure(extension) });
131
- })();
132
- return () => {
133
- cancelled = true;
134
- editor.destroy();
135
- editorRef.current = null;
136
- };
137
- }, [activeFilename]);
138
- useEffect(() => {
139
- const editor = editorRef.current;
140
- if (!editor) return;
141
- editor.dispatch({ effects: themeCompartmentRef.current.reconfigure(getThemeExtensions(colorScheme)) });
142
- }, [colorScheme]);
143
- const handleDismiss = useCallback(() => {
144
- onFilesChange?.(editFiles);
145
- dismiss();
146
- }, [
147
- editFiles,
148
- onFilesChange,
149
- dismiss
150
- ]);
151
- const handleAddFile = useCallback(() => {
152
- const name = `untitled-${editFiles.length + 1}.ts`;
153
- const newFile = {
154
- filename: name,
155
- code: "",
156
- language: "typescript"
157
- };
158
- setEditFiles((prev) => [...prev, newFile]);
159
- setActiveFilename(name);
160
- }, [editFiles.length]);
161
- const handleDeleteFile = useCallback((filename) => {
162
- if (editFiles.length <= 1) return;
163
- const newFiles = editFiles.filter((f) => f.filename !== filename);
164
- setEditFiles(newFiles);
165
- if (activeFilename === filename) setActiveFilename(newFiles[0]?.filename ?? "");
166
- }, [editFiles, activeFilename]);
167
- const handleRenameFile = useCallback((oldName, newName) => {
168
- if (!newName.trim() || editFiles.some((f) => f.filename === newName && f.filename !== oldName)) {
169
- setEditingFilename(null);
170
- return;
171
- }
172
- setEditFiles((prev) => prev.map((f) => f.filename === oldName ? {
173
- ...f,
174
- filename: newName,
175
- language: void 0
176
- } : f));
177
- if (activeFilename === oldName) setActiveFilename(newName);
178
- setEditingFilename(null);
179
- }, [editFiles, activeFilename]);
180
- const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }));
181
- const fileIds = useMemo(() => editFiles.map((f) => f.filename), [editFiles]);
182
- const handleDragEnd = useCallback((event) => {
183
- const { active, over } = event;
184
- setDragActiveId(null);
185
- if (!over || active.id === over.id) return;
186
- const oldIndex = editFiles.findIndex((f) => f.filename === active.id);
187
- const newIndex = editFiles.findIndex((f) => f.filename === over.id);
188
- if (oldIndex === -1 || newIndex === -1) return;
189
- setEditFiles(arrayMove(editFiles, oldIndex, newIndex));
190
- }, [editFiles]);
191
- const dragActiveFile = dragActiveId ? editFiles.find((f) => f.filename === dragActiveId) : null;
192
- const { className: portalThemeClassName } = usePortalTheme();
193
- const language = activeFile ? activeFile.language ?? getLanguageFromFilename(activeFile.filename) : "";
194
- return /* @__PURE__ */ jsxs("div", {
195
- className: `${modal} ${semanticClassNames.modal}`,
196
- children: [/* @__PURE__ */ jsxs("div", {
197
- className: `${modalTitlebar} ${semanticClassNames.modalTitlebar}`,
198
- children: [/* @__PURE__ */ jsx("span", {
199
- className: `${modalTitle} ${semanticClassNames.modalTitle}`,
200
- children: "Code Snippet"
201
- }), /* @__PURE__ */ jsx("button", {
202
- className: `${modalIconButton} ${semanticClassNames.modalIconButton}`,
203
- type: "button",
204
- onClick: handleDismiss,
205
- children: /* @__PURE__ */ jsx(X, { size: 14 })
206
- })]
207
- }), /* @__PURE__ */ jsxs("div", {
208
- className: `${modalBody} ${semanticClassNames.modalBody}`,
209
- children: [/* @__PURE__ */ jsxs("div", {
210
- className: `${modalSidebar} ${semanticClassNames.modalSidebar}`,
211
- children: [/* @__PURE__ */ jsxs("div", {
212
- className: `${sidebarHeader} ${semanticClassNames.sidebarHeader}`,
213
- children: [/* @__PURE__ */ jsx("span", { children: "Files" }), /* @__PURE__ */ jsx("button", {
214
- "aria-label": "Add file",
215
- className: `${sidebarAddButton} ${semanticClassNames.sidebarAddButton}`,
216
- type: "button",
217
- onClick: handleAddFile,
218
- children: /* @__PURE__ */ jsx(Plus, { size: 14 })
219
- })]
220
- }), /* @__PURE__ */ jsx("div", {
221
- className: `${fileList} ${semanticClassNames.fileList}`,
222
- children: /* @__PURE__ */ jsxs(DndContext, {
223
- collisionDetection: closestCenter,
224
- sensors,
225
- onDragCancel: () => setDragActiveId(null),
226
- onDragEnd: handleDragEnd,
227
- onDragStart: (event) => setDragActiveId(event.active.id),
228
- children: [/* @__PURE__ */ jsx(SortableContext, {
229
- items: fileIds,
230
- strategy: verticalListSortingStrategy,
231
- children: editFiles.map((file) => /* @__PURE__ */ jsx(SortableFileItem, {
232
- canDelete: editFiles.length > 1,
233
- editValue: newFilenameInput,
234
- file,
235
- isActive: file.filename === activeFilename,
236
- isEditing: editingFilename === file.filename,
237
- onCancelRename: () => setEditingFilename(null),
238
- onCommitRename: () => handleRenameFile(file.filename, newFilenameInput),
239
- onDelete: () => handleDeleteFile(file.filename),
240
- onEditChange: setNewFilenameInput,
241
- onSelect: () => setActiveFilename(file.filename),
242
- onStartRename: () => {
243
- setEditingFilename(file.filename);
244
- setNewFilenameInput(file.filename);
245
- }
246
- }, file.filename))
247
- }), typeof document !== "undefined" ? createPortal(/* @__PURE__ */ jsx(DragOverlay, { children: /* @__PURE__ */ jsx("div", {
248
- className: portalThemeClassName,
249
- style: { display: "contents" },
250
- children: dragActiveFile ? /* @__PURE__ */ jsxs("div", {
251
- className: `${fileItem()} ${semanticClassNames.fileItem} ${dragOverlay} ${semanticClassNames.dragOverlay}`,
252
- children: [/* @__PURE__ */ jsx(FileIcon, {
253
- className: `${fileIcon} ${semanticClassNames.fileIcon}`,
254
- filename: dragActiveFile.filename,
255
- size: 14
256
- }), /* @__PURE__ */ jsx("span", {
257
- className: `${fileName} ${semanticClassNames.fileName}`,
258
- children: dragActiveFile.filename
259
- })]
260
- }) : null
261
- }) }), document.body) : null]
262
- })
263
- })]
264
- }), /* @__PURE__ */ jsxs("div", {
265
- className: `${modalEditor} ${semanticClassNames.modalEditor}`,
266
- children: [/* @__PURE__ */ jsx("div", {
267
- className: `${breadcrumb} ${semanticClassNames.breadcrumb}`,
268
- children: /* @__PURE__ */ jsx("div", {
269
- className: `${breadcrumbLeft} ${semanticClassNames.breadcrumbLeft}`,
270
- children: activeFile && /* @__PURE__ */ jsxs(Fragment, { children: [
271
- /* @__PURE__ */ jsx(FileIcon, {
272
- className: `hjkrycf ${semanticClassNames.fileIcon}`,
273
- filename: activeFile.filename,
274
- size: 14
275
- }),
276
- /* @__PURE__ */ jsx("span", {
277
- className: `hjkryc16 ${semanticClassNames.breadcrumbName}`,
278
- children: activeFile.filename
279
- }),
280
- language && /* @__PURE__ */ jsx("span", {
281
- className: `hjkryc17 ${semanticClassNames.breadcrumbLang}`,
282
- children: language
283
- })
284
- ] })
285
- })
286
- }), /* @__PURE__ */ jsx("div", {
287
- className: `${editorContainer} ${semanticClassNames.editorContainer}`,
288
- ref: containerRef
289
- })]
290
- })]
291
- })]
292
- });
103
+ const CodeEditorModal = ({
104
+ files: initialFiles,
105
+ onFilesChange,
106
+ dismiss,
107
+ colorScheme
108
+ }) => {
109
+ const [editFiles, setEditFiles] = useState(() => initialFiles.map((f) => ({ ...f })));
110
+ const [activeFilename, setActiveFilename] = useState(initialFiles[0]?.filename ?? "");
111
+ const [editingFilename, setEditingFilename] = useState(null);
112
+ const [newFilenameInput, setNewFilenameInput] = useState("");
113
+ const [dragActiveId, setDragActiveId] = useState(null);
114
+ const containerRef = useRef(null);
115
+ const editorRef = useRef(null);
116
+ const languageCompartmentRef = useRef(null);
117
+ const themeCompartmentRef = useRef(null);
118
+ if (!languageCompartmentRef.current) languageCompartmentRef.current = new Compartment();
119
+ if (!themeCompartmentRef.current) themeCompartmentRef.current = new Compartment();
120
+ const onCodeChangeRef = useRef(void 0);
121
+ const editFilesRef = useRef(editFiles);
122
+ editFilesRef.current = editFiles;
123
+ const activeFile = editFiles.find((f) => f.filename === activeFilename) ?? editFiles[0];
124
+ onCodeChangeRef.current = (code) => {
125
+ setEditFiles((prev) => prev.map((f) => f.filename === activeFilename ? { ...f, code } : f));
126
+ };
127
+ useEffect(() => {
128
+ const container = containerRef.current;
129
+ if (!container) return;
130
+ const file = editFilesRef.current.find((f) => f.filename === activeFilename);
131
+ if (!file) return;
132
+ let cancelled = false;
133
+ const lang = normalizeLanguage(file.language ?? getLanguageFromFilename(file.filename));
134
+ const editor = new EditorView({
135
+ parent: container,
136
+ state: EditorState.create({
137
+ doc: file.code,
138
+ extensions: [
139
+ history(),
140
+ keymap.of([...defaultKeymap, ...historyKeymap, indentWithTab]),
141
+ EditorView.updateListener.of((update) => {
142
+ if (!update.docChanged) return;
143
+ onCodeChangeRef.current?.(update.state.doc.toString());
144
+ }),
145
+ lineNumbers(),
146
+ themeCompartmentRef.current.of(getThemeExtensions(colorScheme)),
147
+ languageCompartmentRef.current.of([])
148
+ ]
149
+ })
150
+ });
151
+ editorRef.current = editor;
152
+ (async () => {
153
+ const extension = await loadLanguageExtension(lang);
154
+ if (cancelled) return;
155
+ editor.dispatch({
156
+ effects: languageCompartmentRef.current.reconfigure(extension)
157
+ });
158
+ })();
159
+ return () => {
160
+ cancelled = true;
161
+ editor.destroy();
162
+ editorRef.current = null;
163
+ };
164
+ }, [activeFilename]);
165
+ useEffect(() => {
166
+ const editor = editorRef.current;
167
+ if (!editor) return;
168
+ editor.dispatch({
169
+ effects: themeCompartmentRef.current.reconfigure(getThemeExtensions(colorScheme))
170
+ });
171
+ }, [colorScheme]);
172
+ const handleDismiss = useCallback(() => {
173
+ onFilesChange?.(editFiles);
174
+ dismiss();
175
+ }, [editFiles, onFilesChange, dismiss]);
176
+ const handleAddFile = useCallback(() => {
177
+ const name = `untitled-${editFiles.length + 1}.ts`;
178
+ const newFile = {
179
+ filename: name,
180
+ code: "",
181
+ language: "typescript"
182
+ };
183
+ setEditFiles((prev) => [...prev, newFile]);
184
+ setActiveFilename(name);
185
+ }, [editFiles.length]);
186
+ const handleDeleteFile = useCallback(
187
+ (filename) => {
188
+ if (editFiles.length <= 1) return;
189
+ const newFiles = editFiles.filter((f) => f.filename !== filename);
190
+ setEditFiles(newFiles);
191
+ if (activeFilename === filename) {
192
+ setActiveFilename(newFiles[0]?.filename ?? "");
193
+ }
194
+ },
195
+ [editFiles, activeFilename]
196
+ );
197
+ const handleRenameFile = useCallback(
198
+ (oldName, newName) => {
199
+ if (!newName.trim() || editFiles.some((f) => f.filename === newName && f.filename !== oldName)) {
200
+ setEditingFilename(null);
201
+ return;
202
+ }
203
+ setEditFiles(
204
+ (prev) => prev.map(
205
+ (f) => f.filename === oldName ? { ...f, filename: newName, language: void 0 } : f
206
+ )
207
+ );
208
+ if (activeFilename === oldName) {
209
+ setActiveFilename(newName);
210
+ }
211
+ setEditingFilename(null);
212
+ },
213
+ [editFiles, activeFilename]
214
+ );
215
+ const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }));
216
+ const fileIds = useMemo(() => editFiles.map((f) => f.filename), [editFiles]);
217
+ const handleDragEnd = useCallback(
218
+ (event) => {
219
+ const { active, over } = event;
220
+ setDragActiveId(null);
221
+ if (!over || active.id === over.id) return;
222
+ const oldIndex = editFiles.findIndex((f) => f.filename === active.id);
223
+ const newIndex = editFiles.findIndex((f) => f.filename === over.id);
224
+ if (oldIndex === -1 || newIndex === -1) return;
225
+ setEditFiles(arrayMove(editFiles, oldIndex, newIndex));
226
+ },
227
+ [editFiles]
228
+ );
229
+ const dragActiveFile = dragActiveId ? editFiles.find((f) => f.filename === dragActiveId) : null;
230
+ const { className: portalThemeClassName } = usePortalTheme();
231
+ const language = activeFile ? activeFile.language ?? getLanguageFromFilename(activeFile.filename) : "";
232
+ return /* @__PURE__ */ jsxs("div", { className: `${modal} ${semanticClassNames.modal}`, children: [
233
+ /* @__PURE__ */ jsxs("div", { className: `${modalTitlebar} ${semanticClassNames.modalTitlebar}`, children: [
234
+ /* @__PURE__ */ jsx("span", { className: `${modalTitle} ${semanticClassNames.modalTitle}`, children: "Code Snippet" }),
235
+ /* @__PURE__ */ jsx(
236
+ "button",
237
+ {
238
+ className: `${modalIconButton} ${semanticClassNames.modalIconButton}`,
239
+ type: "button",
240
+ onClick: handleDismiss,
241
+ children: /* @__PURE__ */ jsx(X, { size: 14 })
242
+ }
243
+ )
244
+ ] }),
245
+ /* @__PURE__ */ jsxs("div", { className: `${modalBody} ${semanticClassNames.modalBody}`, children: [
246
+ /* @__PURE__ */ jsxs("div", { className: `${modalSidebar} ${semanticClassNames.modalSidebar}`, children: [
247
+ /* @__PURE__ */ jsxs("div", { className: `${sidebarHeader} ${semanticClassNames.sidebarHeader}`, children: [
248
+ /* @__PURE__ */ jsx("span", { children: "Files" }),
249
+ /* @__PURE__ */ jsx(
250
+ "button",
251
+ {
252
+ "aria-label": "Add file",
253
+ className: `${sidebarAddButton} ${semanticClassNames.sidebarAddButton}`,
254
+ type: "button",
255
+ onClick: handleAddFile,
256
+ children: /* @__PURE__ */ jsx(Plus, { size: 14 })
257
+ }
258
+ )
259
+ ] }),
260
+ /* @__PURE__ */ jsx("div", { className: `${fileList} ${semanticClassNames.fileList}`, children: /* @__PURE__ */ jsxs(
261
+ DndContext,
262
+ {
263
+ collisionDetection: closestCenter,
264
+ sensors,
265
+ onDragCancel: () => setDragActiveId(null),
266
+ onDragEnd: handleDragEnd,
267
+ onDragStart: (event) => setDragActiveId(event.active.id),
268
+ children: [
269
+ /* @__PURE__ */ jsx(SortableContext, { items: fileIds, strategy: verticalListSortingStrategy, children: editFiles.map((file) => /* @__PURE__ */ jsx(
270
+ SortableFileItem,
271
+ {
272
+ canDelete: editFiles.length > 1,
273
+ editValue: newFilenameInput,
274
+ file,
275
+ isActive: file.filename === activeFilename,
276
+ isEditing: editingFilename === file.filename,
277
+ onCancelRename: () => setEditingFilename(null),
278
+ onCommitRename: () => handleRenameFile(file.filename, newFilenameInput),
279
+ onDelete: () => handleDeleteFile(file.filename),
280
+ onEditChange: setNewFilenameInput,
281
+ onSelect: () => setActiveFilename(file.filename),
282
+ onStartRename: () => {
283
+ setEditingFilename(file.filename);
284
+ setNewFilenameInput(file.filename);
285
+ }
286
+ },
287
+ file.filename
288
+ )) }),
289
+ typeof document !== "undefined" ? createPortal(
290
+ /* @__PURE__ */ jsx(DragOverlay, { children: /* @__PURE__ */ jsx("div", { className: portalThemeClassName, style: { display: "contents" }, children: dragActiveFile ? /* @__PURE__ */ jsxs(
291
+ "div",
292
+ {
293
+ className: `${fileItem()} ${semanticClassNames.fileItem} ${dragOverlay} ${semanticClassNames.dragOverlay}`,
294
+ children: [
295
+ /* @__PURE__ */ jsx(
296
+ FileIcon,
297
+ {
298
+ className: `${fileIcon} ${semanticClassNames.fileIcon}`,
299
+ filename: dragActiveFile.filename,
300
+ size: 14
301
+ }
302
+ ),
303
+ /* @__PURE__ */ jsx(
304
+ "span",
305
+ {
306
+ className: `${fileName} ${semanticClassNames.fileName}`,
307
+ children: dragActiveFile.filename
308
+ }
309
+ )
310
+ ]
311
+ }
312
+ ) : null }) }),
313
+ document.body
314
+ ) : null
315
+ ]
316
+ }
317
+ ) })
318
+ ] }),
319
+ /* @__PURE__ */ jsxs("div", { className: `${modalEditor} ${semanticClassNames.modalEditor}`, children: [
320
+ /* @__PURE__ */ jsx("div", { className: `${breadcrumb} ${semanticClassNames.breadcrumb}`, children: /* @__PURE__ */ jsx("div", { className: `${breadcrumbLeft} ${semanticClassNames.breadcrumbLeft}`, children: activeFile && /* @__PURE__ */ jsxs(Fragment, { children: [
321
+ /* @__PURE__ */ jsx(
322
+ FileIcon,
323
+ {
324
+ className: `${fileIcon} ${semanticClassNames.fileIcon}`,
325
+ filename: activeFile.filename,
326
+ size: 14
327
+ }
328
+ ),
329
+ /* @__PURE__ */ jsx(
330
+ "span",
331
+ {
332
+ className: `${breadcrumbName} ${semanticClassNames.breadcrumbName}`,
333
+ children: activeFile.filename
334
+ }
335
+ ),
336
+ language && /* @__PURE__ */ jsx(
337
+ "span",
338
+ {
339
+ className: `${breadcrumbLang} ${semanticClassNames.breadcrumbLang}`,
340
+ children: language
341
+ }
342
+ )
343
+ ] }) }) }),
344
+ /* @__PURE__ */ jsx(
345
+ "div",
346
+ {
347
+ className: `${editorContainer} ${semanticClassNames.editorContainer}`,
348
+ ref: containerRef
349
+ }
350
+ )
351
+ ] })
352
+ ] })
353
+ ] });
293
354
  };
294
- //#endregion
295
- //#region src/CodeSnippetEditRenderer.tsx
296
- var CodeSnippetEditRenderer = ({ files, onFilesChange }) => {
297
- const { className: portalClassName } = usePortalTheme();
298
- const colorScheme = useColorScheme();
299
- const handleEdit = useCallback(() => {
300
- presentDialog({
301
- content: ({ dismiss }) => /* @__PURE__ */ jsx(CodeEditorModal, {
302
- colorScheme,
303
- dismiss,
304
- files,
305
- onFilesChange
306
- }),
307
- className: codeSnippetDialogPopup,
308
- portalClassName,
309
- theme: colorScheme,
310
- showCloseButton: false,
311
- clickOutsideToDismiss: false
312
- });
313
- }, [
314
- files,
315
- onFilesChange,
316
- portalClassName,
317
- colorScheme
318
- ]);
319
- return /* @__PURE__ */ jsxs("div", {
320
- className: `${editContainer} ${semanticClassNames.editContainer}`,
321
- children: [/* @__PURE__ */ jsx(CodeSnippetRenderer, { files }), /* @__PURE__ */ jsx("button", {
322
- "aria-label": "Edit code snippet",
323
- className: `${editOverlay} ${semanticClassNames.editOverlay}`,
324
- type: "button",
325
- onClick: handleEdit,
326
- children: /* @__PURE__ */ jsxs("span", {
327
- className: `${editLabel} ${semanticClassNames.editLabel}`,
328
- children: [/* @__PURE__ */ jsx(Pencil, { size: 14 }), "Edit"]
329
- })
330
- })]
331
- });
355
+ const CodeSnippetEditRenderer = ({
356
+ files,
357
+ onFilesChange
358
+ }) => {
359
+ const { className: portalClassName } = usePortalTheme();
360
+ const colorScheme = useColorScheme();
361
+ const handleEdit = useCallback(() => {
362
+ presentDialog({
363
+ content: ({ dismiss }) => /* @__PURE__ */ jsx(
364
+ CodeEditorModal,
365
+ {
366
+ colorScheme,
367
+ dismiss,
368
+ files,
369
+ onFilesChange
370
+ }
371
+ ),
372
+ className: codeSnippetDialogPopup,
373
+ portalClassName,
374
+ theme: colorScheme,
375
+ showCloseButton: false,
376
+ clickOutsideToDismiss: false
377
+ });
378
+ }, [files, onFilesChange, portalClassName, colorScheme]);
379
+ return /* @__PURE__ */ jsxs("div", { className: `${editContainer} ${semanticClassNames.editContainer}`, children: [
380
+ /* @__PURE__ */ jsx(CodeSnippetRenderer, { files }),
381
+ /* @__PURE__ */ jsx(
382
+ "button",
383
+ {
384
+ "aria-label": "Edit code snippet",
385
+ className: `${editOverlay} ${semanticClassNames.editOverlay}`,
386
+ type: "button",
387
+ onClick: handleEdit,
388
+ children: /* @__PURE__ */ jsxs("span", { className: `${editLabel} ${semanticClassNames.editLabel}`, children: [
389
+ /* @__PURE__ */ jsx(Pencil, { size: 14 }),
390
+ "Edit"
391
+ ] })
392
+ }
393
+ )
394
+ ] });
332
395
  };
333
- //#endregion
334
- //#region ../../node_modules/.pnpm/@lexical+react@0.41.0_react-dom@19.2.4_react@19.2.4__react@19.2.4_yjs@13.6.29/node_modules/@lexical/react/LexicalComposerContext.prod.mjs
335
- /**
336
- * Copyright (c) Meta Platforms, Inc. and affiliates.
337
- *
338
- * This source code is licensed under the MIT license found in the
339
- * LICENSE file in the root directory of this source tree.
340
- *
341
- */
342
- var r = createContext(null);
396
+ const r = createContext(null);
343
397
  function o() {
344
- const n = useContext(r);
345
- return n ?? function(n, ...e) {
346
- const r = new URL("https://lexical.dev/docs/error"), t = new URLSearchParams();
347
- t.append("code", n);
348
- for (const n of e) t.append("v", n);
349
- throw r.search = t.toString(), Error(`Minified Lexical error #${n}; visit ${r.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`);
350
- }(8), n;
398
+ const n = useContext(r);
399
+ return null == n && (function(n2, ...e) {
400
+ const r2 = new URL("https://lexical.dev/docs/error"), t = new URLSearchParams();
401
+ t.append("code", n2);
402
+ for (const n3 of e) t.append("v", n3);
403
+ throw r2.search = t.toString(), Error(`Minified Lexical error #${n2}; visit ${r2.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`);
404
+ })(8), n;
351
405
  }
352
- //#endregion
353
- //#region src/CodeSnippetEditDecorator.tsx
354
- var CodeSnippetEditDecorator = ({ nodeKey, files }) => {
355
- const [editor] = o();
356
- return /* @__PURE__ */ jsx(CodeSnippetEditRenderer, {
357
- files,
358
- onFilesChange: useCallback((newFiles) => {
359
- editor.update(() => {
360
- const node = $getNodeByKey(nodeKey);
361
- if ($isCodeSnippetNode(node)) node.setFiles(newFiles);
362
- });
363
- }, [editor, nodeKey])
364
- });
406
+ const CodeSnippetEditDecorator = ({ nodeKey, files }) => {
407
+ const [editor] = o();
408
+ const onFilesChange = useCallback(
409
+ (newFiles) => {
410
+ editor.update(() => {
411
+ const node = $getNodeByKey(nodeKey);
412
+ if ($isCodeSnippetNode(node)) {
413
+ node.setFiles(newFiles);
414
+ }
415
+ });
416
+ },
417
+ [editor, nodeKey]
418
+ );
419
+ return /* @__PURE__ */ jsx(CodeSnippetEditRenderer, { files, onFilesChange });
365
420
  };
366
- //#endregion
367
- //#region src/nodes/CodeSnippetEditNode.ts
368
- var CodeSnippetEditNode = class CodeSnippetEditNode extends CodeSnippetNode {
369
- static clone(node) {
370
- return new CodeSnippetEditNode(node.__files, node.__key);
371
- }
372
- static importJSON(serializedNode) {
373
- return new CodeSnippetEditNode(serializedNode.files);
374
- }
375
- decorate(_editor, _config) {
376
- return createElement(CodeSnippetEditDecorator, {
377
- nodeKey: this.__key,
378
- files: this.__files
379
- });
380
- }
421
+ const _CodeSnippetEditNode = class _CodeSnippetEditNode extends CodeSnippetNode {
422
+ static clone(node) {
423
+ return new _CodeSnippetEditNode(node.__files, node.__key);
424
+ }
425
+ static importJSON(serializedNode) {
426
+ return new _CodeSnippetEditNode(serializedNode.files);
427
+ }
428
+ decorate(_editor, _config) {
429
+ return createElement(CodeSnippetEditDecorator, {
430
+ nodeKey: this.__key,
431
+ files: this.__files
432
+ });
433
+ }
381
434
  };
382
- _defineProperty(CodeSnippetEditNode, "commandItems", [{
383
- title: "Code Snippet",
384
- icon: createElement(FileCode, { size: 20 }),
385
- description: "Multi-file code snippet with tabs",
386
- keywords: [
387
- "code",
388
- "snippet",
389
- "files",
390
- "tabs"
391
- ],
392
- section: "MEDIA",
393
- placement: ["slash", "toolbar"],
394
- group: "insert",
395
- onSelect: (editor) => {
396
- editor.update(() => {
397
- $insertNodes([$createCodeSnippetEditNode([{
398
- filename: "index.ts",
399
- code: "",
400
- language: "typescript"
401
- }])]);
402
- });
403
- }
404
- }]);
435
+ __publicField(_CodeSnippetEditNode, "commandItems", [
436
+ {
437
+ title: "Code Snippet",
438
+ icon: createElement(FileCode, { size: 20 }),
439
+ description: "Multi-file code snippet with tabs",
440
+ keywords: ["code", "snippet", "files", "tabs"],
441
+ section: "MEDIA",
442
+ placement: ["slash", "toolbar"],
443
+ group: "insert",
444
+ onSelect: (editor) => {
445
+ editor.update(() => {
446
+ $insertNodes([
447
+ $createCodeSnippetEditNode([
448
+ { filename: "index.ts", code: "", language: "typescript" }
449
+ ])
450
+ ]);
451
+ });
452
+ }
453
+ }
454
+ ]);
455
+ let CodeSnippetEditNode = _CodeSnippetEditNode;
405
456
  function $createCodeSnippetEditNode(files) {
406
- return new CodeSnippetEditNode(files);
457
+ return new CodeSnippetEditNode(files);
407
458
  }
408
459
  function $isCodeSnippetEditNode(node) {
409
- return node instanceof CodeSnippetEditNode;
460
+ return node instanceof CodeSnippetEditNode;
410
461
  }
411
- //#endregion
412
- //#region src/nodes/index.ts
413
- var codeSnippetNodes = [CodeSnippetNode];
414
- var codeSnippetEditNodes = [CodeSnippetEditNode];
415
- //#endregion
416
- export { $createCodeSnippetEditNode, $createCodeSnippetNode, $isCodeSnippetEditNode, $isCodeSnippetNode, CODE_SNIPPET_BLOCK_TRANSFORMER, CodeSnippetEditNode, CodeSnippetEditRenderer, CodeSnippetNode, CodeSnippetRenderer, codeSnippetEditNodes, codeSnippetNodes };
462
+ const codeSnippetNodes = [CodeSnippetNode];
463
+ const codeSnippetEditNodes = [CodeSnippetEditNode];
464
+ export {
465
+ $createCodeSnippetEditNode,
466
+ E as $createCodeSnippetNode,
467
+ $isCodeSnippetEditNode,
468
+ $isCodeSnippetNode,
469
+ CODE_SNIPPET_BLOCK_TRANSFORMER,
470
+ CodeSnippetEditNode,
471
+ CodeSnippetEditRenderer,
472
+ CodeSnippetNode,
473
+ CodeSnippetRenderer,
474
+ codeSnippetEditNodes,
475
+ codeSnippetNodes
476
+ };