@bloklabs/vue 1.3.0 → 1.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/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # @bloklabs/vue
2
+
3
+ The Vue 3 block editor bindings for [Blok](https://blokeditor.com) — a headless, Notion-like rich text editor whose content is JSON blocks, not HTML.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @bloklabs/vue @bloklabs/core
9
+ ```
10
+
11
+ `@bloklabs/core` and `vue` are peer dependencies.
12
+
13
+ ## Usage
14
+
15
+ `<BlokEditor>` is the all-in-one component: it mounts the editor, manages its lifecycle, and takes every editor config option as a prop.
16
+
17
+ ```vue
18
+ <script setup lang="ts">
19
+ import { BlokEditor } from '@bloklabs/vue';
20
+ import { Header, Paragraph, List } from '@bloklabs/core/tools';
21
+
22
+ const tools = {
23
+ paragraph: Paragraph,
24
+ header: { class: Header, placeholder: 'Enter a heading' },
25
+ list: List,
26
+ };
27
+ </script>
28
+
29
+ <template>
30
+ <BlokEditor :tools="tools" />
31
+ </template>
32
+ ```
33
+
34
+ ## Saving
35
+
36
+ The `save` emit fires with the latest content on every change, so you never have to call `save()` by hand.
37
+
38
+ ```vue
39
+ <script setup lang="ts">
40
+ import { ref } from 'vue';
41
+ import { BlokEditor } from '@bloklabs/vue';
42
+ import type { OutputData } from '@bloklabs/core';
43
+
44
+ const data = ref<OutputData>();
45
+ </script>
46
+
47
+ <template>
48
+ <BlokEditor @save="(d: OutputData) => (data = d)" />
49
+ <pre>{{ data?.blocks }}</pre>
50
+ </template>
51
+ ```
52
+
53
+ ## Also exported
54
+
55
+ - `useBlok(config, recreateKey?)` — the composable behind the component, returns a `Ref<Blok | null>`.
56
+ - `BlokContent` — the mount-point element, if you want to wire the composable yourself.
57
+ - `useBlocks(editor)` — a reactive snapshot of the block tree plus a manipulation API.
58
+ - `createVueBlock` — author block tools as Vue components.
59
+ - `provideBlok` / `useBlokDefaults` — share default editor config through provide/inject.
60
+
61
+ ## Docs
62
+
63
+ - [Quick start](https://blokeditor.com/docs/quick-start?framework=vue)
64
+ - [`BlokEditor` reference](https://blokeditor.com/docs/blok-editor?framework=vue)
65
+ - [`useBlocks` reference](https://blokeditor.com/docs/use-blocks?framework=vue)
66
+
67
+ Licensed under Apache-2.0.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("vue"),t=require("@bloklabs/core"),n=require("@bloklabs/core/adapters");var r=new WeakMap;function i(e,t){r.set(e,t)}function a(e){return r.get(e)}function o(e){r.delete(e)}function s(e){"@babel/helpers - typeof";return s=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},s(e)}function c(e,t){if(s(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(s(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function l(e){var t=c(e,`string`);return s(t)==`symbol`?t:t+``}function u(e,t,n){return(t=l(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function d(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function f(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?d(Object(n),!0).forEach(function(t){u(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):d(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}var p=Symbol(`BLOK_DEFAULT_CONFIG`);function m(t){(0,e.provide)(p,t)}function h(){return(0,e.inject)(p,{})}function g(e,t){if(Object.keys(e).length===0)return t;let n=f({},e);for(let e of Object.keys(t)){let r=t[e];r!==void 0&&(n[e]=r)}return(e.tools!==void 0||t.tools!==void 0)&&(n.tools=f(f({},e.tools),t.tools)),n}var _=`__blokPortalRegistry`,v=()=>{let t=(0,e.reactive)(new Map);return{entries:t,register(n,r){t.set(n,(0,e.markRaw)(r))},unregister(e){t.delete(e)},setProps(e,n){let r=t.get(e);r!==void 0&&Object.assign(r.props,n)}}},y=new WeakMap;function b(e,t){y.set(e,t)}function x(e){return y.get(e)}function S(e){y.delete(e)}var C=(e,t)=>{if(typeof e!=`object`||!e)return e;let n={};for(let[i,a]of Object.entries(e)){var r;let e=typeof a==`function`?a:a==null?void 0:a.class;if(!(typeof e==`function`&&e.__isBlokVueBlock===!0)){n[i]=a;continue}let o=typeof a==`function`?{class:a}:f({},a);o.config=f(f({},(r=o.config)==null?{}:r),{},{[_]:t}),n[i]=o}return n};function w(r,a){let s=(0,e.shallowRef)(null),c=(0,e.inject)(p,{}),l=()=>g(c,(0,e.toValue)(r)),u={current:null,holder:null,lastRenderedData:l().data,seededEditor:null,renderChain:Promise.resolve()},d=()=>{let t=f({},g((0,e.toRaw)(c),(0,e.toRaw)((0,e.toValue)(r))));return delete t.holder,t.data!==void 0&&(t.data=(0,e.toRaw)(t.data)),t},m=()=>{if(u.current!==null){o(u.current),S(u.current);try{u.current.destroy()}catch(e){}}u.current=null,u.holder=null,s.value=null},h=()=>{let e=document.createElement(`div`);u.holder=e;let n=d(),r=v();n.tools!==void 0&&(n.tools=C(n.tools,r)),typeof n.onSave==`function`&&(n.onSave=(...e)=>{var t,n;u.lastRenderedData=e[0],(t=(n=l()).onSave)==null||t.call(n,...e)});let a=new t.Blok(f(f({},n),{},{holder:e}));u.current=a,i(a,e),b(a,r),a.isReady.then(()=>{u.current===a&&(s.value=a)}).catch(()=>{u.current===a&&m()})};(0,e.watch)([s,()=>(0,n.normalizeReadOnlyConfig)(l().readOnly).enabled],([e,t])=>{e&&e.readOnly.set(t)},{immediate:!0}),(0,e.watch)([s,()=>l().theme],([e,t])=>{e&&t!==void 0&&e.theme.set(t)},{immediate:!0}),(0,e.watch)([s,()=>l().width],([e,t])=>{e&&t!==void 0&&e.width.set(t)},{immediate:!0}),(0,e.watch)([s,()=>l().placeholder],([e,t])=>{e&&t!==void 0&&e.placeholder.set(t)},{immediate:!0});let _={value:void 0};return(0,e.watch)([s,()=>{var e;return(e=l().style)==null?void 0:e.tokens}],([e,t])=>{!e||t===void 0||(0,n.deepEqual)(t,_.value)||(_.value=f({},t),e.tokens.set(t))},{immediate:!0,deep:!0}),(0,e.watch)([s,()=>l().autofocus],([e,t])=>{e&&t&&e.focus()},{immediate:!0}),(0,e.watch)([s,()=>l().data],([t,r])=>{if(!(!t||r===void 0)){if(u.seededEditor!==t){u.seededEditor=t,u.lastRenderedData=r;return}(0,n.deepEqual)(r,u.lastRenderedData)||(u.lastRenderedData=r,u.renderChain=u.renderChain.catch(()=>void 0).then(()=>t.render((0,e.toRaw)(r))))}},{immediate:!0}),a!==void 0&&(0,e.watch)(()=>(0,e.toValue)(a),()=>{m(),h()}),(0,e.onMounted)(h),(0,e.onBeforeUnmount)(m),s}var T=`block changed`;function E(t){let r=(0,e.shallowRef)(0),i=()=>{let n=(0,e.toValue)(t);return n===null?null:(0,e.toRaw)(n)},a=()=>{r.value},o=(0,e.shallowRef)(n.EMPTY_API),s={editor:null,handler:null},c=()=>{s.editor!==null&&s.handler!==null&&s.editor.off(T,s.handler),s.editor=null,s.handler=null};return(0,e.watch)(()=>i(),e=>{if(c(),r.value+=1,e===null){o.value=n.EMPTY_API;return}let t=()=>{r.value+=1};e.on(T,t),s.editor=e,s.handler=t,o.value=(0,n.createBlocksApiForEditor)(e,a)},{immediate:!0}),(0,e.onScopeDispose)(c),{getById:e=>o.value.getById(e),getChildren:e=>o.value.getChildren(e),insert:e=>o.value.insert(e),insertMany:e=>o.value.insertMany(e),insertTree:e=>o.value.insertTree(e),insertMarkdown:(e,t)=>o.value.insertMarkdown(e,t),exportMarkdown:()=>o.value.exportMarkdown(),move:(e,t)=>o.value.move(e,t),nest:(e,t)=>o.value.nest(e,t),unnest:e=>o.value.unnest(e),remove:e=>o.value.remove(e),update:(e,t,n)=>o.value.update(e,t,n),convert:(e,t,n,r)=>o.value.convert(e,t,n,r),transact:e=>o.value.transact(e),transactWithoutCapture:e=>o.value.transactWithoutCapture(e),getBlocksCount:()=>o.value.getBlocksCount(),getCurrentBlockIndex:()=>o.value.getCurrentBlockIndex(),getBlockByIndex:e=>o.value.getBlockByIndex(e),getBlockByElement:e=>o.value.getBlockByElement(e),getBlockData:e=>o.value.getBlockData(e),getBlockIndex:e=>o.value.getBlockIndex(e),composeBlockData:e=>o.value.composeBlockData(e),renderFromHTML:e=>o.value.renderFromHTML(e),insertOutputData:(e,t)=>o.value.insertOutputData(e,t),splitBlock:(e,t,n,r,i)=>o.value.splitBlock(e,t,n,r,i),insertInsideParent:(e,t,n)=>o.value.insertInsideParent(e,t,n),render:e=>o.value.render(e),clear:()=>o.value.clear(),isSyncingFromYjs:()=>o.value.isSyncingFromYjs()}}var D=(0,e.defineComponent)({name:`BlockErrorBoundary`,setup(t,{slots:n}){return(0,e.onErrorCaptured)(()=>!1),()=>{var e;return(e=n.default)==null?void 0:e.call(n)}}}),O=(0,e.defineComponent)({name:`BlockPortalHost`,props:{registry:{type:Object,required:!0}},setup(t){return()=>(0,e.h)(e.Fragment,Array.from(t.registry.entries.entries()).map(([t,n])=>(0,e.h)(e.Teleport,{key:t,to:n.hostEl},[(0,e.h)(D,null,{default:()=>(0,e.h)(n.component,n.props)})])))}}),k=(0,e.defineComponent)({name:`BlokContent`,props:{editor:{type:Object,default:null}},setup(t){let n=(0,e.ref)(null),r=t=>{if(n.value===null||t===null)return;let r=a((0,e.toRaw)(t));r!==void 0&&n.value.appendChild(r)},i=t=>{var n;t!==null&&((n=a((0,e.toRaw)(t)))==null||n.remove())};return(0,e.onMounted)(()=>{r(t.editor)}),(0,e.watch)(()=>t.editor,(e,t)=>{i(t==null?null:t),r(e)}),(0,e.onBeforeUnmount)(()=>{i(t.editor)}),()=>{let r=t.editor,i=r===null?void 0:x((0,e.toRaw)(r));return(0,e.h)(`div`,{ref:n},i===void 0?[]:[(0,e.h)(O,{registry:i})])}}}),A=`autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.inlineToolbar.tunes.style.theme.scrollToBlock.user.resolveUser.notifierPosition.notifier.width.onBeforeRender.onBeforePaste.onEnter`.split(`.`),j=(0,e.defineComponent)({name:`BlokEditor`,inheritAttrs:!1,props:{autofocus:{type:Boolean,default:void 0},defaultBlock:{type:String,default:void 0},dataModel:{type:String,default:void 0},placeholder:{type:[String,Boolean],default:void 0},sanitizer:{type:Object,default:void 0},hideToolbar:{type:Boolean,default:void 0},maxHistoryLength:{type:Number,default:void 0},historyDebounceTime:{type:Number,default:void 0},newGroupDelay:{type:Number,default:void 0},globalUndoRedo:{type:Boolean,default:void 0},tools:{type:Object,default:void 0},data:{type:Object,default:void 0},minHeight:{type:Number,default:void 0},logLevel:{type:String,default:void 0},readOnly:{type:Boolean,default:void 0},i18n:{type:Object,default:void 0},link:{type:Object,default:void 0},linkPaste:{type:Object,default:void 0},inlineToolbar:{type:[Array,Boolean],default:void 0},tunes:{type:Array,default:void 0},style:{type:Object,default:void 0},theme:{type:String,default:void 0},scrollToBlock:{type:Object,default:void 0},user:{type:Object,default:void 0},resolveUser:{type:Function,default:void 0},notifierPosition:{type:String,default:void 0},notifier:{type:Function,default:void 0},width:{type:String,default:void 0},onBeforeRender:{type:Function,default:void 0},onBeforePaste:{type:Function,default:void 0},onEnter:{type:Function,default:void 0},recreateKey:{type:null}},emits:{ready:e=>!0,change:e=>!0,save:e=>!0,"update:data":e=>!0,"after-render":e=>!0,"theme-change":e=>!0,"blocks-rendered":e=>!0,"block-rendered":e=>!0},setup(t,{emit:n,expose:r,attrs:i}){let a=(0,e.getCurrentInstance)(),o=e=>{let t=a==null?void 0:a.vnode.props;return t!=null&&e in t},s=()=>{let e={};for(let n of A){let r=t[n];r!==void 0&&(e[n]=r)}return o(`onChange`)&&(e.onChange=(e,t)=>{n(`change`,{api:e,event:t})}),(o(`onSave`)||o(`onUpdate:data`))&&(e.onSave=e=>{n(`update:data`,e),n(`save`,e)}),o(`onAfterRender`)&&(e.onAfterRender=e=>{n(`after-render`,e)}),o(`onThemeChange`)&&(e.onThemeChange=e=>{n(`theme-change`,e)}),e},c=w(()=>s(),()=>t.recreateKey);(0,e.watch)(c,(e,t,r)=>{if(e===null)return;let i=[];if(o(`onBlocksRendered`)){let t=e=>n(`blocks-rendered`,e);e.on(`blocks:rendered`,t),i.push([`blocks:rendered`,t])}if(o(`onBlockRendered`)){let t=e=>n(`block-rendered`,e);e.on(`block:rendered`,t),i.push([`block:rendered`,t])}r(()=>{for(let[t,n]of i)e.off(t,n)})});let l={last:null};return(0,e.watch)(c,e=>{e!==null&&e!==l.last&&(l.last=e,n(`ready`,e))}),r({instance:(0,e.computed)(()=>c.value),save:()=>{var e;return(e=c.value)==null?void 0:e.save()},focus:e=>{var t;(t=c.value)==null||t.focus(e)},render:e=>{var t;return(t=c.value)==null?void 0:t.render(e)}}),()=>(0,e.h)(k,f({editor:c.value},i))}});function M(t){var r;let i=(0,e.defineComponent)({name:`VueBlock(${t.type})`,props:{ctx:{type:Object,required:!0}},setup(e){return t.setup(e.ctx)}});return r=class{static get toolbox(){return t.toolbox}static get isReadOnlySupported(){return!0}constructor(r){var i,a;this.hostEl=null,this.pendingDispatch=!1,this.commit=e=>{let r=(0,n.fillDefaults)(t.propSchema,f(f({},this.mirror),e));(0,n.deepEqual)(r,this.mirror)||(this.mirror=r,this.lastRendered=r,this.dataRef.value=r,this.flushDispatch())},this.blockApi=r.block;let o=(i=r.config)==null?{}:i;this.registry=o[_];let s=r.api;this.pointerDrag=()=>{var e;return(s==null||(e=s.blocks)==null?void 0:e.isPointerDragActive)===!0},this.mirror=(0,n.fillDefaults)(t.propSchema,(0,e.toRaw)((a=r.data)==null?{}:a)),this.lastRendered=this.mirror,this.dataRef=(0,e.shallowRef)(this.mirror),this.readOnlyRef=(0,e.shallowRef)(r.readOnly);let c=this.blockApi;this.childrenComponent=(0,e.defineComponent)({name:`VueBlockChildren(${t.type})`,setup(){let t=(0,e.ref)(null),r=()=>{t.value!==null&&(0,n.mountChildBlocks)(t.value,c.getChildren())};return(0,e.onMounted)(r),(0,e.onUpdated)(r),()=>(0,e.h)(`div`,{ref:t,[n.DATA_ATTR.nestedBlocks]:``})}})}render(){var e;let t=document.createElement(`div`);t.setAttribute(`data-blok-mutation-free`,`true`),this.hostEl=t;let n={data:this.dataRef,commit:this.commit,block:this.blockApi,readOnly:this.readOnlyRef,BlockChildren:this.childrenComponent};return(e=this.registry)==null||e.register(this.blockApi.id,{hostEl:t,component:i,props:{ctx:n}}),t}rendered(){var e;(e=t.onRendered)==null||e.call(t,this.blockApi)}save(){return this.mirror}async setData(r){var i=this;let a=(0,n.fillDefaults)(t.propSchema,(0,e.toRaw)(r==null?{}:r));return(0,n.deepEqual)(a,i.lastRendered)?!0:(i.mirror=a,i.lastRendered=a,i.dataRef.value=a,await(0,e.nextTick)(),!0)}setReadOnly(e){this.readOnlyRef.value=e}moved(){var e;(e=t.onMoved)==null||e.call(t,this.blockApi)}removed(){var e,n;(e=this.registry)==null||e.unregister(this.blockApi.id),(n=t.onRemoved)==null||n.call(t,this.blockApi)}destroy(){var e;(e=this.registry)==null||e.unregister(this.blockApi.id)}flushDispatch(){if(!this.pointerDrag()){this.pendingDispatch=!1,this.blockApi.dispatchChange();return}if(this.pendingDispatch)return;this.pendingDispatch=!0;let e=()=>{if(this.pointerDrag()){requestAnimationFrame(e);return}this.pendingDispatch=!1,this.blockApi.dispatchChange()};requestAnimationFrame(e)}},r.__isBlokVueBlock=!0,r}exports.BLOK_DEFAULT_CONFIG=p,exports.BlokContent=k,exports.BlokEditor=j,exports.createVueBlock=M,exports.provideBlok=m,exports.useBlocks=E,exports.useBlok=w,exports.useBlokDefaults=h;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("vue"),t=require("@bloklabs/core"),n=require("@bloklabs/core/adapters");var r=new WeakMap;function i(e,t){r.set(e,t)}function a(e){return r.get(e)}function o(e){r.delete(e)}function s(e){"@babel/helpers - typeof";return s=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},s(e)}function c(e,t){if(s(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(s(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function l(e){var t=c(e,`string`);return s(t)==`symbol`?t:t+``}function u(e,t,n){return(t=l(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function d(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function f(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?d(Object(n),!0).forEach(function(t){u(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):d(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}var p=Symbol(`BLOK_DEFAULT_CONFIG`);function m(t){(0,e.provide)(p,t)}function h(){return(0,e.inject)(p,{})}function g(e,t){if(Object.keys(e).length===0)return t;let n=f({},e);for(let e of Object.keys(t)){let r=t[e];r!==void 0&&(n[e]=r)}return(e.tools!==void 0||t.tools!==void 0)&&(n.tools=f(f({},e.tools),t.tools)),n}var _=`__blokPortalRegistry`,v=()=>{let t=(0,e.reactive)(new Map);return{entries:t,register(n,r){t.set(n,(0,e.markRaw)(r))},unregister(e){t.delete(e)},setProps(e,n){let r=t.get(e);r!==void 0&&Object.assign(r.props,n)}}},y=new WeakMap;function b(e,t){y.set(e,t)}function x(e){return y.get(e)}function S(e){y.delete(e)}var C=(e,t)=>{if(typeof e!=`object`||!e)return e;let n={};for(let[i,a]of Object.entries(e)){var r;let e=typeof a==`function`?a:a==null?void 0:a.class;if(!(typeof e==`function`&&e.__isBlokVueBlock===!0)){n[i]=a;continue}let o=typeof a==`function`?{class:a}:f({},a);o.config=f(f({},(r=o.config)==null?{}:r),{},{[_]:t}),n[i]=o}return n};function w(r,a){let s=(0,e.shallowRef)(null),c=(0,e.inject)(p,{}),l=()=>g(c,(0,e.toValue)(r)),u={current:null,holder:null,lastRenderedData:l().data,seededEditor:null,renderChain:Promise.resolve()},d=()=>{let t=f({},g((0,e.toRaw)(c),(0,e.toRaw)((0,e.toValue)(r))));return delete t.holder,t.data!==void 0&&(t.data=(0,e.toRaw)(t.data)),t},m=()=>{if(u.current!==null){o(u.current),S(u.current);try{u.current.destroy()}catch(e){}}u.current=null,u.holder=null,s.value=null},h=()=>{let e=document.createElement(`div`);u.holder=e;let n=d(),r=v();n.tools!==void 0&&(n.tools=C(n.tools,r)),typeof n.onSave==`function`&&(n.onSave=(...e)=>{var t,n;u.lastRenderedData=e[0],(t=(n=l()).onSave)==null||t.call(n,...e)});let a=new t.Blok(f(f({},n),{},{holder:e}));u.current=a,i(a,e),b(a,r),a.isReady.then(()=>{u.current===a&&(s.value=a)}).catch(()=>{u.current===a&&m()})};(0,e.watch)([s,()=>(0,n.normalizeReadOnlyConfig)(l().readOnly).enabled,()=>(0,n.normalizeReadOnlyConfig)(l().readOnly).hideControls,()=>typeof l().readOnly==`object`],([e,t,n,r])=>{e&&(r?e.readOnly.set(t,{hideControls:n}):e.readOnly.set(t))},{immediate:!0}),(0,e.watch)([s,()=>l().hideToolbar],([e,t])=>{e&&e.toolbar.setHidden(!!t)},{immediate:!0}),(0,e.watch)([s,()=>l().theme],([e,t])=>{e&&t!==void 0&&e.theme.set(t)},{immediate:!0}),(0,e.watch)([s,()=>l().width],([e,t])=>{e&&t!==void 0&&e.width.set(t)},{immediate:!0}),(0,e.watch)([s,()=>l().placeholder],([e,t])=>{e&&t!==void 0&&e.placeholder.set(t)},{immediate:!0});let _={value:void 0};(0,e.watch)([s,()=>{var e;return(e=l().style)==null?void 0:e.tokens}],([e,t])=>{!e||t===void 0||(0,n.deepEqual)(t,_.value)||(_.value=f({},t),e.tokens.set(t))},{immediate:!0,deep:!0});let y={value:l().i18n};(0,e.watch)([s,()=>l().i18n],([e,t])=>{if(!e||t===void 0||(0,n.deepEqual)(t,y.value))return;y.value=f({},t);let{locale:r,messages:i,direction:a}=t;e.i18n.update(f(f(f({},r===void 0?{}:{locale:r}),i===void 0?{}:{messages:i}),a===void 0?{}:{direction:a}))},{immediate:!0,deep:!0});let x={editor:null,value:void 0};return(0,e.watch)([s,()=>l().inlineToolbar],([e,t])=>{if(!e||t===void 0||x.editor===e&&(0,n.deepEqual)(t,x.value))return;let r=Array.isArray(t)?[...t]:t;x.editor=e,x.value=r,e.tools.setInlineToolbar(r)},{immediate:!0,deep:!0}),(0,e.watch)([s,()=>l().autofocus],([e,t])=>{e&&t&&e.focus()},{immediate:!0}),(0,e.watch)([s,()=>l().data],([t,r])=>{if(!(!t||r===void 0)){if(u.seededEditor!==t){u.seededEditor=t,u.lastRenderedData=r;return}(0,n.deepEqual)(r,u.lastRenderedData)||(u.lastRenderedData=r,u.renderChain=u.renderChain.catch(()=>void 0).then(()=>t.render((0,e.toRaw)(r))))}},{immediate:!0}),a!==void 0&&(0,e.watch)(()=>(0,e.toValue)(a),()=>{m(),h()}),(0,e.onMounted)(h),(0,e.onBeforeUnmount)(m),s}var T=`block changed`;function E(t){let r=(0,e.shallowRef)(0),i=()=>{let n=(0,e.toValue)(t);return n===null?null:(0,e.toRaw)(n)},a=()=>{r.value},o=(0,e.shallowRef)(n.EMPTY_API),s={editor:null,handler:null},c=()=>{s.editor!==null&&s.handler!==null&&s.editor.off(T,s.handler),s.editor=null,s.handler=null};return(0,e.watch)(()=>i(),e=>{if(c(),r.value+=1,e===null){o.value=n.EMPTY_API;return}let t=()=>{r.value+=1};e.on(T,t),s.editor=e,s.handler=t,o.value=(0,n.createBlocksApiForEditor)(e,a)},{immediate:!0}),(0,e.onScopeDispose)(c),{getById:e=>o.value.getById(e),getChildren:e=>o.value.getChildren(e),insert:e=>o.value.insert(e),insertMany:e=>o.value.insertMany(e),insertTree:e=>o.value.insertTree(e),insertMarkdown:(e,t)=>o.value.insertMarkdown(e,t),exportMarkdown:()=>o.value.exportMarkdown(),move:(e,t)=>o.value.move(e,t),nest:(e,t)=>o.value.nest(e,t),unnest:e=>o.value.unnest(e),remove:e=>o.value.remove(e),update:(e,t,n)=>o.value.update(e,t,n),convert:(e,t,n,r)=>o.value.convert(e,t,n,r),transact:e=>o.value.transact(e),transactWithoutCapture:e=>o.value.transactWithoutCapture(e),getBlocksCount:()=>o.value.getBlocksCount(),getCurrentBlockIndex:()=>o.value.getCurrentBlockIndex(),getBlockByIndex:e=>o.value.getBlockByIndex(e),getBlockByElement:e=>o.value.getBlockByElement(e),getBlockData:e=>o.value.getBlockData(e),getBlockIndex:e=>o.value.getBlockIndex(e),composeBlockData:e=>o.value.composeBlockData(e),renderFromHTML:e=>o.value.renderFromHTML(e),insertOutputData:(e,t)=>o.value.insertOutputData(e,t),splitBlock:(e,t,n,r,i)=>o.value.splitBlock(e,t,n,r,i),insertInsideParent:(e,t,n)=>o.value.insertInsideParent(e,t,n),render:e=>o.value.render(e),clear:()=>o.value.clear(),isSyncingFromYjs:()=>o.value.isSyncingFromYjs()}}function D(n={}){let{within:r,settleOn:i}=n,a=(0,e.shallowRef)(!1),o=()=>{var n;let o=r===void 0||(n=(0,e.toValue)(r))==null?null:n;a.value=r!==void 0&&o===null?!1:t.Blok.readyState({within:o,settleOn:i}).ready};return(0,e.onScopeDispose)(t.Blok.subscribeReady(o)),(0,e.onMounted)(o),a}var O=(0,e.defineComponent)({name:`BlockErrorBoundary`,setup(t,{slots:n}){return(0,e.onErrorCaptured)(()=>!1),()=>{var e;return(e=n.default)==null?void 0:e.call(n)}}}),k=(0,e.defineComponent)({name:`BlockPortalHost`,props:{registry:{type:Object,required:!0}},setup(t){return()=>(0,e.h)(e.Fragment,Array.from(t.registry.entries.entries()).map(([t,n])=>(0,e.h)(e.Teleport,{key:t,to:n.hostEl},[(0,e.h)(O,null,{default:()=>(0,e.h)(n.component,n.props)})])))}}),A=(0,e.defineComponent)({name:`BlokContent`,props:{editor:{type:Object,default:null}},setup(t){let n=(0,e.ref)(null),r=t=>{if(n.value===null||t===null)return;let r=a((0,e.toRaw)(t));r!==void 0&&n.value.appendChild(r)},i=t=>{var n;t!==null&&((n=a((0,e.toRaw)(t)))==null||n.remove())};return(0,e.onMounted)(()=>{r(t.editor)}),(0,e.watch)(()=>t.editor,(e,t)=>{i(t==null?null:t),r(e)}),(0,e.onBeforeUnmount)(()=>{i(t.editor)}),()=>{let r=t.editor,i=r===null?void 0:x((0,e.toRaw)(r));return(0,e.h)(`div`,{ref:n},i===void 0?[]:[(0,e.h)(k,{registry:i})])}}}),j=`autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.inlineToolbar.tunes.style.theme.scrollToBlock.user.resolveUser.notifierPosition.notifier.width.onBeforeRender.onBeforePaste.onEnter.onError`.split(`.`),M=(0,e.defineComponent)({name:`BlokEditor`,inheritAttrs:!1,props:{autofocus:{type:Boolean,default:void 0},defaultBlock:{type:String,default:void 0},dataModel:{type:String,default:void 0},placeholder:{type:[String,Boolean],default:void 0},sanitizer:{type:Object,default:void 0},hideToolbar:{type:Boolean,default:void 0},maxHistoryLength:{type:Number,default:void 0},historyDebounceTime:{type:Number,default:void 0},newGroupDelay:{type:Number,default:void 0},globalUndoRedo:{type:Boolean,default:void 0},tools:{type:Object,default:void 0},data:{type:Object,default:void 0},minHeight:{type:Number,default:void 0},logLevel:{type:String,default:void 0},readOnly:{type:[Boolean,Object],default:void 0},i18n:{type:Object,default:void 0},link:{type:Object,default:void 0},linkPaste:{type:Object,default:void 0},inlineToolbar:{type:[Array,Boolean],default:void 0},tunes:{type:Array,default:void 0},style:{type:Object,default:void 0},theme:{type:String,default:void 0},scrollToBlock:{type:Object,default:void 0},user:{type:Object,default:void 0},resolveUser:{type:Function,default:void 0},notifierPosition:{type:String,default:void 0},notifier:{type:Function,default:void 0},width:{type:String,default:void 0},onBeforeRender:{type:Function,default:void 0},onBeforePaste:{type:Function,default:void 0},onEnter:{type:Function,default:void 0},onError:{type:Function,default:void 0},recreateKey:{type:null}},emits:{ready:e=>!0,change:e=>!0,save:e=>!0,"update:data":e=>!0,"after-render":e=>!0,"theme-change":e=>!0,"blocks-rendered":e=>!0,"block-rendered":e=>!0},setup(t,{emit:n,expose:r,attrs:i}){let a=(0,e.getCurrentInstance)(),o=e=>{let t=a==null?void 0:a.vnode.props;return t!=null&&e in t},s=()=>{let e={};for(let n of j){let r=t[n];r!==void 0&&(e[n]=r)}return o(`onChange`)&&(e.onChange=(e,t)=>{n(`change`,{api:e,event:t})}),(o(`onSave`)||o(`onUpdate:data`))&&(e.onSave=e=>{n(`update:data`,e),n(`save`,e)}),o(`onAfterRender`)&&(e.onAfterRender=e=>{n(`after-render`,e)}),o(`onThemeChange`)&&(e.onThemeChange=e=>{n(`theme-change`,e)}),e},c=w(()=>s(),()=>t.recreateKey);(0,e.watch)(c,(e,t,r)=>{if(e===null)return;let i=[];if(o(`onBlocksRendered`)){let t=e=>n(`blocks-rendered`,e);e.on(`blocks:rendered`,t),i.push([`blocks:rendered`,t])}if(o(`onBlockRendered`)){let t=e=>n(`block-rendered`,e);e.on(`block:rendered`,t),i.push([`block:rendered`,t])}r(()=>{for(let[t,n]of i)e.off(t,n)})});let l={last:null};return(0,e.watch)(c,e=>{e!==null&&e!==l.last&&(l.last=e,n(`ready`,e))}),r({instance:(0,e.computed)(()=>c.value),save:()=>{var e;return(e=c.value)==null?void 0:e.save()},focus:e=>{var t;(t=c.value)==null||t.focus(e)},render:e=>{var t;return(t=c.value)==null?void 0:t.render(e)}}),()=>(0,e.h)(A,f({editor:c.value},i))}});function N(t){var r;let i=(0,e.defineComponent)({name:`VueBlock(${t.type})`,props:{ctx:{type:Object,required:!0}},setup(e){return t.setup(e.ctx)}});return r=class{static get toolbox(){return t.toolbox}static get isReadOnlySupported(){return!0}constructor(r){var i,a;this.hostEl=null,this.pendingDispatch=!1,this.commit=e=>{let r=(0,n.fillDefaults)(t.propSchema,f(f({},this.mirror),e));(0,n.deepEqual)(r,this.mirror)||(this.mirror=r,this.lastRendered=r,this.dataRef.value=r,this.flushDispatch())},this.blockApi=r.block;let o=(i=r.config)==null?{}:i;this.registry=o[_];let s=r.api;this.pointerDrag=()=>{var e;return(s==null||(e=s.blocks)==null?void 0:e.isPointerDragActive)===!0},this.mirror=(0,n.fillDefaults)(t.propSchema,(0,e.toRaw)((a=r.data)==null?{}:a)),this.lastRendered=this.mirror,this.dataRef=(0,e.shallowRef)(this.mirror),this.readOnlyRef=(0,e.shallowRef)(r.readOnly);let c=this.blockApi;this.childrenComponent=(0,e.defineComponent)({name:`VueBlockChildren(${t.type})`,setup(){let t=(0,e.ref)(null),r=()=>{t.value!==null&&(0,n.mountChildBlocks)(t.value,c.getChildren())};return(0,e.onMounted)(r),(0,e.onUpdated)(r),()=>(0,e.h)(`div`,{ref:t,[n.DATA_ATTR.nestedBlocks]:``})}})}render(){var e;let t=document.createElement(`div`);t.setAttribute(`data-blok-mutation-free`,`true`),this.hostEl=t;let n={data:this.dataRef,commit:this.commit,block:this.blockApi,readOnly:this.readOnlyRef,BlockChildren:this.childrenComponent};return(e=this.registry)==null||e.register(this.blockApi.id,{hostEl:t,component:i,props:{ctx:n}}),t}rendered(){var e;(e=t.onRendered)==null||e.call(t,this.blockApi)}save(){return this.mirror}async setData(r){var i=this;let a=(0,n.fillDefaults)(t.propSchema,(0,e.toRaw)(r==null?{}:r));return(0,n.deepEqual)(a,i.lastRendered)?!0:(i.mirror=a,i.lastRendered=a,i.dataRef.value=a,await(0,e.nextTick)(),!0)}setReadOnly(e){this.readOnlyRef.value=e}moved(){var e;(e=t.onMoved)==null||e.call(t,this.blockApi)}removed(){var e,n;(e=this.registry)==null||e.unregister(this.blockApi.id),(n=t.onRemoved)==null||n.call(t,this.blockApi)}destroy(){var e;(e=this.registry)==null||e.unregister(this.blockApi.id)}flushDispatch(){if(!this.pointerDrag()){this.pendingDispatch=!1,this.blockApi.dispatchChange();return}if(this.pendingDispatch)return;this.pendingDispatch=!0;let e=()=>{if(this.pointerDrag()){requestAnimationFrame(e);return}this.pendingDispatch=!1,this.blockApi.dispatchChange()};requestAnimationFrame(e)}},r.__isBlokVueBlock=!0,r}exports.BLOK_DEFAULT_CONFIG=p,exports.BlokContent=A,exports.BlokEditor=M,exports.createVueBlock=N,exports.provideBlok=m,exports.useBlocks=E,exports.useBlok=w,exports.useBlokDefaults=h,exports.useBlokReady=D;
package/dist/index.mjs CHANGED
@@ -1,49 +1,49 @@
1
- import { Fragment as e, Teleport as t, computed as n, defineComponent as r, getCurrentInstance as i, h as a, inject as o, markRaw as s, nextTick as c, onBeforeUnmount as l, onErrorCaptured as u, onMounted as d, onScopeDispose as f, onUpdated as p, provide as m, reactive as ee, ref as h, shallowRef as g, toRaw as _, toValue as v, watch as y } from "vue";
2
- import { Blok as b } from "@bloklabs/core";
3
- import { DATA_ATTR as x, EMPTY_API as S, createBlocksApiForEditor as C, deepEqual as w, fillDefaults as T, mountChildBlocks as E, normalizeReadOnlyConfig as D } from "@bloklabs/core/adapters";
1
+ import { Fragment as e, Teleport as t, computed as n, defineComponent as r, getCurrentInstance as i, h as a, inject as o, markRaw as s, nextTick as c, onBeforeUnmount as l, onErrorCaptured as u, onMounted as d, onScopeDispose as f, onUpdated as p, provide as m, reactive as h, ref as g, shallowRef as _, toRaw as v, toValue as y, watch as b } from "vue";
2
+ import { Blok as x } from "@bloklabs/core";
3
+ import { DATA_ATTR as S, EMPTY_API as C, createBlocksApiForEditor as w, deepEqual as T, fillDefaults as E, mountChildBlocks as D, normalizeReadOnlyConfig as O } from "@bloklabs/core/adapters";
4
4
  //#region src/holder-map.ts
5
- var O = /* @__PURE__ */ new WeakMap();
6
- function k(e, t) {
7
- O.set(e, t);
8
- }
9
- function A(e) {
10
- return O.get(e);
5
+ var k = /* @__PURE__ */ new WeakMap();
6
+ function A(e, t) {
7
+ k.set(e, t);
11
8
  }
12
9
  function j(e) {
13
- O.delete(e);
10
+ return k.get(e);
11
+ }
12
+ function M(e) {
13
+ k.delete(e);
14
14
  }
15
15
  //#endregion
16
16
  //#region \0@oxc-project+runtime@0.139.0/helpers/esm/typeof.js
17
- function M(e) {
17
+ function N(e) {
18
18
  "@babel/helpers - typeof";
19
- return M = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(e) {
19
+ return N = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(e) {
20
20
  return typeof e;
21
21
  } : function(e) {
22
22
  return e && typeof Symbol == "function" && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e;
23
- }, M(e);
23
+ }, N(e);
24
24
  }
25
25
  //#endregion
26
26
  //#region \0@oxc-project+runtime@0.139.0/helpers/esm/toPrimitive.js
27
- function N(e, t) {
28
- if (M(e) != "object" || !e) return e;
27
+ function P(e, t) {
28
+ if (N(e) != "object" || !e) return e;
29
29
  var n = e[Symbol.toPrimitive];
30
30
  if (n !== void 0) {
31
31
  var r = n.call(e, t || "default");
32
- if (M(r) != "object") return r;
32
+ if (N(r) != "object") return r;
33
33
  throw TypeError("@@toPrimitive must return a primitive value.");
34
34
  }
35
35
  return (t === "string" ? String : Number)(e);
36
36
  }
37
37
  //#endregion
38
38
  //#region \0@oxc-project+runtime@0.139.0/helpers/esm/toPropertyKey.js
39
- function P(e) {
40
- var t = N(e, "string");
41
- return M(t) == "symbol" ? t : t + "";
39
+ function F(e) {
40
+ var t = P(e, "string");
41
+ return N(t) == "symbol" ? t : t + "";
42
42
  }
43
43
  //#endregion
44
44
  //#region \0@oxc-project+runtime@0.139.0/helpers/esm/defineProperty.js
45
- function F(e, t, n) {
46
- return (t = P(t)) in e ? Object.defineProperty(e, t, {
45
+ function I(e, t, n) {
46
+ return (t = F(t)) in e ? Object.defineProperty(e, t, {
47
47
  value: n,
48
48
  enumerable: !0,
49
49
  configurable: !0,
@@ -52,7 +52,7 @@ function F(e, t, n) {
52
52
  }
53
53
  //#endregion
54
54
  //#region \0@oxc-project+runtime@0.139.0/helpers/esm/objectSpread2.js
55
- function I(e, t) {
55
+ function L(e, t) {
56
56
  var n = Object.keys(e);
57
57
  if (Object.getOwnPropertySymbols) {
58
58
  var r = Object.getOwnPropertySymbols(e);
@@ -62,12 +62,12 @@ function I(e, t) {
62
62
  }
63
63
  return n;
64
64
  }
65
- function L(e) {
65
+ function R(e) {
66
66
  for (var t = 1; t < arguments.length; t++) {
67
67
  var n = arguments[t] == null ? {} : arguments[t];
68
- t % 2 ? I(Object(n), !0).forEach(function(t) {
69
- F(e, t, n[t]);
70
- }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : I(Object(n)).forEach(function(t) {
68
+ t % 2 ? L(Object(n), !0).forEach(function(t) {
69
+ I(e, t, n[t]);
70
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : L(Object(n)).forEach(function(t) {
71
71
  Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(n, t));
72
72
  });
73
73
  }
@@ -75,26 +75,26 @@ function L(e) {
75
75
  }
76
76
  //#endregion
77
77
  //#region src/provide-blok.ts
78
- var R = Symbol("BLOK_DEFAULT_CONFIG");
79
- function z(e) {
80
- m(R, e);
78
+ var z = Symbol("BLOK_DEFAULT_CONFIG");
79
+ function B(e) {
80
+ m(z, e);
81
81
  }
82
- function B() {
83
- return o(R, {});
82
+ function V() {
83
+ return o(z, {});
84
84
  }
85
- function V(e, t) {
85
+ function H(e, t) {
86
86
  if (Object.keys(e).length === 0) return t;
87
- let n = L({}, e);
87
+ let n = R({}, e);
88
88
  for (let e of Object.keys(t)) {
89
89
  let r = t[e];
90
90
  r !== void 0 && (n[e] = r);
91
91
  }
92
- return (e.tools !== void 0 || t.tools !== void 0) && (n.tools = L(L({}, e.tools), t.tools)), n;
92
+ return (e.tools !== void 0 || t.tools !== void 0) && (n.tools = R(R({}, e.tools), t.tools)), n;
93
93
  }
94
94
  //#endregion
95
95
  //#region src/block-portal-registry.ts
96
- var H = "__blokPortalRegistry", U = () => {
97
- let e = ee(/* @__PURE__ */ new Map());
96
+ var U = "__blokPortalRegistry", W = () => {
97
+ let e = h(/* @__PURE__ */ new Map());
98
98
  return {
99
99
  entries: e,
100
100
  register(t, n) {
@@ -108,19 +108,19 @@ var H = "__blokPortalRegistry", U = () => {
108
108
  r !== void 0 && Object.assign(r.props, n);
109
109
  }
110
110
  };
111
- }, W = /* @__PURE__ */ new WeakMap();
112
- function G(e, t) {
113
- W.set(e, t);
114
- }
115
- function K(e) {
116
- return W.get(e);
111
+ }, G = /* @__PURE__ */ new WeakMap();
112
+ function K(e, t) {
113
+ G.set(e, t);
117
114
  }
118
115
  function q(e) {
119
- W.delete(e);
116
+ return G.get(e);
117
+ }
118
+ function J(e) {
119
+ G.delete(e);
120
120
  }
121
121
  //#endregion
122
122
  //#region src/useBlok.ts
123
- var J = (e, t) => {
123
+ var Y = (e, t) => {
124
124
  if (typeof e != "object" || !e) return e;
125
125
  let n = {};
126
126
  for (let [i, a] of Object.entries(e)) {
@@ -130,24 +130,24 @@ var J = (e, t) => {
130
130
  n[i] = a;
131
131
  continue;
132
132
  }
133
- let o = typeof a == "function" ? { class: a } : L({}, a);
134
- o.config = L(L({}, (r = o.config) == null ? {} : r), {}, { [H]: t }), n[i] = o;
133
+ let o = typeof a == "function" ? { class: a } : R({}, a);
134
+ o.config = R(R({}, (r = o.config) == null ? {} : r), {}, { [U]: t }), n[i] = o;
135
135
  }
136
136
  return n;
137
137
  };
138
- function Y(e, t) {
139
- let n = g(null), r = o(R, {}), i = () => V(r, v(e)), a = {
138
+ function X(e, t) {
139
+ let n = _(null), r = o(z, {}), i = () => H(r, y(e)), a = {
140
140
  current: null,
141
141
  holder: null,
142
142
  lastRenderedData: i().data,
143
143
  seededEditor: null,
144
144
  renderChain: Promise.resolve()
145
145
  }, s = () => {
146
- let t = L({}, V(_(r), _(v(e))));
147
- return delete t.holder, t.data !== void 0 && (t.data = _(t.data)), t;
146
+ let t = R({}, H(v(r), v(y(e))));
147
+ return delete t.holder, t.data !== void 0 && (t.data = v(t.data)), t;
148
148
  }, c = () => {
149
149
  if (a.current !== null) {
150
- j(a.current), q(a.current);
150
+ M(a.current), J(a.current);
151
151
  try {
152
152
  a.current.destroy();
153
153
  } catch (e) {}
@@ -156,74 +156,103 @@ function Y(e, t) {
156
156
  }, u = () => {
157
157
  let e = document.createElement("div");
158
158
  a.holder = e;
159
- let t = s(), r = U();
160
- t.tools !== void 0 && (t.tools = J(t.tools, r)), typeof t.onSave == "function" && (t.onSave = (...e) => {
159
+ let t = s(), r = W();
160
+ t.tools !== void 0 && (t.tools = Y(t.tools, r)), typeof t.onSave == "function" && (t.onSave = (...e) => {
161
161
  var t, n;
162
162
  a.lastRenderedData = e[0], (t = (n = i()).onSave) == null || t.call(n, ...e);
163
163
  });
164
- let o = new b(L(L({}, t), {}, { holder: e }));
165
- a.current = o, k(o, e), G(o, r), o.isReady.then(() => {
164
+ let o = new x(R(R({}, t), {}, { holder: e }));
165
+ a.current = o, A(o, e), K(o, r), o.isReady.then(() => {
166
166
  a.current === o && (n.value = o);
167
167
  }).catch(() => {
168
168
  a.current === o && c();
169
169
  });
170
170
  };
171
- y([n, () => D(i().readOnly).enabled], ([e, t]) => {
172
- e && e.readOnly.set(t);
173
- }, { immediate: !0 }), y([n, () => i().theme], ([e, t]) => {
171
+ b([
172
+ n,
173
+ () => O(i().readOnly).enabled,
174
+ () => O(i().readOnly).hideControls,
175
+ () => typeof i().readOnly == "object"
176
+ ], ([e, t, n, r]) => {
177
+ e && (r ? e.readOnly.set(t, { hideControls: n }) : e.readOnly.set(t));
178
+ }, { immediate: !0 }), b([n, () => i().hideToolbar], ([e, t]) => {
179
+ e && e.toolbar.setHidden(!!t);
180
+ }, { immediate: !0 }), b([n, () => i().theme], ([e, t]) => {
174
181
  e && t !== void 0 && e.theme.set(t);
175
- }, { immediate: !0 }), y([n, () => i().width], ([e, t]) => {
182
+ }, { immediate: !0 }), b([n, () => i().width], ([e, t]) => {
176
183
  e && t !== void 0 && e.width.set(t);
177
- }, { immediate: !0 }), y([n, () => i().placeholder], ([e, t]) => {
184
+ }, { immediate: !0 }), b([n, () => i().placeholder], ([e, t]) => {
178
185
  e && t !== void 0 && e.placeholder.set(t);
179
186
  }, { immediate: !0 });
180
187
  let f = { value: void 0 };
181
- return y([n, () => {
188
+ b([n, () => {
182
189
  var e;
183
190
  return (e = i().style) == null ? void 0 : e.tokens;
184
191
  }], ([e, t]) => {
185
- !e || t === void 0 || w(t, f.value) || (f.value = L({}, t), e.tokens.set(t));
192
+ !e || t === void 0 || T(t, f.value) || (f.value = R({}, t), e.tokens.set(t));
193
+ }, {
194
+ immediate: !0,
195
+ deep: !0
196
+ });
197
+ let p = { value: i().i18n };
198
+ b([n, () => i().i18n], ([e, t]) => {
199
+ if (!e || t === void 0 || T(t, p.value)) return;
200
+ p.value = R({}, t);
201
+ let { locale: n, messages: r, direction: i } = t;
202
+ e.i18n.update(R(R(R({}, n === void 0 ? {} : { locale: n }), r === void 0 ? {} : { messages: r }), i === void 0 ? {} : { direction: i }));
203
+ }, {
204
+ immediate: !0,
205
+ deep: !0
206
+ });
207
+ let m = {
208
+ editor: null,
209
+ value: void 0
210
+ };
211
+ return b([n, () => i().inlineToolbar], ([e, t]) => {
212
+ if (!e || t === void 0 || m.editor === e && T(t, m.value)) return;
213
+ let n = Array.isArray(t) ? [...t] : t;
214
+ m.editor = e, m.value = n, e.tools.setInlineToolbar(n);
186
215
  }, {
187
216
  immediate: !0,
188
217
  deep: !0
189
- }), y([n, () => i().autofocus], ([e, t]) => {
218
+ }), b([n, () => i().autofocus], ([e, t]) => {
190
219
  e && t && e.focus();
191
- }, { immediate: !0 }), y([n, () => i().data], ([e, t]) => {
220
+ }, { immediate: !0 }), b([n, () => i().data], ([e, t]) => {
192
221
  if (!(!e || t === void 0)) {
193
222
  if (a.seededEditor !== e) {
194
223
  a.seededEditor = e, a.lastRenderedData = t;
195
224
  return;
196
225
  }
197
- w(t, a.lastRenderedData) || (a.lastRenderedData = t, a.renderChain = a.renderChain.catch(() => void 0).then(() => e.render(_(t))));
226
+ T(t, a.lastRenderedData) || (a.lastRenderedData = t, a.renderChain = a.renderChain.catch(() => void 0).then(() => e.render(v(t))));
198
227
  }
199
- }, { immediate: !0 }), t !== void 0 && y(() => v(t), () => {
228
+ }, { immediate: !0 }), t !== void 0 && b(() => y(t), () => {
200
229
  c(), u();
201
230
  }), d(u), l(c), n;
202
231
  }
203
232
  //#endregion
204
233
  //#region src/useBlocks.ts
205
- var X = "block changed";
206
- function Z(e) {
207
- let t = g(0), n = () => {
208
- let t = v(e);
209
- return t === null ? null : _(t);
234
+ var Z = "block changed";
235
+ function Q(e) {
236
+ let t = _(0), n = () => {
237
+ let t = y(e);
238
+ return t === null ? null : v(t);
210
239
  }, r = () => {
211
240
  t.value;
212
- }, i = g(S), a = {
241
+ }, i = _(C), a = {
213
242
  editor: null,
214
243
  handler: null
215
244
  }, o = () => {
216
- a.editor !== null && a.handler !== null && a.editor.off(X, a.handler), a.editor = null, a.handler = null;
245
+ a.editor !== null && a.handler !== null && a.editor.off(Z, a.handler), a.editor = null, a.handler = null;
217
246
  };
218
- return y(() => n(), (e) => {
247
+ return b(() => n(), (e) => {
219
248
  if (o(), t.value += 1, e === null) {
220
- i.value = S;
249
+ i.value = C;
221
250
  return;
222
251
  }
223
252
  let n = () => {
224
253
  t.value += 1;
225
254
  };
226
- e.on(X, n), a.editor = e, a.handler = n, i.value = C(e, r);
255
+ e.on(Z, n), a.editor = e, a.handler = n, i.value = w(e, r);
227
256
  }, { immediate: !0 }), f(o), {
228
257
  getById: (e) => i.value.getById(e),
229
258
  getChildren: (e) => i.value.getChildren(e),
@@ -257,8 +286,21 @@ function Z(e) {
257
286
  };
258
287
  }
259
288
  //#endregion
289
+ //#region src/useBlokReady.ts
290
+ function ee(e = {}) {
291
+ let { within: t, settleOn: n } = e, r = _(!1), i = () => {
292
+ var e;
293
+ let i = t === void 0 || (e = y(t)) == null ? null : e;
294
+ r.value = t !== void 0 && i === null ? !1 : x.readyState({
295
+ within: i,
296
+ settleOn: n
297
+ }).ready;
298
+ };
299
+ return f(x.subscribeReady(i)), d(i), r;
300
+ }
301
+ //#endregion
260
302
  //#region src/BlockPortalHost.ts
261
- var Q = r({
303
+ var te = r({
262
304
  name: "BlockErrorBoundary",
263
305
  setup(e, { slots: t }) {
264
306
  return u(() => !1), () => {
@@ -266,7 +308,7 @@ var Q = r({
266
308
  return (e = t.default) == null ? void 0 : e.call(t);
267
309
  };
268
310
  }
269
- }), te = r({
311
+ }), ne = r({
270
312
  name: "BlockPortalHost",
271
313
  props: { registry: {
272
314
  type: Object,
@@ -276,7 +318,7 @@ var Q = r({
276
318
  return () => a(e, Array.from(n.registry.entries.entries()).map(([e, n]) => a(t, {
277
319
  key: e,
278
320
  to: n.hostEl
279
- }, [a(Q, null, { default: () => a(n.component, n.props) })])));
321
+ }, [a(te, null, { default: () => a(n.component, n.props) })])));
280
322
  }
281
323
  }), $ = r({
282
324
  name: "BlokContent",
@@ -285,26 +327,26 @@ var Q = r({
285
327
  default: null
286
328
  } },
287
329
  setup(e) {
288
- let t = h(null), n = (e) => {
330
+ let t = g(null), n = (e) => {
289
331
  if (t.value === null || e === null) return;
290
- let n = A(_(e));
332
+ let n = j(v(e));
291
333
  n !== void 0 && t.value.appendChild(n);
292
334
  }, r = (e) => {
293
335
  var t;
294
- e !== null && ((t = A(_(e))) == null || t.remove());
336
+ e !== null && ((t = j(v(e))) == null || t.remove());
295
337
  };
296
338
  return d(() => {
297
339
  n(e.editor);
298
- }), y(() => e.editor, (e, t) => {
340
+ }), b(() => e.editor, (e, t) => {
299
341
  r(t == null ? null : t), n(e);
300
342
  }), l(() => {
301
343
  r(e.editor);
302
344
  }), () => {
303
- let n = e.editor, r = n === null ? void 0 : K(_(n));
304
- return a("div", { ref: t }, r === void 0 ? [] : [a(te, { registry: r })]);
345
+ let n = e.editor, r = n === null ? void 0 : q(v(n));
346
+ return a("div", { ref: t }, r === void 0 ? [] : [a(ne, { registry: r })]);
305
347
  };
306
348
  }
307
- }), ne = /* @__PURE__ */ "autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.inlineToolbar.tunes.style.theme.scrollToBlock.user.resolveUser.notifierPosition.notifier.width.onBeforeRender.onBeforePaste.onEnter".split("."), re = r({
349
+ }), re = /* @__PURE__ */ "autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.inlineToolbar.tunes.style.theme.scrollToBlock.user.resolveUser.notifierPosition.notifier.width.onBeforeRender.onBeforePaste.onEnter.onError".split("."), ie = r({
308
350
  name: "BlokEditor",
309
351
  inheritAttrs: !1,
310
352
  props: {
@@ -365,7 +407,7 @@ var Q = r({
365
407
  default: void 0
366
408
  },
367
409
  readOnly: {
368
- type: Boolean,
410
+ type: [Boolean, Object],
369
411
  default: void 0
370
412
  },
371
413
  i18n: {
@@ -432,6 +474,10 @@ var Q = r({
432
474
  type: Function,
433
475
  default: void 0
434
476
  },
477
+ onError: {
478
+ type: Function,
479
+ default: void 0
480
+ },
435
481
  recreateKey: { type: null }
436
482
  },
437
483
  emits: {
@@ -450,7 +496,7 @@ var Q = r({
450
496
  return t != null && e in t;
451
497
  }, l = () => {
452
498
  let n = {};
453
- for (let t of ne) {
499
+ for (let t of re) {
454
500
  let r = e[t];
455
501
  r !== void 0 && (n[t] = r);
456
502
  }
@@ -466,8 +512,8 @@ var Q = r({
466
512
  }), c("onThemeChange") && (n.onThemeChange = (e) => {
467
513
  t("theme-change", e);
468
514
  }), n;
469
- }, u = Y(() => l(), () => e.recreateKey);
470
- y(u, (e, n, r) => {
515
+ }, u = X(() => l(), () => e.recreateKey);
516
+ b(u, (e, n, r) => {
471
517
  if (e === null) return;
472
518
  let i = [];
473
519
  if (c("onBlocksRendered")) {
@@ -483,7 +529,7 @@ var Q = r({
483
529
  });
484
530
  });
485
531
  let d = { last: null };
486
- return y(u, (e) => {
532
+ return b(u, (e) => {
487
533
  e !== null && e !== d.last && (d.last = e, t("ready", e));
488
534
  }), r({
489
535
  instance: n(() => u.value),
@@ -499,12 +545,12 @@ var Q = r({
499
545
  var t;
500
546
  return (t = u.value) == null ? void 0 : t.render(e);
501
547
  }
502
- }), () => a($, L({ editor: u.value }, o));
548
+ }), () => a($, R({ editor: u.value }, o));
503
549
  }
504
550
  });
505
551
  //#endregion
506
552
  //#region src/createVueBlock.ts
507
- function ie(e) {
553
+ function ae(e) {
508
554
  var t;
509
555
  let n = r({
510
556
  name: `VueBlock(${e.type})`,
@@ -526,26 +572,26 @@ function ie(e) {
526
572
  constructor(t) {
527
573
  var n, i;
528
574
  this.hostEl = null, this.pendingDispatch = !1, this.commit = (t) => {
529
- let n = T(e.propSchema, L(L({}, this.mirror), t));
530
- w(n, this.mirror) || (this.mirror = n, this.lastRendered = n, this.dataRef.value = n, this.flushDispatch());
575
+ let n = E(e.propSchema, R(R({}, this.mirror), t));
576
+ T(n, this.mirror) || (this.mirror = n, this.lastRendered = n, this.dataRef.value = n, this.flushDispatch());
531
577
  }, this.blockApi = t.block;
532
578
  let o = (n = t.config) == null ? {} : n;
533
- this.registry = o[H];
579
+ this.registry = o[U];
534
580
  let s = t.api;
535
581
  this.pointerDrag = () => {
536
582
  var e;
537
583
  return (s == null || (e = s.blocks) == null ? void 0 : e.isPointerDragActive) === !0;
538
- }, this.mirror = T(e.propSchema, _((i = t.data) == null ? {} : i)), this.lastRendered = this.mirror, this.dataRef = g(this.mirror), this.readOnlyRef = g(t.readOnly);
584
+ }, this.mirror = E(e.propSchema, v((i = t.data) == null ? {} : i)), this.lastRendered = this.mirror, this.dataRef = _(this.mirror), this.readOnlyRef = _(t.readOnly);
539
585
  let c = this.blockApi;
540
586
  this.childrenComponent = r({
541
587
  name: `VueBlockChildren(${e.type})`,
542
588
  setup() {
543
- let e = h(null), t = () => {
544
- e.value !== null && E(e.value, c.getChildren());
589
+ let e = g(null), t = () => {
590
+ e.value !== null && D(e.value, c.getChildren());
545
591
  };
546
592
  return d(t), p(t), () => a("div", {
547
593
  ref: e,
548
- [x.nestedBlocks]: ""
594
+ [S.nestedBlocks]: ""
549
595
  });
550
596
  }
551
597
  });
@@ -576,8 +622,8 @@ function ie(e) {
576
622
  }
577
623
  async setData(t) {
578
624
  var n = this;
579
- let r = T(e.propSchema, _(t == null ? {} : t));
580
- return w(r, n.lastRendered) ? !0 : (n.mirror = r, n.lastRendered = r, n.dataRef.value = r, await c(), !0);
625
+ let r = E(e.propSchema, v(t == null ? {} : t));
626
+ return T(r, n.lastRendered) ? !0 : (n.mirror = r, n.lastRendered = r, n.dataRef.value = r, await c(), !0);
581
627
  }
582
628
  setReadOnly(e) {
583
629
  this.readOnlyRef.value = e;
@@ -613,4 +659,4 @@ function ie(e) {
613
659
  }, t.__isBlokVueBlock = !0, t;
614
660
  }
615
661
  //#endregion
616
- export { R as BLOK_DEFAULT_CONFIG, $ as BlokContent, re as BlokEditor, ie as createVueBlock, z as provideBlok, Z as useBlocks, Y as useBlok, B as useBlokDefaults };
662
+ export { z as BLOK_DEFAULT_CONFIG, $ as BlokContent, ie as BlokEditor, ae as createVueBlock, B as provideBlok, Q as useBlocks, X as useBlok, V as useBlokDefaults, ee as useBlokReady };
package/package.json CHANGED
@@ -1,14 +1,35 @@
1
1
  {
2
2
  "name": "@bloklabs/vue",
3
- "version": "1.3.0",
4
- "description": "Vue 3 bindings for the Blok editor",
3
+ "version": "1.4.1",
4
+ "description": "Vue block editor — official Vue 3 bindings for Blok, the headless Notion-like rich text editor. Composables and components that render blocks and save to JSON.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "JackUait",
7
+ "homepage": "https://blokeditor.com",
7
8
  "repository": {
8
9
  "type": "git",
9
10
  "url": "git+https://github.com/JackUait/blok.git",
10
11
  "directory": "packages/vue"
11
12
  },
13
+ "bugs": {
14
+ "url": "https://github.com/JackUait/blok/issues"
15
+ },
16
+ "keywords": [
17
+ "blok",
18
+ "vue",
19
+ "vue3",
20
+ "vue-component",
21
+ "block-editor",
22
+ "rich-text-editor",
23
+ "wysiwyg",
24
+ "editor",
25
+ "notion",
26
+ "notion-like",
27
+ "headless",
28
+ "block-based",
29
+ "contenteditable",
30
+ "json",
31
+ "typescript"
32
+ ],
12
33
  "type": "module",
13
34
  "sideEffects": false,
14
35
  "main": "./dist/index.cjs",
@@ -33,7 +54,7 @@
33
54
  "build": "yarn run -T vite build --mode production"
34
55
  },
35
56
  "peerDependencies": {
36
- "@bloklabs/core": "^1.3.0",
57
+ "@bloklabs/core": "^1.4.1",
37
58
  "vue": "^3.5.0"
38
59
  }
39
60
  }
package/src/BlokEditor.ts CHANGED
@@ -45,7 +45,9 @@ export const BlokEditor = defineComponent({
45
45
  data: { type: Object as PropType<OutputData>, default: undefined },
46
46
  minHeight: { type: Number, default: undefined },
47
47
  logLevel: { type: String as PropType<BlokConfig['logLevel']>, default: undefined },
48
- readOnly: { type: Boolean as PropType<boolean | undefined>, default: undefined },
48
+ // [Boolean, Object]: the object form ({ hideControls }) must not be dropped
49
+ // or dev-warned — it always means read-only enabled (reactive contract).
50
+ readOnly: { type: [Boolean, Object] as PropType<BlokConfig['readOnly']>, default: undefined },
49
51
  i18n: { type: Object as PropType<BlokConfig['i18n']>, default: undefined },
50
52
  link: { type: Object as PropType<BlokConfig['link']>, default: undefined },
51
53
  linkPaste: { type: Object as PropType<BlokConfig['linkPaste']>, default: undefined },
@@ -64,6 +66,8 @@ export const BlokEditor = defineComponent({
64
66
  // Return-valued hook (the boolean is the "handled" signal), so it is a
65
67
  // declared prop copied into the config — not an emit-mapped callback.
66
68
  onEnter: { type: Function as PropType<BlokConfig['onEnter']>, default: undefined },
69
+ // Fire-and-forget error channel — a plain declared prop copied into config.
70
+ onError: { type: Function as PropType<BlokConfig['onError']>, default: undefined },
67
71
  /** Changing this prop's identity destroys and recreates the editor. */
68
72
  recreateKey: { type: null as unknown as PropType<unknown> },
69
73
  },
@@ -45,6 +45,7 @@ export const BLOK_EDITOR_CONFIG_KEYS = [
45
45
  'onBeforeRender',
46
46
  'onBeforePaste',
47
47
  'onEnter',
48
+ 'onError',
48
49
  ] as const satisfies readonly (keyof UseBlokConfig)[];
49
50
 
50
51
  export type BlokEditorConfigKey = (typeof BLOK_EDITOR_CONFIG_KEYS)[number];
package/src/index.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  export { useBlok } from './useBlok';
2
2
  export { useBlocks } from './useBlocks';
3
+ export { useBlokReady } from './useBlokReady';
3
4
  export { BlokContent } from './BlokContent';
4
5
  export { BlokEditor } from './BlokEditor';
5
6
  export { provideBlok, useBlokDefaults, BLOK_DEFAULT_CONFIG } from './provide-blok';
6
7
  export { createVueBlock } from './createVueBlock';
7
8
  export type { UseBlokConfig, BlokContentProps } from './types';
9
+ export type { UseBlokReadyOptions } from './useBlokReady';
8
10
  export type {
9
11
  UseBlocksApi,
10
12
  BlockNode,
package/src/types.ts CHANGED
@@ -6,7 +6,12 @@ import type { BlokConfig, Blok, EditorWidth } from '@/types';
6
6
  * reactive `width` prop.
7
7
  *
8
8
  * Reactive props (sync after mount without recreation):
9
- * - `readOnly` — calls `editor.readOnly.set(value)`
9
+ * - `readOnly` — calls `editor.readOnly.set(enabled, { hideControls })`; the
10
+ * object form's `hideControls` is live too (toggles in place — see
11
+ * `editor.readOnly.togglesInPlace`)
12
+ * - `hideToolbar` — calls `editor.toolbar.setHidden(value)` (undefined → false)
13
+ * - `inlineToolbar` — calls `editor.tools.setInlineToolbar(value)`
14
+ * (content-compared, so a fresh array with the same names is a no-op)
10
15
  * - `autofocus` — calls `editor.focus()` when changed to true
11
16
  * - `theme` — calls `editor.theme.set(value)`
12
17
  * - `width` — calls `editor.width.set(value)`
package/src/useBlok.ts CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  type BlockPortalRegistry,
20
20
  } from './block-portal-registry';
21
21
  import { setRegistry, removeRegistry } from './registry-map';
22
- import type { Blok, LooseOutputData, OutputData } from '@/types';
22
+ import type { Blok, BlokConfig, LooseOutputData, OutputData } from '@/types';
23
23
  import type { UseBlokConfig } from './types';
24
24
 
25
25
  /**
@@ -199,11 +199,31 @@ export function useBlok(
199
199
  // once the instance appears (the Vue analog of React's `editor` effect-dep).
200
200
  // `theme`/`width`/`placeholder` guard on `=== undefined` (NOT falsiness) so a
201
201
  // real `placeholder: false` (clear) still propagates.
202
+ // readOnly syncs the full normalized pair: `enabled` always, `hideControls`
203
+ // only for the object form (`readOnly.set` toggles IN PLACE — see
204
+ // `readOnly.togglesInPlace` — so no recreation is ever needed).
202
205
  watch(
203
- [editor, () => normalizeReadOnlyConfig(mergedConfig().readOnly).enabled],
204
- ([ed, readOnlyEnabled]) => {
206
+ [
207
+ editor,
208
+ () => normalizeReadOnlyConfig(mergedConfig().readOnly).enabled,
209
+ () => normalizeReadOnlyConfig(mergedConfig().readOnly).hideControls,
210
+ () => typeof mergedConfig().readOnly === 'object',
211
+ ],
212
+ ([ed, readOnlyEnabled, hideControls, isObjectForm]) => {
205
213
  if (ed) {
206
- void ed.readOnly.set(readOnlyEnabled);
214
+ void (isObjectForm ? ed.readOnly.set(readOnlyEnabled, { hideControls }) : ed.readOnly.set(readOnlyEnabled));
215
+ }
216
+ },
217
+ { immediate: true }
218
+ );
219
+
220
+ // hideToolbar toggles the hover toolbar and its gutter in place. Coerces
221
+ // undefined to false (like readOnly) so clearing the option propagates.
222
+ watch(
223
+ [editor, () => mergedConfig().hideToolbar],
224
+ ([ed, hideToolbar]) => {
225
+ if (ed) {
226
+ ed.toolbar.setHidden(Boolean(hideToolbar));
207
227
  }
208
228
  },
209
229
  { immediate: true }
@@ -258,6 +278,69 @@ export function useBlok(
258
278
  { immediate: true, deep: true }
259
279
  );
260
280
 
281
+ // `config.i18n` was consumed once during boot, so a host driving a language
282
+ // switcher had to recreate the editor (losing caret, focus and undo stack)
283
+ // to relabel the UI. This drives the runtime `i18n.update` API instead.
284
+ // Deep-equal-deduped and `deep: true` for the same reasons as tokens.
285
+ // `defaultLocale` is not forwarded: it only affects the INITIAL locale
286
+ // resolution, so it is inert after mount.
287
+ /*
288
+ * Seeded with the mount-time value: construction already applied it, so the
289
+ * immediate run is a no-op and only genuine changes push.
290
+ */
291
+ const appliedI18n: { value: BlokConfig['i18n'] | undefined } = { value: mergedConfig().i18n };
292
+
293
+ watch(
294
+ [editor, () => mergedConfig().i18n],
295
+ ([ed, i18n]) => {
296
+ if (!ed || i18n === undefined || deepEqual(i18n, appliedI18n.value)) {
297
+ return;
298
+ }
299
+
300
+ appliedI18n.value = { ...i18n };
301
+
302
+ const { locale, messages, direction } = i18n;
303
+
304
+ void ed.i18n.update({
305
+ ...(locale === undefined ? {} : { locale }),
306
+ ...(messages === undefined ? {} : { messages }),
307
+ ...(direction === undefined ? {} : { direction }),
308
+ });
309
+ },
310
+ { immediate: true, deep: true }
311
+ );
312
+
313
+ // inlineToolbar re-assigns inline tools in place. Content-compared (not
314
+ // identity-compared) because `boolean | string[]` configs are typically fresh
315
+ // array literals; the baseline is tracked per editor instance so a recreated
316
+ // editor gets the current value applied again. `deep: true` so mutating the
317
+ // same array still propagates (mirrors the tokens watch).
318
+ const appliedInlineToolbar: { editor: Blok | null; value: boolean | string[] | undefined } = {
319
+ editor: null,
320
+ value: undefined,
321
+ };
322
+
323
+ watch(
324
+ [editor, () => mergedConfig().inlineToolbar],
325
+ ([ed, inlineToolbar]) => {
326
+ if (!ed || inlineToolbar === undefined) {
327
+ return;
328
+ }
329
+
330
+ if (appliedInlineToolbar.editor === ed && deepEqual(inlineToolbar, appliedInlineToolbar.value)) {
331
+ return;
332
+ }
333
+
334
+ // De-proxy: copy an array so no Vue reactive proxy reaches core.
335
+ const plain = Array.isArray(inlineToolbar) ? [...inlineToolbar] : inlineToolbar;
336
+
337
+ appliedInlineToolbar.editor = ed;
338
+ appliedInlineToolbar.value = plain;
339
+ ed.tools.setInlineToolbar(plain);
340
+ },
341
+ { immediate: true, deep: true }
342
+ );
343
+
261
344
  watch(
262
345
  [editor, () => mergedConfig().autofocus],
263
346
  ([ed, autofocus]) => {
@@ -0,0 +1,70 @@
1
+ // packages/vue/src/useBlokReady.ts
2
+ import {
3
+ onMounted,
4
+ onScopeDispose,
5
+ shallowRef,
6
+ toValue,
7
+ type MaybeRefOrGetter,
8
+ type ShallowRef,
9
+ } from 'vue';
10
+
11
+ import { Blok as BlokRuntime } from '@bloklabs/core';
12
+
13
+ /** Options accepted by {@link useBlokReady}. */
14
+ export interface UseBlokReadyOptions {
15
+ /**
16
+ * Restrict the wait to editors mounted inside this element. Accepts the
17
+ * template ref you already hold on the container (or a getter); it is
18
+ * re-read on every readiness change, so a ref that fills in on mount is
19
+ * picked up.
20
+ *
21
+ * Omit it to observe every editor on the page. Passing it while it still
22
+ * resolves to null reports NOT ready — an unresolved scope must never fall
23
+ * back to the page-global one.
24
+ */
25
+ within?: MaybeRefOrGetter<Element | null | undefined>;
26
+ /**
27
+ * `'ready'` (default) settles when each editor has finished booting.
28
+ * `'rendered'` also waits for its content to be in the DOM and re-arms on
29
+ * every post-boot re-render.
30
+ */
31
+ settleOn?: 'ready' | 'rendered';
32
+ }
33
+
34
+ /**
35
+ * Vue composable exposing the live readiness of the Blok editors in a DOM
36
+ * scope as a boolean ref.
37
+ *
38
+ * The readiness logic itself is framework-agnostic and lives in core
39
+ * (`Blok.readyState` / `Blok.subscribeReady`) — the SAME implementation behind
40
+ * React's `useBlokReady` and Angular's `injectBlokReady`, so the three adapters
41
+ * cannot drift. This composable supplies only Vue's reactivity wrapper: a
42
+ * `shallowRef` re-read on every registry change, with the subscription
43
+ * disposed by the surrounding effect scope.
44
+ *
45
+ * The ref starts `false` and takes its first real reading on mount, once the
46
+ * template ref has filled in. Over-waiting is safe; under-waiting is a bug.
47
+ * @param options - scope and readiness depth
48
+ */
49
+ export function useBlokReady(options: UseBlokReadyOptions = {}): Readonly<ShallowRef<boolean>> {
50
+ const { within, settleOn } = options;
51
+ const ready = shallowRef(false);
52
+
53
+ const read = (): void => {
54
+ const scope = within === undefined ? null : (toValue(within) ?? null);
55
+
56
+ // A scope that was asked for but has not resolved yet is NOT the global
57
+ // scope — reporting ready here would gate on the wrong set of editors.
58
+ ready.value = within !== undefined && scope === null
59
+ ? false
60
+ : BlokRuntime.readyState({
61
+ within: scope,
62
+ settleOn,
63
+ }).ready;
64
+ };
65
+
66
+ onScopeDispose(BlokRuntime.subscribeReady(read));
67
+ onMounted(read);
68
+
69
+ return ready;
70
+ }
package/types/index.d.ts CHANGED
@@ -22,11 +22,22 @@ import type { MarkdownImportConfig } from '@bloklabs/core/markdown';
22
22
  * plus a reactive `width` prop.
23
23
  *
24
24
  * Reactive props (sync after mount without recreation):
25
- * - `readOnly` — calls `editor.readOnly.set(value)`
25
+ * - `readOnly` — calls `editor.readOnly.set(enabled, { hideControls })`; the
26
+ * object form's `hideControls` is live too (toggles in place — see
27
+ * `editor.readOnly.togglesInPlace`)
28
+ * - `hideToolbar` — calls `editor.toolbar.setHidden(value)` (undefined → false)
29
+ * - `inlineToolbar` — calls `editor.tools.setInlineToolbar(value)`
30
+ * (content-compared, so a fresh array with the same names is a no-op)
26
31
  * - `autofocus` — calls `editor.focus()` when changed to true
27
32
  * - `theme` — calls `editor.theme.set(value)`
28
33
  * - `width` — calls `editor.width.set(value)`
29
34
  * - `placeholder` — calls `editor.placeholder.set(value)`
35
+ * - `style.tokens` — calls `editor.tokens.set(value)` (deep-equal–deduped;
36
+ * replace semantics, so pass the complete token set on each change)
37
+ * - `i18n` — calls `editor.i18n.update({ locale, messages, direction })`
38
+ * (deep-equal–deduped; relabels the editor chrome in place, so caret, focus
39
+ * and undo history survive a language switch). `defaultLocale` is not
40
+ * forwarded — it only affects the initial locale resolution.
30
41
  * - `data` — re-renders via `editor.render(value)` when content changes
31
42
  * (deep-equal–deduped and serialized; seeds the initial content at creation)
32
43
  *
@@ -437,6 +448,48 @@ export interface UseBlocksApi {
437
448
  */
438
449
  export declare function useBlocks(editor: MaybeRefOrGetter<Blok | null>): UseBlocksApi;
439
450
 
451
+ /** Options accepted by {@link useBlokReady}. */
452
+ export interface UseBlokReadyOptions {
453
+ /**
454
+ * Restrict the wait to editors mounted inside this element. Accepts the
455
+ * template ref you already hold on the container (or a getter); it is
456
+ * re-read on every readiness change, so a ref that fills in on mount is
457
+ * picked up.
458
+ *
459
+ * Omit it to observe every editor on the page. Passing it while it still
460
+ * resolves to null reports NOT ready — an unresolved scope must never fall
461
+ * back to the page-global one.
462
+ */
463
+ within?: MaybeRefOrGetter<Element | null | undefined>;
464
+ /**
465
+ * `'ready'` (default) settles when each editor has finished booting.
466
+ * `'rendered'` also waits for its content to be in the DOM and re-arms on
467
+ * every post-boot re-render.
468
+ */
469
+ settleOn?: 'ready' | 'rendered';
470
+ }
471
+
472
+ /**
473
+ * Composable exposing the live readiness of the Blok editors in a DOM scope as
474
+ * a boolean ref. Mirrors React's `useBlokReady` and Angular's
475
+ * `injectBlokReady` — all three wrap the same core registry, so they cannot
476
+ * drift.
477
+ *
478
+ * The ref starts `false` and takes its first real reading on mount, once the
479
+ * template ref has filled in. Editors mounted later re-close the gate, and with
480
+ * `settleOn: 'rendered'` so does every re-render. A scope holding no editors is
481
+ * ready.
482
+ *
483
+ * @param options - scope and readiness depth
484
+ *
485
+ * @example
486
+ * ```ts
487
+ * const list = ref<HTMLElement | null>(null);
488
+ * const ready = useBlokReady({ within: list, settleOn: 'rendered' });
489
+ * ```
490
+ */
491
+ export declare function useBlokReady(options?: UseBlokReadyOptions): Readonly<ShallowRef<boolean>>;
492
+
440
493
  /** One field of a {@link CreateVueBlockSpec.propSchema}. */
441
494
  export interface PropSchemaEntry {
442
495
  default: unknown;