@pixerate/editor-react 0.10.0 → 0.10.1
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 +55 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +61 -42
- 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
|
|