@blockslides/vue-3 0.3.0 → 0.4.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blockslides/vue-3",
3
3
  "description": "Vue 3 components for blockslides",
4
- "version": "0.3.0",
4
+ "version": "0.4.1",
5
5
  "homepage": "https://github.com/keivanmojmali/blockslides",
6
6
  "keywords": [
7
7
  "blockslides",
@@ -18,14 +18,6 @@
18
18
  },
19
19
  "import": "./dist/index.js",
20
20
  "require": "./dist/index.cjs"
21
- },
22
- "./menus": {
23
- "types": {
24
- "import": "./dist/menus/index.d.ts",
25
- "require": "./dist/menus/index.d.cts"
26
- },
27
- "import": "./dist/menus/index.js",
28
- "require": "./dist/menus/index.cjs"
29
21
  }
30
22
  },
31
23
  "main": "dist/index.cjs",
@@ -38,7 +30,7 @@
38
30
  ],
39
31
  "dependencies": {
40
32
  "@blockslides/ai-context": "^0.3.1",
41
- "@blockslides/extension-kit": "^0.7.2"
33
+ "@blockslides/extension-kit": "^0.7.3"
42
34
  },
43
35
  "devDependencies": {
44
36
  "@floating-ui/dom": "^1.0.0",
@@ -49,10 +41,6 @@
49
41
  "@blockslides/core": "^0.3.3",
50
42
  "@blockslides/pm": "^0.1.1"
51
43
  },
