@pixerate/editor-react 0.10.0 → 0.10.2
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 +122 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +135 -93
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -11,7 +11,11 @@ export { ImageEditor, ImageEditorProps, UseImageEditorReturn, useImageEditor } f
|
|
|
11
11
|
import '@pixerate/editor/image-editor';
|
|
12
12
|
|
|
13
13
|
interface UsePromptEditorProps {
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* The editor content as plain text. Changes from the parent (e.g. clearing
|
|
16
|
+
* after submit) are applied to the editor; echoes of the editor's own
|
|
17
|
+
* updates via `onContentChange` are ignored.
|
|
18
|
+
*/
|
|
15
19
|
content: string;
|
|
16
20
|
/** Callback fired when the editor content changes (returns plain text) */
|
|
17
21
|
onContentChange: (text: string) => void;
|
|
@@ -43,7 +47,10 @@ interface UsePromptEditorProps {
|
|
|
43
47
|
clearSlashCommand?: () => void;
|
|
44
48
|
/** Whether a slash command menu is currently active */
|
|
45
49
|
slashCommandActive?: boolean;
|
|
46
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Callback fired the first time each milestone is reached while the editor
|
|
52
|
+
* is mounted: `used_variable` ({variable}) and `used_magic` (__instruction__).
|
|
53
|
+
*/
|
|
47
54
|
onMilestone?: (milestone: string) => void;
|
|
48
55
|
/** DOM element ID of the container, used for positioning popovers */
|
|
49
56
|
containerId?: string;
|
|
@@ -216,7 +223,7 @@ declare function useSpreadsheetEditor(options?: SpreadsheetControllerOptions): {
|
|
|
216
223
|
registerDataSource: (ds: SpreadsheetDataSource) => void;
|
|
217
224
|
setPrimaryDataSource: (id: string | undefined) => void;
|
|
218
225
|
recalculateAll: () => void;
|
|
219
|
-
exportToTsv: () => string;
|
|
226
|
+
exportToTsv: (range?: CellRange | null) => string;
|
|
220
227
|
importFromTsv: (data: string) => void;
|
|
221
228
|
undo: () => void;
|
|
222
229
|
redo: () => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,11 @@ export { ImageEditor, ImageEditorProps, UseImageEditorReturn, useImageEditor } f
|
|
|
11
11
|
import '@pixerate/editor/image-editor';
|
|
12
12
|
|
|
13
13
|
interface UsePromptEditorProps {
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* The editor content as plain text. Changes from the parent (e.g. clearing
|
|
16
|
+
* after submit) are applied to the editor; echoes of the editor's own
|
|
17
|
+
* updates via `onContentChange` are ignored.
|
|
18
|
+
*/
|
|
15
19
|
content: string;
|
|
16
20
|
/** Callback fired when the editor content changes (returns plain text) */
|
|
17
21
|
onContentChange: (text: string) => void;
|
|
@@ -43,7 +47,10 @@ interface UsePromptEditorProps {
|
|
|
43
47
|
clearSlashCommand?: () => void;
|
|
44
48
|
/** Whether a slash command menu is currently active */
|
|
45
49
|
slashCommandActive?: boolean;
|
|
46
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Callback fired the first time each milestone is reached while the editor
|
|
52
|
+
* is mounted: `used_variable` ({variable}) and `used_magic` (__instruction__).
|
|
53
|
+
*/
|
|
47
54
|
onMilestone?: (milestone: string) => void;
|
|
48
55
|
/** DOM element ID of the container, used for positioning popovers */
|
|
49
56
|
containerId?: string;
|
|
@@ -216,7 +223,7 @@ declare function useSpreadsheetEditor(options?: SpreadsheetControllerOptions): {
|
|
|
216
223
|
registerDataSource: (ds: SpreadsheetDataSource) => void;
|
|
217
224
|
setPrimaryDataSource: (id: string | undefined) => void;
|
|
218
225
|
recalculateAll: () => void;
|
|
219
|
-
exportToTsv: () => string;
|
|
226
|
+
exportToTsv: (range?: CellRange | null) => string;
|
|
220
227
|
importFromTsv: (data: string) => void;
|
|
221
228
|
undo: () => void;
|
|
222
229
|
redo: () => void;
|
package/dist/index.js
CHANGED
|
@@ -8,18 +8,22 @@ import { useMemo, useEffect, useRef } from "react";
|
|
|
8
8
|
import { useEditor } from "@tiptap/react";
|
|
9
9
|
import StarterKit from "@tiptap/starter-kit";
|
|
10
10
|
import Placeholder from "@tiptap/extension-placeholder";
|
|
11
|
-
import { Slice
|
|
11
|
+
import { Slice } from "@tiptap/pm/model";
|
|
12
12
|
import {
|
|
13
13
|
GradientText,
|
|
14
14
|
TemplateSuggestions,
|
|
15
15
|
LoadingNode,
|
|
16
16
|
plainTextToTipTapHtml,
|
|
17
|
-
|
|
17
|
+
plainTextToSlice,
|
|
18
|
+
getEditorText,
|
|
19
|
+
tokenizePrompt
|
|
18
20
|
} from "@pixerate/editor";
|
|
19
21
|
var DEFAULT_TEMPLATES = [];
|
|
20
22
|
var DEFAULT_COLOR_MAP = /* @__PURE__ */ new Map([
|
|
21
23
|
["default", { from: "#f43f5e", to: "#8b5cf6" }]
|
|
22
24
|
]);
|
|
25
|
+
var DEFAULT_CLASS_NAME = "w-full border border-input rounded-md p-3 font-mono text-sm leading-relaxed focus:outline-none focus:ring-2 focus:ring-primary whitespace-pre-wrap break-words";
|
|
26
|
+
var normalizeNewlines = (text) => text.replace(/\r\n?/g, "\n");
|
|
23
27
|
function usePromptEditor({
|
|
24
28
|
content,
|
|
25
29
|
onContentChange,
|
|
@@ -60,6 +64,7 @@ function usePromptEditor({
|
|
|
60
64
|
const templateKey = useMemo(() => {
|
|
61
65
|
return (templates || []).map((t) => `${t.id || t.name}:${t.latestVersion || ""}`).sort().join(",");
|
|
62
66
|
}, [templates]);
|
|
67
|
+
const colorMapKey = userColorMap ? JSON.stringify(Array.from(userColorMap.entries())) : "";
|
|
63
68
|
const resolvedColorMap = useMemo(() => {
|
|
64
69
|
if (userColorMap) return userColorMap;
|
|
65
70
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -67,7 +72,9 @@ function usePromptEditor({
|
|
|
67
72
|
map.set(t.name, { from: "#f43f5e", to: "#8b5cf6" });
|
|
68
73
|
});
|
|
69
74
|
return map.size > 0 ? map : DEFAULT_COLOR_MAP;
|
|
70
|
-
}, [
|
|
75
|
+
}, [colorMapKey, templateKey]);
|
|
76
|
+
const jsonVariablesKey = (jsonVariables || []).join("\0");
|
|
77
|
+
const reachedMilestonesRef = useRef(/* @__PURE__ */ new Set());
|
|
71
78
|
const StarterKitExt = StarterKit?.configure ? StarterKit : StarterKit?.default?.configure ? StarterKit?.default : StarterKit;
|
|
72
79
|
const PlaceholderExt = Placeholder?.configure ? Placeholder : Placeholder?.default?.configure ? Placeholder?.default : Placeholder;
|
|
73
80
|
const editor = useEditor(
|
|
@@ -97,11 +104,13 @@ function usePromptEditor({
|
|
|
97
104
|
const plainText = getEditorText(ed);
|
|
98
105
|
onContentChangeRef.current?.(plainText);
|
|
99
106
|
if (onMilestoneRef.current) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
const reached = reachedMilestonesRef.current;
|
|
108
|
+
for (const token of tokenizePrompt(plainText)) {
|
|
109
|
+
const milestone = token.type === "variable" ? "used_variable" : token.type === "instruction" ? "used_magic" : null;
|
|
110
|
+
if (milestone && !reached.has(milestone)) {
|
|
111
|
+
reached.add(milestone);
|
|
112
|
+
onMilestoneRef.current(milestone);
|
|
113
|
+
}
|
|
105
114
|
}
|
|
106
115
|
}
|
|
107
116
|
const { state, view } = ed;
|
|
@@ -139,7 +148,7 @@ function usePromptEditor({
|
|
|
139
148
|
},
|
|
140
149
|
editorProps: {
|
|
141
150
|
attributes: {
|
|
142
|
-
class: className ||
|
|
151
|
+
class: className || DEFAULT_CLASS_NAME,
|
|
143
152
|
role: "textbox",
|
|
144
153
|
"aria-label": "Prompt editor"
|
|
145
154
|
},
|
|
@@ -171,51 +180,61 @@ function usePromptEditor({
|
|
|
171
180
|
event.preventDefault();
|
|
172
181
|
const schema = view.state.schema;
|
|
173
182
|
if (!schema) return false;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const nodeJson = { type: "paragraph" };
|
|
178
|
-
if (line.length > 0) {
|
|
179
|
-
nodeJson.content = [{ type: "text", text: line }];
|
|
180
|
-
}
|
|
181
|
-
try {
|
|
182
|
-
const node = ProsemirrorNode.fromJSON(schema, nodeJson);
|
|
183
|
-
nodes.push(node);
|
|
184
|
-
} catch {
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
const parsedSlice = Slice.maxOpen(Fragment.fromArray(nodes));
|
|
188
|
-
const tr = view.state.tr.replaceSelection(parsedSlice);
|
|
189
|
-
view.dispatch(tr);
|
|
183
|
+
view.dispatch(
|
|
184
|
+
view.state.tr.replaceSelection(plainTextToSlice(text, schema))
|
|
185
|
+
);
|
|
190
186
|
return true;
|
|
191
187
|
},
|
|
192
188
|
clipboardTextParser: (text, context, _plain, view) => {
|
|
193
189
|
const schema = context?.doc?.type?.schema || context?.schema || view?.state?.schema;
|
|
194
190
|
if (!schema) return Slice.empty;
|
|
195
|
-
|
|
196
|
-
const nodes = [];
|
|
197
|
-
blocks.forEach((line) => {
|
|
198
|
-
const nodeJson = { type: "paragraph" };
|
|
199
|
-
if (line.length > 0) {
|
|
200
|
-
nodeJson.content = [{ type: "text", text: line }];
|
|
201
|
-
}
|
|
202
|
-
try {
|
|
203
|
-
const node = ProsemirrorNode.fromJSON(schema, nodeJson);
|
|
204
|
-
nodes.push(node);
|
|
205
|
-
} catch {
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
return Slice.maxOpen(Fragment.fromArray(nodes));
|
|
191
|
+
return plainTextToSlice(text, schema);
|
|
209
192
|
}
|
|
210
193
|
}
|
|
211
194
|
},
|
|
212
|
-
|
|
195
|
+
// Only options baked into extensions recreate the editor; editable state,
|
|
196
|
+
// placeholder, class names and content are applied to the live instance.
|
|
197
|
+
[resolvedColorMap, templateKey, speed, jsonVariablesKey]
|
|
213
198
|
);
|
|
214
199
|
useEffect(() => {
|
|
215
200
|
if (editor && !editor.isDestroyed) {
|
|
216
201
|
editor.setEditable(isEditing);
|
|
217
202
|
}
|
|
218
203
|
}, [editor, isEditing]);
|
|
204
|
+
useEffect(() => {
|
|
205
|
+
if (!editor || editor.isDestroyed) return;
|
|
206
|
+
if (normalizeNewlines(content) === getEditorText(editor)) return;
|
|
207
|
+
const { from, to } = editor.state.selection;
|
|
208
|
+
editor.commands.setContent(plainTextToTipTapHtml(content), false);
|
|
209
|
+
const max = editor.state.doc.content.size;
|
|
210
|
+
editor.commands.setTextSelection({
|
|
211
|
+
from: Math.min(from, max),
|
|
212
|
+
to: Math.min(to, max)
|
|
213
|
+
});
|
|
214
|
+
}, [editor, content]);
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
if (!editor || editor.isDestroyed) return;
|
|
217
|
+
editor.setOptions({
|
|
218
|
+
editorProps: {
|
|
219
|
+
...editor.options.editorProps,
|
|
220
|
+
attributes: {
|
|
221
|
+
...editor.options.editorProps.attributes,
|
|
222
|
+
class: className || DEFAULT_CLASS_NAME
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}, [editor, className]);
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
if (!editor || editor.isDestroyed) return;
|
|
229
|
+
const placeholderExt = editor.extensionManager.extensions.find(
|
|
230
|
+
(ext) => ext.name === "placeholder"
|
|
231
|
+
);
|
|
232
|
+
if (!placeholderExt || placeholderExt.options.placeholder === placeholder) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
placeholderExt.options.placeholder = placeholder;
|
|
236
|
+
editor.view.dispatch(editor.state.tr);
|
|
237
|
+
}, [editor, placeholder]);
|
|
219
238
|
return editor;
|
|
220
239
|
}
|
|
221
240
|
|
|
@@ -518,7 +537,7 @@ var BubbleMenu = ({
|
|
|
518
537
|
// src/components/TemplateRenderer.tsx
|
|
519
538
|
import { useMemo as useMemo3 } from "react";
|
|
520
539
|
import {
|
|
521
|
-
tokenizePrompt,
|
|
540
|
+
tokenizePrompt as tokenizePrompt2,
|
|
522
541
|
resolveTemplates
|
|
523
542
|
} from "@pixerate/editor";
|
|
524
543
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
@@ -536,7 +555,7 @@ var TemplateRenderer = ({
|
|
|
536
555
|
return resolveTemplates(content, templates);
|
|
537
556
|
}, [content, templates, resolve]);
|
|
538
557
|
const tokens = useMemo3(() => {
|
|
539
|
-
return
|
|
558
|
+
return tokenizePrompt2(displayText);
|
|
540
559
|
}, [displayText]);
|
|
541
560
|
return /* @__PURE__ */ jsx2("div", { className, children: tokens.map((token, index) => {
|
|
542
561
|
if (token.type === "template") {
|
|
@@ -597,41 +616,37 @@ import {
|
|
|
597
616
|
} from "@pixerate/editor";
|
|
598
617
|
|
|
599
618
|
// src/spreadsheet/useSpreadsheetEditor.ts
|
|
600
|
-
import { useState as useState4,
|
|
619
|
+
import { useState as useState4, useRef as useRef5, useCallback as useCallback4 } from "react";
|
|
601
620
|
import {
|
|
602
621
|
SpreadsheetController
|
|
603
622
|
} from "@pixerate/editor";
|
|
604
623
|
function useSpreadsheetEditor(options = {}) {
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
cells: options.document?.cells || {},
|
|
611
|
-
createdAt: options.document?.createdAt || Date.now(),
|
|
612
|
-
updatedAt: options.document?.updatedAt || Date.now()
|
|
613
|
-
}));
|
|
614
|
-
const [activeCell, setActiveCell] = useState4(null);
|
|
615
|
-
const [selectedRange, setSelectedRange] = useState4(null);
|
|
616
|
-
const [editingCell, setEditingCell] = useState4(null);
|
|
617
|
-
const [draftValue, setDraftValue] = useState4("");
|
|
618
|
-
const controller = useMemo4(() => {
|
|
619
|
-
return new SpreadsheetController({
|
|
624
|
+
const optionsRef = useRef5(options);
|
|
625
|
+
optionsRef.current = options;
|
|
626
|
+
const settersRef = useRef5({});
|
|
627
|
+
const [controller] = useState4(
|
|
628
|
+
() => new SpreadsheetController({
|
|
620
629
|
...options,
|
|
621
630
|
onDocumentChange: (updated) => {
|
|
622
|
-
setDoc({ ...updated });
|
|
623
|
-
|
|
631
|
+
settersRef.current.setDoc?.({ ...updated });
|
|
632
|
+
optionsRef.current.onDocumentChange?.(updated);
|
|
624
633
|
},
|
|
625
634
|
onSelectionChange: (active, range) => {
|
|
626
|
-
setActiveCell(active);
|
|
627
|
-
setSelectedRange(range);
|
|
628
|
-
|
|
635
|
+
settersRef.current.setActiveCell?.(active);
|
|
636
|
+
settersRef.current.setSelectedRange?.(range);
|
|
637
|
+
optionsRef.current.onSelectionChange?.(active, range);
|
|
629
638
|
},
|
|
630
639
|
onCellCommit: (rowId, colId, raw, value) => {
|
|
631
|
-
|
|
640
|
+
optionsRef.current.onCellCommit?.(rowId, colId, raw, value);
|
|
632
641
|
}
|
|
633
|
-
})
|
|
634
|
-
|
|
642
|
+
})
|
|
643
|
+
);
|
|
644
|
+
const [doc, setDoc] = useState4(() => ({ ...controller.document }));
|
|
645
|
+
const [activeCell, setActiveCell] = useState4(controller.activeCell);
|
|
646
|
+
const [selectedRange, setSelectedRange] = useState4(controller.selectedRange);
|
|
647
|
+
const [editingCell, setEditingCell] = useState4(null);
|
|
648
|
+
const [draftValue, setDraftValue] = useState4("");
|
|
649
|
+
settersRef.current = { setDoc, setActiveCell, setSelectedRange };
|
|
635
650
|
const setCellValue = useCallback4((rowId, colId, raw) => {
|
|
636
651
|
controller.setCellValue(rowId, colId, raw);
|
|
637
652
|
setDoc({ ...controller.document });
|
|
@@ -749,7 +764,7 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
749
764
|
registerDataSource,
|
|
750
765
|
setPrimaryDataSource,
|
|
751
766
|
recalculateAll,
|
|
752
|
-
exportToTsv: () => controller.exportToTsv(),
|
|
767
|
+
exportToTsv: (range) => controller.exportToTsv(range),
|
|
753
768
|
importFromTsv: (data) => {
|
|
754
769
|
controller.importFromTsv(data);
|
|
755
770
|
setDoc({ ...controller.document });
|
|
@@ -760,7 +775,7 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
760
775
|
}
|
|
761
776
|
|
|
762
777
|
// src/spreadsheet/SpreadsheetEditor.tsx
|
|
763
|
-
import { useRef as
|
|
778
|
+
import { useRef as useRef6, useState as useState5, useMemo as useMemo4, useEffect as useEffect5, useCallback as useCallback5 } from "react";
|
|
764
779
|
import {
|
|
765
780
|
indexToColName
|
|
766
781
|
} from "@pixerate/editor";
|
|
@@ -775,23 +790,42 @@ var SpreadsheetEditor = ({
|
|
|
775
790
|
}) => {
|
|
776
791
|
const defaultState = useSpreadsheetEditor();
|
|
777
792
|
const state = externalState || defaultState;
|
|
778
|
-
const gridRef =
|
|
793
|
+
const gridRef = useRef6(null);
|
|
779
794
|
const [resizingColId, setResizingColId] = useState5(null);
|
|
780
795
|
const [hoveredColId, setHoveredColId] = useState5(null);
|
|
781
796
|
const [resizeStartX, setResizeStartX] = useState5(0);
|
|
782
797
|
const [resizeStartWidth, setResizeStartWidth] = useState5(0);
|
|
783
|
-
const activeRawValue =
|
|
798
|
+
const activeRawValue = useMemo4(() => {
|
|
784
799
|
if (!state.activeCell) return "";
|
|
785
800
|
const row = state.document.rows[state.activeCell.row];
|
|
786
801
|
const col = state.document.columns[state.activeCell.col];
|
|
787
802
|
if (!row || !col) return "";
|
|
788
803
|
return state.getCell(row.id, col.id).raw;
|
|
789
804
|
}, [state.activeCell, state.document]);
|
|
790
|
-
const coordLabel =
|
|
805
|
+
const coordLabel = useMemo4(() => {
|
|
791
806
|
if (!state.activeCell) return "--";
|
|
792
807
|
const colName = indexToColName(state.activeCell.col);
|
|
793
808
|
return `${colName}${state.activeCell.row + 1}`;
|
|
794
809
|
}, [state.activeCell]);
|
|
810
|
+
const [formulaDraft, setFormulaDraft] = useState5(null);
|
|
811
|
+
const activeColumn = state.activeCell ? state.document.columns[state.activeCell.col] : void 0;
|
|
812
|
+
const formulaBarReadOnly = readOnly || !state.activeCell || !!activeColumn?.readOnly;
|
|
813
|
+
useEffect5(() => {
|
|
814
|
+
setFormulaDraft(null);
|
|
815
|
+
}, [state.activeCell?.row, state.activeCell?.col]);
|
|
816
|
+
const commitFormulaBar = () => {
|
|
817
|
+
if (state.editingCell) {
|
|
818
|
+
state.commitEditing();
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
if (formulaDraft === null || !state.activeCell) return;
|
|
822
|
+
const row = state.document.rows[state.activeCell.row];
|
|
823
|
+
const col = state.document.columns[state.activeCell.col];
|
|
824
|
+
if (row && col && !formulaBarReadOnly && formulaDraft !== activeRawValue) {
|
|
825
|
+
state.setCellValue(row.id, col.id, formulaDraft);
|
|
826
|
+
}
|
|
827
|
+
setFormulaDraft(null);
|
|
828
|
+
};
|
|
795
829
|
const handleCellClick = useCallback5((rIdx, cIdx, e) => {
|
|
796
830
|
if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
|
|
797
831
|
state.commitEditing();
|
|
@@ -850,16 +884,19 @@ var SpreadsheetEditor = ({
|
|
|
850
884
|
e.preventDefault();
|
|
851
885
|
state.setCellValue(row.id, col.id, "");
|
|
852
886
|
}
|
|
853
|
-
} else if ((e.metaKey || e.ctrlKey) && e.key === "z") {
|
|
887
|
+
} else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
854
888
|
e.preventDefault();
|
|
855
889
|
if (e.shiftKey) {
|
|
856
890
|
state.redo();
|
|
857
891
|
} else {
|
|
858
892
|
state.undo();
|
|
859
893
|
}
|
|
860
|
-
} else if (
|
|
894
|
+
} else if (e.ctrlKey && !e.metaKey && e.key.toLowerCase() === "y") {
|
|
861
895
|
e.preventDefault();
|
|
862
|
-
|
|
896
|
+
state.redo();
|
|
897
|
+
} else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "c") {
|
|
898
|
+
e.preventDefault();
|
|
899
|
+
const tsv = state.exportToTsv(state.selectedRange);
|
|
863
900
|
navigator.clipboard?.writeText(tsv);
|
|
864
901
|
} else if (!readOnly && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
865
902
|
const col = state.document.columns[state.activeCell.col];
|
|
@@ -868,6 +905,10 @@ var SpreadsheetEditor = ({
|
|
|
868
905
|
}
|
|
869
906
|
}
|
|
870
907
|
}, [readOnly, state]);
|
|
908
|
+
const stateRef = useRef6(state);
|
|
909
|
+
stateRef.current = state;
|
|
910
|
+
const onColumnResizeRef = useRef6(onColumnResize);
|
|
911
|
+
onColumnResizeRef.current = onColumnResize;
|
|
871
912
|
useEffect5(() => {
|
|
872
913
|
if (!resizingColId) return;
|
|
873
914
|
if (typeof document !== "undefined") {
|
|
@@ -886,7 +927,7 @@ var SpreadsheetEditor = ({
|
|
|
886
927
|
if (rafId === null) {
|
|
887
928
|
rafId = requestAnimationFrame(() => {
|
|
888
929
|
rafId = null;
|
|
889
|
-
|
|
930
|
+
stateRef.current.setColumnWidth(resizingColId, pendingWidth);
|
|
890
931
|
});
|
|
891
932
|
}
|
|
892
933
|
};
|
|
@@ -896,11 +937,8 @@ var SpreadsheetEditor = ({
|
|
|
896
937
|
rafId = null;
|
|
897
938
|
}
|
|
898
939
|
if (hasDragged) {
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
if (col && onColumnResize) {
|
|
902
|
-
onColumnResize(col.id, col.width || pendingWidth);
|
|
903
|
-
}
|
|
940
|
+
stateRef.current.setColumnWidth(resizingColId, pendingWidth);
|
|
941
|
+
onColumnResizeRef.current?.(resizingColId, pendingWidth);
|
|
904
942
|
}
|
|
905
943
|
setResizingColId(null);
|
|
906
944
|
if (typeof document !== "undefined") {
|
|
@@ -921,7 +959,7 @@ var SpreadsheetEditor = ({
|
|
|
921
959
|
window.removeEventListener("mousemove", handleMouseMove);
|
|
922
960
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
923
961
|
};
|
|
924
|
-
}, [resizingColId, resizeStartX, resizeStartWidth
|
|
962
|
+
}, [resizingColId, resizeStartX, resizeStartWidth]);
|
|
925
963
|
const measureElementContentWidth = useCallback5((el, container) => {
|
|
926
964
|
if (typeof document === "undefined") return 0;
|
|
927
965
|
let maxW = el.scrollWidth || 0;
|
|
@@ -1053,25 +1091,29 @@ var SpreadsheetEditor = ({
|
|
|
1053
1091
|
type: "text",
|
|
1054
1092
|
className: "flex-1 bg-transparent px-2 py-0.5 outline-none font-sans text-xs text-foreground placeholder:text-muted-foreground/60 focus:bg-background focus:ring-1 focus:ring-primary rounded",
|
|
1055
1093
|
placeholder: "Enter a value or formula (e.g. =SUM(A1:A5))",
|
|
1056
|
-
|
|
1094
|
+
"aria-label": "Formula bar",
|
|
1095
|
+
readOnly: formulaBarReadOnly,
|
|
1096
|
+
value: state.editingCell ? state.draftValue : formulaDraft ?? activeRawValue,
|
|
1097
|
+
onFocus: () => {
|
|
1098
|
+
if (!state.editingCell) setFormulaDraft(activeRawValue);
|
|
1099
|
+
},
|
|
1057
1100
|
onChange: (e) => {
|
|
1058
|
-
if (state.
|
|
1101
|
+
if (state.editingCell) {
|
|
1059
1102
|
state.setDraftValue(e.target.value);
|
|
1103
|
+
} else if (state.activeCell) {
|
|
1104
|
+
setFormulaDraft(e.target.value);
|
|
1060
1105
|
}
|
|
1061
1106
|
},
|
|
1107
|
+
onBlur: () => commitFormulaBar(),
|
|
1062
1108
|
onKeyDown: (e) => {
|
|
1109
|
+
e.stopPropagation();
|
|
1063
1110
|
if (e.key === "Enter") {
|
|
1064
1111
|
e.preventDefault();
|
|
1065
|
-
|
|
1066
|
-
const row = state.document.rows[state.activeCell.row];
|
|
1067
|
-
const col = state.document.columns[state.activeCell.col];
|
|
1068
|
-
if (row && col) {
|
|
1069
|
-
state.setCellValue(row.id, col.id, e.target.value);
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1112
|
+
commitFormulaBar();
|
|
1072
1113
|
} else if (e.key === "Escape") {
|
|
1073
1114
|
e.preventDefault();
|
|
1074
|
-
|
|
1115
|
+
setFormulaDraft(null);
|
|
1116
|
+
if (state.editingCell) state.cancelEditing();
|
|
1075
1117
|
}
|
|
1076
1118
|
}
|
|
1077
1119
|
}
|
|
@@ -1197,7 +1239,7 @@ var SpreadsheetEditor = ({
|
|
|
1197
1239
|
};
|
|
1198
1240
|
|
|
1199
1241
|
// src/slots.tsx
|
|
1200
|
-
import { createContext, useContext, useMemo as
|
|
1242
|
+
import { createContext, useContext, useMemo as useMemo5 } from "react";
|
|
1201
1243
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1202
1244
|
var defaultSlots = {
|
|
1203
1245
|
Button: (props) => /* @__PURE__ */ jsx4(
|
|
@@ -1221,7 +1263,7 @@ var defaultSlots = {
|
|
|
1221
1263
|
};
|
|
1222
1264
|
var EditorSlotsContext = createContext(defaultSlots);
|
|
1223
1265
|
function EditorSlotsProvider({ slots, children }) {
|
|
1224
|
-
const mergedSlots =
|
|
1266
|
+
const mergedSlots = useMemo5(() => ({ ...defaultSlots, ...slots }), [slots]);
|
|
1225
1267
|
return /* @__PURE__ */ jsx4(EditorSlotsContext.Provider, { value: mergedSlots, children });
|
|
1226
1268
|
}
|
|
1227
1269
|
function useEditorSlots() {
|