@bloklabs/vue 1.3.0 → 1.4.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/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`.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},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));
186
193
  }, {
187
194
  immediate: !0,
188
195
  deep: !0
189
- }), y([n, () => i().autofocus], ([e, t]) => {
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);
215
+ }, {
216
+ immediate: !0,
217
+ deep: !0
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".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: {
@@ -450,7 +492,7 @@ var Q = r({
450
492
  return t != null && e in t;
451
493
  }, l = () => {
452
494
  let n = {};
453
- for (let t of ne) {
495
+ for (let t of re) {
454
496
  let r = e[t];
455
497
  r !== void 0 && (n[t] = r);
456
498
  }
@@ -466,8 +508,8 @@ var Q = r({
466
508
  }), c("onThemeChange") && (n.onThemeChange = (e) => {
467
509
  t("theme-change", e);
468
510
  }), n;
469
- }, u = Y(() => l(), () => e.recreateKey);
470
- y(u, (e, n, r) => {
511
+ }, u = X(() => l(), () => e.recreateKey);
512
+ b(u, (e, n, r) => {
471
513
  if (e === null) return;
472
514
  let i = [];
473
515
  if (c("onBlocksRendered")) {
@@ -483,7 +525,7 @@ var Q = r({
483
525
  });
484
526
  });
485
527
  let d = { last: null };
486
- return y(u, (e) => {
528
+ return b(u, (e) => {
487
529
  e !== null && e !== d.last && (d.last = e, t("ready", e));
488
530
  }), r({
489
531
  instance: n(() => u.value),
@@ -499,12 +541,12 @@ var Q = r({
499
541
  var t;
500
542
  return (t = u.value) == null ? void 0 : t.render(e);
501
543
  }
502
- }), () => a($, L({ editor: u.value }, o));
544
+ }), () => a($, R({ editor: u.value }, o));
503
545
  }
504
546
  });
505
547
  //#endregion
506
548
  //#region src/createVueBlock.ts
507
- function ie(e) {
549
+ function ae(e) {
508
550
  var t;
509
551
  let n = r({
510
552
  name: `VueBlock(${e.type})`,
@@ -526,26 +568,26 @@ function ie(e) {
526
568
  constructor(t) {
527
569
  var n, i;
528
570
  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());
571
+ let n = E(e.propSchema, R(R({}, this.mirror), t));
572
+ T(n, this.mirror) || (this.mirror = n, this.lastRendered = n, this.dataRef.value = n, this.flushDispatch());
531
573
  }, this.blockApi = t.block;
532
574
  let o = (n = t.config) == null ? {} : n;
533
- this.registry = o[H];
575
+ this.registry = o[U];
534
576
  let s = t.api;
535
577
  this.pointerDrag = () => {
536
578
  var e;
537
579
  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);
580
+ }, this.mirror = E(e.propSchema, v((i = t.data) == null ? {} : i)), this.lastRendered = this.mirror, this.dataRef = _(this.mirror), this.readOnlyRef = _(t.readOnly);
539
581
  let c = this.blockApi;
540
582
  this.childrenComponent = r({
541
583
  name: `VueBlockChildren(${e.type})`,
542
584
  setup() {
543
- let e = h(null), t = () => {
544
- e.value !== null && E(e.value, c.getChildren());
585
+ let e = g(null), t = () => {
586
+ e.value !== null && D(e.value, c.getChildren());
545
587
  };
546
588
  return d(t), p(t), () => a("div", {
547
589
  ref: e,
548
- [x.nestedBlocks]: ""
590
+ [S.nestedBlocks]: ""
549
591
  });
550
592
  }
551
593
  });
@@ -576,8 +618,8 @@ function ie(e) {
576
618
  }
577
619
  async setData(t) {
578
620
  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);
621
+ let r = E(e.propSchema, v(t == null ? {} : t));
622
+ return T(r, n.lastRendered) ? !0 : (n.mirror = r, n.lastRendered = r, n.dataRef.value = r, await c(), !0);
581
623
  }
582
624
  setReadOnly(e) {
583
625
  this.readOnlyRef.value = e;
@@ -613,4 +655,4 @@ function ie(e) {
613
655
  }, t.__isBlokVueBlock = !0, t;
614
656
  }
615
657
  //#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 };
658
+ 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.0",
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.0",
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 },
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;