52
- "optionalDependencies": {
53
- "@blockslides/extension-bubble-menu": "^0.1.1",
54
- "@blockslides/extension-floating-menu": "^0.1.1"
55
- },
56
44
  "peerDependencies": {
57
45
  "@floating-ui/dom": "^1.0.0",
58
46
  "vue": "^3.0.0",
package/src/index.ts CHANGED
@@ -3,10 +3,7 @@ export * from './EditorContent.js'
3
3
  export * from './NodeViewContent.js'
4
4
  export * from './NodeViewWrapper.js'
5
5
  export * from './useEditor.js'
6
- export * from './useSlideEditor.js'
7
- export { default as SlideEditor } from './SlideEditor.vue'
8
6
  export * from './VueMarkViewRenderer.js'
9
7
  export * from './VueNodeViewRenderer.js'
10
8
  export * from './VueRenderer.js'
11
- export * from '@blockslides/core'
12
- export * from './menus/index.js'
9
+ export * from '@blockslides/core'
@@ -1,226 +0,0 @@
1
- import { defineComponent as m, ref as f, onMounted as g, watch as D, onBeforeUnmount as y, openBlock as _, createElementBlock as A, createCommentVNode as F, nextTick as M, h as v } from "vue";
2
- import { BubbleMenuPlugin as E } from "@blockslides/extension-bubble-menu";
3
- import { NodeSelection as N } from "@blockslides/pm/state";
4
- import { buildMenuElement as C, DEFAULT_ALIGNMENTS as x, DEFAULT_FONT_SIZES as B, DEFAULT_FONTS as P, DEFAULT_HIGHLIGHT_PALETTE as j, DEFAULT_COLOR_PALETTE as L, DEFAULT_ITEMS as O } from "@blockslides/extension-bubble-menu-preset";
5
- import { isTextSelection as R } from "@blockslides/core";
6
- import { FloatingMenuPlugin as w } from "@blockslides/extension-floating-menu";
7
- const z = {
8
- key: 0,
9
- style: { display: "none" }
10
- }, S = "bubbleMenuPreset", H = /* @__PURE__ */ m({
11
- __name: "BubbleMenuPreset",
12
- props: {
13
- editor: {},
14
- updateDelay: {},
15
- resizeDelay: {},
16
- appendTo: {},
17
- shouldShow: {},
18
- getReferencedVirtualElement: {},
19
- options: {},
20
- items: {},
21
- className: {},
22
- injectStyles: { type: Boolean, default: !0 },
23
- textColors: {},
24
- highlightColors: {},
25
- fonts: {},
26
- fontSizes: {},
27
- alignments: {},
28
- onTextAction: {},
29
- onImageReplace: {}
30
- },
31
- setup(r) {
32
- const e = r, l = f(null);
33
- let o;
34
- const n = () => {
35
- const t = e.editor;
36
- if (!t || t.isDestroyed)
37
- return;
38
- o && (o(), o = void 0);
39
- const { element: a, cleanup: s } = C(t, {
40
- items: e.items ?? O,
41
- className: e.className ?? "",
42
- injectStyles: e.injectStyles !== !1,
43
- textColors: e.textColors ?? L,
44
- highlightColors: e.highlightColors ?? j,
45
- fonts: e.fonts ?? P,
46
- fontSizes: e.fontSizes ?? B,
47
- alignments: e.alignments ?? x,
48
- onTextAction: e.onTextAction,
49
- onImageReplace: e.onImageReplace
50
- });
51
- l.value = a, o = s;
52
- const d = ({ state: c, editor: p }) => {
53
- var b, T;
54
- const i = c.selection, h = i instanceof N && ["image", "imageBlock"].includes((T = (b = i.node) == null ? void 0 : b.type) == null ? void 0 : T.name) || p.isActive("image") || p.isActive("imageBlock");
55
- return !!(h || R(i) && !i.empty && !h);
56
- }, u = E({
57
- editor: t,
58
- element: a,
59
- updateDelay: e.updateDelay,
60
- resizeDelay: e.resizeDelay,
61
- appendTo: e.appendTo,
62
- pluginKey: S,
63
- shouldShow: e.shouldShow ?? d,
64
- getReferencedVirtualElement: e.getReferencedVirtualElement,
65
- options: e.options
66
- });
67
- t.registerPlugin(u);
68
- };
69
- return g(() => {
70
- n();
71
- }), D(
72
- () => [
73
- e.editor,
74
- e.updateDelay,
75
- e.resizeDelay,
76
- e.appendTo,
77
- e.shouldShow,
78
- e.getReferencedVirtualElement,
79
- e.options,
80
- e.items,
81
- e.className,
82
- e.injectStyles,
83
- e.textColors,
84
- e.highlightColors,
85
- e.fonts,
86
- e.fontSizes,
87
- e.alignments,
88
- e.onTextAction,
89
- e.onImageReplace
90
- ],
91
- () => {
92
- n();
93
- }
94
- ), y(() => {
95
- var t;
96
- e.editor && e.editor.unregisterPlugin(S), o && o(), (t = l.value) != null && t.parentNode && l.value.parentNode.removeChild(l.value);
97
- }), (t, a) => l.value ? (_(), A("div", z)) : F("", !0);
98
- }
99
- }), q = m({
100
- name: "BubbleMenu",
101
- inheritAttrs: !1,
102
- props: {
103
- pluginKey: {
104
- type: [String, Object],
105
- default: "bubbleMenu"
106
- },
107
- editor: {
108
- type: Object,
109
- required: !0
110
- },
111
- updateDelay: {
112
- type: Number,
113
- default: void 0
114
- },
115
- resizeDelay: {
116
- type: Number,
117
- default: void 0
118
- },
119
- options: {
120
- type: Object,
121
- default: () => ({})
122
- },
123
- appendTo: {
124
- type: [Object, Function],
125
- default: void 0
126
- },
127
- shouldShow: {
128
- type: Function,
129
- default: null
130
- },
131
- getReferencedVirtualElement: {
132
- type: Function,
133
- default: void 0
134
- }
135
- },
136
- setup(r, { slots: e, attrs: l }) {
137
- const o = f(null);
138
- return g(() => {
139
- const {
140
- editor: n,
141
- options: t,
142
- pluginKey: a,
143
- resizeDelay: s,
144
- appendTo: d,
145
- shouldShow: u,
146
- getReferencedVirtualElement: c,
147
- updateDelay: p
148
- } = r, i = o.value;
149
- i && (i.style.visibility = "hidden", i.style.position = "absolute", i.remove(), M(() => {
150
- n.registerPlugin(
151
- E({
152
- editor: n,
153
- element: i,
154
- options: t,
155
- pluginKey: a,
156
- resizeDelay: s,
157
- appendTo: d,
158
- shouldShow: u,
159
- getReferencedVirtualElement: c,
160
- updateDelay: p
161
- })
162
- );
163
- }));
164
- }), y(() => {
165
- const { pluginKey: n, editor: t } = r;
166
- t.unregisterPlugin(n);
167
- }), () => {
168
- var n;
169
- return v("div", { ref: o, ...l }, (n = e.default) == null ? void 0 : n.call(e));
170
- };
171
- }
172
- }), Z = m({
173
- name: "FloatingMenu",
174
- inheritAttrs: !1,
175
- props: {
176
- pluginKey: {
177
- // TODO: TypeScript breaks
178
- // type: [String, Object as PropType<Exclude<FloatingMenuPluginProps['pluginKey'], string>>],
179
- type: null,
180
- default: "floatingMenu"
181
- },
182
- editor: {
183
- type: Object,
184
- required: !0
185
- },
186
- options: {
187
- type: Object,
188
- default: () => ({})
189
- },
190
- appendTo: {
191
- type: [Object, Function],
192
- default: void 0
193
- },
194
- shouldShow: {
195
- type: Function,
196
- default: null
197
- }
198
- },
199
- setup(r, { slots: e, attrs: l }) {
200
- const o = f(null);
201
- return g(() => {
202
- const { pluginKey: n, editor: t, options: a, appendTo: s, shouldShow: d } = r, u = o.value;
203
- u && (u.style.visibility = "hidden", u.style.position = "absolute", u.remove(), t.registerPlugin(
204
- w({
205
- pluginKey: n,
206
- editor: t,
207
- element: u,
208
- options: a,
209
- appendTo: s,
210
- shouldShow: d
211
- })
212
- ));
213
- }), y(() => {
214
- const { pluginKey: n, editor: t } = r;
215
- t.unregisterPlugin(n);
216
- }), () => {
217
- var n;
218
- return v("div", { ref: o, ...l }, (n = e.default) == null ? void 0 : n.call(e));
219
- };
220
- }
221
- });
222
- export {
223
- q as B,
224
- Z as F,
225
- H as _
226
- };
@@ -1 +0,0 @@
1
- "use strict";const t=require("vue"),T=require("@blockslides/extension-bubble-menu"),S=require("@blockslides/pm/state"),c=require("@blockslides/extension-bubble-menu-preset"),v=require("@blockslides/core"),E=require("@blockslides/extension-floating-menu"),M={key:0,style:{display:"none"}},b="bubbleMenuPreset",D=t.defineComponent({__name:"BubbleMenuPreset",props:{editor:{},updateDelay:{},resizeDelay:{},appendTo:{},shouldShow:{},getReferencedVirtualElement:{},options:{},items:{},className:{},injectStyles:{type:Boolean,default:!0},textColors:{},highlightColors:{},fonts:{},fontSizes:{},alignments:{},onTextAction:{},onImageReplace:{}},setup(s){const e=s,u=t.ref(null);let i;const o=()=>{const n=e.editor;if(!n||n.isDestroyed)return;i&&(i(),i=void 0);const{element:a,cleanup:d}=c.buildMenuElement(n,{items:e.items??c.DEFAULT_ITEMS,className:e.className??"",injectStyles:e.injectStyles!==!1,textColors:e.textColors??c.DEFAULT_COLOR_PALETTE,highlightColors:e.highlightColors??c.DEFAULT_HIGHLIGHT_PALETTE,fonts:e.fonts??c.DEFAULT_FONTS,fontSizes:e.fontSizes??c.DEFAULT_FONT_SIZES,alignments:e.alignments??c.DEFAULT_ALIGNMENTS,onTextAction:e.onTextAction,onImageReplace:e.onImageReplace});u.value=a,i=d;const p=({state:g,editor:f})=>{var y,h;const l=g.selection,m=l instanceof S.NodeSelection&&["image","imageBlock"].includes((h=(y=l.node)==null?void 0:y.type)==null?void 0:h.name)||f.isActive("image")||f.isActive("imageBlock");return!!(m||v.isTextSelection(l)&&!l.empty&&!m)},r=T.BubbleMenuPlugin({editor:n,element:a,updateDelay:e.updateDelay,resizeDelay:e.resizeDelay,appendTo:e.appendTo,pluginKey:b,shouldShow:e.shouldShow??p,getReferencedVirtualElement:e.getReferencedVirtualElement,options:e.options});n.registerPlugin(r)};return t.onMounted(()=>{o()}),t.watch(()=>[e.editor,e.updateDelay,e.resizeDelay,e.appendTo,e.shouldShow,e.getReferencedVirtualElement,e.options,e.items,e.className,e.injectStyles,e.textColors,e.highlightColors,e.fonts,e.fontSizes,e.alignments,e.onTextAction,e.onImageReplace],()=>{o()}),t.onBeforeUnmount(()=>{var n;e.editor&&e.editor.unregisterPlugin(b),i&&i(),(n=u.value)!=null&&n.parentNode&&u.value.parentNode.removeChild(u.value)}),(n,a)=>u.value?(t.openBlock(),t.createElementBlock("div",M)):t.createCommentVNode("",!0)}}),_=t.defineComponent({name:"BubbleMenu",inheritAttrs:!1,props:{pluginKey:{type:[String,Object],default:"bubbleMenu"},editor:{type:Object,required:!0},updateDelay:{type:Number,default:void 0},resizeDelay:{type:Number,default:void 0},options:{type:Object,default:()=>({})},appendTo:{type:[Object,Function],default:void 0},shouldShow:{type:Function,default:null},getReferencedVirtualElement:{type:Function,default:void 0}},setup(s,{slots:e,attrs:u}){const i=t.ref(null);return t.onMounted(()=>{const{editor:o,options:n,pluginKey:a,resizeDelay:d,appendTo:p,shouldShow:r,getReferencedVirtualElement:g,updateDelay:f}=s,l=i.value;l&&(l.style.visibility="hidden",l.style.position="absolute",l.remove(),t.nextTick(()=>{o.registerPlugin(T.BubbleMenuPlugin({editor:o,element:l,options:n,pluginKey:a,resizeDelay:d,appendTo:p,shouldShow:r,getReferencedVirtualElement:g,updateDelay:f}))}))}),t.onBeforeUnmount(()=>{const{pluginKey:o,editor:n}=s;n.unregisterPlugin(o)}),()=>{var o;return t.h("div",{ref:i,...u},(o=e.default)==null?void 0:o.call(e))}}}),F=t.defineComponent({name:"FloatingMenu",inheritAttrs:!1,props:{pluginKey:{type:null,default:"floatingMenu"},editor:{type:Object,required:!0},options:{type:Object,default:()=>({})},appendTo:{type:[Object,Function],default:void 0},shouldShow:{type:Function,default:null}},setup(s,{slots:e,attrs:u}){const i=t.ref(null);return t.onMounted(()=>{const{pluginKey:o,editor:n,options:a,appendTo:d,shouldShow:p}=s,r=i.value;r&&(r.style.visibility="hidden",r.style.position="absolute",r.remove(),n.registerPlugin(E.FloatingMenuPlugin({pluginKey:o,editor:n,element:r,options:a,appendTo:d,shouldShow:p})))}),t.onBeforeUnmount(()=>{const{pluginKey:o,editor:n}=s;n.unregisterPlugin(o)}),()=>{var o;return t.h("div",{ref:i,...u},(o=e.default)==null?void 0:o.call(e))}}});exports.BubbleMenu=_;exports.FloatingMenu=F;exports._sfc_main=D;
@@ -1,6 +0,0 @@
1
- import { BubbleMenuPluginProps } from '../../../extension-bubble-menu/src';
2
-
3
- type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
4
- export type BubbleMenuProps = Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>;
5
- export declare const BubbleMenu: any;
6
- export {};
@@ -1,6 +0,0 @@
1
- import { FloatingMenuPluginProps } from '../../../extension-floating-menu/src';
2
-
3
- type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
4
- export type FloatingMenuProps = Omit<Optional<FloatingMenuPluginProps, 'pluginKey'>, 'element'>;
5
- export declare const FloatingMenu: any;
6
- export {};
@@ -1,3 +0,0 @@
1
- export * from './BubbleMenu.js';
2
- export * from './FloatingMenu.js';
3
- export { default as BubbleMenuPreset } from './BubbleMenuPreset.vue';
package/dist/menus.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./FloatingMenu-Un--4r7A.cjs");exports.BubbleMenu=e.BubbleMenu;exports.BubbleMenuPreset=e._sfc_main;exports.FloatingMenu=e.FloatingMenu;
package/dist/menus.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from './menus/index'
package/dist/menus.js DELETED
@@ -1,6 +0,0 @@
1
- import { B as a, _ as b, F as n } from "./FloatingMenu-AygIYJQV.js";
2
- export {
3
- a as BubbleMenu,
4
- b as BubbleMenuPreset,
5
- n as FloatingMenu
6
- };
@@ -1,53 +0,0 @@
1
- import { templatesV1 } from '../../ai-context/src';
2
- import { AnyExtension, Editor, JSONContent, EditorOptions } from '../../core/src';
3
- import { ExtensionKitOptions } from '../../extension-kit/src';
4
-
5
- type PresetTemplates = ReturnType<typeof templatesV1.listPresetTemplates>;
6
- export interface UseSlideEditorProps {
7
- /**
8
- * Initial content for the editor. If omitted, a single preset slide is used.
9
- */
10
- content?: EditorOptions['content'];
11
- /**
12
- * Called on every update with the current JSON document.
13
- */
14
- onChange?: (doc: JSONContent, editor: Editor) => void;
15
- /**
16
- * Additional extensions to append after the ExtensionKit bundle.
17
- */
18
- extensions?: AnyExtension[];
19
- /**
20
- * Customize or disable pieces of ExtensionKit (e.g., bubbleMenu: false).
21
- */
22
- extensionKitOptions?: ExtensionKitOptions;
23
- /**
24
- * Optional preset list to power the add-slide button.
25
- */
26
- presetTemplates?: PresetTemplates;
27
- /**
28
- * Called once when an editor instance is ready.
29
- */
30
- onEditorReady?: (editor: Editor) => void;
31
- /**
32
- * Editor theme for UI styling
33
- */
34
- theme?: EditorOptions['theme'];
35
- /**
36
- * The editor's props
37
- */
38
- editorProps?: EditorOptions['editorProps'];
39
- /**
40
- * Called on every update
41
- */
42
- onUpdate?: EditorOptions['onUpdate'];
43
- /**
44
- * Additional editor options to pass through to the core editor.
45
- * This allows passing any EditorOptions without Vue auto-initializing them.
46
- */
47
- editorOptions?: Partial<EditorOptions>;
48
- }
49
- export declare const useSlideEditor: (props?: UseSlideEditorProps) => {
50
- editor: import('vue').ShallowRef<import('./Editor.js').Editor | undefined, import('./Editor.js').Editor | undefined>;
51
- presets: import('vue').ComputedRef<templatesV1.PresetTemplate[]>;
52
- };
53
- export {};
@@ -1,54 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, watch, onMounted } from 'vue'
3
- import { EditorContent } from './EditorContent'
4
- import BubbleMenuPreset from './menus/BubbleMenuPreset.vue'
5
- import { useSlideEditor, type UseSlideEditorProps } from './useSlideEditor'
6
- import type { Editor } from '@blockslides/core'
7
-
8
- export interface BubbleMenuPresetProps {
9
- editor: Editor
10
- [key: string]: any
11
- }
12
-
13
- export interface SlideEditorProps extends UseSlideEditorProps {
14
- /**
15
- * Toggle or customize the built-in BubbleMenuPreset.
16
- * - true (default): render with defaults
17
- * - false: disable entirely
18
- * - object: pass through to BubbleMenuPreset
19
- */
20
- bubbleMenuPreset?: boolean | BubbleMenuPresetProps
21
- className?: string
22
- style?: any
23
- }
24
-
25
- const props = withDefaults(defineProps<SlideEditorProps>(), {
26
- bubbleMenuPreset: true,
27
- })
28
-
29
- const {
30
- bubbleMenuPreset,
31
- className,
32
- style,
33
- ...hookProps
34
- } = props
35
-
36
- const { editor } = useSlideEditor(hookProps)
37
-
38
- const bubbleMenuProps = computed(() => {
39
- if (props.bubbleMenuPreset === false) return null
40
- if (props.bubbleMenuPreset === true) return {}
41
- return props.bubbleMenuPreset
42
- })
43
-
44
- </script>
45
-
46
- <template>
47
- <div v-if="editor" :class="className" :style="style">
48
- <div class="bs-viewport">
49
- <EditorContent :editor="editor" />
50
- <BubbleMenuPreset v-if="bubbleMenuProps" :editor="editor" v-bind="bubbleMenuProps" />
51
- </div>
52
- </div>
53
- </template>
54
-
@@ -1,111 +0,0 @@
1
- import type { BubbleMenuPluginProps } from '@blockslides/extension-bubble-menu'
2
- import { BubbleMenuPlugin } from '@blockslides/extension-bubble-menu'
3
- import type { PropType } from 'vue'
4
- import { defineComponent, h, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
5
-
6
- type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>
7
-
8
- export type BubbleMenuProps = Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>
9
-
10
- export const BubbleMenu = defineComponent({
11
- name: 'BubbleMenu',
12
-
13
- inheritAttrs: false,
14
-
15
- props: {
16
- pluginKey: {
17
- type: [String, Object] as PropType<BubbleMenuPluginProps['pluginKey']>,
18
- default: 'bubbleMenu',
19
- },
20
-
21
- editor: {
22
- type: Object as PropType<BubbleMenuPluginProps['editor']>,
23
- required: true,
24
- },
25
-
26
- updateDelay: {
27
- type: Number as PropType<BubbleMenuPluginProps['updateDelay']>,
28
- default: undefined,
29
- },
30
-
31
- resizeDelay: {
32
- type: Number as PropType<BubbleMenuPluginProps['resizeDelay']>,
33
- default: undefined,
34
- },
35
-
36
- options: {
37
- type: Object as PropType<BubbleMenuPluginProps['options']>,
38
- default: () => ({}),
39
- },
40
-
41
- appendTo: {
42
- type: [Object, Function] as PropType<BubbleMenuPluginProps['appendTo']>,
43
- default: undefined,
44
- },
45
-
46
- shouldShow: {
47
- type: Function as PropType<Exclude<Required<BubbleMenuPluginProps>['shouldShow'], null>>,
48
- default: null,
49
- },
50
-
51
- getReferencedVirtualElement: {
52
- type: Function as PropType<Exclude<Required<BubbleMenuPluginProps>['getReferencedVirtualElement'], null>>,
53
- default: undefined,
54
- },
55
- },
56
-
57
- setup(props, { slots, attrs }) {
58
- const root = ref<HTMLElement | null>(null)
59
-
60
- onMounted(() => {
61
- const {
62
- editor,
63
- options,
64
- pluginKey,
65
- resizeDelay,
66
- appendTo,
67
- shouldShow,
68
- getReferencedVirtualElement,
69
- updateDelay,
70
- } = props
71
-
72
- const el = root.value
73
-
74
- if (!el) {
75
- return
76
- }
77
-
78
- el.style.visibility = 'hidden'
79
- el.style.position = 'absolute'
80
-
81
- // Remove element from DOM; plugin will re-parent it when shown
82
- el.remove()
83
-
84
- nextTick(() => {
85
- editor.registerPlugin(
86
- BubbleMenuPlugin({
87
- editor,
88
- element: el,
89
- options,
90
- pluginKey,
91
- resizeDelay,
92
- appendTo,
93
- shouldShow,
94
- getReferencedVirtualElement,
95
- updateDelay,
96
- }),
97
- )
98
- })
99
- })
100
-
101
- onBeforeUnmount(() => {
102
- const { pluginKey, editor } = props
103
-
104
- editor.unregisterPlugin(pluginKey)
105
- })
106
-
107
- // Vue owns this element; attrs are applied reactively by Vue
108
- // Plugin re-parents it when showing the menu
109
- return () => h('div', { ref: root, ...attrs }, slots.default?.())
110
- },
111
- }) as any
@@ -1,137 +0,0 @@
1
- <script setup lang="ts">
2
- import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
3
- import { BubbleMenuPlugin, type BubbleMenuPluginProps } from '@blockslides/extension-bubble-menu'
4
- import { NodeSelection } from '@blockslides/pm/state'
5
- import {
6
- type BubbleMenuPresetOptions,
7
- buildMenuElement,
8
- DEFAULT_ITEMS,
9
- DEFAULT_COLOR_PALETTE,
10
- DEFAULT_HIGHLIGHT_PALETTE,
11
- DEFAULT_FONTS,
12
- DEFAULT_FONT_SIZES,
13
- DEFAULT_ALIGNMENTS,
14
- } from '@blockslides/extension-bubble-menu-preset'
15
- import { isTextSelection, type Editor } from '@blockslides/core'
16
-
17
- export interface BubbleMenuPresetProps extends Omit<BubbleMenuPresetOptions, 'element' | 'pluginKey'> {
18
- editor: Editor
19
- updateDelay?: number
20
- resizeDelay?: number
21
- appendTo?: HTMLElement | (() => HTMLElement)
22
- shouldShow?: BubbleMenuPluginProps['shouldShow']
23
- getReferencedVirtualElement?: () => any
24
- options?: any
25
- }
26
-
27
- const props = withDefaults(defineProps<BubbleMenuPresetProps>(), {
28
- injectStyles: true,
29
- })
30
-
31
- const pluginKey = 'bubbleMenuPreset'
32
- const menuEl = ref<HTMLElement | null>(null)
33
- let cleanup: (() => void) | undefined
34
-
35
- const setupBubbleMenu = () => {
36
- const attachToEditor = props.editor
37
-
38
- if (!attachToEditor || (attachToEditor as any).isDestroyed) {
39
- return
40
- }
41
-
42
- // Cleanup previous instance if any
43
- if (cleanup) {
44
- cleanup()
45
- cleanup = undefined
46
- }
47
-
48
- const { element, cleanup: elementCleanup } = buildMenuElement(attachToEditor, {
49
- items: props.items ?? DEFAULT_ITEMS,
50
- className: props.className ?? '',
51
- injectStyles: props.injectStyles !== false,
52
- textColors: props.textColors ?? DEFAULT_COLOR_PALETTE,
53
- highlightColors: props.highlightColors ?? DEFAULT_HIGHLIGHT_PALETTE,
54
- fonts: props.fonts ?? DEFAULT_FONTS,
55
- fontSizes: props.fontSizes ?? DEFAULT_FONT_SIZES,
56
- alignments: props.alignments ?? DEFAULT_ALIGNMENTS,
57
- onTextAction: props.onTextAction,
58
- onImageReplace: props.onImageReplace,
59
- })
60
-
61
- menuEl.value = element
62
- cleanup = elementCleanup
63
-
64
- const defaultShouldShow: Exclude<BubbleMenuPluginProps['shouldShow'], null> = ({ state, editor }) => {
65
- const sel = state.selection
66
- const imageSelection =
67
- (sel instanceof NodeSelection && ['image', 'imageBlock'].includes((sel as any).node?.type?.name)) ||
68
- editor.isActive('image') ||
69
- editor.isActive('imageBlock')
70
-
71
- if (imageSelection) return true
72
- if (isTextSelection(sel) && !sel.empty && !imageSelection) return true
73
- return false
74
- }
75
-
76
- const plugin = BubbleMenuPlugin({
77
- editor: attachToEditor,
78
- element,
79
- updateDelay: props.updateDelay,
80
- resizeDelay: props.resizeDelay,
81
- appendTo: props.appendTo,
82
- pluginKey,
83
- shouldShow: props.shouldShow ?? defaultShouldShow,
84
- getReferencedVirtualElement: props.getReferencedVirtualElement,
85
- options: props.options,
86
- })
87
-
88
- attachToEditor.registerPlugin(plugin)
89
- }
90
-
91
- onMounted(() => {
92
- setupBubbleMenu()
93
- })
94
-
95
- // Watch for prop changes and rebuild
96
- watch(
97
- () => [
98
- props.editor,
99
- props.updateDelay,
100
- props.resizeDelay,
101
- props.appendTo,
102
- props.shouldShow,
103
- props.getReferencedVirtualElement,
104
- props.options,
105
- props.items,
106
- props.className,
107
- props.injectStyles,
108
- props.textColors,
109
- props.highlightColors,
110
- props.fonts,
111
- props.fontSizes,
112
- props.alignments,
113
- props.onTextAction,
114
- props.onImageReplace,
115
- ],
116
- () => {
117
- setupBubbleMenu()
118
- }
119
- )
120
-
121
- onBeforeUnmount(() => {
122
- if (props.editor) {
123
- props.editor.unregisterPlugin(pluginKey)
124
- }
125
- if (cleanup) {
126
- cleanup()
127
- }
128
- if (menuEl.value?.parentNode) {
129
- menuEl.value.parentNode.removeChild(menuEl.value)
130
- }
131
- })
132
- </script>
133
-
134
- <template>
135
- <!-- Vue doesn't need portal here as buildMenuElement handles DOM placement -->
136
- <div v-if="menuEl" style="display: none"></div>
137
- </template>