@blockslides/react-prebuilts 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.md +36 -0
- package/dist/index.cjs +381 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +86 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +354 -0
- package/dist/index.js.map +1 -0
- package/dist/menus/index.cjs +281 -0
- package/dist/menus/index.cjs.map +1 -0
- package/dist/menus/index.d.cts +28 -0
- package/dist/menus/index.d.ts +28 -0
- package/dist/menus/index.js +252 -0
- package/dist/menus/index.js.map +1 -0
- package/package.json +76 -0
- package/src/SlideEditor.tsx +73 -0
- package/src/index.ts +8 -0
- package/src/menus/BubbleMenu.tsx +89 -0
- package/src/menus/BubbleMenuPreset.tsx +144 -0
- package/src/menus/FloatingMenu.tsx +69 -0
- package/src/menus/index.ts +3 -0
- package/src/useSlideEditor.ts +250 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
// src/SlideEditor.tsx
|
|
2
|
+
import { forwardRef, useMemo as useMemo2 } from "react";
|
|
3
|
+
import { EditorContent } from "@blockslides/react";
|
|
4
|
+
|
|
5
|
+
// src/menus/BubbleMenuPreset.tsx
|
|
6
|
+
import React, { useEffect, useRef } from "react";
|
|
7
|
+
import { createPortal } from "react-dom";
|
|
8
|
+
import { useCurrentEditor } from "@blockslides/react";
|
|
9
|
+
import {
|
|
10
|
+
BubbleMenuPlugin
|
|
11
|
+
} from "@blockslides/extension-bubble-menu";
|
|
12
|
+
import { NodeSelection } from "@blockslides/pm/state";
|
|
13
|
+
import {
|
|
14
|
+
buildMenuElement,
|
|
15
|
+
DEFAULT_ITEMS,
|
|
16
|
+
DEFAULT_COLOR_PALETTE,
|
|
17
|
+
DEFAULT_HIGHLIGHT_PALETTE,
|
|
18
|
+
DEFAULT_FONTS,
|
|
19
|
+
DEFAULT_FONT_SIZES,
|
|
20
|
+
DEFAULT_ALIGNMENTS
|
|
21
|
+
} from "@blockslides/extension-bubble-menu-preset";
|
|
22
|
+
import { isTextSelection } from "@blockslides/core";
|
|
23
|
+
import { jsx } from "react/jsx-runtime";
|
|
24
|
+
var BubbleMenuPreset = React.forwardRef(
|
|
25
|
+
({
|
|
26
|
+
editor,
|
|
27
|
+
updateDelay,
|
|
28
|
+
resizeDelay,
|
|
29
|
+
appendTo,
|
|
30
|
+
shouldShow,
|
|
31
|
+
getReferencedVirtualElement,
|
|
32
|
+
options,
|
|
33
|
+
items,
|
|
34
|
+
className,
|
|
35
|
+
injectStyles,
|
|
36
|
+
textColors,
|
|
37
|
+
highlightColors,
|
|
38
|
+
fonts,
|
|
39
|
+
fontSizes,
|
|
40
|
+
alignments,
|
|
41
|
+
onTextAction,
|
|
42
|
+
onImageReplace,
|
|
43
|
+
...rest
|
|
44
|
+
}, ref) => {
|
|
45
|
+
const pluginKey = "bubbleMenuPreset";
|
|
46
|
+
const { editor: currentEditor } = useCurrentEditor();
|
|
47
|
+
const menuEl = useRef(null);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
const attachToEditor = editor || currentEditor;
|
|
50
|
+
if (!attachToEditor || attachToEditor.isDestroyed) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const { element, cleanup } = buildMenuElement(attachToEditor, {
|
|
54
|
+
items: items != null ? items : DEFAULT_ITEMS,
|
|
55
|
+
className: className != null ? className : "",
|
|
56
|
+
injectStyles: injectStyles !== false,
|
|
57
|
+
textColors: textColors != null ? textColors : DEFAULT_COLOR_PALETTE,
|
|
58
|
+
highlightColors: highlightColors != null ? highlightColors : DEFAULT_HIGHLIGHT_PALETTE,
|
|
59
|
+
fonts: fonts != null ? fonts : DEFAULT_FONTS,
|
|
60
|
+
fontSizes: fontSizes != null ? fontSizes : DEFAULT_FONT_SIZES,
|
|
61
|
+
alignments: alignments != null ? alignments : DEFAULT_ALIGNMENTS,
|
|
62
|
+
onTextAction,
|
|
63
|
+
onImageReplace
|
|
64
|
+
});
|
|
65
|
+
menuEl.current = element;
|
|
66
|
+
if (typeof ref === "function") {
|
|
67
|
+
ref(element);
|
|
68
|
+
} else if (ref) {
|
|
69
|
+
;
|
|
70
|
+
ref.current = element;
|
|
71
|
+
}
|
|
72
|
+
const defaultShouldShow = ({
|
|
73
|
+
state,
|
|
74
|
+
editor: editor2
|
|
75
|
+
}) => {
|
|
76
|
+
var _a, _b;
|
|
77
|
+
const sel = state.selection;
|
|
78
|
+
const imageSelection = sel instanceof NodeSelection && ["image", "imageBlock"].includes((_b = (_a = sel.node) == null ? void 0 : _a.type) == null ? void 0 : _b.name) || editor2.isActive("image") || editor2.isActive("imageBlock");
|
|
79
|
+
if (imageSelection) return true;
|
|
80
|
+
if (isTextSelection(sel) && !sel.empty && !imageSelection) return true;
|
|
81
|
+
return false;
|
|
82
|
+
};
|
|
83
|
+
const plugin = BubbleMenuPlugin({
|
|
84
|
+
editor: attachToEditor,
|
|
85
|
+
element,
|
|
86
|
+
updateDelay,
|
|
87
|
+
resizeDelay,
|
|
88
|
+
appendTo,
|
|
89
|
+
pluginKey,
|
|
90
|
+
shouldShow: shouldShow != null ? shouldShow : defaultShouldShow,
|
|
91
|
+
getReferencedVirtualElement,
|
|
92
|
+
options
|
|
93
|
+
});
|
|
94
|
+
attachToEditor.registerPlugin(plugin);
|
|
95
|
+
return () => {
|
|
96
|
+
attachToEditor.unregisterPlugin(pluginKey);
|
|
97
|
+
cleanup == null ? void 0 : cleanup();
|
|
98
|
+
if (element.parentNode) {
|
|
99
|
+
element.parentNode.removeChild(element);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}, [
|
|
103
|
+
editor,
|
|
104
|
+
currentEditor,
|
|
105
|
+
updateDelay,
|
|
106
|
+
resizeDelay,
|
|
107
|
+
appendTo,
|
|
108
|
+
shouldShow,
|
|
109
|
+
getReferencedVirtualElement,
|
|
110
|
+
options,
|
|
111
|
+
items,
|
|
112
|
+
className,
|
|
113
|
+
injectStyles,
|
|
114
|
+
textColors,
|
|
115
|
+
highlightColors,
|
|
116
|
+
fonts,
|
|
117
|
+
fontSizes,
|
|
118
|
+
alignments,
|
|
119
|
+
onTextAction,
|
|
120
|
+
onImageReplace,
|
|
121
|
+
ref
|
|
122
|
+
]);
|
|
123
|
+
return menuEl.current ? createPortal(/* @__PURE__ */ jsx("div", { ...rest }), menuEl.current) : null;
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
BubbleMenuPreset.displayName = "BubbleMenuPreset";
|
|
127
|
+
|
|
128
|
+
// src/useSlideEditor.ts
|
|
129
|
+
import { useEffect as useEffect2, useMemo } from "react";
|
|
130
|
+
import { templatesV1 } from "@blockslides/ai-context";
|
|
131
|
+
import {
|
|
132
|
+
ExtensionKit
|
|
133
|
+
} from "@blockslides/extension-kit";
|
|
134
|
+
import {
|
|
135
|
+
useEditor
|
|
136
|
+
} from "@blockslides/react";
|
|
137
|
+
var defaultSlide = () => ({
|
|
138
|
+
/**
|
|
139
|
+
* Placeholder slide if no content is provided.
|
|
140
|
+
*/
|
|
141
|
+
type: "doc",
|
|
142
|
+
content: [
|
|
143
|
+
{
|
|
144
|
+
type: "slide",
|
|
145
|
+
attrs: {
|
|
146
|
+
size: "16x9",
|
|
147
|
+
className: "",
|
|
148
|
+
id: "slide-1",
|
|
149
|
+
backgroundMode: "none",
|
|
150
|
+
backgroundColor: null,
|
|
151
|
+
backgroundImage: null,
|
|
152
|
+
backgroundOverlayColor: null,
|
|
153
|
+
backgroundOverlayOpacity: null
|
|
154
|
+
},
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: "column",
|
|
158
|
+
attrs: {
|
|
159
|
+
align: "center",
|
|
160
|
+
padding: "lg",
|
|
161
|
+
margin: null,
|
|
162
|
+
gap: "md",
|
|
163
|
+
backgroundColor: "#ffffff",
|
|
164
|
+
backgroundImage: null,
|
|
165
|
+
borderRadius: null,
|
|
166
|
+
border: null,
|
|
167
|
+
fill: true,
|
|
168
|
+
width: null,
|
|
169
|
+
height: null,
|
|
170
|
+
justify: "center"
|
|
171
|
+
},
|
|
172
|
+
content: [
|
|
173
|
+
{
|
|
174
|
+
type: "heading",
|
|
175
|
+
attrs: {
|
|
176
|
+
align: null,
|
|
177
|
+
padding: null,
|
|
178
|
+
margin: null,
|
|
179
|
+
gap: null,
|
|
180
|
+
backgroundColor: null,
|
|
181
|
+
backgroundImage: null,
|
|
182
|
+
borderRadius: null,
|
|
183
|
+
border: null,
|
|
184
|
+
fill: null,
|
|
185
|
+
width: null,
|
|
186
|
+
height: null,
|
|
187
|
+
justify: null,
|
|
188
|
+
id: "1fc4664c-333d-4203-a3f1-3ad27a54c535",
|
|
189
|
+
"data-toc-id": "1fc4664c-333d-4203-a3f1-3ad27a54c535",
|
|
190
|
+
level: 1
|
|
191
|
+
},
|
|
192
|
+
content: [
|
|
193
|
+
{
|
|
194
|
+
type: "text",
|
|
195
|
+
text: "Lorem ipsum dolor sit amet"
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
type: "paragraph",
|
|
201
|
+
attrs: {
|
|
202
|
+
align: null,
|
|
203
|
+
padding: null,
|
|
204
|
+
margin: null,
|
|
205
|
+
gap: null,
|
|
206
|
+
backgroundColor: null,
|
|
207
|
+
backgroundImage: null,
|
|
208
|
+
borderRadius: null,
|
|
209
|
+
border: null,
|
|
210
|
+
fill: null,
|
|
211
|
+
width: null,
|
|
212
|
+
height: null,
|
|
213
|
+
justify: null
|
|
214
|
+
},
|
|
215
|
+
content: [
|
|
216
|
+
{
|
|
217
|
+
type: "text",
|
|
218
|
+
text: "Consectetur adipiscing elit. Sed do eiusmod tempor incididunt. "
|
|
219
|
+
}
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
]
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
});
|
|
228
|
+
var defaultAddSlideButton = (presets) => ({
|
|
229
|
+
showPresets: true,
|
|
230
|
+
presets,
|
|
231
|
+
presetBackground: "#0f172a",
|
|
232
|
+
presetForeground: "#e5e7eb"
|
|
233
|
+
});
|
|
234
|
+
var defaultSlideOptions = {
|
|
235
|
+
renderMode: "dynamic",
|
|
236
|
+
hoverOutline: { color: "#3b82f6", width: "1.5px", offset: "4px" },
|
|
237
|
+
hoverOutlineCascade: false
|
|
238
|
+
};
|
|
239
|
+
var useSlideEditor = ({
|
|
240
|
+
content,
|
|
241
|
+
onChange,
|
|
242
|
+
extensions,
|
|
243
|
+
extensionKitOptions,
|
|
244
|
+
presetTemplates,
|
|
245
|
+
deps = [],
|
|
246
|
+
onEditorReady,
|
|
247
|
+
immediatelyRender = false,
|
|
248
|
+
shouldRerenderOnTransaction = false,
|
|
249
|
+
theme = "light",
|
|
250
|
+
editorProps,
|
|
251
|
+
onUpdate,
|
|
252
|
+
...editorOptions
|
|
253
|
+
} = {}) => {
|
|
254
|
+
var _a;
|
|
255
|
+
const presets = useMemo(
|
|
256
|
+
() => presetTemplates != null ? presetTemplates : templatesV1.listPresetTemplates(),
|
|
257
|
+
[presetTemplates]
|
|
258
|
+
);
|
|
259
|
+
const mergedExtensionKitOptions = useMemo(() => {
|
|
260
|
+
var _a2, _b;
|
|
261
|
+
const addSlideButton = (extensionKitOptions == null ? void 0 : extensionKitOptions.addSlideButton) === false ? false : {
|
|
262
|
+
...defaultAddSlideButton(presets),
|
|
263
|
+
...(_a2 = extensionKitOptions == null ? void 0 : extensionKitOptions.addSlideButton) != null ? _a2 : {}
|
|
264
|
+
};
|
|
265
|
+
const slide = (extensionKitOptions == null ? void 0 : extensionKitOptions.slide) === false ? false : {
|
|
266
|
+
...defaultSlideOptions,
|
|
267
|
+
...(_b = extensionKitOptions == null ? void 0 : extensionKitOptions.slide) != null ? _b : {}
|
|
268
|
+
};
|
|
269
|
+
return {
|
|
270
|
+
...extensionKitOptions,
|
|
271
|
+
addSlideButton,
|
|
272
|
+
slide
|
|
273
|
+
};
|
|
274
|
+
}, [extensionKitOptions, presets]);
|
|
275
|
+
const resolvedExtensions = useMemo(() => {
|
|
276
|
+
const kit = ExtensionKit.configure(mergedExtensionKitOptions);
|
|
277
|
+
return extensions ? [kit, ...extensions] : [kit];
|
|
278
|
+
}, [extensions, mergedExtensionKitOptions]);
|
|
279
|
+
const initialContent = content != null ? content : defaultSlide();
|
|
280
|
+
const editor = useEditor(
|
|
281
|
+
{
|
|
282
|
+
content: initialContent,
|
|
283
|
+
extensions: resolvedExtensions,
|
|
284
|
+
immediatelyRender,
|
|
285
|
+
shouldRerenderOnTransaction,
|
|
286
|
+
theme,
|
|
287
|
+
editorProps: {
|
|
288
|
+
attributes: {
|
|
289
|
+
autocomplete: "off",
|
|
290
|
+
autocorrect: "off",
|
|
291
|
+
autocapitalize: "off",
|
|
292
|
+
class: "min-h-full min-w-full",
|
|
293
|
+
...(_a = editorProps == null ? void 0 : editorProps.attributes) != null ? _a : {}
|
|
294
|
+
},
|
|
295
|
+
...editorProps
|
|
296
|
+
},
|
|
297
|
+
...editorOptions,
|
|
298
|
+
onUpdate: (ctx) => {
|
|
299
|
+
const json = ctx.editor.getJSON();
|
|
300
|
+
onChange == null ? void 0 : onChange(json, ctx.editor);
|
|
301
|
+
onUpdate == null ? void 0 : onUpdate(ctx);
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
deps
|
|
305
|
+
);
|
|
306
|
+
useEffect2(() => {
|
|
307
|
+
if (editor && !editor.isDestroyed) {
|
|
308
|
+
onEditorReady == null ? void 0 : onEditorReady(editor);
|
|
309
|
+
}
|
|
310
|
+
}, [editor, onEditorReady]);
|
|
311
|
+
return { editor, presets };
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
// src/SlideEditor.tsx
|
|
315
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
316
|
+
var SlideEditor = forwardRef(
|
|
317
|
+
({
|
|
318
|
+
bubbleMenuPreset = true,
|
|
319
|
+
editorContentProps,
|
|
320
|
+
viewportScale = 1,
|
|
321
|
+
className,
|
|
322
|
+
style,
|
|
323
|
+
...hookProps
|
|
324
|
+
}, ref) => {
|
|
325
|
+
const { editor } = useSlideEditor(hookProps);
|
|
326
|
+
const bubbleMenuProps = useMemo2(() => {
|
|
327
|
+
if (bubbleMenuPreset === false) return null;
|
|
328
|
+
if (bubbleMenuPreset === true) return {};
|
|
329
|
+
return bubbleMenuPreset;
|
|
330
|
+
}, [bubbleMenuPreset]);
|
|
331
|
+
if (!editor) return null;
|
|
332
|
+
return /* @__PURE__ */ jsx2("div", { ref, className, style, children: /* @__PURE__ */ jsxs(
|
|
333
|
+
"div",
|
|
334
|
+
{
|
|
335
|
+
className: "bs-viewport",
|
|
336
|
+
style: { ["--zoom"]: viewportScale },
|
|
337
|
+
children: [
|
|
338
|
+
/* @__PURE__ */ jsx2(EditorContent, { editor, ...editorContentProps }),
|
|
339
|
+
bubbleMenuProps && /* @__PURE__ */ jsx2(BubbleMenuPreset, { editor, ...bubbleMenuProps })
|
|
340
|
+
]
|
|
341
|
+
}
|
|
342
|
+
) });
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
SlideEditor.displayName = "SlideEditor";
|
|
346
|
+
|
|
347
|
+
// src/index.ts
|
|
348
|
+
export * from "@blockslides/react";
|
|
349
|
+
export {
|
|
350
|
+
BubbleMenuPreset,
|
|
351
|
+
SlideEditor as ReactSlideEditor,
|
|
352
|
+
useSlideEditor
|
|
353
|
+
};
|
|
354
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/SlideEditor.tsx","../src/menus/BubbleMenuPreset.tsx","../src/useSlideEditor.ts","../src/index.ts"],"sourcesContent":["import React, { forwardRef, useMemo } from \"react\";\nimport type { CSSProperties } from \"react\";\n\nimport { EditorContent, type EditorContentProps } from \"@blockslides/react\";\nimport {\n BubbleMenuPreset,\n type BubbleMenuPresetProps,\n} from \"./menus/BubbleMenuPreset.js\";\nimport {\n useSlideEditor,\n type UseSlideEditorProps,\n} from \"./useSlideEditor.js\";\n\nexport type SlideEditorProps = UseSlideEditorProps & {\n /**\n * Toggle or customize the built-in BubbleMenuPreset.\n * - true (default): render with defaults\n * - false: disable entirely\n * - object: pass through to BubbleMenuPreset\n */\n bubbleMenuPreset?: boolean | BubbleMenuPresetProps;\n /**\n * Additional props forwarded to EditorContent.\n */\n editorContentProps?: Omit<EditorContentProps, \"editor\">;\n /**\n * Viewport scale factor applied to the slide viewport.\n * @default 1\n */\n viewportScale?: number;\n className?: string;\n style?: CSSProperties;\n};\n\nexport const SlideEditor = forwardRef<HTMLDivElement, SlideEditorProps>(\n (\n {\n bubbleMenuPreset = true,\n editorContentProps,\n viewportScale = 1,\n className,\n style,\n ...hookProps\n },\n ref\n ) => {\n const { editor } = useSlideEditor(hookProps);\n\n const bubbleMenuProps = useMemo(() => {\n if (bubbleMenuPreset === false) return null;\n if (bubbleMenuPreset === true) return {};\n return bubbleMenuPreset;\n }, [bubbleMenuPreset]);\n\n if (!editor) return null;\n\n return (\n <div ref={ref} className={className} style={style}>\n <div\n className=\"bs-viewport\"\n style={{ [\"--zoom\" as any]: viewportScale }}\n >\n <EditorContent editor={editor} {...editorContentProps} />\n {bubbleMenuProps && (\n <BubbleMenuPreset editor={editor} {...bubbleMenuProps} />\n )}\n </div>\n </div>\n );\n }\n);\n\nSlideEditor.displayName = \"SlideEditor\";\n","import React, { useEffect, useRef } from 'react'\nimport { createPortal } from 'react-dom'\nimport { useCurrentEditor } from '@blockslides/react'\nimport {\n BubbleMenuPlugin,\n type BubbleMenuPluginProps,\n} from '@blockslides/extension-bubble-menu'\nimport { NodeSelection } from '@blockslides/pm/state'\nimport {\n type BubbleMenuPresetOptions,\n buildMenuElement,\n DEFAULT_ITEMS,\n DEFAULT_COLOR_PALETTE,\n DEFAULT_HIGHLIGHT_PALETTE,\n DEFAULT_FONTS,\n DEFAULT_FONT_SIZES,\n DEFAULT_ALIGNMENTS,\n} from '@blockslides/extension-bubble-menu-preset'\nimport { isNodeSelection, isTextSelection, type Editor } from '@blockslides/core'\n\nexport type BubbleMenuPresetProps = Omit<BubbleMenuPresetOptions, 'element' | 'pluginKey'> &\n React.HTMLAttributes<HTMLElement> & {\n editor?: Editor | null\n }\n\nexport const BubbleMenuPreset = React.forwardRef<HTMLElement, BubbleMenuPresetProps>(\n (\n {\n editor,\n updateDelay,\n resizeDelay,\n appendTo,\n shouldShow,\n getReferencedVirtualElement,\n options,\n items,\n className,\n injectStyles,\n textColors,\n highlightColors,\n fonts,\n fontSizes,\n alignments,\n onTextAction,\n onImageReplace,\n ...rest\n },\n ref,\n ) => {\n const pluginKey = 'bubbleMenuPreset'\n const { editor: currentEditor } = useCurrentEditor()\n const menuEl = useRef<HTMLElement | null>(null)\n\n useEffect(() => {\n const attachToEditor = (editor || currentEditor) as Editor | null\n if (!attachToEditor || (attachToEditor as any).isDestroyed) {\n return\n }\n\n const { element, cleanup } = buildMenuElement(attachToEditor, {\n items: items ?? DEFAULT_ITEMS,\n className: className ?? '',\n injectStyles: injectStyles !== false,\n textColors: textColors ?? DEFAULT_COLOR_PALETTE,\n highlightColors: highlightColors ?? DEFAULT_HIGHLIGHT_PALETTE,\n fonts: fonts ?? DEFAULT_FONTS,\n fontSizes: fontSizes ?? DEFAULT_FONT_SIZES,\n alignments: alignments ?? DEFAULT_ALIGNMENTS,\n onTextAction,\n onImageReplace,\n })\n\n menuEl.current = element\n\n if (typeof ref === 'function') {\n ref(element)\n } else if (ref) {\n ;(ref as React.MutableRefObject<HTMLElement | null>).current = element\n }\n\n const defaultShouldShow: Exclude<BubbleMenuPluginProps['shouldShow'], null> = ({\n state,\n editor,\n }) => {\n const sel = state.selection\n const imageSelection =\n (sel instanceof NodeSelection &&\n ['image', 'imageBlock'].includes((sel as any).node?.type?.name)) ||\n editor.isActive('image') ||\n editor.isActive('imageBlock')\n\n if (imageSelection) return true\n if (isTextSelection(sel) && !sel.empty && !imageSelection) return true\n return false\n }\n\n const plugin = BubbleMenuPlugin({\n editor: attachToEditor,\n element,\n updateDelay,\n resizeDelay,\n appendTo,\n pluginKey,\n shouldShow: shouldShow ?? defaultShouldShow,\n getReferencedVirtualElement,\n options,\n })\n\n attachToEditor.registerPlugin(plugin)\n\n return () => {\n attachToEditor.unregisterPlugin(pluginKey)\n cleanup?.()\n if (element.parentNode) {\n element.parentNode.removeChild(element)\n }\n }\n }, [\n editor,\n currentEditor,\n updateDelay,\n resizeDelay,\n appendTo,\n shouldShow,\n getReferencedVirtualElement,\n options,\n items,\n className,\n injectStyles,\n textColors,\n highlightColors,\n fonts,\n fontSizes,\n alignments,\n onTextAction,\n onImageReplace,\n ref,\n ])\n\n return menuEl.current ? createPortal(<div {...rest} />, menuEl.current) : null\n },\n)\n\nBubbleMenuPreset.displayName = 'BubbleMenuPreset'\n","import { useEffect, useMemo } from \"react\";\nimport type { DependencyList } from \"react\";\nimport { templatesV1 } from \"@blockslides/ai-context\";\nimport type { AnyExtension, Editor, JSONContent } from \"@blockslides/core\";\nimport type { SlideOptions } from \"@blockslides/extension-slide\";\nimport {\n ExtensionKit,\n type ExtensionKitOptions,\n} from \"@blockslides/extension-kit\";\n\nimport {\n useEditor,\n type UseEditorOptions,\n} from \"@blockslides/react\";\n\ntype PresetTemplates = ReturnType<typeof templatesV1.listPresetTemplates>;\n\nexport type UseSlideEditorProps = {\n /**\n * Initial content for the editor. If omitted, a single preset slide is used.\n */\n content?: UseEditorOptions[\"content\"];\n /**\n * Called on every update with the current JSON document.\n */\n onChange?: (doc: JSONContent, editor: Editor) => void;\n /**\n * Additional extensions to append after the ExtensionKit bundle.\n */\n extensions?: AnyExtension[];\n /**\n * Customize or disable pieces of ExtensionKit (e.g., bubbleMenu: false).\n */\n extensionKitOptions?: ExtensionKitOptions;\n /**\n * Optional preset list to power the add-slide button.\n */\n presetTemplates?: PresetTemplates;\n /**\n * Dependencies array forwarded to useEditor for re-instantiation control.\n * Leave empty to avoid recreating the editor on prop changes.\n */\n deps?: DependencyList;\n /**\n * Called once when an editor instance is ready.\n */\n onEditorReady?: (editor: Editor) => void;\n} & Omit<UseEditorOptions, \"extensions\" | \"content\">;\n\nconst defaultSlide = () => ({\n /**\n * Placeholder slide if no content is provided.\n */\n\n type: \"doc\",\n content: [\n {\n type: \"slide\",\n attrs: {\n size: \"16x9\",\n className: \"\",\n id: \"slide-1\",\n backgroundMode: \"none\",\n backgroundColor: null,\n backgroundImage: null,\n backgroundOverlayColor: null,\n backgroundOverlayOpacity: null,\n },\n content: [\n {\n type: \"column\",\n attrs: {\n align: \"center\",\n padding: \"lg\",\n margin: null,\n gap: \"md\",\n backgroundColor: \"#ffffff\",\n backgroundImage: null,\n borderRadius: null,\n border: null,\n fill: true,\n width: null,\n height: null,\n justify: \"center\",\n },\n content: [\n {\n type: \"heading\",\n attrs: {\n align: null,\n padding: null,\n margin: null,\n gap: null,\n backgroundColor: null,\n backgroundImage: null,\n borderRadius: null,\n border: null,\n fill: null,\n width: null,\n height: null,\n justify: null,\n id: \"1fc4664c-333d-4203-a3f1-3ad27a54c535\",\n \"data-toc-id\": \"1fc4664c-333d-4203-a3f1-3ad27a54c535\",\n level: 1,\n },\n content: [\n {\n type: \"text\",\n text: \"Lorem ipsum dolor sit amet\",\n },\n ],\n },\n {\n type: \"paragraph\",\n attrs: {\n align: null,\n padding: null,\n margin: null,\n gap: null,\n backgroundColor: null,\n backgroundImage: null,\n borderRadius: null,\n border: null,\n fill: null,\n width: null,\n height: null,\n justify: null,\n },\n content: [\n {\n type: \"text\",\n text: \"Consectetur adipiscing elit. Sed do eiusmod tempor incididunt. \",\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n});\n\nconst defaultAddSlideButton = (presets: PresetTemplates) => ({\n showPresets: true,\n presets,\n presetBackground: \"#0f172a\",\n presetForeground: \"#e5e7eb\",\n});\n\nconst defaultSlideOptions: Partial<SlideOptions> = {\n renderMode: \"dynamic\",\n hoverOutline: { color: \"#3b82f6\", width: \"1.5px\", offset: \"4px\" },\n hoverOutlineCascade: false,\n};\n\nexport const useSlideEditor = ({\n content,\n onChange,\n extensions,\n extensionKitOptions,\n presetTemplates,\n deps = [],\n onEditorReady,\n immediatelyRender = false,\n shouldRerenderOnTransaction = false,\n theme = \"light\",\n editorProps,\n onUpdate,\n ...editorOptions\n}: UseSlideEditorProps = {}) => {\n\n\n /**\n * Presets for add slide button.\n */\n const presets = useMemo<PresetTemplates>(\n () => presetTemplates ?? templatesV1.listPresetTemplates(),\n [presetTemplates]\n );\n\n const mergedExtensionKitOptions = useMemo<ExtensionKitOptions>(() => {\n const addSlideButton =\n extensionKitOptions?.addSlideButton === false\n ? false\n : {\n ...defaultAddSlideButton(presets),\n ...(extensionKitOptions?.addSlideButton ?? {}),\n };\n\n const slide =\n extensionKitOptions?.slide === false\n ? false\n : {\n ...defaultSlideOptions,\n ...(extensionKitOptions?.slide ?? {}),\n };\n\n return {\n ...extensionKitOptions,\n addSlideButton,\n slide,\n };\n }, [extensionKitOptions, presets]);\n\n const resolvedExtensions = useMemo<AnyExtension[]>(() => {\n const kit = ExtensionKit.configure(mergedExtensionKitOptions);\n return extensions ? [kit, ...extensions] : [kit];\n }, [extensions, mergedExtensionKitOptions]);\n\n /**\n * Initial content for the editor.\n * content, initialContent, defaultValue, value etc are all the same thing\n */\n const initialContent = content ?? defaultSlide();\n\n const editor = useEditor(\n {\n content: initialContent,\n extensions: resolvedExtensions,\n immediatelyRender,\n shouldRerenderOnTransaction,\n theme,\n editorProps: {\n attributes: {\n autocomplete: \"off\",\n autocorrect: \"off\",\n autocapitalize: \"off\",\n class: \"min-h-full min-w-full\",\n ...(editorProps?.attributes ?? {}),\n },\n ...editorProps,\n },\n ...editorOptions,\n onUpdate: (ctx) => {\n const json = ctx.editor.getJSON();\n onChange?.(json, ctx.editor);\n onUpdate?.(ctx);\n },\n },\n deps\n );\n\n useEffect(() => {\n if (editor && !editor.isDestroyed) {\n onEditorReady?.(editor);\n }\n }, [editor, onEditorReady]);\n\n return { editor, presets };\n};\n","export { SlideEditor as ReactSlideEditor } from \"./SlideEditor.js\";\nexport * from \"./useSlideEditor.js\";\nexport * from \"./menus/BubbleMenuPreset.js\";\n\n// Re-export everything from @blockslides/react core\nexport * from \"@blockslides/react\";\n\n// Note: @blockslides/core is already re-exported by @blockslides/react\n"],"mappings":"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","names":["useMemo","editor","useEffect","_a","jsx","useMemo"]}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/menus/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
BubbleMenu: () => BubbleMenu,
|
|
34
|
+
BubbleMenuPreset: () => BubbleMenuPreset,
|
|
35
|
+
FloatingMenu: () => FloatingMenu
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
|
+
|
|
39
|
+
// src/menus/BubbleMenu.tsx
|
|
40
|
+
var import_extension_bubble_menu = require("@blockslides/extension-bubble-menu");
|
|
41
|
+
var import_react = require("@blockslides/react");
|
|
42
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
43
|
+
var import_react_dom = require("react-dom");
|
|
44
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
45
|
+
var BubbleMenu = import_react2.default.forwardRef(
|
|
46
|
+
({
|
|
47
|
+
pluginKey = "bubbleMenu",
|
|
48
|
+
editor,
|
|
49
|
+
updateDelay,
|
|
50
|
+
resizeDelay,
|
|
51
|
+
appendTo,
|
|
52
|
+
shouldShow = null,
|
|
53
|
+
getReferencedVirtualElement,
|
|
54
|
+
options,
|
|
55
|
+
children,
|
|
56
|
+
...restProps
|
|
57
|
+
}, ref) => {
|
|
58
|
+
const menuEl = (0, import_react2.useRef)(document.createElement("div"));
|
|
59
|
+
if (typeof ref === "function") {
|
|
60
|
+
ref(menuEl.current);
|
|
61
|
+
} else if (ref) {
|
|
62
|
+
ref.current = menuEl.current;
|
|
63
|
+
}
|
|
64
|
+
const { editor: currentEditor } = (0, import_react.useCurrentEditor)();
|
|
65
|
+
(0, import_react2.useEffect)(() => {
|
|
66
|
+
const bubbleMenuElement = menuEl.current;
|
|
67
|
+
bubbleMenuElement.style.visibility = "hidden";
|
|
68
|
+
bubbleMenuElement.style.position = "absolute";
|
|
69
|
+
if ((editor == null ? void 0 : editor.isDestroyed) || (currentEditor == null ? void 0 : currentEditor.isDestroyed)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const attachToEditor = editor || currentEditor;
|
|
73
|
+
if (!attachToEditor) {
|
|
74
|
+
console.warn("BubbleMenu component is not rendered inside of an editor component or does not have editor prop.");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const plugin = (0, import_extension_bubble_menu.BubbleMenuPlugin)({
|
|
78
|
+
updateDelay,
|
|
79
|
+
resizeDelay,
|
|
80
|
+
editor: attachToEditor,
|
|
81
|
+
element: bubbleMenuElement,
|
|
82
|
+
appendTo,
|
|
83
|
+
pluginKey,
|
|
84
|
+
shouldShow,
|
|
85
|
+
getReferencedVirtualElement,
|
|
86
|
+
options
|
|
87
|
+
});
|
|
88
|
+
attachToEditor.registerPlugin(plugin);
|
|
89
|
+
return () => {
|
|
90
|
+
attachToEditor.unregisterPlugin(pluginKey);
|
|
91
|
+
window.requestAnimationFrame(() => {
|
|
92
|
+
if (bubbleMenuElement.parentNode) {
|
|
93
|
+
bubbleMenuElement.parentNode.removeChild(bubbleMenuElement);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
}, [
|
|
98
|
+
editor,
|
|
99
|
+
currentEditor,
|
|
100
|
+
pluginKey,
|
|
101
|
+
updateDelay,
|
|
102
|
+
resizeDelay,
|
|
103
|
+
appendTo,
|
|
104
|
+
shouldShow,
|
|
105
|
+
getReferencedVirtualElement,
|
|
106
|
+
options
|
|
107
|
+
]);
|
|
108
|
+
return (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...restProps, children }), menuEl.current);
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// src/menus/FloatingMenu.tsx
|
|
113
|
+
var import_extension_floating_menu = require("@blockslides/extension-floating-menu");
|
|
114
|
+
var import_react3 = require("@blockslides/react");
|
|
115
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
116
|
+
var import_react_dom2 = require("react-dom");
|
|
117
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
118
|
+
var FloatingMenu = import_react4.default.forwardRef(
|
|
119
|
+
({ pluginKey = "floatingMenu", editor, appendTo, shouldShow = null, options, children, ...restProps }, ref) => {
|
|
120
|
+
const menuEl = (0, import_react4.useRef)(document.createElement("div"));
|
|
121
|
+
if (typeof ref === "function") {
|
|
122
|
+
ref(menuEl.current);
|
|
123
|
+
} else if (ref) {
|
|
124
|
+
ref.current = menuEl.current;
|
|
125
|
+
}
|
|
126
|
+
const { editor: currentEditor } = (0, import_react3.useCurrentEditor)();
|
|
127
|
+
(0, import_react4.useEffect)(() => {
|
|
128
|
+
const floatingMenuElement = menuEl.current;
|
|
129
|
+
floatingMenuElement.style.visibility = "hidden";
|
|
130
|
+
floatingMenuElement.style.position = "absolute";
|
|
131
|
+
if ((editor == null ? void 0 : editor.isDestroyed) || (currentEditor == null ? void 0 : currentEditor.isDestroyed)) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const attachToEditor = editor || currentEditor;
|
|
135
|
+
if (!attachToEditor) {
|
|
136
|
+
console.warn(
|
|
137
|
+
"FloatingMenu component is not rendered inside of an editor component or does not have editor prop."
|
|
138
|
+
);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const plugin = (0, import_extension_floating_menu.FloatingMenuPlugin)({
|
|
142
|
+
editor: attachToEditor,
|
|
143
|
+
element: floatingMenuElement,
|
|
144
|
+
pluginKey,
|
|
145
|
+
appendTo,
|
|
146
|
+
shouldShow,
|
|
147
|
+
options
|
|
148
|
+
});
|
|
149
|
+
attachToEditor.registerPlugin(plugin);
|
|
150
|
+
return () => {
|
|
151
|
+
attachToEditor.unregisterPlugin(pluginKey);
|
|
152
|
+
window.requestAnimationFrame(() => {
|
|
153
|
+
if (floatingMenuElement.parentNode) {
|
|
154
|
+
floatingMenuElement.parentNode.removeChild(floatingMenuElement);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
}, [editor, currentEditor, appendTo, pluginKey, shouldShow, options]);
|
|
159
|
+
return (0, import_react_dom2.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ...restProps, children }), menuEl.current);
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// src/menus/BubbleMenuPreset.tsx
|
|
164
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
165
|
+
var import_react_dom3 = require("react-dom");
|
|
166
|
+
var import_react6 = require("@blockslides/react");
|
|
167
|
+
var import_extension_bubble_menu2 = require("@blockslides/extension-bubble-menu");
|
|
168
|
+
var import_state = require("@blockslides/pm/state");
|
|
169
|
+
var import_extension_bubble_menu_preset = require("@blockslides/extension-bubble-menu-preset");
|
|
170
|
+
var import_core = require("@blockslides/core");
|
|
171
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
172
|
+
var BubbleMenuPreset = import_react5.default.forwardRef(
|
|
173
|
+
({
|
|
174
|
+
editor,
|
|
175
|
+
updateDelay,
|
|
176
|
+
resizeDelay,
|
|
177
|
+
appendTo,
|
|
178
|
+
shouldShow,
|
|
179
|
+
getReferencedVirtualElement,
|
|
180
|
+
options,
|
|
181
|
+
items,
|
|
182
|
+
className,
|
|
183
|
+
injectStyles,
|
|
184
|
+
textColors,
|
|
185
|
+
highlightColors,
|
|
186
|
+
fonts,
|
|
187
|
+
fontSizes,
|
|
188
|
+
alignments,
|
|
189
|
+
onTextAction,
|
|
190
|
+
onImageReplace,
|
|
191
|
+
...rest
|
|
192
|
+
}, ref) => {
|
|
193
|
+
const pluginKey = "bubbleMenuPreset";
|
|
194
|
+
const { editor: currentEditor } = (0, import_react6.useCurrentEditor)();
|
|
195
|
+
const menuEl = (0, import_react5.useRef)(null);
|
|
196
|
+
(0, import_react5.useEffect)(() => {
|
|
197
|
+
const attachToEditor = editor || currentEditor;
|
|
198
|
+
if (!attachToEditor || attachToEditor.isDestroyed) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const { element, cleanup } = (0, import_extension_bubble_menu_preset.buildMenuElement)(attachToEditor, {
|
|
202
|
+
items: items != null ? items : import_extension_bubble_menu_preset.DEFAULT_ITEMS,
|
|
203
|
+
className: className != null ? className : "",
|
|
204
|
+
injectStyles: injectStyles !== false,
|
|
205
|
+
textColors: textColors != null ? textColors : import_extension_bubble_menu_preset.DEFAULT_COLOR_PALETTE,
|
|
206
|
+
highlightColors: highlightColors != null ? highlightColors : import_extension_bubble_menu_preset.DEFAULT_HIGHLIGHT_PALETTE,
|
|
207
|
+
fonts: fonts != null ? fonts : import_extension_bubble_menu_preset.DEFAULT_FONTS,
|
|
208
|
+
fontSizes: fontSizes != null ? fontSizes : import_extension_bubble_menu_preset.DEFAULT_FONT_SIZES,
|
|
209
|
+
alignments: alignments != null ? alignments : import_extension_bubble_menu_preset.DEFAULT_ALIGNMENTS,
|
|
210
|
+
onTextAction,
|
|
211
|
+
onImageReplace
|
|
212
|
+
});
|
|
213
|
+
menuEl.current = element;
|
|
214
|
+
if (typeof ref === "function") {
|
|
215
|
+
ref(element);
|
|
216
|
+
} else if (ref) {
|
|
217
|
+
;
|
|
218
|
+
ref.current = element;
|
|
219
|
+
}
|
|
220
|
+
const defaultShouldShow = ({
|
|
221
|
+
state,
|
|
222
|
+
editor: editor2
|
|
223
|
+
}) => {
|
|
224
|
+
var _a, _b;
|
|
225
|
+
const sel = state.selection;
|
|
226
|
+
const imageSelection = sel instanceof import_state.NodeSelection && ["image", "imageBlock"].includes((_b = (_a = sel.node) == null ? void 0 : _a.type) == null ? void 0 : _b.name) || editor2.isActive("image") || editor2.isActive("imageBlock");
|
|
227
|
+
if (imageSelection) return true;
|
|
228
|
+
if ((0, import_core.isTextSelection)(sel) && !sel.empty && !imageSelection) return true;
|
|
229
|
+
return false;
|
|
230
|
+
};
|
|
231
|
+
const plugin = (0, import_extension_bubble_menu2.BubbleMenuPlugin)({
|
|
232
|
+
editor: attachToEditor,
|
|
233
|
+
element,
|
|
234
|
+
updateDelay,
|
|
235
|
+
resizeDelay,
|
|
236
|
+
appendTo,
|
|
237
|
+
pluginKey,
|
|
238
|
+
shouldShow: shouldShow != null ? shouldShow : defaultShouldShow,
|
|
239
|
+
getReferencedVirtualElement,
|
|
240
|
+
options
|
|
241
|
+
});
|
|
242
|
+
attachToEditor.registerPlugin(plugin);
|
|
243
|
+
return () => {
|
|
244
|
+
attachToEditor.unregisterPlugin(pluginKey);
|
|
245
|
+
cleanup == null ? void 0 : cleanup();
|
|
246
|
+
if (element.parentNode) {
|
|
247
|
+
element.parentNode.removeChild(element);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}, [
|
|
251
|
+
editor,
|
|
252
|
+
currentEditor,
|
|
253
|
+
updateDelay,
|
|
254
|
+
resizeDelay,
|
|
255
|
+
appendTo,
|
|
256
|
+
shouldShow,
|
|
257
|
+
getReferencedVirtualElement,
|
|
258
|
+
options,
|
|
259
|
+
items,
|
|
260
|
+
className,
|
|
261
|
+
injectStyles,
|
|
262
|
+
textColors,
|
|
263
|
+
highlightColors,
|
|
264
|
+
fonts,
|
|
265
|
+
fontSizes,
|
|
266
|
+
alignments,
|
|
267
|
+
onTextAction,
|
|
268
|
+
onImageReplace,
|
|
269
|
+
ref
|
|
270
|
+
]);
|
|
271
|
+
return menuEl.current ? (0, import_react_dom3.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ...rest }), menuEl.current) : null;
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
BubbleMenuPreset.displayName = "BubbleMenuPreset";
|
|
275
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
276
|
+
0 && (module.exports = {
|
|
277
|
+
BubbleMenu,
|
|
278
|
+
BubbleMenuPreset,
|
|
279
|
+
FloatingMenu
|
|
280
|
+
});
|
|
281
|
+
//# sourceMappingURL=index.cjs.map
|