@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.cjs
CHANGED
|
@@ -64,6 +64,8 @@ var DEFAULT_TEMPLATES = [];
|
|
|
64
64
|
var DEFAULT_COLOR_MAP = /* @__PURE__ */ new Map([
|
|
65
65
|
["default", { from: "#f43f5e", to: "#8b5cf6" }]
|
|
66
66
|
]);
|
|
67
|
+
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";
|
|
68
|
+
var normalizeNewlines = (text) => text.replace(/\r\n?/g, "\n");
|
|
67
69
|
function usePromptEditor({
|
|
68
70
|
content,
|
|
69
71
|
onContentChange,
|
|
@@ -104,6 +106,7 @@ function usePromptEditor({
|
|
|
104
106
|
const templateKey = (0, import_react.useMemo)(() => {
|
|
105
107
|
return (templates || []).map((t) => `${t.id || t.name}:${t.latestVersion || ""}`).sort().join(",");
|
|
106
108
|
}, [templates]);
|
|
109
|
+
const colorMapKey = userColorMap ? JSON.stringify(Array.from(userColorMap.entries())) : "";
|
|
107
110
|
const resolvedColorMap = (0, import_react.useMemo)(() => {
|
|
108
111
|
if (userColorMap) return userColorMap;
|
|
109
112
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -111,7 +114,9 @@ function usePromptEditor({
|
|
|
111
114
|
map.set(t.name, { from: "#f43f5e", to: "#8b5cf6" });
|
|
112
115
|
});
|
|
113
116
|
return map.size > 0 ? map : DEFAULT_COLOR_MAP;
|
|
114
|
-
}, [
|
|
117
|
+
}, [colorMapKey, templateKey]);
|
|
118
|
+
const jsonVariablesKey = (jsonVariables || []).join("\0");
|
|
119
|
+
const reachedMilestonesRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
115
120
|
const StarterKitExt = import_starter_kit.default?.configure ? import_starter_kit.default : import_starter_kit.default?.default?.configure ? import_starter_kit.default?.default : import_starter_kit.default;
|
|
116
121
|
const PlaceholderExt = import_extension_placeholder.default?.configure ? import_extension_placeholder.default : import_extension_placeholder.default?.default?.configure ? import_extension_placeholder.default?.default : import_extension_placeholder.default;
|
|
117
122
|
const editor = (0, import_react2.useEditor)(
|
|
@@ -141,11 +146,13 @@ function usePromptEditor({
|
|
|
141
146
|
const plainText = (0, import_editor.getEditorText)(ed);
|
|
142
147
|
onContentChangeRef.current?.(plainText);
|
|
143
148
|
if (onMilestoneRef.current) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
const reached = reachedMilestonesRef.current;
|
|
150
|
+
for (const token of (0, import_editor.tokenizePrompt)(plainText)) {
|
|
151
|
+
const milestone = token.type === "variable" ? "used_variable" : token.type === "instruction" ? "used_magic" : null;
|
|
152
|
+
if (milestone && !reached.has(milestone)) {
|
|
153
|
+
reached.add(milestone);
|
|
154
|
+
onMilestoneRef.current(milestone);
|
|
155
|
+
}
|
|
149
156
|
}
|
|
150
157
|
}
|
|
151
158
|
const { state, view } = ed;
|
|
@@ -183,7 +190,7 @@ function usePromptEditor({
|
|
|
183
190
|
},
|
|
184
191
|
editorProps: {
|
|
185
192
|
attributes: {
|
|
186
|
-
class: className ||
|
|
193
|
+
class: className || DEFAULT_CLASS_NAME,
|
|
187
194
|
role: "textbox",
|
|
188
195
|
"aria-label": "Prompt editor"
|
|
189
196
|
},
|
|
@@ -215,51 +222,61 @@ function usePromptEditor({
|
|
|
215
222
|
event.preventDefault();
|
|
216
223
|
const schema = view.state.schema;
|
|
217
224
|
if (!schema) return false;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const nodeJson = { type: "paragraph" };
|
|
222
|
-
if (line.length > 0) {
|
|
223
|
-
nodeJson.content = [{ type: "text", text: line }];
|
|
224
|
-
}
|
|
225
|
-
try {
|
|
226
|
-
const node = import_model.Node.fromJSON(schema, nodeJson);
|
|
227
|
-
nodes.push(node);
|
|
228
|
-
} catch {
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
const parsedSlice = import_model.Slice.maxOpen(import_model.Fragment.fromArray(nodes));
|
|
232
|
-
const tr = view.state.tr.replaceSelection(parsedSlice);
|
|
233
|
-
view.dispatch(tr);
|
|
225
|
+
view.dispatch(
|
|
226
|
+
view.state.tr.replaceSelection((0, import_editor.plainTextToSlice)(text, schema))
|
|
227
|
+
);
|
|
234
228
|
return true;
|
|
235
229
|
},
|
|
236
230
|
clipboardTextParser: (text, context, _plain, view) => {
|
|
237
231
|
const schema = context?.doc?.type?.schema || context?.schema || view?.state?.schema;
|
|
238
232
|
if (!schema) return import_model.Slice.empty;
|
|
239
|
-
|
|
240
|
-
const nodes = [];
|
|
241
|
-
blocks.forEach((line) => {
|
|
242
|
-
const nodeJson = { type: "paragraph" };
|
|
243
|
-
if (line.length > 0) {
|
|
244
|
-
nodeJson.content = [{ type: "text", text: line }];
|
|
245
|
-
}
|
|
246
|
-
try {
|
|
247
|
-
const node = import_model.Node.fromJSON(schema, nodeJson);
|
|
248
|
-
nodes.push(node);
|
|
249
|
-
} catch {
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
return import_model.Slice.maxOpen(import_model.Fragment.fromArray(nodes));
|
|
233
|
+
return (0, import_editor.plainTextToSlice)(text, schema);
|
|
253
234
|
}
|
|
254
235
|
}
|
|
255
236
|
},
|
|
256
|
-
|
|
237
|
+
// Only options baked into extensions recreate the editor; editable state,
|
|
238
|
+
// placeholder, class names and content are applied to the live instance.
|
|
239
|
+
[resolvedColorMap, templateKey, speed, jsonVariablesKey]
|
|
257
240
|
);
|
|
258
241
|
(0, import_react.useEffect)(() => {
|
|
259
242
|
if (editor && !editor.isDestroyed) {
|
|
260
243
|
editor.setEditable(isEditing);
|
|
261
244
|
}
|
|
262
245
|
}, [editor, isEditing]);
|
|
246
|
+
(0, import_react.useEffect)(() => {
|
|
247
|
+
if (!editor || editor.isDestroyed) return;
|
|
248
|
+
if (normalizeNewlines(content) === (0, import_editor.getEditorText)(editor)) return;
|
|
249
|
+
const { from, to } = editor.state.selection;
|
|
250
|
+
editor.commands.setContent((0, import_editor.plainTextToTipTapHtml)(content), false);
|
|
251
|
+
const max = editor.state.doc.content.size;
|
|
252
|
+
editor.commands.setTextSelection({
|
|
253
|
+
from: Math.min(from, max),
|
|
254
|
+
to: Math.min(to, max)
|
|
255
|
+
});
|
|
256
|
+
}, [editor, content]);
|
|
257
|
+
(0, import_react.useEffect)(() => {
|
|
258
|
+
if (!editor || editor.isDestroyed) return;
|
|
259
|
+
editor.setOptions({
|
|
260
|
+
editorProps: {
|
|
261
|
+
...editor.options.editorProps,
|
|
262
|
+
attributes: {
|
|
263
|
+
...editor.options.editorProps.attributes,
|
|
264
|
+
class: className || DEFAULT_CLASS_NAME
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}, [editor, className]);
|
|
269
|
+
(0, import_react.useEffect)(() => {
|
|
270
|
+
if (!editor || editor.isDestroyed) return;
|
|
271
|
+
const placeholderExt = editor.extensionManager.extensions.find(
|
|
272
|
+
(ext) => ext.name === "placeholder"
|
|
273
|
+
);
|
|
274
|
+
if (!placeholderExt || placeholderExt.options.placeholder === placeholder) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
placeholderExt.options.placeholder = placeholder;
|
|
278
|
+
editor.view.dispatch(editor.state.tr);
|
|
279
|
+
}, [editor, placeholder]);
|
|
263
280
|
return editor;
|
|
264
281
|
}
|
|
265
282
|
|
|
@@ -628,36 +645,32 @@ var import_editor7 = require("@pixerate/editor");
|
|
|
628
645
|
var import_react11 = require("react");
|
|
629
646
|
var import_editor5 = require("@pixerate/editor");
|
|
630
647
|
function useSpreadsheetEditor(options = {}) {
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
cells: options.document?.cells || {},
|
|
637
|
-
createdAt: options.document?.createdAt || Date.now(),
|
|
638
|
-
updatedAt: options.document?.updatedAt || Date.now()
|
|
639
|
-
}));
|
|
640
|
-
const [activeCell, setActiveCell] = (0, import_react11.useState)(null);
|
|
641
|
-
const [selectedRange, setSelectedRange] = (0, import_react11.useState)(null);
|
|
642
|
-
const [editingCell, setEditingCell] = (0, import_react11.useState)(null);
|
|
643
|
-
const [draftValue, setDraftValue] = (0, import_react11.useState)("");
|
|
644
|
-
const controller = (0, import_react11.useMemo)(() => {
|
|
645
|
-
return new import_editor5.SpreadsheetController({
|
|
648
|
+
const optionsRef = (0, import_react11.useRef)(options);
|
|
649
|
+
optionsRef.current = options;
|
|
650
|
+
const settersRef = (0, import_react11.useRef)({});
|
|
651
|
+
const [controller] = (0, import_react11.useState)(
|
|
652
|
+
() => new import_editor5.SpreadsheetController({
|
|
646
653
|
...options,
|
|
647
654
|
onDocumentChange: (updated) => {
|
|
648
|
-
setDoc({ ...updated });
|
|
649
|
-
|
|
655
|
+
settersRef.current.setDoc?.({ ...updated });
|
|
656
|
+
optionsRef.current.onDocumentChange?.(updated);
|
|
650
657
|
},
|
|
651
658
|
onSelectionChange: (active, range) => {
|
|
652
|
-
setActiveCell(active);
|
|
653
|
-
setSelectedRange(range);
|
|
654
|
-
|
|
659
|
+
settersRef.current.setActiveCell?.(active);
|
|
660
|
+
settersRef.current.setSelectedRange?.(range);
|
|
661
|
+
optionsRef.current.onSelectionChange?.(active, range);
|
|
655
662
|
},
|
|
656
663
|
onCellCommit: (rowId, colId, raw, value) => {
|
|
657
|
-
|
|
664
|
+
optionsRef.current.onCellCommit?.(rowId, colId, raw, value);
|
|
658
665
|
}
|
|
659
|
-
})
|
|
660
|
-
|
|
666
|
+
})
|
|
667
|
+
);
|
|
668
|
+
const [doc, setDoc] = (0, import_react11.useState)(() => ({ ...controller.document }));
|
|
669
|
+
const [activeCell, setActiveCell] = (0, import_react11.useState)(controller.activeCell);
|
|
670
|
+
const [selectedRange, setSelectedRange] = (0, import_react11.useState)(controller.selectedRange);
|
|
671
|
+
const [editingCell, setEditingCell] = (0, import_react11.useState)(null);
|
|
672
|
+
const [draftValue, setDraftValue] = (0, import_react11.useState)("");
|
|
673
|
+
settersRef.current = { setDoc, setActiveCell, setSelectedRange };
|
|
661
674
|
const setCellValue = (0, import_react11.useCallback)((rowId, colId, raw) => {
|
|
662
675
|
controller.setCellValue(rowId, colId, raw);
|
|
663
676
|
setDoc({ ...controller.document });
|
|
@@ -775,7 +788,7 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
775
788
|
registerDataSource,
|
|
776
789
|
setPrimaryDataSource,
|
|
777
790
|
recalculateAll,
|
|
778
|
-
exportToTsv: () => controller.exportToTsv(),
|
|
791
|
+
exportToTsv: (range) => controller.exportToTsv(range),
|
|
779
792
|
importFromTsv: (data) => {
|
|
780
793
|
controller.importFromTsv(data);
|
|
781
794
|
setDoc({ ...controller.document });
|
|
@@ -816,6 +829,25 @@ var SpreadsheetEditor = ({
|
|
|
816
829
|
const colName = (0, import_editor6.indexToColName)(state.activeCell.col);
|
|
817
830
|
return `${colName}${state.activeCell.row + 1}`;
|
|
818
831
|
}, [state.activeCell]);
|
|
832
|
+
const [formulaDraft, setFormulaDraft] = (0, import_react12.useState)(null);
|
|
833
|
+
const activeColumn = state.activeCell ? state.document.columns[state.activeCell.col] : void 0;
|
|
834
|
+
const formulaBarReadOnly = readOnly || !state.activeCell || !!activeColumn?.readOnly;
|
|
835
|
+
(0, import_react12.useEffect)(() => {
|
|
836
|
+
setFormulaDraft(null);
|
|
837
|
+
}, [state.activeCell?.row, state.activeCell?.col]);
|
|
838
|
+
const commitFormulaBar = () => {
|
|
839
|
+
if (state.editingCell) {
|
|
840
|
+
state.commitEditing();
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
if (formulaDraft === null || !state.activeCell) return;
|
|
844
|
+
const row = state.document.rows[state.activeCell.row];
|
|
845
|
+
const col = state.document.columns[state.activeCell.col];
|
|
846
|
+
if (row && col && !formulaBarReadOnly && formulaDraft !== activeRawValue) {
|
|
847
|
+
state.setCellValue(row.id, col.id, formulaDraft);
|
|
848
|
+
}
|
|
849
|
+
setFormulaDraft(null);
|
|
850
|
+
};
|
|
819
851
|
const handleCellClick = (0, import_react12.useCallback)((rIdx, cIdx, e) => {
|
|
820
852
|
if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
|
|
821
853
|
state.commitEditing();
|
|
@@ -874,16 +906,19 @@ var SpreadsheetEditor = ({
|
|
|
874
906
|
e.preventDefault();
|
|
875
907
|
state.setCellValue(row.id, col.id, "");
|
|
876
908
|
}
|
|
877
|
-
} else if ((e.metaKey || e.ctrlKey) && e.key === "z") {
|
|
909
|
+
} else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
878
910
|
e.preventDefault();
|
|
879
911
|
if (e.shiftKey) {
|
|
880
912
|
state.redo();
|
|
881
913
|
} else {
|
|
882
914
|
state.undo();
|
|
883
915
|
}
|
|
884
|
-
} else if (
|
|
916
|
+
} else if (e.ctrlKey && !e.metaKey && e.key.toLowerCase() === "y") {
|
|
917
|
+
e.preventDefault();
|
|
918
|
+
state.redo();
|
|
919
|
+
} else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "c") {
|
|
885
920
|
e.preventDefault();
|
|
886
|
-
const tsv = state.exportToTsv();
|
|
921
|
+
const tsv = state.exportToTsv(state.selectedRange);
|
|
887
922
|
navigator.clipboard?.writeText(tsv);
|
|
888
923
|
} else if (!readOnly && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
889
924
|
const col = state.document.columns[state.activeCell.col];
|
|
@@ -892,6 +927,10 @@ var SpreadsheetEditor = ({
|
|
|
892
927
|
}
|
|
893
928
|
}
|
|
894
929
|
}, [readOnly, state]);
|
|
930
|
+
const stateRef = (0, import_react12.useRef)(state);
|
|
931
|
+
stateRef.current = state;
|
|
932
|
+
const onColumnResizeRef = (0, import_react12.useRef)(onColumnResize);
|
|
933
|
+
onColumnResizeRef.current = onColumnResize;
|
|
895
934
|
(0, import_react12.useEffect)(() => {
|
|
896
935
|
if (!resizingColId) return;
|
|
897
936
|
if (typeof document !== "undefined") {
|
|
@@ -910,7 +949,7 @@ var SpreadsheetEditor = ({
|
|
|
910
949
|
if (rafId === null) {
|
|
911
950
|
rafId = requestAnimationFrame(() => {
|
|
912
951
|
rafId = null;
|
|
913
|
-
|
|
952
|
+
stateRef.current.setColumnWidth(resizingColId, pendingWidth);
|
|
914
953
|
});
|
|
915
954
|
}
|
|
916
955
|
};
|
|
@@ -920,11 +959,8 @@ var SpreadsheetEditor = ({
|
|
|
920
959
|
rafId = null;
|
|
921
960
|
}
|
|
922
961
|
if (hasDragged) {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
if (col && onColumnResize) {
|
|
926
|
-
onColumnResize(col.id, col.width || pendingWidth);
|
|
927
|
-
}
|
|
962
|
+
stateRef.current.setColumnWidth(resizingColId, pendingWidth);
|
|
963
|
+
onColumnResizeRef.current?.(resizingColId, pendingWidth);
|
|
928
964
|
}
|
|
929
965
|
setResizingColId(null);
|
|
930
966
|
if (typeof document !== "undefined") {
|
|
@@ -945,7 +981,7 @@ var SpreadsheetEditor = ({
|
|
|
945
981
|
window.removeEventListener("mousemove", handleMouseMove);
|
|
946
982
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
947
983
|
};
|
|
948
|
-
}, [resizingColId, resizeStartX, resizeStartWidth
|
|
984
|
+
}, [resizingColId, resizeStartX, resizeStartWidth]);
|
|
949
985
|
const measureElementContentWidth = (0, import_react12.useCallback)((el, container) => {
|
|
950
986
|
if (typeof document === "undefined") return 0;
|
|
951
987
|
let maxW = el.scrollWidth || 0;
|
|
@@ -1077,25 +1113,29 @@ var SpreadsheetEditor = ({
|
|
|
1077
1113
|
type: "text",
|
|
1078
1114
|
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",
|
|
1079
1115
|
placeholder: "Enter a value or formula (e.g. =SUM(A1:A5))",
|
|
1080
|
-
|
|
1116
|
+
"aria-label": "Formula bar",
|
|
1117
|
+
readOnly: formulaBarReadOnly,
|
|
1118
|
+
value: state.editingCell ? state.draftValue : formulaDraft ?? activeRawValue,
|
|
1119
|
+
onFocus: () => {
|
|
1120
|
+
if (!state.editingCell) setFormulaDraft(activeRawValue);
|
|
1121
|
+
},
|
|
1081
1122
|
onChange: (e) => {
|
|
1082
|
-
if (state.
|
|
1123
|
+
if (state.editingCell) {
|
|
1083
1124
|
state.setDraftValue(e.target.value);
|
|
1125
|
+
} else if (state.activeCell) {
|
|
1126
|
+
setFormulaDraft(e.target.value);
|
|
1084
1127
|
}
|
|
1085
1128
|
},
|
|
1129
|
+
onBlur: () => commitFormulaBar(),
|
|
1086
1130
|
onKeyDown: (e) => {
|
|
1131
|
+
e.stopPropagation();
|
|
1087
1132
|
if (e.key === "Enter") {
|
|
1088
1133
|
e.preventDefault();
|
|
1089
|
-
|
|
1090
|
-
const row = state.document.rows[state.activeCell.row];
|
|
1091
|
-
const col = state.document.columns[state.activeCell.col];
|
|
1092
|
-
if (row && col) {
|
|
1093
|
-
state.setCellValue(row.id, col.id, e.target.value);
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1134
|
+
commitFormulaBar();
|
|
1096
1135
|
} else if (e.key === "Escape") {
|
|
1097
1136
|
e.preventDefault();
|
|
1098
|
-
|
|
1137
|
+
setFormulaDraft(null);
|
|
1138
|
+
if (state.editingCell) state.cancelEditing();
|
|
1099
1139
|
}
|
|
1100
1140
|
}
|
|
1101
1141
|
}
|