@pixerate/editor-svelte 0.1.0
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/LICENSE +21 -0
- package/dist/index.css +9 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +222 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/src/BubbleMenu.svelte +42 -0
- package/src/EditableTextNodeEditor.svelte +94 -0
- package/src/TemplateRenderer.svelte +69 -0
- package/src/editor.svelte.ts +65 -0
- package/src/index.d.ts +80 -0
- package/src/index.ts +52 -0
- package/src/svelte.d.ts +5 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jack James
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["svelte-css:src/EditableTextNodeEditor.svelte.css"],"sourcesContent":["\n .pixerate-editor-content .is-empty::before {\n content: attr(data-placeholder);\n float: left;\n color: #9ca3af;\n pointer-events: none;\n height: 0;\n }\n\n"],"mappings":";AACE,CAAC,wBAAwB,CAAC,QAAQ;AAChC,WAAS,KAAK;AACd,SAAO;AACP,SAAO;AACP,kBAAgB;AAChB,UAAQ;AACV;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Component } from "svelte";
|
|
2
|
+
import type { Editor, Content, Extensions, EditorOptions } from "@tiptap/core";
|
|
3
|
+
import type {
|
|
4
|
+
Template,
|
|
5
|
+
TemplateVersion,
|
|
6
|
+
Token,
|
|
7
|
+
TokenType,
|
|
8
|
+
ColorGradient,
|
|
9
|
+
RichTextPresetOptions,
|
|
10
|
+
} from "@pixerate/editor";
|
|
11
|
+
|
|
12
|
+
export interface SvelteInitiateEditorOptions extends Partial<EditorOptions> {
|
|
13
|
+
richTextOptions?: RichTextPresetOptions;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export declare const initiateEditor: (
|
|
17
|
+
element?: HTMLElement,
|
|
18
|
+
content?: Content,
|
|
19
|
+
extensions?: Extensions,
|
|
20
|
+
options?: SvelteInitiateEditorOptions,
|
|
21
|
+
) => Editor;
|
|
22
|
+
|
|
23
|
+
export interface ReactiveEditorState {
|
|
24
|
+
editor: Editor | undefined;
|
|
25
|
+
content: string;
|
|
26
|
+
isEditable: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export declare function createReactiveEditor(
|
|
30
|
+
initialContent?: string,
|
|
31
|
+
extensions?: Extensions,
|
|
32
|
+
options?: Partial<EditorOptions>,
|
|
33
|
+
): {
|
|
34
|
+
readonly current: Editor | undefined;
|
|
35
|
+
mount(element: HTMLElement): Editor;
|
|
36
|
+
destroy(): void;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export interface EditableTextNodeEditorProps {
|
|
40
|
+
class?: string;
|
|
41
|
+
content?: Content;
|
|
42
|
+
showMenu?: boolean;
|
|
43
|
+
editable?: boolean;
|
|
44
|
+
editor?: Editor;
|
|
45
|
+
extensions?: Extensions;
|
|
46
|
+
onUpdate?: () => void;
|
|
47
|
+
onFocus?: () => void;
|
|
48
|
+
onBlur?: () => void;
|
|
49
|
+
onCreate?: () => void;
|
|
50
|
+
placeholder?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface BubbleMenuProps {
|
|
54
|
+
editor?: Editor;
|
|
55
|
+
class?: string;
|
|
56
|
+
children?: any;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface TemplateRendererProps {
|
|
60
|
+
content: string;
|
|
61
|
+
templates?: Template[];
|
|
62
|
+
templateColorMap?: Map<string, ColorGradient>;
|
|
63
|
+
resolve?: boolean;
|
|
64
|
+
class?: string;
|
|
65
|
+
onTemplateClick?: (templateName: string) => void;
|
|
66
|
+
onVariableClick?: (variableName: string) => void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export declare const EditableTextNodeEditor: Component<EditableTextNodeEditorProps>;
|
|
70
|
+
export declare const BubbleMenu: Component<BubbleMenuProps>;
|
|
71
|
+
export declare const TemplateRenderer: Component<TemplateRendererProps>;
|
|
72
|
+
|
|
73
|
+
export type {
|
|
74
|
+
Template,
|
|
75
|
+
TemplateVersion,
|
|
76
|
+
Token,
|
|
77
|
+
TokenType,
|
|
78
|
+
ColorGradient,
|
|
79
|
+
RichTextPresetOptions,
|
|
80
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// src/EditableTextNodeEditor.svelte
|
|
2
|
+
import "svelte/internal/disclose-version";
|
|
3
|
+
import * as $2 from "svelte/internal/client";
|
|
4
|
+
import { onDestroy, onMount } from "svelte";
|
|
5
|
+
import Placeholder from "@tiptap/extension-placeholder";
|
|
6
|
+
|
|
7
|
+
// src/editor.svelte.ts
|
|
8
|
+
import * as $ from "svelte/internal/client";
|
|
9
|
+
import { Editor } from "@tiptap/core";
|
|
10
|
+
import { createRichTextPreset } from "@pixerate/editor";
|
|
11
|
+
var initiateEditor = (element, content, extensions, options) => {
|
|
12
|
+
const { richTextOptions, ...editorOptions } = options || {};
|
|
13
|
+
const defaultPreset = createRichTextPreset(richTextOptions);
|
|
14
|
+
const editor = new Editor({
|
|
15
|
+
element,
|
|
16
|
+
content,
|
|
17
|
+
extensions: [...defaultPreset, ...extensions ?? []],
|
|
18
|
+
autofocus: true,
|
|
19
|
+
...editorOptions
|
|
20
|
+
});
|
|
21
|
+
return editor;
|
|
22
|
+
};
|
|
23
|
+
function createReactiveEditor(initialContent = "", extensions = [], options = {}) {
|
|
24
|
+
let editorInstance;
|
|
25
|
+
return {
|
|
26
|
+
get current() {
|
|
27
|
+
return editorInstance;
|
|
28
|
+
},
|
|
29
|
+
mount(element) {
|
|
30
|
+
editorInstance = initiateEditor(element, initialContent, extensions, options);
|
|
31
|
+
return editorInstance;
|
|
32
|
+
},
|
|
33
|
+
destroy() {
|
|
34
|
+
if (editorInstance) {
|
|
35
|
+
editorInstance.destroy();
|
|
36
|
+
editorInstance = void 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/EditableTextNodeEditor.svelte
|
|
43
|
+
var root = $2.from_html(`<div class="flex items-center justify-center p-4 text-sm text-gray-500">Loading editor...</div>`);
|
|
44
|
+
var root_1 = $2.from_html(`<div draggable="false"><!> <div class="pixerate-editor-content prose w-full max-w-none focus:outline-none"></div></div>`);
|
|
45
|
+
function EditableTextNodeEditor($$anchor, $$props) {
|
|
46
|
+
$2.push($$props, true);
|
|
47
|
+
let className = $2.prop($$props, "class", 3, ""), content = $2.prop($$props, "content", 3, void 0), showMenu = $2.prop($$props, "showMenu", 3, true), editable = $2.prop($$props, "editable", 3, true), editor = $2.prop($$props, "editor", 15), extensions = $2.prop($$props, "extensions", 19, () => []), placeholder = $2.prop($$props, "placeholder", 3, "");
|
|
48
|
+
let element = $2.state(void 0);
|
|
49
|
+
$2.user_effect(() => {
|
|
50
|
+
if (editor() && editor().isEditable !== editable()) {
|
|
51
|
+
editor().setEditable(editable());
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
onMount(() => {
|
|
55
|
+
editor(initiateEditor(
|
|
56
|
+
$2.get(element),
|
|
57
|
+
content(),
|
|
58
|
+
[
|
|
59
|
+
Placeholder.configure({ placeholder: placeholder() }),
|
|
60
|
+
...extensions()
|
|
61
|
+
],
|
|
62
|
+
{
|
|
63
|
+
editable: editable(),
|
|
64
|
+
onCreate: $$props.onCreate,
|
|
65
|
+
onUpdate: $$props.onUpdate,
|
|
66
|
+
onFocus() {
|
|
67
|
+
if ($$props.onFocus) $$props.onFocus();
|
|
68
|
+
},
|
|
69
|
+
onBlur() {
|
|
70
|
+
if ($$props.onBlur) $$props.onBlur();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
));
|
|
74
|
+
});
|
|
75
|
+
onDestroy(() => {
|
|
76
|
+
if (editor()) {
|
|
77
|
+
editor().destroy();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
var div = root_1();
|
|
81
|
+
var node = $2.child(div);
|
|
82
|
+
{
|
|
83
|
+
var consequent = ($$anchor2) => {
|
|
84
|
+
var div_1 = root();
|
|
85
|
+
$2.append($$anchor2, div_1);
|
|
86
|
+
};
|
|
87
|
+
$2.if(node, ($$render) => {
|
|
88
|
+
if (!editor()) $$render(consequent);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
var div_2 = $2.sibling(node, 2);
|
|
92
|
+
$2.bind_this(div_2, ($$value) => $2.set(element, $$value), () => $2.get(element));
|
|
93
|
+
$2.reset(div);
|
|
94
|
+
$2.template_effect(() => $2.set_class(div, 1, `pixerate-editor-container ${className()}`));
|
|
95
|
+
$2.append($$anchor, div);
|
|
96
|
+
$2.pop();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/BubbleMenu.svelte
|
|
100
|
+
import "svelte/internal/disclose-version";
|
|
101
|
+
import * as $3 from "svelte/internal/client";
|
|
102
|
+
import BubbleMenuPlugin from "@tiptap/extension-bubble-menu";
|
|
103
|
+
import { onMount as onMount2, onDestroy as onDestroy2 } from "svelte";
|
|
104
|
+
var root2 = $3.from_html(`<div><!></div>`);
|
|
105
|
+
function BubbleMenu($$anchor, $$props) {
|
|
106
|
+
$3.push($$props, true);
|
|
107
|
+
let className = $3.prop($$props, "class", 3, "flex items-center gap-1 bg-white border border-gray-200 shadow-md rounded-md p-1");
|
|
108
|
+
let menuElement = $3.state(void 0);
|
|
109
|
+
onMount2(() => {
|
|
110
|
+
if ($$props.editor && $3.get(menuElement)) {
|
|
111
|
+
$$props.editor.registerPlugin(BubbleMenuPlugin.configure({ element: $3.get(menuElement), tippyOptions: { duration: 100 } }));
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
onDestroy2(() => {
|
|
115
|
+
if ($$props.editor) {
|
|
116
|
+
$$props.editor.unregisterPlugin("bubbleMenu");
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
var div = root2();
|
|
120
|
+
var node = $3.child(div);
|
|
121
|
+
{
|
|
122
|
+
var consequent = ($$anchor2) => {
|
|
123
|
+
var fragment = $3.comment();
|
|
124
|
+
var node_1 = $3.first_child(fragment);
|
|
125
|
+
$3.snippet(node_1, () => $$props.children);
|
|
126
|
+
$3.append($$anchor2, fragment);
|
|
127
|
+
};
|
|
128
|
+
$3.if(node, ($$render) => {
|
|
129
|
+
if ($$props.children) $$render(consequent);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
$3.reset(div);
|
|
133
|
+
$3.bind_this(div, ($$value) => $3.set(menuElement, $$value), () => $3.get(menuElement));
|
|
134
|
+
$3.template_effect(() => $3.set_class(div, 1, $3.clsx(className())));
|
|
135
|
+
$3.append($$anchor, div);
|
|
136
|
+
$3.pop();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/TemplateRenderer.svelte
|
|
140
|
+
import "svelte/internal/disclose-version";
|
|
141
|
+
import * as $4 from "svelte/internal/client";
|
|
142
|
+
import { tokenizePrompt, resolveTemplates } from "@pixerate/editor";
|
|
143
|
+
var root3 = $4.from_html(`<span class="inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs font-semibold rounded-md border border-[var(--color-to)]/40 bg-gradient-to-r from-[var(--color-from)]/15 to-[var(--color-to)]/15 text-[var(--color-to)] hover:brightness-110 cursor-pointer transition-all"> </span>`);
|
|
144
|
+
var root_12 = $4.from_html(`<span class="inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs font-medium rounded-md border border-violet-400/40 bg-violet-400/15 text-violet-600 hover:brightness-110 cursor-pointer transition-all"> </span>`);
|
|
145
|
+
var root_2 = $4.from_html(`<span class="inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs italic font-medium rounded-md border border-rose-400/40 bg-rose-400/15 text-rose-600"> </span>`);
|
|
146
|
+
var root_3 = $4.from_html(`<span> </span>`);
|
|
147
|
+
var root_4 = $4.from_html(`<div></div>`);
|
|
148
|
+
function TemplateRenderer($$anchor, $$props) {
|
|
149
|
+
$4.push($$props, true);
|
|
150
|
+
let templates = $4.prop($$props, "templates", 19, () => []), resolve = $4.prop($$props, "resolve", 3, false), className = $4.prop($$props, "class", 3, "font-mono text-sm leading-relaxed whitespace-pre-wrap break-words");
|
|
151
|
+
let displayText = $4.derived(() => resolve() && templates().length > 0 ? resolveTemplates($$props.content, templates()) : $$props.content);
|
|
152
|
+
let tokens = $4.derived(() => tokenizePrompt($4.get(displayText)));
|
|
153
|
+
var div = root_4();
|
|
154
|
+
$4.each(div, 21, () => $4.get(tokens), $4.index, ($$anchor2, token) => {
|
|
155
|
+
var fragment = $4.comment();
|
|
156
|
+
var node = $4.first_child(fragment);
|
|
157
|
+
{
|
|
158
|
+
var consequent = ($$anchor3) => {
|
|
159
|
+
const colors = $4.derived(() => $$props.templateColorMap?.get($4.get(token).value) || { from: "#f43f5e", to: "#8b5cf6" });
|
|
160
|
+
var span = root3();
|
|
161
|
+
var text = $4.only_child(span, true);
|
|
162
|
+
$4.template_effect(() => {
|
|
163
|
+
$4.set_style(span, `--color-from: ${$4.get(colors).from}; --color-to: ${$4.get(colors).to};`);
|
|
164
|
+
$4.set_attribute(span, "title", `Template: ${$4.get(token).value}`);
|
|
165
|
+
$4.set_text(text, `{{${$4.get(token).value}}}`);
|
|
166
|
+
});
|
|
167
|
+
$4.delegated("click", span, () => $$props.onTemplateClick?.($4.get(token).value));
|
|
168
|
+
$4.append($$anchor3, span);
|
|
169
|
+
};
|
|
170
|
+
var consequent_1 = ($$anchor3) => {
|
|
171
|
+
var span_1 = root_12();
|
|
172
|
+
var text_1 = $4.only_child(span_1, true);
|
|
173
|
+
$4.template_effect(() => {
|
|
174
|
+
$4.set_attribute(span_1, "title", `Variable: ${$4.get(token).value}`);
|
|
175
|
+
$4.set_text(text_1, `{${$4.get(token).value}}`);
|
|
176
|
+
});
|
|
177
|
+
$4.delegated("click", span_1, () => $$props.onVariableClick?.($4.get(token).value));
|
|
178
|
+
$4.append($$anchor3, span_1);
|
|
179
|
+
};
|
|
180
|
+
var consequent_2 = ($$anchor3) => {
|
|
181
|
+
var span_2 = root_2();
|
|
182
|
+
var text_2 = $4.only_child(span_2, true);
|
|
183
|
+
$4.template_effect(() => {
|
|
184
|
+
$4.set_attribute(span_2, "title", `Instruction: ${$4.get(token).value}`);
|
|
185
|
+
$4.set_text(text_2, `__${$4.get(token).value}__`);
|
|
186
|
+
});
|
|
187
|
+
$4.append($$anchor3, span_2);
|
|
188
|
+
};
|
|
189
|
+
var alternate = ($$anchor3) => {
|
|
190
|
+
var span_3 = root_3();
|
|
191
|
+
var text_3 = $4.only_child(span_3, true);
|
|
192
|
+
$4.template_effect(() => $4.set_text(text_3, $4.get(token).value));
|
|
193
|
+
$4.append($$anchor3, span_3);
|
|
194
|
+
};
|
|
195
|
+
$4.if(node, ($$render) => {
|
|
196
|
+
if ($4.get(token).type === "template") $$render(consequent);
|
|
197
|
+
else if ($4.get(token).type === "variable") $$render(consequent_1, 1);
|
|
198
|
+
else if ($4.get(token).type === "instruction") $$render(consequent_2, 2);
|
|
199
|
+
else $$render(alternate, -1);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
$4.append($$anchor2, fragment);
|
|
203
|
+
});
|
|
204
|
+
$4.reset(div);
|
|
205
|
+
$4.template_effect(() => $4.set_class(div, 1, $4.clsx(className())));
|
|
206
|
+
$4.append($$anchor, div);
|
|
207
|
+
$4.pop();
|
|
208
|
+
}
|
|
209
|
+
$4.delegate(["click"]);
|
|
210
|
+
|
|
211
|
+
// src/index.ts
|
|
212
|
+
var EditableTextNodeEditor2 = EditableTextNodeEditor;
|
|
213
|
+
var BubbleMenu2 = BubbleMenu;
|
|
214
|
+
var TemplateRenderer2 = TemplateRenderer;
|
|
215
|
+
export {
|
|
216
|
+
BubbleMenu2 as BubbleMenu,
|
|
217
|
+
EditableTextNodeEditor2 as EditableTextNodeEditor,
|
|
218
|
+
TemplateRenderer2 as TemplateRenderer,
|
|
219
|
+
createReactiveEditor,
|
|
220
|
+
initiateEditor
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/EditableTextNodeEditor.svelte","../src/editor.svelte.ts","../src/BubbleMenu.svelte","../src/TemplateRenderer.svelte","../src/index.ts"],"sourcesContent":["import 'EditableTextNodeEditor.svelte.css';import 'svelte/internal/disclose-version';\nimport * as $ from 'svelte/internal/client';\nimport { onDestroy, onMount } from \"svelte\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport { initiateEditor } from \"./editor.svelte\";\n\nvar root = $.from_html(`<div class=\"flex items-center justify-center p-4 text-sm text-gray-500\">Loading editor...</div>`);\nvar root_1 = $.from_html(`<div draggable=\"false\"><!> <div class=\"pixerate-editor-content prose w-full max-w-none focus:outline-none\"></div></div>`);\n\nexport default function EditableTextNodeEditor($$anchor, $$props) {\n\t$.push($$props, true);\n\n\tlet className = $.prop($$props, 'class', 3, \"\"),\n\t\tcontent = $.prop($$props, 'content', 3, undefined),\n\t\tshowMenu = $.prop($$props, 'showMenu', 3, true),\n\t\teditable = $.prop($$props, 'editable', 3, true),\n\t\teditor = $.prop($$props, 'editor', 15),\n\t\textensions = $.prop($$props, 'extensions', 19, () => []),\n\t\tplaceholder = $.prop($$props, 'placeholder', 3, \"\");\n\n\tlet element = $.state(void 0);\n\n\t$.user_effect(() => {\n\t\tif (editor() && editor().isEditable !== editable()) {\n\t\t\teditor().setEditable(editable());\n\t\t}\n\t});\n\n\tonMount(() => {\n\t\teditor(initiateEditor(\n\t\t\t$.get(element),\n\t\t\tcontent(),\n\t\t\t[\n\t\t\t\tPlaceholder.configure({ placeholder: placeholder() }),\n\t\t\t\t...extensions()\n\t\t\t],\n\t\t\t{\n\t\t\t\teditable: editable(),\n\t\t\t\tonCreate: $$props.onCreate,\n\t\t\t\tonUpdate: $$props.onUpdate,\n\t\t\t\tonFocus() {\n\t\t\t\t\tif ($$props.onFocus) $$props.onFocus();\n\t\t\t\t},\n\n\t\t\t\tonBlur() {\n\t\t\t\t\tif ($$props.onBlur) $$props.onBlur();\n\t\t\t\t}\n\t\t\t}\n\t\t));\n\t});\n\n\tonDestroy(() => {\n\t\tif (editor()) {\n\t\t\teditor().destroy();\n\t\t}\n\t});\n\n\tvar div = root_1();\n\tvar node = $.child(div);\n\n\t{\n\t\tvar consequent = ($$anchor) => {\n\t\t\tvar div_1 = root();\n\n\t\t\t$.append($$anchor, div_1);\n\t\t};\n\n\t\t$.if(node, ($$render) => {\n\t\t\tif (!editor()) $$render(consequent);\n\t\t});\n\t}\n\n\tvar div_2 = $.sibling(node, 2);\n\n\t$.bind_this(div_2, ($$value) => $.set(element, $$value), () => $.get(element));\n\t$.reset(div);\n\t$.template_effect(() => $.set_class(div, 1, `pixerate-editor-container ${className()}`));\n\t$.append($$anchor, div);\n\t$.pop();\n}","import { Editor } from \"@tiptap/core\";\nimport { createRichTextPreset } from \"@pixerate/editor\";\nexport const initiateEditor = (element, content, extensions, options) => {\n const { richTextOptions, ...editorOptions } = options || {};\n const defaultPreset = createRichTextPreset(richTextOptions);\n const editor = new Editor({\n element,\n content,\n extensions: [\n ...defaultPreset,\n ...extensions ?? []\n ],\n autofocus: true,\n ...editorOptions\n });\n return editor;\n};\nexport function createReactiveEditor(initialContent = \"\", extensions = [], options = {}) {\n let editorInstance;\n return {\n get current() {\n return editorInstance;\n },\n mount(element) {\n editorInstance = initiateEditor(element, initialContent, extensions, options);\n return editorInstance;\n },\n destroy() {\n if (editorInstance) {\n editorInstance.destroy();\n editorInstance = void 0;\n }\n }\n };\n}\n","import 'svelte/internal/disclose-version';\nimport * as $ from 'svelte/internal/client';\nimport BubbleMenuPlugin from \"@tiptap/extension-bubble-menu\";\nimport { onMount, onDestroy } from \"svelte\";\n\nvar root = $.from_html(`<div><!></div>`);\n\nexport default function BubbleMenu($$anchor, $$props) {\n\t$.push($$props, true);\n\n\tlet className = $.prop($$props, 'class', 3, \"flex items-center gap-1 bg-white border border-gray-200 shadow-md rounded-md p-1\");\n\tlet menuElement = $.state(void 0);\n\n\tonMount(() => {\n\t\tif ($$props.editor && $.get(menuElement)) {\n\t\t\t$$props.editor.registerPlugin(BubbleMenuPlugin.configure({ element: $.get(menuElement), tippyOptions: { duration: 100 } }));\n\t\t}\n\t});\n\n\tonDestroy(() => {\n\t\tif ($$props.editor) {\n\t\t\t$$props.editor.unregisterPlugin(\"bubbleMenu\");\n\t\t}\n\t});\n\n\tvar div = root();\n\tvar node = $.child(div);\n\n\t{\n\t\tvar consequent = ($$anchor) => {\n\t\t\tvar fragment = $.comment();\n\t\t\tvar node_1 = $.first_child(fragment);\n\n\t\t\t$.snippet(node_1, () => $$props.children);\n\t\t\t$.append($$anchor, fragment);\n\t\t};\n\n\t\t$.if(node, ($$render) => {\n\t\t\tif ($$props.children) $$render(consequent);\n\t\t});\n\t}\n\n\t$.reset(div);\n\t$.bind_this(div, ($$value) => $.set(menuElement, $$value), () => $.get(menuElement));\n\t$.template_effect(() => $.set_class(div, 1, $.clsx(className())));\n\t$.append($$anchor, div);\n\t$.pop();\n}","import 'svelte/internal/disclose-version';\nimport * as $ from 'svelte/internal/client';\nimport { tokenizePrompt, resolveTemplates } from \"@pixerate/editor\";\n\nvar root = $.from_html(`<span class=\"inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs font-semibold rounded-md border border-[var(--color-to)]/40 bg-gradient-to-r from-[var(--color-from)]/15 to-[var(--color-to)]/15 text-[var(--color-to)] hover:brightness-110 cursor-pointer transition-all\"> </span>`);\nvar root_1 = $.from_html(`<span class=\"inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs font-medium rounded-md border border-violet-400/40 bg-violet-400/15 text-violet-600 hover:brightness-110 cursor-pointer transition-all\"> </span>`);\nvar root_2 = $.from_html(`<span class=\"inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs italic font-medium rounded-md border border-rose-400/40 bg-rose-400/15 text-rose-600\"> </span>`);\nvar root_3 = $.from_html(`<span> </span>`);\nvar root_4 = $.from_html(`<div></div>`);\n\nexport default function TemplateRenderer($$anchor, $$props) {\n\t$.push($$props, true);\n\n\tlet templates = $.prop($$props, 'templates', 19, () => []),\n\t\tresolve = $.prop($$props, 'resolve', 3, false),\n\t\tclassName = $.prop($$props, 'class', 3, \"font-mono text-sm leading-relaxed whitespace-pre-wrap break-words\");\n\n\tlet displayText = $.derived(() => resolve() && templates().length > 0\n\t\t? resolveTemplates($$props.content, templates())\n\t\t: $$props.content);\n\n\tlet tokens = $.derived(() => tokenizePrompt($.get(displayText)));\n\tvar div = root_4();\n\n\t$.each(div, 21, () => $.get(tokens), $.index, ($$anchor, token) => {\n\t\tvar fragment = $.comment();\n\t\tvar node = $.first_child(fragment);\n\n\t\t{\n\t\t\tvar consequent = ($$anchor) => {\n\t\t\t\tconst colors = $.derived(() => $$props.templateColorMap?.get($.get(token).value) || { from: \"#f43f5e\", to: \"#8b5cf6\" });\n\t\t\t\tvar span = root();\n\t\t\t\tvar text = $.only_child(span, true);\n\n\t\t\t\t$.template_effect(() => {\n\t\t\t\t\t$.set_style(span, `--color-from: ${$.get(colors).from}; --color-to: ${$.get(colors).to};`);\n\t\t\t\t\t$.set_attribute(span, 'title', `Template: ${$.get(token).value}`);\n\t\t\t\t\t$.set_text(text, `{{${$.get(token).value}}}`);\n\t\t\t\t});\n\n\t\t\t\t$.delegated('click', span, () => $$props.onTemplateClick?.($.get(token).value));\n\t\t\t\t$.append($$anchor, span);\n\t\t\t};\n\n\t\t\tvar consequent_1 = ($$anchor) => {\n\t\t\t\tvar span_1 = root_1();\n\t\t\t\tvar text_1 = $.only_child(span_1, true);\n\n\t\t\t\t$.template_effect(() => {\n\t\t\t\t\t$.set_attribute(span_1, 'title', `Variable: ${$.get(token).value}`);\n\t\t\t\t\t$.set_text(text_1, `{${$.get(token).value}}`);\n\t\t\t\t});\n\n\t\t\t\t$.delegated('click', span_1, () => $$props.onVariableClick?.($.get(token).value));\n\t\t\t\t$.append($$anchor, span_1);\n\t\t\t};\n\n\t\t\tvar consequent_2 = ($$anchor) => {\n\t\t\t\tvar span_2 = root_2();\n\t\t\t\tvar text_2 = $.only_child(span_2, true);\n\n\t\t\t\t$.template_effect(() => {\n\t\t\t\t\t$.set_attribute(span_2, 'title', `Instruction: ${$.get(token).value}`);\n\t\t\t\t\t$.set_text(text_2, `__${$.get(token).value}__`);\n\t\t\t\t});\n\n\t\t\t\t$.append($$anchor, span_2);\n\t\t\t};\n\n\t\t\tvar alternate = ($$anchor) => {\n\t\t\t\tvar span_3 = root_3();\n\t\t\t\tvar text_3 = $.only_child(span_3, true);\n\n\t\t\t\t$.template_effect(() => $.set_text(text_3, $.get(token).value));\n\t\t\t\t$.append($$anchor, span_3);\n\t\t\t};\n\n\t\t\t$.if(node, ($$render) => {\n\t\t\t\tif ($.get(token).type === \"template\") $$render(consequent); else if ($.get(token).type === \"variable\") $$render(consequent_1, 1); else if ($.get(token).type === \"instruction\") $$render(consequent_2, 2); else $$render(alternate, -1);\n\t\t\t});\n\t\t}\n\n\t\t$.append($$anchor, fragment);\n\t});\n\n\t$.reset(div);\n\t$.template_effect(() => $.set_class(div, 1, $.clsx(className())));\n\t$.append($$anchor, div);\n\t$.pop();\n}\n\n$.delegate(['click']);","import type { Component } from \"svelte\";\nimport type { Editor, Content, Extensions } from \"@tiptap/core\";\nimport type { Template, ColorGradient } from \"@pixerate/editor\";\n\nimport EditableTextNodeEditorComponent from \"./EditableTextNodeEditor.svelte\";\nimport BubbleMenuComponent from \"./BubbleMenu.svelte\";\nimport TemplateRendererComponent from \"./TemplateRenderer.svelte\";\n\nexport * from \"./editor.svelte\";\n\nexport interface EditableTextNodeEditorProps {\n class?: string;\n content?: Content;\n showMenu?: boolean;\n editable?: boolean;\n editor?: Editor;\n extensions?: Extensions;\n onUpdate?: () => void;\n onFocus?: () => void;\n onBlur?: () => void;\n onCreate?: () => void;\n placeholder?: string;\n}\n\nexport interface BubbleMenuProps {\n editor?: Editor;\n class?: string;\n children?: any;\n}\n\nexport interface TemplateRendererProps {\n content: string;\n templates?: Template[];\n templateColorMap?: Map<string, ColorGradient>;\n resolve?: boolean;\n class?: string;\n onTemplateClick?: (templateName: string) => void;\n onVariableClick?: (variableName: string) => void;\n}\n\nexport const EditableTextNodeEditor = EditableTextNodeEditorComponent as unknown as Component<EditableTextNodeEditorProps>;\nexport const BubbleMenu = BubbleMenuComponent as unknown as Component<BubbleMenuProps>;\nexport const TemplateRenderer = TemplateRendererComponent as unknown as Component<TemplateRendererProps>;\n\nexport type {\n Template,\n TemplateVersion,\n Token,\n TokenType,\n ColorGradient,\n RichTextPresetOptions,\n} from \"@pixerate/editor\";\n"],"mappings":"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","names":["$","$$anchor","$","onMount","onDestroy","root","$$anchor","$","root","root_1","$$anchor","EditableTextNodeEditor","BubbleMenu","TemplateRenderer"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pixerate/editor-svelte",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
|
|
5
|
+
"author": "Pixerate",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"svelte": "./src/index.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"svelte": "./src/index.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"src"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@tiptap/core": "^2.11.5",
|
|
26
|
+
"@tiptap/extension-bubble-menu": "^2.11.5",
|
|
27
|
+
"@tiptap/extension-placeholder": "^2.11.5",
|
|
28
|
+
"@tiptap/pm": "^2.11.5",
|
|
29
|
+
"@tiptap/starter-kit": "^2.11.5",
|
|
30
|
+
"@pixerate/editor": "0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"svelte": "^4.0.0 || ^5.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"esbuild-svelte": "^0.9.5",
|
|
37
|
+
"svelte": "^5.0.0",
|
|
38
|
+
"svelte-preprocess": "^6.0.5",
|
|
39
|
+
"tsup": "^8.4.0",
|
|
40
|
+
"typescript": "^5.7.3",
|
|
41
|
+
"vitest": "^3.0.5"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"test": "vitest run"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Editor } from "@tiptap/core";
|
|
3
|
+
import BubbleMenuPlugin from "@tiptap/extension-bubble-menu";
|
|
4
|
+
import { onMount, onDestroy } from "svelte";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
editor?: Editor;
|
|
8
|
+
class?: string;
|
|
9
|
+
children?: import("svelte").Snippet;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
editor,
|
|
14
|
+
class: className = "flex items-center gap-1 bg-white border border-gray-200 shadow-md rounded-md p-1",
|
|
15
|
+
children,
|
|
16
|
+
}: Props = $props();
|
|
17
|
+
|
|
18
|
+
let menuElement = $state<HTMLElement>();
|
|
19
|
+
|
|
20
|
+
onMount(() => {
|
|
21
|
+
if (editor && menuElement) {
|
|
22
|
+
editor.registerPlugin(
|
|
23
|
+
BubbleMenuPlugin.configure({
|
|
24
|
+
element: menuElement,
|
|
25
|
+
tippyOptions: { duration: 100 },
|
|
26
|
+
})
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
onDestroy(() => {
|
|
32
|
+
if (editor) {
|
|
33
|
+
editor.unregisterPlugin("bubbleMenu");
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<div bind:this={menuElement} class={className}>
|
|
39
|
+
{#if children}
|
|
40
|
+
{@render children()}
|
|
41
|
+
{/if}
|
|
42
|
+
</div>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Editor, Content, Extensions } from "@tiptap/core";
|
|
3
|
+
import { onDestroy, onMount } from "svelte";
|
|
4
|
+
import Placeholder from "@tiptap/extension-placeholder";
|
|
5
|
+
import { initiateEditor } from "./editor.svelte";
|
|
6
|
+
|
|
7
|
+
interface EditorProps {
|
|
8
|
+
class?: string;
|
|
9
|
+
content?: Content;
|
|
10
|
+
showMenu?: boolean;
|
|
11
|
+
editable?: boolean;
|
|
12
|
+
editor?: Editor;
|
|
13
|
+
extensions?: Extensions;
|
|
14
|
+
onUpdate?: () => void;
|
|
15
|
+
onFocus?: () => void;
|
|
16
|
+
onBlur?: () => void;
|
|
17
|
+
onCreate?: () => void;
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
class: className = "",
|
|
23
|
+
content = undefined,
|
|
24
|
+
showMenu = true,
|
|
25
|
+
editable = true,
|
|
26
|
+
editor = $bindable<Editor | undefined>(),
|
|
27
|
+
extensions = [],
|
|
28
|
+
onUpdate,
|
|
29
|
+
onFocus,
|
|
30
|
+
onBlur,
|
|
31
|
+
onCreate,
|
|
32
|
+
placeholder = "",
|
|
33
|
+
}: EditorProps = $props();
|
|
34
|
+
|
|
35
|
+
let element = $state<HTMLElement>();
|
|
36
|
+
|
|
37
|
+
$effect(() => {
|
|
38
|
+
if (editor && editor.isEditable !== editable) {
|
|
39
|
+
editor.setEditable(editable);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
onMount(() => {
|
|
44
|
+
editor = initiateEditor(
|
|
45
|
+
element,
|
|
46
|
+
content,
|
|
47
|
+
[
|
|
48
|
+
Placeholder.configure({
|
|
49
|
+
placeholder,
|
|
50
|
+
}),
|
|
51
|
+
...extensions,
|
|
52
|
+
],
|
|
53
|
+
{
|
|
54
|
+
editable,
|
|
55
|
+
onCreate,
|
|
56
|
+
onUpdate,
|
|
57
|
+
onFocus() {
|
|
58
|
+
if (onFocus) onFocus();
|
|
59
|
+
},
|
|
60
|
+
onBlur() {
|
|
61
|
+
if (onBlur) onBlur();
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
onDestroy(() => {
|
|
68
|
+
if (editor) {
|
|
69
|
+
editor.destroy();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<div class={`pixerate-editor-container ${className}`} draggable="false">
|
|
75
|
+
{#if !editor}
|
|
76
|
+
<div class="flex items-center justify-center p-4 text-sm text-gray-500">
|
|
77
|
+
Loading editor...
|
|
78
|
+
</div>
|
|
79
|
+
{/if}
|
|
80
|
+
<div
|
|
81
|
+
bind:this={element}
|
|
82
|
+
class="pixerate-editor-content prose w-full max-w-none focus:outline-none"
|
|
83
|
+
></div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<style>
|
|
87
|
+
:global(.pixerate-editor-content .is-empty::before) {
|
|
88
|
+
content: attr(data-placeholder);
|
|
89
|
+
float: left;
|
|
90
|
+
color: #9ca3af;
|
|
91
|
+
pointer-events: none;
|
|
92
|
+
height: 0;
|
|
93
|
+
}
|
|
94
|
+
</style>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
tokenizePrompt,
|
|
4
|
+
resolveTemplates,
|
|
5
|
+
type Template,
|
|
6
|
+
type ColorGradient,
|
|
7
|
+
} from "@pixerate/editor";
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
content: string;
|
|
11
|
+
templates?: Template[];
|
|
12
|
+
templateColorMap?: Map<string, ColorGradient>;
|
|
13
|
+
resolve?: boolean;
|
|
14
|
+
class?: string;
|
|
15
|
+
onTemplateClick?: (templateName: string) => void;
|
|
16
|
+
onVariableClick?: (variableName: string) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
content,
|
|
21
|
+
templates = [],
|
|
22
|
+
templateColorMap,
|
|
23
|
+
resolve = false,
|
|
24
|
+
class: className = "font-mono text-sm leading-relaxed whitespace-pre-wrap break-words",
|
|
25
|
+
onTemplateClick,
|
|
26
|
+
onVariableClick,
|
|
27
|
+
}: Props = $props();
|
|
28
|
+
|
|
29
|
+
let displayText = $derived(
|
|
30
|
+
resolve && templates.length > 0
|
|
31
|
+
? resolveTemplates(content, templates)
|
|
32
|
+
: content
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
let tokens = $derived(tokenizePrompt(displayText));
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<div class={className}>
|
|
39
|
+
{#each tokens as token}
|
|
40
|
+
{#if token.type === "template"}
|
|
41
|
+
{@const colors = templateColorMap?.get(token.value) || { from: "#f43f5e", to: "#8b5cf6" }}
|
|
42
|
+
<span
|
|
43
|
+
style={`--color-from: ${colors.from}; --color-to: ${colors.to};`}
|
|
44
|
+
onclick={() => onTemplateClick?.(token.value)}
|
|
45
|
+
class="inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs font-semibold rounded-md border border-[var(--color-to)]/40 bg-gradient-to-r from-[var(--color-from)]/15 to-[var(--color-to)]/15 text-[var(--color-to)] hover:brightness-110 cursor-pointer transition-all"
|
|
46
|
+
title={`Template: ${token.value}`}
|
|
47
|
+
>
|
|
48
|
+
{`{{${token.value}}}`}
|
|
49
|
+
</span>
|
|
50
|
+
{:else if token.type === "variable"}
|
|
51
|
+
<span
|
|
52
|
+
onclick={() => onVariableClick?.(token.value)}
|
|
53
|
+
class="inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs font-medium rounded-md border border-violet-400/40 bg-violet-400/15 text-violet-600 hover:brightness-110 cursor-pointer transition-all"
|
|
54
|
+
title={`Variable: ${token.value}`}
|
|
55
|
+
>
|
|
56
|
+
{`{${token.value}}`}
|
|
57
|
+
</span>
|
|
58
|
+
{:else if token.type === "instruction"}
|
|
59
|
+
<span
|
|
60
|
+
class="inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs italic font-medium rounded-md border border-rose-400/40 bg-rose-400/15 text-rose-600"
|
|
61
|
+
title={`Instruction: ${token.value}`}
|
|
62
|
+
>
|
|
63
|
+
{`__${token.value}__`}
|
|
64
|
+
</span>
|
|
65
|
+
{:else}
|
|
66
|
+
<span>{token.value}</span>
|
|
67
|
+
{/if}
|
|
68
|
+
{/each}
|
|
69
|
+
</div>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Editor, type Content, type EditorOptions, type Extensions } from "@tiptap/core";
|
|
2
|
+
import { createRichTextPreset, type RichTextPresetOptions } from "@pixerate/editor";
|
|
3
|
+
|
|
4
|
+
export interface SvelteInitiateEditorOptions extends Partial<EditorOptions> {
|
|
5
|
+
richTextOptions?: RichTextPresetOptions;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initializes a TipTap editor instance preconfigured with rich text extensions.
|
|
10
|
+
*/
|
|
11
|
+
export const initiateEditor = (
|
|
12
|
+
element?: HTMLElement,
|
|
13
|
+
content?: Content,
|
|
14
|
+
extensions?: Extensions,
|
|
15
|
+
options?: SvelteInitiateEditorOptions,
|
|
16
|
+
): Editor => {
|
|
17
|
+
const { richTextOptions, ...editorOptions } = options || {};
|
|
18
|
+
const defaultPreset = createRichTextPreset(richTextOptions);
|
|
19
|
+
|
|
20
|
+
const editor = new Editor({
|
|
21
|
+
element,
|
|
22
|
+
content,
|
|
23
|
+
extensions: [
|
|
24
|
+
...defaultPreset,
|
|
25
|
+
...(extensions ?? []),
|
|
26
|
+
],
|
|
27
|
+
autofocus: true,
|
|
28
|
+
...editorOptions,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return editor;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export interface ReactiveEditorState {
|
|
35
|
+
editor: Editor | undefined;
|
|
36
|
+
content: string;
|
|
37
|
+
isEditable: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates a reactive editor state manager for Svelte 5.
|
|
42
|
+
*/
|
|
43
|
+
export function createReactiveEditor(
|
|
44
|
+
initialContent: string = "",
|
|
45
|
+
extensions: Extensions = [],
|
|
46
|
+
options: Partial<EditorOptions> = {},
|
|
47
|
+
) {
|
|
48
|
+
let editorInstance: Editor | undefined;
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
get current() {
|
|
52
|
+
return editorInstance;
|
|
53
|
+
},
|
|
54
|
+
mount(element: HTMLElement) {
|
|
55
|
+
editorInstance = initiateEditor(element, initialContent, extensions, options);
|
|
56
|
+
return editorInstance;
|
|
57
|
+
},
|
|
58
|
+
destroy() {
|
|
59
|
+
if (editorInstance) {
|
|
60
|
+
editorInstance.destroy();
|
|
61
|
+
editorInstance = undefined;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Component } from "svelte";
|
|
2
|
+
import type { Editor, Content, Extensions, EditorOptions } from "@tiptap/core";
|
|
3
|
+
import type {
|
|
4
|
+
Template,
|
|
5
|
+
TemplateVersion,
|
|
6
|
+
Token,
|
|
7
|
+
TokenType,
|
|
8
|
+
ColorGradient,
|
|
9
|
+
RichTextPresetOptions,
|
|
10
|
+
} from "@pixerate/editor";
|
|
11
|
+
|
|
12
|
+
export interface SvelteInitiateEditorOptions extends Partial<EditorOptions> {
|
|
13
|
+
richTextOptions?: RichTextPresetOptions;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export declare const initiateEditor: (
|
|
17
|
+
element?: HTMLElement,
|
|
18
|
+
content?: Content,
|
|
19
|
+
extensions?: Extensions,
|
|
20
|
+
options?: SvelteInitiateEditorOptions,
|
|
21
|
+
) => Editor;
|
|
22
|
+
|
|
23
|
+
export interface ReactiveEditorState {
|
|
24
|
+
editor: Editor | undefined;
|
|
25
|
+
content: string;
|
|
26
|
+
isEditable: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export declare function createReactiveEditor(
|
|
30
|
+
initialContent?: string,
|
|
31
|
+
extensions?: Extensions,
|
|
32
|
+
options?: Partial<EditorOptions>,
|
|
33
|
+
): {
|
|
34
|
+
readonly current: Editor | undefined;
|
|
35
|
+
mount(element: HTMLElement): Editor;
|
|
36
|
+
destroy(): void;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export interface EditableTextNodeEditorProps {
|
|
40
|
+
class?: string;
|
|
41
|
+
content?: Content;
|
|
42
|
+
showMenu?: boolean;
|
|
43
|
+
editable?: boolean;
|
|
44
|
+
editor?: Editor;
|
|
45
|
+
extensions?: Extensions;
|
|
46
|
+
onUpdate?: () => void;
|
|
47
|
+
onFocus?: () => void;
|
|
48
|
+
onBlur?: () => void;
|
|
49
|
+
onCreate?: () => void;
|
|
50
|
+
placeholder?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface BubbleMenuProps {
|
|
54
|
+
editor?: Editor;
|
|
55
|
+
class?: string;
|
|
56
|
+
children?: any;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface TemplateRendererProps {
|
|
60
|
+
content: string;
|
|
61
|
+
templates?: Template[];
|
|
62
|
+
templateColorMap?: Map<string, ColorGradient>;
|
|
63
|
+
resolve?: boolean;
|
|
64
|
+
class?: string;
|
|
65
|
+
onTemplateClick?: (templateName: string) => void;
|
|
66
|
+
onVariableClick?: (variableName: string) => void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export declare const EditableTextNodeEditor: Component<EditableTextNodeEditorProps>;
|
|
70
|
+
export declare const BubbleMenu: Component<BubbleMenuProps>;
|
|
71
|
+
export declare const TemplateRenderer: Component<TemplateRendererProps>;
|
|
72
|
+
|
|
73
|
+
export type {
|
|
74
|
+
Template,
|
|
75
|
+
TemplateVersion,
|
|
76
|
+
Token,
|
|
77
|
+
TokenType,
|
|
78
|
+
ColorGradient,
|
|
79
|
+
RichTextPresetOptions,
|
|
80
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Component } from "svelte";
|
|
2
|
+
import type { Editor, Content, Extensions } from "@tiptap/core";
|
|
3
|
+
import type { Template, ColorGradient } from "@pixerate/editor";
|
|
4
|
+
|
|
5
|
+
import EditableTextNodeEditorComponent from "./EditableTextNodeEditor.svelte";
|
|
6
|
+
import BubbleMenuComponent from "./BubbleMenu.svelte";
|
|
7
|
+
import TemplateRendererComponent from "./TemplateRenderer.svelte";
|
|
8
|
+
|
|
9
|
+
export * from "./editor.svelte";
|
|
10
|
+
|
|
11
|
+
export interface EditableTextNodeEditorProps {
|
|
12
|
+
class?: string;
|
|
13
|
+
content?: Content;
|
|
14
|
+
showMenu?: boolean;
|
|
15
|
+
editable?: boolean;
|
|
16
|
+
editor?: Editor;
|
|
17
|
+
extensions?: Extensions;
|
|
18
|
+
onUpdate?: () => void;
|
|
19
|
+
onFocus?: () => void;
|
|
20
|
+
onBlur?: () => void;
|
|
21
|
+
onCreate?: () => void;
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface BubbleMenuProps {
|
|
26
|
+
editor?: Editor;
|
|
27
|
+
class?: string;
|
|
28
|
+
children?: any;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface TemplateRendererProps {
|
|
32
|
+
content: string;
|
|
33
|
+
templates?: Template[];
|
|
34
|
+
templateColorMap?: Map<string, ColorGradient>;
|
|
35
|
+
resolve?: boolean;
|
|
36
|
+
class?: string;
|
|
37
|
+
onTemplateClick?: (templateName: string) => void;
|
|
38
|
+
onVariableClick?: (variableName: string) => void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const EditableTextNodeEditor = EditableTextNodeEditorComponent as unknown as Component<EditableTextNodeEditorProps>;
|
|
42
|
+
export const BubbleMenu = BubbleMenuComponent as unknown as Component<BubbleMenuProps>;
|
|
43
|
+
export const TemplateRenderer = TemplateRendererComponent as unknown as Component<TemplateRendererProps>;
|
|
44
|
+
|
|
45
|
+
export type {
|
|
46
|
+
Template,
|
|
47
|
+
TemplateVersion,
|
|
48
|
+
Token,
|
|
49
|
+
TokenType,
|
|
50
|
+
ColorGradient,
|
|
51
|
+
RichTextPresetOptions,
|
|
52
|
+
} from "@pixerate/editor";
|