@bloklabs/react 1.2.2 → 1.2.4
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/dist/index.cjs +1 -1
- package/dist/index.mjs +188 -136
- package/package.json +2 -2
- package/src/BlokEditor.tsx +7 -5
- package/src/block-portal-registry.ts +41 -1
- package/src/createReactBlock.tsx +48 -6
- package/src/index.ts +1 -0
- package/src/live-tool-config.ts +42 -0
- package/src/useBlok.ts +80 -12
- package/types/index.d.ts +40 -8
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`react`),t=require(`@bloklabs/core`),n=require(`@bloklabs/core/adapters`),r=require(`react/jsx-runtime`),i=require(`react-dom`);var a=new WeakMap;function o(e,t){a.set(e,t)}function s(e){return a.get(e)}function c(e){a.delete(e)}function l(e){"@babel/helpers - typeof";return l=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},l(e)}function u(e,t){if(l(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(l(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function d(e){var t=u(e,`string`);return l(t)==`symbol`?t:t+``}function f(e,t,n){return(t=d(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function p(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 m(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?p(Object(n),!0).forEach(function(t){f(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):p(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}var h=(0,e.createContext)({});function g({defaults:e,children:t}){return(0,r.jsx)(h.Provider,{value:e,children:t})}function _(){return(0,e.useContext)(h)}function v(e,t){if(Object.keys(e).length===0)return t;let n=m({},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=m(m({},e.tools),t.tools)),n}var y=`__blokPortalRegistry`,b=()=>{let e={snapshot:new Map},t=new Set,n=n=>{e.snapshot=n,t.forEach(e=>e())};return{register(t,r){let i=new Map(e.snapshot);i.set(t,r),n(i)},unregister(t){if(!e.snapshot.has(t))return;let r=new Map(e.snapshot);r.delete(t),n(r)},setProps(t,r){let i=e.snapshot.get(t);if(i===void 0)return;let a=new Map(e.snapshot);a.set(t,m(m({},i),{},{props:m(m({},i.props),r)})),n(a)},subscribe(e){return t.add(e),()=>{t.delete(e)}},getSnapshot(){return e.snapshot}}},x=new WeakMap;function S(e,t){x.set(e,t)}function C(e){return x.get(e)}function w(e){x.delete(e)}var T=e=>{if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},E=(e,t)=>t.reduce((e,t)=>{if(Array.isArray(e))return typeof t==`number`?e[t]:void 0;if(T(e))return e[t]},e),D=(e,t)=>{if(!T(e))return e;let n={};for(let[r,i]of Object.entries(e)){if(!T(i)||!T(i.config)){n[r]=i;continue}let e=new WeakSet,a=(n,i)=>{if(typeof n==`function`){let e=n;return function(...n){let a=t(),o=T(a)?a[r]:void 0,s=E(T(o)?o.config:void 0,i);return Reflect.apply(typeof s==`function`?s:e,this,n)}}if(Array.isArray(n))return e.has(n)?n:(e.add(n),n.map((e,t)=>a(e,[...i,t])));if(T(n)){if(e.has(n))return n;e.add(n);let t={};for(let[e,r]of Object.entries(n))t[e]=a(r,[...i,e]);return t}return n};n[r]=m(m({},i),{},{config:a(i.config,[])})}return n},O=(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.__isBlokReactBlock===!0)){n[i]=a;continue}let o=typeof a==`function`?{class:a}:m({},a);o.config=m(m({},(r=o.config)==null?{}:r),{},{[y]:t}),n[i]=o}return n};function k(r,i){let a=v((0,e.useContext)(h),r),[s,l]=(0,e.useState)(null),u=(0,e.useRef)(a);u.current=a;let d=(0,e.useRef)({editor:null,holder:null,destroyTimeout:null,isDestroyed:!1,isEditorReady:!1,depsToken:null}),f=(0,e.useMemo)(()=>({}),i==null?[]:i),p=(0,e.useRef)(a.data),g=(0,e.useRef)(null),_=(0,e.useRef)(a.data),y=(0,e.useRef)(Promise.resolve()),x=(0,e.useRef)(void 0);(0,e.useEffect)(()=>{if(typeof window>`u`)return;let e=d.current;if(e.destroyTimeout!==null&&(clearTimeout(e.destroyTimeout),e.destroyTimeout=null),e.editor!==null&&!e.isDestroyed&&e.depsToken===f)return e.isEditorReady&&l(e.editor),()=>{A(e,l)};if(e.editor!==null&&!e.isDestroyed){c(e.editor),w(e.editor);try{e.editor.destroy()}catch(e){}e.editor=null,e.holder=null,e.isDestroyed=!0,e.isEditorReady=!1,l(null)}let n=document.createElement(`div`);e.holder=n,e.isDestroyed=!1,e.isEditorReady=!1,e.depsToken=f;let r=u.current,i=b(),a=r.tools===void 0?void 0:O(D(r.tools,()=>u.current.tools),i),s=m(m(m({},r),a===void 0?{}:{tools:a}),{},{holder:n,onReady:(...e)=>{var t,n;(t=(n=u.current).onReady)==null||t.call(n,...e)},onChange:(...e)=>{var t,n;(t=(n=u.current).onChange)==null||t.call(n,...e)}});r.onSave&&(s.onSave=(...e)=>{var t,n;p.current=e[0],(t=(n=u.current).onSave)==null||t.call(n,...e)}),r.onBeforeRender&&(s.onBeforeRender=(...e)=>{var t,n,r;return(t=(n=(r=u.current).onBeforeRender)==null?void 0:n.call(r,...e))==null?e[0]:t}),r.onAfterRender&&(s.onAfterRender=(...e)=>{var t,n;(t=(n=u.current).onAfterRender)==null||t.call(n,...e)});let h=new t.Blok(s);return e.editor=h,_.current=r.data,o(h,n),S(h,i),h.isReady.then(()=>{e.editor===h&&!e.isDestroyed&&(e.isEditorReady=!0,l(h))}).catch(()=>{if(e.editor===h&&!e.isDestroyed){c(h),w(h);try{h.destroy()}catch(e){}e.editor=null,e.holder=null,e.isDestroyed=!0,e.isEditorReady=!1,l(null)}}),()=>{A(e,l)}},[f]);let C=(0,n.normalizeReadOnlyConfig)(a.readOnly).enabled;(0,e.useEffect)(()=>{s!==null&&s.readOnly.set(C)},[s,C]);let{autofocus:T}=a;(0,e.useEffect)(()=>{s===null||!T||s.focus()},[s,T]);let{theme:E}=a;(0,e.useEffect)(()=>{s===null||E===void 0||s.theme.set(E)},[s,E]);let{width:k}=a;(0,e.useEffect)(()=>{s===null||k===void 0||s.width.set(k)},[s,k]);let{placeholder:j}=a;(0,e.useEffect)(()=>{s===null||j===void 0||s.placeholder.set(j)},[s,j]);let{data:M}=a;return(0,e.useEffect)(()=>{if(s===null||M===void 0)return;let e=d.current;if(!(e.editor!==s||e.isDestroyed)){if(g.current!==s&&(g.current=s,x.current=void 0,(0,n.deepEqual)(M,_.current))){p.current=M;return}(0,n.deepEqual)(M,p.current)||(0,n.deepEqual)(M,x.current)||(x.current=M,y.current=y.current.catch(()=>void 0).then(()=>s.render(M)).then(()=>{p.current=M},()=>{}).then(()=>{x.current===M&&(x.current=void 0)}))}},[s,M]),s}function A(e,t){e.destroyTimeout=setTimeout(()=>{if(e.editor!==null){c(e.editor),w(e.editor);try{e.editor.destroy()}catch(e){}e.editor=null,e.holder=null,e.isDestroyed=!0,e.isEditorReady=!1,e.destroyTimeout=null,t(null)}},0)}var j=class extends e.Component{constructor(...e){super(...e),this.state={failed:!1}}static getDerivedStateFromError(){return{failed:!0}}componentDidCatch(){}render(){return this.state.failed?null:this.props.children}};function M({registry:t}){let n=(0,e.useSyncExternalStore)(t.subscribe,t.getSnapshot,t.getSnapshot);return(0,r.jsx)(r.Fragment,{children:Array.from(n.entries()).map(([e,t])=>{let n=t.component;return(0,i.createPortal)((0,r.jsx)(j,{children:(0,r.jsx)(n,m({},t.props))}),t.hostEl,e)})})}function N(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.includes(r))continue;n[r]=e[r]}return n}function P(e,t){if(e==null)return{};var n,r,i=N(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.includes(n)||{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var F=[`editor`],I=(0,e.forwardRef)(function(t,n){let{editor:i}=t,a=P(t,F),o=(0,e.useRef)(null),c=e=>{if(o.current=e,typeof n==`function`)n(e);else if(n!=null){let t=n;t.current=e}};(0,e.useEffect)(()=>{if(i===null||o.current===null)return;let e=s(i);if(e!==void 0)return o.current.appendChild(e),()=>{e.remove()}},[i]);let l=i===null?void 0:C(i);return(0,r.jsx)(`div`,m(m({ref:c},a),{},{children:l===void 0?null:(0,r.jsx)(M,{registry:l})}))}),L=`autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.onBeforePaste.onReady.onChange.onSave.onBeforeRender.onAfterRender.inlineToolbar.tunes.style.theme.onThemeChange.scrollToBlock.user.resolveUser.notifierPosition.notifier.width`.split(`.`),R=[`deps`,`onReady`,`onBlocksRendered`,`onBlockRendered`],z=new Set(L),B=(0,e.forwardRef)(function(t,n){let{deps:i,onReady:a,onBlocksRendered:o,onBlockRendered:s}=t,c=P(t,R),l={},u={};for(let e of Object.keys(c)){let t=c[e];z.has(e)?l[e]=t:u[e]=t}let d=k(l,i);(0,e.useImperativeHandle)(n,()=>d,[d]);let f=(0,e.useRef)(a);f.current=a,(0,e.useEffect)(()=>{if(d!==null){var e;(e=f.current)==null||e.call(f,d)}},[d]);let p=(0,e.useRef)(o);p.current=o;let h=(0,e.useRef)(s);h.current=s;let g=!!o,_=!!s;return(0,e.useEffect)(()=>{if(d===null)return;let e=[];if(g){let t=e=>{var t;return(t=p.current)==null?void 0:t.call(p,e)};d.on(`blocks:rendered`,t),e.push([`blocks:rendered`,t])}if(_){let t=e=>{var t;return(t=h.current)==null?void 0:t.call(h,e)};d.on(`block:rendered`,t),e.push([`block:rendered`,t])}return()=>{for(let[t,n]of e)d.off(t,n)}},[d,g,_]),(0,r.jsx)(I,m({editor:d},u))}),V=`block changed`;function H(t){let r=(0,e.useRef)(0),i=(0,e.useRef)(t);i.current!==t&&(i.current=t,r.current=0);let a=(0,e.useCallback)(e=>{if(t===null)return()=>void 0;let n=()=>{r.current+=1,e()};return t.on(V,n),()=>t.off(V,n)},[t]),o=(0,e.useCallback)(()=>r.current,[]);return(0,e.useSyncExternalStore)(a,o,o),(0,e.useMemo)(()=>t===null?n.EMPTY_API:(0,n.createBlocksApiForEditor)(t),[t])}function U(t){var a;return a=class{static get toolbox(){return t.toolbox}static get isReadOnlySupported(){return!0}constructor(i){var a,o;this.hostEl=null,this.pendingDispatch=!1,this.commit=e=>{var r;let i=(0,n.fillDefaults)(t.propSchema,m(m({},this.mirror),e));this.mirror=i,this.lastRendered=i,(r=this.registry)==null||r.setProps(this.blockApi.id,{data:i}),this.flushDispatch()},this.blockApi=i.block;let s=(a=i.config)==null?{}:a;this.registry=s[y];let c=i.api;this.pointerDrag=()=>{var e;return(c==null||(e=c.blocks)==null?void 0:e.isPointerDragActive)===!0},this.mirror=(0,n.fillDefaults)(t.propSchema,(o=i.data)==null?{}:o),this.lastRendered=this.mirror,this.readOnly=i.readOnly;let l=this.blockApi;this.childrenComponent=function(){let t=(0,e.useRef)(null);return(0,e.useEffect)(()=>{t.current!==null&&(0,n.mountChildBlocks)(t.current,l.getChildren())}),(0,r.jsx)(`div`,{ref:t,[n.DATA_ATTR.nestedBlocks]:``})}}render(){var e;let n=document.createElement(`div`);return n.setAttribute(`data-blok-mutation-free`,`true`),this.hostEl=n,(e=this.registry)==null||e.register(this.blockApi.id,{hostEl:n,component:t.component,props:this.buildProps()}),n}rendered(){var e;(e=t.onRendered)==null||e.call(t,this.blockApi)}save(){return this.mirror}async setData(e){var r=this;let i=(0,n.fillDefaults)(t.propSchema,e==null?{}:e);return(0,n.deepEqual)(i,r.lastRendered)?!0:(r.mirror=i,r.lastRendered=i,r.pushProps({data:i}),!0)}setReadOnly(e){this.readOnly=e,this.pushProps({readOnly: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)}buildProps(){return{data:this.mirror,commit:this.commit,block:this.blockApi,readOnly:this.readOnly,BlockChildren:this.childrenComponent}}pushProps(e){let t=this.registry;t!==void 0&&(0,i.flushSync)(()=>{t.setProps(this.blockApi.id,e)})}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)}},a.__isBlokReactBlock=!0,a}exports.BLOK_PORTAL_REGISTRY_CONFIG_KEY=y,exports.BlockPortalHost=M,exports.BlokContent=I,exports.BlokEditor=B,exports.BlokProvider=g,exports.createBlockPortalRegistry=b,exports.createReactBlock=U,exports.useBlocks=H,exports.useBlok=k,exports.useBlokDefaults=_;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`react`),t=require(`@bloklabs/core`),n=require(`@bloklabs/core/adapters`),r=require(`react/jsx-runtime`),i=require(`react-dom`);var a=new WeakMap;function o(e,t){a.set(e,t)}function s(e){return a.get(e)}function c(e){a.delete(e)}function l(e){"@babel/helpers - typeof";return l=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},l(e)}function u(e,t){if(l(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(l(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function d(e){var t=u(e,`string`);return l(t)==`symbol`?t:t+``}function f(e,t,n){return(t=d(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function p(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 m(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?p(Object(n),!0).forEach(function(t){f(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):p(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}var h=(0,e.createContext)({});function g({defaults:e,children:t}){return(0,r.jsx)(h.Provider,{value:e,children:t})}function _(){return(0,e.useContext)(h)}function v(e,t){if(Object.keys(e).length===0)return t;let n=m({},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=m(m({},e.tools),t.tools)),n}var y=`__blokPortalRegistry`,b=`__blokToolName`,x=()=>{let e={snapshot:new Map},t=new Set,n=new Map,r=n=>{e.snapshot=n,t.forEach(e=>e())};return{register(t,i){let a=new Map(e.snapshot),o=i.toolName===void 0?void 0:n.get(i.toolName);a.set(t,o===void 0?i:m(m({},i),{},{props:m(m({},i.props),{},{config:o})})),r(a)},unregister(t){if(!e.snapshot.has(t))return;let n=new Map(e.snapshot);n.delete(t),r(n)},setProps(t,n){let i=e.snapshot.get(t);if(i===void 0)return;let a=new Map(e.snapshot);a.set(t,m(m({},i),{},{props:m(m({},i.props),n)})),r(a)},setToolConfig(t,i){n.set(t,i);let a=[...e.snapshot].filter(([,e])=>e.toolName===t);if(a.length===0)return;let o=new Map(e.snapshot);for(let[e,t]of a)o.set(e,m(m({},t),{},{props:m(m({},t.props),{},{config:i})}));r(o)},subscribe(e){return t.add(e),()=>{t.delete(e)}},getSnapshot(){return e.snapshot}}},S=new WeakMap;function C(e,t){S.set(e,t)}function w(e){return S.get(e)}function T(e){S.delete(e)}var E=e=>{if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},D=(e,t)=>t.reduce((e,t)=>{if(Array.isArray(e))return typeof t==`number`?e[t]:void 0;if(E(e))return e[t]},e),O=(e,t)=>{let n=(e,t)=>{if(typeof e==`function`)return typeof t==`function`?t:e;if(Array.isArray(e)){let r=Array.isArray(t)?t:[];return e.map((e,t)=>n(e,r[t]))}if(E(e)){let r=E(t)?t:{},i={};for(let[t,a]of Object.entries(e))i[t]=n(a,r[t]);return i}return e},r=n(t,e);return E(r)?r:{}},k=(e,t)=>{if(!E(e))return e;let n={};for(let[r,i]of Object.entries(e)){if(!E(i)||!E(i.config)){n[r]=i;continue}let e=new WeakSet,a=(n,i)=>{if(typeof n==`function`){let e=n;return function(...n){let a=t(),o=E(a)?a[r]:void 0,s=D(E(o)?o.config:void 0,i);return Reflect.apply(typeof s==`function`?s:e,this,n)}}if(Array.isArray(n))return e.has(n)?n:(e.add(n),n.map((e,t)=>a(e,[...i,t])));if(E(n)){if(e.has(n))return n;e.add(n);let t={};for(let[e,r]of Object.entries(n))t[e]=a(r,[...i,e]);return t}return n};n[r]=m(m({},i),{},{config:a(i.config,[])})}return n},A=e=>{let t=typeof e==`function`?e:e==null?void 0:e.class;return typeof t==`function`&&t.__isBlokReactBlock===!0},j=(e,t)=>{if(typeof e!=`object`||!e)return e;let n={};for(let[i,a]of Object.entries(e)){var r;if(!A(a)){n[i]=a;continue}let e=typeof a==`function`?{class:a}:m({},a);e.config=m(m({},(r=e.config)==null?{}:r),{},{[y]:t,[b]:i}),n[i]=e}return n};function M(r,i){let a=v((0,e.useContext)(h),r),[s,l]=(0,e.useState)(null),u=(0,e.useRef)(a);u.current=a;let d=(0,e.useRef)({editor:null,holder:null,destroyTimeout:null,isDestroyed:!1,isEditorReady:!1,depsToken:null}),f=(0,e.useMemo)(()=>({}),i==null?[]:i),p=(0,e.useRef)(a.data),g=(0,e.useRef)(null),_=(0,e.useRef)(a.data),y=(0,e.useRef)(Promise.resolve()),b=(0,e.useRef)(void 0),S=(0,e.useRef)(null),w=(0,e.useRef)(void 0),E=(0,e.useRef)(new Map);(0,e.useEffect)(()=>{if(typeof window>`u`)return;let e=d.current;if(e.destroyTimeout!==null&&(clearTimeout(e.destroyTimeout),e.destroyTimeout=null),e.editor!==null&&!e.isDestroyed&&e.depsToken===f)return e.isEditorReady&&l(e.editor),()=>{N(e,l)};if(e.editor!==null&&!e.isDestroyed){c(e.editor),T(e.editor);try{e.editor.destroy()}catch(e){}e.editor=null,e.holder=null,e.isDestroyed=!0,e.isEditorReady=!1,l(null)}let n=document.createElement(`div`);e.holder=n,e.isDestroyed=!1,e.isEditorReady=!1,e.depsToken=f;let r=u.current,i=x(),a=r.tools===void 0?void 0:k(r.tools,()=>u.current.tools),s=a===void 0?void 0:j(a,i);S.current=i,w.current=a,E.current=new Map;let h=m(m(m({},r),s===void 0?{}:{tools:s}),{},{holder:n,onReady:(...e)=>{var t,n;(t=(n=u.current).onReady)==null||t.call(n,...e)},onChange:(...e)=>{var t,n;(t=(n=u.current).onChange)==null||t.call(n,...e)}});r.onSave&&(h.onSave=(...e)=>{var t,n;p.current=e[0],(t=(n=u.current).onSave)==null||t.call(n,...e)}),r.onBeforeRender&&(h.onBeforeRender=(...e)=>{var t,n,r;return(t=(n=(r=u.current).onBeforeRender)==null?void 0:n.call(r,...e))==null?e[0]:t}),r.onAfterRender&&(h.onAfterRender=(...e)=>{var t,n;(t=(n=u.current).onAfterRender)==null||t.call(n,...e)});let g=new t.Blok(h);return e.editor=g,_.current=r.data,o(g,n),C(g,i),g.isReady.then(()=>{e.editor===g&&!e.isDestroyed&&(e.isEditorReady=!0,l(g))}).catch(()=>{if(e.editor===g&&!e.isDestroyed){c(g),T(g);try{g.destroy()}catch(e){}e.editor=null,e.holder=null,e.isDestroyed=!0,e.isEditorReady=!1,l(null)}}),()=>{N(e,l)}},[f]),(0,e.useEffect)(()=>{let e=S.current,t=d.current;if(e===null||t.editor===null||t.isDestroyed)return;let r=u.current.tools;if(typeof r!=`object`||!r)return;let i=w.current;for(let[t,o]of Object.entries(r)){var a;if(!A(o))continue;let r=typeof o==`function`||(a=o.config)==null?{}:a,s=i==null?void 0:i[t],c=O(typeof s==`object`&&s?s.config:void 0,r),l=E.current.get(t);if(l!==void 0&&(0,n.deepEqual)(c,l))continue;let u=Object.freeze(c);E.current.set(t,u),e.setToolConfig(t,u)}});let D=(0,n.normalizeReadOnlyConfig)(a.readOnly).enabled;(0,e.useEffect)(()=>{s!==null&&s.readOnly.set(D)},[s,D]);let{autofocus:M}=a;(0,e.useEffect)(()=>{s===null||!M||s.focus()},[s,M]);let{theme:P}=a;(0,e.useEffect)(()=>{s===null||P===void 0||s.theme.set(P)},[s,P]);let{width:F}=a;(0,e.useEffect)(()=>{s===null||F===void 0||s.width.set(F)},[s,F]);let{placeholder:I}=a;(0,e.useEffect)(()=>{s===null||I===void 0||s.placeholder.set(I)},[s,I]);let{data:L}=a;return(0,e.useEffect)(()=>{if(s===null||L===void 0)return;let e=d.current;if(!(e.editor!==s||e.isDestroyed)){if(g.current!==s&&(g.current=s,b.current=void 0,(0,n.deepEqual)(L,_.current))){p.current=L;return}(0,n.deepEqual)(L,p.current)||(0,n.deepEqual)(L,b.current)||(b.current=L,y.current=y.current.catch(()=>void 0).then(()=>s.render(L)).then(()=>{p.current=L},()=>{}).then(()=>{b.current===L&&(b.current=void 0)}))}},[s,L]),s}function N(e,t){e.destroyTimeout=setTimeout(()=>{if(e.editor!==null){c(e.editor),T(e.editor);try{e.editor.destroy()}catch(e){}e.editor=null,e.holder=null,e.isDestroyed=!0,e.isEditorReady=!1,e.destroyTimeout=null,t(null)}},0)}var P=class extends e.Component{constructor(...e){super(...e),this.state={failed:!1}}static getDerivedStateFromError(){return{failed:!0}}componentDidCatch(){}render(){return this.state.failed?null:this.props.children}};function F({registry:t}){let n=(0,e.useSyncExternalStore)(t.subscribe,t.getSnapshot,t.getSnapshot);return(0,r.jsx)(r.Fragment,{children:Array.from(n.entries()).map(([e,t])=>{let n=t.component;return(0,i.createPortal)((0,r.jsx)(P,{children:(0,r.jsx)(n,m({},t.props))}),t.hostEl,e)})})}function I(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.includes(r))continue;n[r]=e[r]}return n}function L(e,t){if(e==null)return{};var n,r,i=I(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.includes(n)||{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var R=[`editor`],z=(0,e.forwardRef)(function(t,n){let{editor:i}=t,a=L(t,R),o=(0,e.useRef)(null),c=e=>{if(o.current=e,typeof n==`function`)n(e);else if(n!=null){let t=n;t.current=e}};(0,e.useEffect)(()=>{if(i===null||o.current===null)return;let e=s(i);if(e!==void 0)return o.current.appendChild(e),()=>{e.remove()}},[i]);let l=i===null?void 0:w(i);return(0,r.jsx)(`div`,m(m({ref:c},a),{},{children:l===void 0?null:(0,r.jsx)(F,{registry:l})}))}),B=`autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.onBeforePaste.onReady.onChange.onSave.onBeforeRender.onAfterRender.inlineToolbar.tunes.style.theme.onThemeChange.scrollToBlock.user.resolveUser.notifierPosition.notifier.width`.split(`.`),V=[`deps`,`onReady`,`onBlocksRendered`,`onBlockRendered`],H=new Set(B),U=(0,e.forwardRef)(function(t,n){let{deps:i,onReady:a,onBlocksRendered:o,onBlockRendered:s}=t,c=L(t,V),l={},u={};for(let e of Object.keys(c)){let t=c[e];H.has(e)?l[e]=t:u[e]=t}let d=M(l,i);(0,e.useImperativeHandle)(n,()=>d,[d]);let f=(0,e.useRef)(a);f.current=a,(0,e.useEffect)(()=>{if(d!==null){var e;(e=f.current)==null||e.call(f,d)}},[d]);let p=(0,e.useRef)(o);p.current=o;let h=(0,e.useRef)(s);h.current=s;let g=!!o,_=!!s;return(0,e.useEffect)(()=>{if(d===null)return;let e=[];if(g){let t=e=>{var t;return(t=p.current)==null?void 0:t.call(p,e)};d.on(`blocks:rendered`,t),e.push([`blocks:rendered`,t])}if(_){let t=e=>{var t;return(t=h.current)==null?void 0:t.call(h,e)};d.on(`block:rendered`,t),e.push([`block:rendered`,t])}return()=>{for(let[t,n]of e)d.off(t,n)}},[d,g,_]),(0,r.jsx)(z,m({editor:d},u))}),W=`block changed`;function G(t){let r=(0,e.useRef)(0),i=(0,e.useRef)(t);i.current!==t&&(i.current=t,r.current=0);let a=(0,e.useCallback)(e=>{if(t===null)return()=>void 0;let n=()=>{r.current+=1,e()};return t.on(W,n),()=>t.off(W,n)},[t]),o=(0,e.useCallback)(()=>r.current,[]);return(0,e.useSyncExternalStore)(a,o,o),(0,e.useMemo)(()=>t===null?n.EMPTY_API:(0,n.createBlocksApiForEditor)(t),[t])}var K=[y,b];function q(t){var a;return a=class{static get toolbox(){return t.toolbox}static get isReadOnlySupported(){return!0}constructor(i){var a,o;this.hostEl=null,this.pendingDispatch=!1,this.commit=e=>{var r;let i=(0,n.fillDefaults)(t.propSchema,m(m({},this.mirror),e));(0,n.deepEqual)(i,this.mirror)||(this.mirror=i,this.lastRendered=i,(r=this.registry)==null||r.setProps(this.blockApi.id,{data:i}),this.flushDispatch())},this.blockApi=i.block;let s=(a=i.config)==null?{}:a;this.registry=s[y];let c=s[b];this.toolName=typeof c==`string`?c:void 0;let l={};for(let[e,t]of Object.entries(s))K.includes(e)||(l[e]=t);this.toolConfig=Object.freeze(l);let u=i.api;this.pointerDrag=()=>{var e;return(u==null||(e=u.blocks)==null?void 0:e.isPointerDragActive)===!0},this.mirror=(0,n.fillDefaults)(t.propSchema,(o=i.data)==null?{}:o),this.lastRendered=this.mirror,this.readOnly=i.readOnly;let d=this.blockApi;this.childrenComponent=function(){let t=(0,e.useRef)(null);return(0,e.useEffect)(()=>{t.current!==null&&(0,n.mountChildBlocks)(t.current,d.getChildren())}),(0,r.jsx)(`div`,{ref:t,[n.DATA_ATTR.nestedBlocks]:``})}}render(){var e;let n=document.createElement(`div`);return n.setAttribute(`data-blok-mutation-free`,`true`),this.hostEl=n,(e=this.registry)==null||e.register(this.blockApi.id,{hostEl:n,component:t.component,props:this.buildProps(),toolName:this.toolName}),n}rendered(){var e;(e=t.onRendered)==null||e.call(t,this.blockApi)}save(){return this.mirror}async setData(e){var r=this;let i=(0,n.fillDefaults)(t.propSchema,e==null?{}:e);return(0,n.deepEqual)(i,r.lastRendered)?!0:(r.mirror=i,r.lastRendered=i,r.pushProps({data:i}),!0)}setReadOnly(e){this.readOnly=e,this.pushProps({readOnly: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)}buildProps(){return{data:this.mirror,commit:this.commit,block:this.blockApi,readOnly:this.readOnly,config:this.toolConfig,BlockChildren:this.childrenComponent}}pushProps(e){let t=this.registry;t!==void 0&&(0,i.flushSync)(()=>{t.setProps(this.blockApi.id,e)})}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)}},a.__isBlokReactBlock=!0,a}exports.BLOK_PORTAL_REGISTRY_CONFIG_KEY=y,exports.BLOK_TOOL_NAME_CONFIG_KEY=b,exports.BlockPortalHost=F,exports.BlokContent=z,exports.BlokEditor=U,exports.BlokProvider=g,exports.createBlockPortalRegistry=x,exports.createReactBlock=q,exports.useBlocks=G,exports.useBlok=M,exports.useBlokDefaults=_;
|
package/dist/index.mjs
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
1
|
import { Component as e, createContext as t, forwardRef as n, useCallback as r, useContext as i, useEffect as a, useImperativeHandle as o, useMemo as s, useRef as c, useState as l, useSyncExternalStore as u } from "react";
|
|
2
2
|
import { Blok as d } from "@bloklabs/core";
|
|
3
|
-
import { DATA_ATTR as f, EMPTY_API as p, createBlocksApiForEditor as m, deepEqual as h, deepEqual as g, fillDefaults as _, mountChildBlocks as v, normalizeReadOnlyConfig as
|
|
4
|
-
import { Fragment as
|
|
5
|
-
import { createPortal as
|
|
3
|
+
import { DATA_ATTR as f, EMPTY_API as p, createBlocksApiForEditor as m, deepEqual as h, deepEqual as g, fillDefaults as _, mountChildBlocks as v, normalizeReadOnlyConfig as y } from "@bloklabs/core/adapters";
|
|
4
|
+
import { Fragment as b, jsx as x } from "react/jsx-runtime";
|
|
5
|
+
import { createPortal as S, flushSync as C } from "react-dom";
|
|
6
6
|
//#region src/holder-map.ts
|
|
7
|
-
var
|
|
8
|
-
function
|
|
9
|
-
|
|
7
|
+
var w = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
function T(e, t) {
|
|
9
|
+
w.set(e, t);
|
|
10
10
|
}
|
|
11
|
-
function
|
|
12
|
-
return
|
|
11
|
+
function E(e) {
|
|
12
|
+
return w.get(e);
|
|
13
13
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
14
|
+
function D(e) {
|
|
15
|
+
w.delete(e);
|
|
16
16
|
}
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region \0@oxc-project+runtime@0.126.0/helpers/typeof.js
|
|
19
|
-
function
|
|
19
|
+
function O(e) {
|
|
20
20
|
"@babel/helpers - typeof";
|
|
21
|
-
return
|
|
21
|
+
return O = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(e) {
|
|
22
22
|
return typeof e;
|
|
23
23
|
} : function(e) {
|
|
24
24
|
return e && typeof Symbol == "function" && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e;
|
|
25
|
-
},
|
|
25
|
+
}, O(e);
|
|
26
26
|
}
|
|
27
27
|
//#endregion
|
|
28
28
|
//#region \0@oxc-project+runtime@0.126.0/helpers/toPrimitive.js
|
|
29
|
-
function
|
|
30
|
-
if (
|
|
29
|
+
function k(e, t) {
|
|
30
|
+
if (O(e) != "object" || !e) return e;
|
|
31
31
|
var n = e[Symbol.toPrimitive];
|
|
32
32
|
if (n !== void 0) {
|
|
33
33
|
var r = n.call(e, t || "default");
|
|
34
|
-
if (
|
|
34
|
+
if (O(r) != "object") return r;
|
|
35
35
|
throw TypeError("@@toPrimitive must return a primitive value.");
|
|
36
36
|
}
|
|
37
37
|
return (t === "string" ? String : Number)(e);
|
|
38
38
|
}
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region \0@oxc-project+runtime@0.126.0/helpers/toPropertyKey.js
|
|
41
|
-
function
|
|
42
|
-
var t =
|
|
43
|
-
return
|
|
41
|
+
function A(e) {
|
|
42
|
+
var t = k(e, "string");
|
|
43
|
+
return O(t) == "symbol" ? t : t + "";
|
|
44
44
|
}
|
|
45
45
|
//#endregion
|
|
46
46
|
//#region \0@oxc-project+runtime@0.126.0/helpers/defineProperty.js
|
|
47
|
-
function
|
|
48
|
-
return (t =
|
|
47
|
+
function j(e, t, n) {
|
|
48
|
+
return (t = A(t)) in e ? Object.defineProperty(e, t, {
|
|
49
49
|
value: n,
|
|
50
50
|
enumerable: !0,
|
|
51
51
|
configurable: !0,
|
|
@@ -54,7 +54,7 @@ function k(e, t, n) {
|
|
|
54
54
|
}
|
|
55
55
|
//#endregion
|
|
56
56
|
//#region \0@oxc-project+runtime@0.126.0/helpers/objectSpread2.js
|
|
57
|
-
function
|
|
57
|
+
function M(e, t) {
|
|
58
58
|
var n = Object.keys(e);
|
|
59
59
|
if (Object.getOwnPropertySymbols) {
|
|
60
60
|
var r = Object.getOwnPropertySymbols(e);
|
|
@@ -64,12 +64,12 @@ function A(e, t) {
|
|
|
64
64
|
}
|
|
65
65
|
return n;
|
|
66
66
|
}
|
|
67
|
-
function
|
|
67
|
+
function N(e) {
|
|
68
68
|
for (var t = 1; t < arguments.length; t++) {
|
|
69
69
|
var n = arguments[t] == null ? {} : arguments[t];
|
|
70
|
-
t % 2 ?
|
|
71
|
-
|
|
72
|
-
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) :
|
|
70
|
+
t % 2 ? M(Object(n), !0).forEach(function(t) {
|
|
71
|
+
j(e, t, n[t]);
|
|
72
|
+
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : M(Object(n)).forEach(function(t) {
|
|
73
73
|
Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(n, t));
|
|
74
74
|
});
|
|
75
75
|
}
|
|
@@ -77,46 +77,54 @@ function j(e) {
|
|
|
77
77
|
}
|
|
78
78
|
//#endregion
|
|
79
79
|
//#region src/provide-blok.tsx
|
|
80
|
-
var
|
|
81
|
-
function
|
|
82
|
-
return /* @__PURE__ */
|
|
80
|
+
var P = t({});
|
|
81
|
+
function F({ defaults: e, children: t }) {
|
|
82
|
+
return /* @__PURE__ */ x(P.Provider, {
|
|
83
83
|
value: e,
|
|
84
84
|
children: t
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
function
|
|
88
|
-
return i(
|
|
87
|
+
function I() {
|
|
88
|
+
return i(P);
|
|
89
89
|
}
|
|
90
|
-
function
|
|
90
|
+
function ee(e, t) {
|
|
91
91
|
if (Object.keys(e).length === 0) return t;
|
|
92
|
-
let n =
|
|
92
|
+
let n = N({}, e);
|
|
93
93
|
for (let e of Object.keys(t)) {
|
|
94
94
|
let r = t[e];
|
|
95
95
|
r !== void 0 && (n[e] = r);
|
|
96
96
|
}
|
|
97
|
-
return (e.tools !== void 0 || t.tools !== void 0) && (n.tools =
|
|
97
|
+
return (e.tools !== void 0 || t.tools !== void 0) && (n.tools = N(N({}, e.tools), t.tools)), n;
|
|
98
98
|
}
|
|
99
99
|
//#endregion
|
|
100
100
|
//#region src/block-portal-registry.ts
|
|
101
|
-
var
|
|
102
|
-
let e = { snapshot: /* @__PURE__ */ new Map() }, t = /* @__PURE__ */ new Set(), n = (n) => {
|
|
101
|
+
var L = "__blokPortalRegistry", R = "__blokToolName", z = () => {
|
|
102
|
+
let e = { snapshot: /* @__PURE__ */ new Map() }, t = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Map(), r = (n) => {
|
|
103
103
|
e.snapshot = n, t.forEach((e) => e());
|
|
104
104
|
};
|
|
105
105
|
return {
|
|
106
|
-
register(t,
|
|
107
|
-
let
|
|
108
|
-
|
|
106
|
+
register(t, i) {
|
|
107
|
+
let a = new Map(e.snapshot), o = i.toolName === void 0 ? void 0 : n.get(i.toolName);
|
|
108
|
+
a.set(t, o === void 0 ? i : N(N({}, i), {}, { props: N(N({}, i.props), {}, { config: o }) })), r(a);
|
|
109
109
|
},
|
|
110
110
|
unregister(t) {
|
|
111
111
|
if (!e.snapshot.has(t)) return;
|
|
112
|
-
let
|
|
113
|
-
|
|
112
|
+
let n = new Map(e.snapshot);
|
|
113
|
+
n.delete(t), r(n);
|
|
114
114
|
},
|
|
115
|
-
setProps(t,
|
|
115
|
+
setProps(t, n) {
|
|
116
116
|
let i = e.snapshot.get(t);
|
|
117
117
|
if (i === void 0) return;
|
|
118
118
|
let a = new Map(e.snapshot);
|
|
119
|
-
a.set(t,
|
|
119
|
+
a.set(t, N(N({}, i), {}, { props: N(N({}, i.props), n) })), r(a);
|
|
120
|
+
},
|
|
121
|
+
setToolConfig(t, i) {
|
|
122
|
+
n.set(t, i);
|
|
123
|
+
let a = [...e.snapshot].filter(([, e]) => e.toolName === t);
|
|
124
|
+
if (a.length === 0) return;
|
|
125
|
+
let o = new Map(e.snapshot);
|
|
126
|
+
for (let [e, t] of a) o.set(e, N(N({}, t), {}, { props: N(N({}, t.props), {}, { config: i }) }));
|
|
127
|
+
r(o);
|
|
120
128
|
},
|
|
121
129
|
subscribe(e) {
|
|
122
130
|
return t.add(e), () => {
|
|
@@ -127,30 +135,45 @@ var I = "__blokPortalRegistry", L = () => {
|
|
|
127
135
|
return e.snapshot;
|
|
128
136
|
}
|
|
129
137
|
};
|
|
130
|
-
},
|
|
131
|
-
function
|
|
132
|
-
|
|
138
|
+
}, B = /* @__PURE__ */ new WeakMap();
|
|
139
|
+
function V(e, t) {
|
|
140
|
+
B.set(e, t);
|
|
133
141
|
}
|
|
134
|
-
function
|
|
135
|
-
return
|
|
142
|
+
function H(e) {
|
|
143
|
+
return B.get(e);
|
|
136
144
|
}
|
|
137
|
-
function
|
|
138
|
-
|
|
145
|
+
function U(e) {
|
|
146
|
+
B.delete(e);
|
|
139
147
|
}
|
|
140
148
|
//#endregion
|
|
141
149
|
//#region src/live-tool-config.ts
|
|
142
|
-
var
|
|
150
|
+
var W = (e) => {
|
|
143
151
|
if (typeof e != "object" || !e) return !1;
|
|
144
152
|
let t = Object.getPrototypeOf(e);
|
|
145
153
|
return t === Object.prototype || t === null;
|
|
146
|
-
},
|
|
154
|
+
}, G = (e, t) => t.reduce((e, t) => {
|
|
147
155
|
if (Array.isArray(e)) return typeof t == "number" ? e[t] : void 0;
|
|
148
|
-
if (
|
|
149
|
-
}, e),
|
|
150
|
-
|
|
156
|
+
if (W(e)) return e[t];
|
|
157
|
+
}, e), K = (e, t) => {
|
|
158
|
+
let n = (e, t) => {
|
|
159
|
+
if (typeof e == "function") return typeof t == "function" ? t : e;
|
|
160
|
+
if (Array.isArray(e)) {
|
|
161
|
+
let r = Array.isArray(t) ? t : [];
|
|
162
|
+
return e.map((e, t) => n(e, r[t]));
|
|
163
|
+
}
|
|
164
|
+
if (W(e)) {
|
|
165
|
+
let r = W(t) ? t : {}, i = {};
|
|
166
|
+
for (let [t, a] of Object.entries(e)) i[t] = n(a, r[t]);
|
|
167
|
+
return i;
|
|
168
|
+
}
|
|
169
|
+
return e;
|
|
170
|
+
}, r = n(t, e);
|
|
171
|
+
return W(r) ? r : {};
|
|
172
|
+
}, te = (e, t) => {
|
|
173
|
+
if (!W(e)) return e;
|
|
151
174
|
let n = {};
|
|
152
175
|
for (let [r, i] of Object.entries(e)) {
|
|
153
|
-
if (!
|
|
176
|
+
if (!W(i) || !W(i.config)) {
|
|
154
177
|
n[r] = i;
|
|
155
178
|
continue;
|
|
156
179
|
}
|
|
@@ -158,12 +181,12 @@ var H = (e) => {
|
|
|
158
181
|
if (typeof n == "function") {
|
|
159
182
|
let e = n;
|
|
160
183
|
return function(...n) {
|
|
161
|
-
let a = t(), o =
|
|
184
|
+
let a = t(), o = W(a) ? a[r] : void 0, s = G(W(o) ? o.config : void 0, i);
|
|
162
185
|
return Reflect.apply(typeof s == "function" ? s : e, this, n);
|
|
163
186
|
};
|
|
164
187
|
}
|
|
165
188
|
if (Array.isArray(n)) return e.has(n) ? n : (e.add(n), n.map((e, t) => a(e, [...i, t])));
|
|
166
|
-
if (
|
|
189
|
+
if (W(n)) {
|
|
167
190
|
if (e.has(n)) return n;
|
|
168
191
|
e.add(n);
|
|
169
192
|
let t = {};
|
|
@@ -172,26 +195,31 @@ var H = (e) => {
|
|
|
172
195
|
}
|
|
173
196
|
return n;
|
|
174
197
|
};
|
|
175
|
-
n[r] =
|
|
198
|
+
n[r] = N(N({}, i), {}, { config: a(i.config, []) });
|
|
176
199
|
}
|
|
177
200
|
return n;
|
|
178
|
-
},
|
|
201
|
+
}, q = (e) => {
|
|
202
|
+
let t = typeof e == "function" ? e : e == null ? void 0 : e.class;
|
|
203
|
+
return typeof t == "function" && t.__isBlokReactBlock === !0;
|
|
204
|
+
}, ne = (e, t) => {
|
|
179
205
|
if (typeof e != "object" || !e) return e;
|
|
180
206
|
let n = {};
|
|
181
207
|
for (let [i, a] of Object.entries(e)) {
|
|
182
208
|
var r;
|
|
183
|
-
|
|
184
|
-
if (!(typeof e == "function" && e.__isBlokReactBlock === !0)) {
|
|
209
|
+
if (!q(a)) {
|
|
185
210
|
n[i] = a;
|
|
186
211
|
continue;
|
|
187
212
|
}
|
|
188
|
-
let
|
|
189
|
-
|
|
213
|
+
let e = typeof a == "function" ? { class: a } : N({}, a);
|
|
214
|
+
e.config = N(N({}, (r = e.config) == null ? {} : r), {}, {
|
|
215
|
+
[L]: t,
|
|
216
|
+
[R]: i
|
|
217
|
+
}), n[i] = e;
|
|
190
218
|
}
|
|
191
219
|
return n;
|
|
192
220
|
};
|
|
193
|
-
function
|
|
194
|
-
let n =
|
|
221
|
+
function J(e, t) {
|
|
222
|
+
let n = ee(i(P), e), [r, o] = l(null), u = c(n);
|
|
195
223
|
u.current = n;
|
|
196
224
|
let f = c({
|
|
197
225
|
editor: null,
|
|
@@ -200,15 +228,15 @@ function K(e, t) {
|
|
|
200
228
|
isDestroyed: !1,
|
|
201
229
|
isEditorReady: !1,
|
|
202
230
|
depsToken: null
|
|
203
|
-
}), p = s(() => ({}), t == null ? [] : t), m = c(n.data), h = c(null), _ = c(n.data), v = c(Promise.resolve()),
|
|
231
|
+
}), p = s(() => ({}), t == null ? [] : t), m = c(n.data), h = c(null), _ = c(n.data), v = c(Promise.resolve()), b = c(void 0), x = c(null), S = c(void 0), C = c(/* @__PURE__ */ new Map());
|
|
204
232
|
a(() => {
|
|
205
233
|
if (typeof window > "u") return;
|
|
206
234
|
let e = f.current;
|
|
207
235
|
if (e.destroyTimeout !== null && (clearTimeout(e.destroyTimeout), e.destroyTimeout = null), e.editor !== null && !e.isDestroyed && e.depsToken === p) return e.isEditorReady && o(e.editor), () => {
|
|
208
|
-
|
|
236
|
+
Y(e, o);
|
|
209
237
|
};
|
|
210
238
|
if (e.editor !== null && !e.isDestroyed) {
|
|
211
|
-
|
|
239
|
+
D(e.editor), U(e.editor);
|
|
212
240
|
try {
|
|
213
241
|
e.editor.destroy();
|
|
214
242
|
} catch (e) {}
|
|
@@ -216,7 +244,9 @@ function K(e, t) {
|
|
|
216
244
|
}
|
|
217
245
|
let t = document.createElement("div");
|
|
218
246
|
e.holder = t, e.isDestroyed = !1, e.isEditorReady = !1, e.depsToken = p;
|
|
219
|
-
let n = u.current, r =
|
|
247
|
+
let n = u.current, r = z(), i = n.tools === void 0 ? void 0 : te(n.tools, () => u.current.tools), a = i === void 0 ? void 0 : ne(i, r);
|
|
248
|
+
x.current = r, S.current = i, C.current = /* @__PURE__ */ new Map();
|
|
249
|
+
let s = N(N(N({}, n), a === void 0 ? {} : { tools: a }), {}, {
|
|
220
250
|
holder: t,
|
|
221
251
|
onReady: (...e) => {
|
|
222
252
|
var t, n;
|
|
@@ -227,72 +257,86 @@ function K(e, t) {
|
|
|
227
257
|
(t = (n = u.current).onChange) == null || t.call(n, ...e);
|
|
228
258
|
}
|
|
229
259
|
});
|
|
230
|
-
n.onSave && (
|
|
260
|
+
n.onSave && (s.onSave = (...e) => {
|
|
231
261
|
var t, n;
|
|
232
262
|
m.current = e[0], (t = (n = u.current).onSave) == null || t.call(n, ...e);
|
|
233
|
-
}), n.onBeforeRender && (
|
|
263
|
+
}), n.onBeforeRender && (s.onBeforeRender = (...e) => {
|
|
234
264
|
var t, n, r;
|
|
235
265
|
return (t = (n = (r = u.current).onBeforeRender) == null ? void 0 : n.call(r, ...e)) == null ? e[0] : t;
|
|
236
|
-
}), n.onAfterRender && (
|
|
266
|
+
}), n.onAfterRender && (s.onAfterRender = (...e) => {
|
|
237
267
|
var t, n;
|
|
238
268
|
(t = (n = u.current).onAfterRender) == null || t.call(n, ...e);
|
|
239
269
|
});
|
|
240
|
-
let
|
|
241
|
-
return e.editor =
|
|
242
|
-
e.editor ===
|
|
270
|
+
let c = new d(s);
|
|
271
|
+
return e.editor = c, _.current = n.data, T(c, t), V(c, r), c.isReady.then(() => {
|
|
272
|
+
e.editor === c && !e.isDestroyed && (e.isEditorReady = !0, o(c));
|
|
243
273
|
}).catch(() => {
|
|
244
|
-
if (e.editor ===
|
|
245
|
-
|
|
274
|
+
if (e.editor === c && !e.isDestroyed) {
|
|
275
|
+
D(c), U(c);
|
|
246
276
|
try {
|
|
247
|
-
|
|
277
|
+
c.destroy();
|
|
248
278
|
} catch (e) {}
|
|
249
279
|
e.editor = null, e.holder = null, e.isDestroyed = !0, e.isEditorReady = !1, o(null);
|
|
250
280
|
}
|
|
251
281
|
}), () => {
|
|
252
|
-
|
|
282
|
+
Y(e, o);
|
|
253
283
|
};
|
|
254
|
-
}, [p])
|
|
255
|
-
|
|
284
|
+
}, [p]), a(() => {
|
|
285
|
+
let e = x.current, t = f.current;
|
|
286
|
+
if (e === null || t.editor === null || t.isDestroyed) return;
|
|
287
|
+
let n = u.current.tools;
|
|
288
|
+
if (typeof n != "object" || !n) return;
|
|
289
|
+
let r = S.current;
|
|
290
|
+
for (let [t, a] of Object.entries(n)) {
|
|
291
|
+
var i;
|
|
292
|
+
if (!q(a)) continue;
|
|
293
|
+
let n = typeof a == "function" || (i = a.config) == null ? {} : i, o = r == null ? void 0 : r[t], s = K(typeof o == "object" && o ? o.config : void 0, n), c = C.current.get(t);
|
|
294
|
+
if (c !== void 0 && g(s, c)) continue;
|
|
295
|
+
let l = Object.freeze(s);
|
|
296
|
+
C.current.set(t, l), e.setToolConfig(t, l);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
let w = y(n.readOnly).enabled;
|
|
256
300
|
a(() => {
|
|
257
|
-
r !== null && r.readOnly.set(
|
|
258
|
-
}, [r,
|
|
259
|
-
let { autofocus:
|
|
301
|
+
r !== null && r.readOnly.set(w);
|
|
302
|
+
}, [r, w]);
|
|
303
|
+
let { autofocus: E } = n;
|
|
260
304
|
a(() => {
|
|
261
|
-
r === null || !
|
|
262
|
-
}, [r,
|
|
263
|
-
let { theme:
|
|
305
|
+
r === null || !E || r.focus();
|
|
306
|
+
}, [r, E]);
|
|
307
|
+
let { theme: O } = n;
|
|
264
308
|
a(() => {
|
|
265
|
-
r === null ||
|
|
266
|
-
}, [r,
|
|
267
|
-
let { width:
|
|
309
|
+
r === null || O === void 0 || r.theme.set(O);
|
|
310
|
+
}, [r, O]);
|
|
311
|
+
let { width: k } = n;
|
|
268
312
|
a(() => {
|
|
269
|
-
r === null ||
|
|
270
|
-
}, [r,
|
|
271
|
-
let { placeholder:
|
|
313
|
+
r === null || k === void 0 || r.width.set(k);
|
|
314
|
+
}, [r, k]);
|
|
315
|
+
let { placeholder: A } = n;
|
|
272
316
|
a(() => {
|
|
273
|
-
r === null ||
|
|
274
|
-
}, [r,
|
|
275
|
-
let { data:
|
|
317
|
+
r === null || A === void 0 || r.placeholder.set(A);
|
|
318
|
+
}, [r, A]);
|
|
319
|
+
let { data: j } = n;
|
|
276
320
|
return a(() => {
|
|
277
|
-
if (r === null ||
|
|
321
|
+
if (r === null || j === void 0) return;
|
|
278
322
|
let e = f.current;
|
|
279
323
|
if (!(e.editor !== r || e.isDestroyed)) {
|
|
280
|
-
if (h.current !== r && (h.current = r,
|
|
281
|
-
m.current =
|
|
324
|
+
if (h.current !== r && (h.current = r, b.current = void 0, g(j, _.current))) {
|
|
325
|
+
m.current = j;
|
|
282
326
|
return;
|
|
283
327
|
}
|
|
284
|
-
g(
|
|
285
|
-
m.current =
|
|
328
|
+
g(j, m.current) || g(j, b.current) || (b.current = j, v.current = v.current.catch(() => void 0).then(() => r.render(j)).then(() => {
|
|
329
|
+
m.current = j;
|
|
286
330
|
}, () => {}).then(() => {
|
|
287
|
-
|
|
331
|
+
b.current === j && (b.current = void 0);
|
|
288
332
|
}));
|
|
289
333
|
}
|
|
290
|
-
}, [r,
|
|
334
|
+
}, [r, j]), r;
|
|
291
335
|
}
|
|
292
|
-
function
|
|
336
|
+
function Y(e, t) {
|
|
293
337
|
e.destroyTimeout = setTimeout(() => {
|
|
294
338
|
if (e.editor !== null) {
|
|
295
|
-
|
|
339
|
+
D(e.editor), U(e.editor);
|
|
296
340
|
try {
|
|
297
341
|
e.editor.destroy();
|
|
298
342
|
} catch (e) {}
|
|
@@ -302,7 +346,7 @@ function q(e, t) {
|
|
|
302
346
|
}
|
|
303
347
|
//#endregion
|
|
304
348
|
//#region src/BlockPortalHost.tsx
|
|
305
|
-
var
|
|
349
|
+
var re = class extends e {
|
|
306
350
|
constructor(...e) {
|
|
307
351
|
super(...e), this.state = { failed: !1 };
|
|
308
352
|
}
|
|
@@ -314,16 +358,16 @@ var J = class extends e {
|
|
|
314
358
|
return this.state.failed ? null : this.props.children;
|
|
315
359
|
}
|
|
316
360
|
};
|
|
317
|
-
function
|
|
361
|
+
function X({ registry: e }) {
|
|
318
362
|
let t = u(e.subscribe, e.getSnapshot, e.getSnapshot);
|
|
319
|
-
return /* @__PURE__ */ b
|
|
363
|
+
return /* @__PURE__ */ x(b, { children: Array.from(t.entries()).map(([e, t]) => {
|
|
320
364
|
let n = t.component;
|
|
321
|
-
return
|
|
365
|
+
return S(/* @__PURE__ */ x(re, { children: /* @__PURE__ */ x(n, N({}, t.props)) }), t.hostEl, e);
|
|
322
366
|
}) });
|
|
323
367
|
}
|
|
324
368
|
//#endregion
|
|
325
369
|
//#region \0@oxc-project+runtime@0.126.0/helpers/objectWithoutPropertiesLoose.js
|
|
326
|
-
function
|
|
370
|
+
function ie(e, t) {
|
|
327
371
|
if (e == null) return {};
|
|
328
372
|
var n = {};
|
|
329
373
|
for (var r in e) if ({}.hasOwnProperty.call(e, r)) {
|
|
@@ -336,7 +380,7 @@ function X(e, t) {
|
|
|
336
380
|
//#region \0@oxc-project+runtime@0.126.0/helpers/objectWithoutProperties.js
|
|
337
381
|
function Z(e, t) {
|
|
338
382
|
if (e == null) return {};
|
|
339
|
-
var n, r, i =
|
|
383
|
+
var n, r, i = ie(e, t);
|
|
340
384
|
if (Object.getOwnPropertySymbols) {
|
|
341
385
|
var a = Object.getOwnPropertySymbols(e);
|
|
342
386
|
for (r = 0; r < a.length; r++) n = a[r], t.includes(n) || {}.propertyIsEnumerable.call(e, n) && (i[n] = e[n]);
|
|
@@ -345,8 +389,8 @@ function Z(e, t) {
|
|
|
345
389
|
}
|
|
346
390
|
//#endregion
|
|
347
391
|
//#region src/BlokContent.tsx
|
|
348
|
-
var
|
|
349
|
-
let { editor: n } = e, r = Z(e,
|
|
392
|
+
var ae = ["editor"], Q = n(function(e, t) {
|
|
393
|
+
let { editor: n } = e, r = Z(e, ae), i = c(null), o = (e) => {
|
|
350
394
|
if (i.current = e, typeof t == "function") t(e);
|
|
351
395
|
else if (t != null) {
|
|
352
396
|
let n = t;
|
|
@@ -355,25 +399,25 @@ var ne = ["editor"], Q = n(function(e, t) {
|
|
|
355
399
|
};
|
|
356
400
|
a(() => {
|
|
357
401
|
if (n === null || i.current === null) return;
|
|
358
|
-
let e =
|
|
402
|
+
let e = E(n);
|
|
359
403
|
if (e !== void 0) return i.current.appendChild(e), () => {
|
|
360
404
|
e.remove();
|
|
361
405
|
};
|
|
362
406
|
}, [n]);
|
|
363
|
-
let s = n === null ? void 0 :
|
|
364
|
-
return /* @__PURE__ */
|
|
365
|
-
}),
|
|
407
|
+
let s = n === null ? void 0 : H(n);
|
|
408
|
+
return /* @__PURE__ */ x("div", N(N({ ref: o }, r), {}, { children: s === void 0 ? null : /* @__PURE__ */ x(X, { registry: s }) }));
|
|
409
|
+
}), oe = /* @__PURE__ */ "autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.onBeforePaste.onReady.onChange.onSave.onBeforeRender.onAfterRender.inlineToolbar.tunes.style.theme.onThemeChange.scrollToBlock.user.resolveUser.notifierPosition.notifier.width".split("."), se = [
|
|
366
410
|
"deps",
|
|
367
411
|
"onReady",
|
|
368
412
|
"onBlocksRendered",
|
|
369
413
|
"onBlockRendered"
|
|
370
|
-
],
|
|
371
|
-
let { deps: n, onReady: r, onBlocksRendered: i, onBlockRendered: s } = e, l = Z(e,
|
|
414
|
+
], ce = new Set(oe), le = n(function(e, t) {
|
|
415
|
+
let { deps: n, onReady: r, onBlocksRendered: i, onBlockRendered: s } = e, l = Z(e, se), u = {}, d = {};
|
|
372
416
|
for (let e of Object.keys(l)) {
|
|
373
417
|
let t = l[e];
|
|
374
|
-
|
|
418
|
+
ce.has(e) ? u[e] = t : d[e] = t;
|
|
375
419
|
}
|
|
376
|
-
let f =
|
|
420
|
+
let f = J(u, n);
|
|
377
421
|
o(t, () => f, [f]);
|
|
378
422
|
let p = c(r);
|
|
379
423
|
p.current = r, a(() => {
|
|
@@ -411,9 +455,9 @@ var ne = ["editor"], Q = n(function(e, t) {
|
|
|
411
455
|
f,
|
|
412
456
|
g,
|
|
413
457
|
_
|
|
414
|
-
]), /* @__PURE__ */
|
|
458
|
+
]), /* @__PURE__ */ x(Q, N({ editor: f }, d));
|
|
415
459
|
}), $ = "block changed";
|
|
416
|
-
function
|
|
460
|
+
function ue(e) {
|
|
417
461
|
let t = c(0), n = c(e);
|
|
418
462
|
n.current !== e && (n.current = e, t.current = 0);
|
|
419
463
|
let i = r((n) => {
|
|
@@ -427,7 +471,8 @@ function se(e) {
|
|
|
427
471
|
}
|
|
428
472
|
//#endregion
|
|
429
473
|
//#region src/createReactBlock.tsx
|
|
430
|
-
|
|
474
|
+
var de = [L, R];
|
|
475
|
+
function fe(e) {
|
|
431
476
|
var t;
|
|
432
477
|
return t = class {
|
|
433
478
|
static get toolbox() {
|
|
@@ -440,22 +485,27 @@ function ce(e) {
|
|
|
440
485
|
var n, r;
|
|
441
486
|
this.hostEl = null, this.pendingDispatch = !1, this.commit = (t) => {
|
|
442
487
|
var n;
|
|
443
|
-
let r = _(e.propSchema,
|
|
444
|
-
this.mirror = r, this.lastRendered = r, (n = this.registry) == null || n.setProps(this.blockApi.id, { data: r }), this.flushDispatch();
|
|
488
|
+
let r = _(e.propSchema, N(N({}, this.mirror), t));
|
|
489
|
+
h(r, this.mirror) || (this.mirror = r, this.lastRendered = r, (n = this.registry) == null || n.setProps(this.blockApi.id, { data: r }), this.flushDispatch());
|
|
445
490
|
}, this.blockApi = t.block;
|
|
446
491
|
let i = (n = t.config) == null ? {} : n;
|
|
447
|
-
this.registry = i[
|
|
448
|
-
let o =
|
|
492
|
+
this.registry = i[L];
|
|
493
|
+
let o = i[R];
|
|
494
|
+
this.toolName = typeof o == "string" ? o : void 0;
|
|
495
|
+
let s = {};
|
|
496
|
+
for (let [e, t] of Object.entries(i)) de.includes(e) || (s[e] = t);
|
|
497
|
+
this.toolConfig = Object.freeze(s);
|
|
498
|
+
let l = t.api;
|
|
449
499
|
this.pointerDrag = () => {
|
|
450
500
|
var e;
|
|
451
|
-
return (
|
|
501
|
+
return (l == null || (e = l.blocks) == null ? void 0 : e.isPointerDragActive) === !0;
|
|
452
502
|
}, this.mirror = _(e.propSchema, (r = t.data) == null ? {} : r), this.lastRendered = this.mirror, this.readOnly = t.readOnly;
|
|
453
|
-
let
|
|
503
|
+
let u = this.blockApi;
|
|
454
504
|
this.childrenComponent = function() {
|
|
455
505
|
let e = c(null);
|
|
456
506
|
return a(() => {
|
|
457
|
-
e.current !== null && v(e.current,
|
|
458
|
-
}), /* @__PURE__ */
|
|
507
|
+
e.current !== null && v(e.current, u.getChildren());
|
|
508
|
+
}), /* @__PURE__ */ x("div", {
|
|
459
509
|
ref: e,
|
|
460
510
|
[f.nestedBlocks]: ""
|
|
461
511
|
});
|
|
@@ -467,7 +517,8 @@ function ce(e) {
|
|
|
467
517
|
return n.setAttribute("data-blok-mutation-free", "true"), this.hostEl = n, (t = this.registry) == null || t.register(this.blockApi.id, {
|
|
468
518
|
hostEl: n,
|
|
469
519
|
component: e.component,
|
|
470
|
-
props: this.buildProps()
|
|
520
|
+
props: this.buildProps(),
|
|
521
|
+
toolName: this.toolName
|
|
471
522
|
}), n;
|
|
472
523
|
}
|
|
473
524
|
rendered() {
|
|
@@ -503,12 +554,13 @@ function ce(e) {
|
|
|
503
554
|
commit: this.commit,
|
|
504
555
|
block: this.blockApi,
|
|
505
556
|
readOnly: this.readOnly,
|
|
557
|
+
config: this.toolConfig,
|
|
506
558
|
BlockChildren: this.childrenComponent
|
|
507
559
|
};
|
|
508
560
|
}
|
|
509
561
|
pushProps(e) {
|
|
510
562
|
let t = this.registry;
|
|
511
|
-
t !== void 0 &&
|
|
563
|
+
t !== void 0 && C(() => {
|
|
512
564
|
t.setProps(this.blockApi.id, e);
|
|
513
565
|
});
|
|
514
566
|
}
|
|
@@ -531,4 +583,4 @@ function ce(e) {
|
|
|
531
583
|
}, t.__isBlokReactBlock = !0, t;
|
|
532
584
|
}
|
|
533
585
|
//#endregion
|
|
534
|
-
export {
|
|
586
|
+
export { L as BLOK_PORTAL_REGISTRY_CONFIG_KEY, R as BLOK_TOOL_NAME_CONFIG_KEY, X as BlockPortalHost, Q as BlokContent, le as BlokEditor, F as BlokProvider, z as createBlockPortalRegistry, fe as createReactBlock, ue as useBlocks, J as useBlok, I as useBlokDefaults };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bloklabs/react",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
4
4
|
"description": "React bindings for the Blok editor",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "JackUait",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"build": "yarn run -T vite build --mode production"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@bloklabs/core": "^1.2.
|
|
36
|
+
"@bloklabs/core": "^1.2.4",
|
|
37
37
|
"react": "^18.0.0 || ^19.0.0",
|
|
38
38
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
39
39
|
}
|
package/src/BlokEditor.tsx
CHANGED
|
@@ -44,11 +44,13 @@ export interface BlokEditorProps
|
|
|
44
44
|
* value referentially stable (primitives or useMemo-stable objects) — a dep
|
|
45
45
|
* whose identity changes every render recreates the editor each time.
|
|
46
46
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* reaches the editor live,
|
|
51
|
-
*
|
|
47
|
+
* Tool configs do NOT belong here — reserve deps for true identity changes
|
|
48
|
+
* (e.g. the document id). FUNCTIONS inside tool configs are re-bound to the
|
|
49
|
+
* latest render's closure automatically (an inline `uploadByFile` with a
|
|
50
|
+
* fresh identity each render reaches the editor live), and non-function
|
|
51
|
+
* config VALUES of `createReactBlock` tools (permissions, URLs, locale…) are
|
|
52
|
+
* pushed to mounted blocks in place when they change. Neither requires
|
|
53
|
+
* recreation or `useState` identity-freezing.
|
|
52
54
|
*/
|
|
53
55
|
deps?: DependencyList;
|
|
54
56
|
/** Test id forwarded to the editor container element (via data-testid). */
|
|
@@ -8,6 +8,15 @@ import type { ComponentType } from 'react';
|
|
|
8
8
|
*/
|
|
9
9
|
export const BLOK_PORTAL_REGISTRY_CONFIG_KEY = '__blokPortalRegistry';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Tool-config key carrying the name the tool was registered under in the
|
|
13
|
+
* consumer's `tools` map (injected next to the registry). The factory needs it
|
|
14
|
+
* to associate portal entries with their tool so live config updates can be
|
|
15
|
+
* routed; it is stripped (with the registry key) before the sanitized config
|
|
16
|
+
* reaches the component.
|
|
17
|
+
*/
|
|
18
|
+
export const BLOK_TOOL_NAME_CONFIG_KEY = '__blokToolName';
|
|
19
|
+
|
|
11
20
|
/**
|
|
12
21
|
* One mounted React block in the portal registry. `hostEl` is the Blok-owned
|
|
13
22
|
* `toolRenderedElement` (tagged `data-blok-mutation-free`) the component is
|
|
@@ -18,6 +27,8 @@ export interface BlockPortalEntry {
|
|
|
18
27
|
hostEl: HTMLElement;
|
|
19
28
|
component: ComponentType<Record<string, unknown>>;
|
|
20
29
|
props: Record<string, unknown>;
|
|
30
|
+
/** Name the tool is registered under — routes per-tool live config updates. */
|
|
31
|
+
toolName?: string;
|
|
21
32
|
}
|
|
22
33
|
|
|
23
34
|
/**
|
|
@@ -40,6 +51,12 @@ export interface BlockPortalRegistry {
|
|
|
40
51
|
unregister(id: string): void;
|
|
41
52
|
/** Merge `props` into the entry's props (in-place update, no remount). */
|
|
42
53
|
setProps(id: string, props: Record<string, unknown>): void;
|
|
54
|
+
/**
|
|
55
|
+
* Replace the `config` prop of every entry registered under `toolName`, and
|
|
56
|
+
* remember it so entries registered LATER start from this latest config
|
|
57
|
+
* instead of their construction-time snapshot.
|
|
58
|
+
*/
|
|
59
|
+
setToolConfig(toolName: string, config: Record<string, unknown>): void;
|
|
43
60
|
/** Subscribe to snapshot changes; returns the unsubscribe function. */
|
|
44
61
|
subscribe(listener: () => void): () => void;
|
|
45
62
|
/** Current immutable snapshot (stable identity until the next mutation). */
|
|
@@ -56,6 +73,8 @@ export const createBlockPortalRegistry = (): BlockPortalRegistry => {
|
|
|
56
73
|
snapshot: new Map<string, BlockPortalEntry>() as ReadonlyMap<string, BlockPortalEntry>,
|
|
57
74
|
};
|
|
58
75
|
const listeners = new Set<() => void>();
|
|
76
|
+
/** Latest per-tool config, applied to mounted entries and future registers. */
|
|
77
|
+
const toolConfigs = new Map<string, Record<string, unknown>>();
|
|
59
78
|
|
|
60
79
|
const commit = (next: Map<string, BlockPortalEntry>): void => {
|
|
61
80
|
state.snapshot = next;
|
|
@@ -65,8 +84,12 @@ export const createBlockPortalRegistry = (): BlockPortalRegistry => {
|
|
|
65
84
|
return {
|
|
66
85
|
register(id: string, entry: BlockPortalEntry): void {
|
|
67
86
|
const next = new Map(state.snapshot);
|
|
87
|
+
const liveConfig = entry.toolName === undefined ? undefined : toolConfigs.get(entry.toolName);
|
|
68
88
|
|
|
69
|
-
next.set(
|
|
89
|
+
next.set(
|
|
90
|
+
id,
|
|
91
|
+
liveConfig === undefined ? entry : { ...entry, props: { ...entry.props, config: liveConfig } }
|
|
92
|
+
);
|
|
70
93
|
commit(next);
|
|
71
94
|
},
|
|
72
95
|
unregister(id: string): void {
|
|
@@ -91,6 +114,23 @@ export const createBlockPortalRegistry = (): BlockPortalRegistry => {
|
|
|
91
114
|
next.set(id, { ...current, props: { ...current.props, ...props } });
|
|
92
115
|
commit(next);
|
|
93
116
|
},
|
|
117
|
+
setToolConfig(toolName: string, config: Record<string, unknown>): void {
|
|
118
|
+
toolConfigs.set(toolName, config);
|
|
119
|
+
|
|
120
|
+
const matching = [...state.snapshot].filter(([, entry]) => entry.toolName === toolName);
|
|
121
|
+
|
|
122
|
+
if (matching.length === 0) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const next = new Map(state.snapshot);
|
|
127
|
+
|
|
128
|
+
for (const [id, entry] of matching) {
|
|
129
|
+
next.set(id, { ...entry, props: { ...entry.props, config } });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
commit(next);
|
|
133
|
+
},
|
|
94
134
|
subscribe(listener: () => void): () => void {
|
|
95
135
|
listeners.add(listener);
|
|
96
136
|
|
package/src/createReactBlock.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { flushSync } from 'react-dom';
|
|
|
3
3
|
import { DATA_ATTR, deepEqual, fillDefaults, mountChildBlocks, type PropSchema } from '@bloklabs/core/adapters';
|
|
4
4
|
import {
|
|
5
5
|
BLOK_PORTAL_REGISTRY_CONFIG_KEY,
|
|
6
|
+
BLOK_TOOL_NAME_CONFIG_KEY,
|
|
6
7
|
type BlockPortalRegistry,
|
|
7
8
|
} from './block-portal-registry';
|
|
8
9
|
import type { BlockAPI } from '@/types/api';
|
|
@@ -10,8 +11,14 @@ import type { BlockToolConstructorOptions, BlockToolData, ToolboxConfig } from '
|
|
|
10
11
|
|
|
11
12
|
export type { PropSchema, PropSchemaEntry } from '@bloklabs/core/adapters';
|
|
12
13
|
|
|
14
|
+
/** Adapter-internal config keys, stripped before the config reaches the component. */
|
|
15
|
+
const INTERNAL_CONFIG_KEYS: readonly string[] = [
|
|
16
|
+
BLOK_PORTAL_REGISTRY_CONFIG_KEY,
|
|
17
|
+
BLOK_TOOL_NAME_CONFIG_KEY,
|
|
18
|
+
];
|
|
19
|
+
|
|
13
20
|
/** Props handed to a React block's `component` (the only data write path is `commit`). */
|
|
14
|
-
export interface ReactBlockRenderProps<Data
|
|
21
|
+
export interface ReactBlockRenderProps<Data, Config = Record<string, unknown>> {
|
|
15
22
|
/** Frozen snapshot of the block data. Re-rendered with a new value on change; never mutate. */
|
|
16
23
|
data: Readonly<Data>;
|
|
17
24
|
/** The ONLY data write path: merge a partial patch and sync once. */
|
|
@@ -26,12 +33,21 @@ export interface ReactBlockRenderProps<Data> {
|
|
|
26
33
|
* the editor is read-only (same contract as a vanilla tool's `setReadOnly`).
|
|
27
34
|
*/
|
|
28
35
|
readOnly: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The tool's `config` from the consumer's `tools` map (adapter-internal keys
|
|
38
|
+
* stripped) — the first-class channel for host props (permissions, CDN/upload
|
|
39
|
+
* URLs, locale…). No context provider needed. Under `useBlok`/`BlokEditor`
|
|
40
|
+
* this prop is LIVE: functions always call the latest render's closure, and
|
|
41
|
+
* changed non-function values are pushed to mounted blocks in place — so
|
|
42
|
+
* config values never belong in `deps`.
|
|
43
|
+
*/
|
|
44
|
+
config: Readonly<Partial<Config>>;
|
|
29
45
|
/** Engine-owned child slot — render `<BlockChildren />` for a container block. */
|
|
30
46
|
BlockChildren: ComponentType;
|
|
31
47
|
}
|
|
32
48
|
|
|
33
49
|
/** Spec for {@link createReactBlock}. */
|
|
34
|
-
export interface CreateReactBlockSpec<Data = BlockToolData
|
|
50
|
+
export interface CreateReactBlockSpec<Data = BlockToolData, Config = Record<string, unknown>> {
|
|
35
51
|
/** Tool type name (registered key). */
|
|
36
52
|
type: string;
|
|
37
53
|
/** Optional toolbox entry. */
|
|
@@ -39,7 +55,7 @@ export interface CreateReactBlockSpec<Data = BlockToolData> {
|
|
|
39
55
|
/** Declarative defaults that also define the exact `save()` key set. */
|
|
40
56
|
propSchema: PropSchema;
|
|
41
57
|
/** The component rendered for each block instance. */
|
|
42
|
-
component: ComponentType<ReactBlockRenderProps<Data>>;
|
|
58
|
+
component: ComponentType<ReactBlockRenderProps<Data, Config>>;
|
|
43
59
|
/** Optional lifecycle callbacks mapped from Blok's block hooks. */
|
|
44
60
|
onRendered?: (block: BlockAPI) => void;
|
|
45
61
|
onMoved?: (block: BlockAPI) => void;
|
|
@@ -64,8 +80,8 @@ export interface CreateReactBlockSpec<Data = BlockToolData> {
|
|
|
64
80
|
* - `commit()` merges a patch and fires `dispatchChange` exactly once.
|
|
65
81
|
* - `removed()`/`destroy()` unregister the portal (deterministic unmount).
|
|
66
82
|
*/
|
|
67
|
-
export function createReactBlock<Data = BlockToolData
|
|
68
|
-
spec: CreateReactBlockSpec<Data>
|
|
83
|
+
export function createReactBlock<Data = BlockToolData, Config = Record<string, unknown>>(
|
|
84
|
+
spec: CreateReactBlockSpec<Data, Config>
|
|
69
85
|
): (new (options: BlockToolConstructorOptions) => {
|
|
70
86
|
render(): HTMLElement;
|
|
71
87
|
save(): BlockToolData;
|
|
@@ -100,6 +116,10 @@ export function createReactBlock<Data = BlockToolData>(
|
|
|
100
116
|
|
|
101
117
|
private readonly blockApi: BlockAPI;
|
|
102
118
|
private readonly registry: BlockPortalRegistry | undefined;
|
|
119
|
+
/** Name this tool is registered under in the consumer's `tools` map. */
|
|
120
|
+
private readonly toolName: string | undefined;
|
|
121
|
+
/** The consumer's tool config with adapter-internal keys stripped. */
|
|
122
|
+
private readonly toolConfig: Readonly<Partial<Config>>;
|
|
103
123
|
private readonly pointerDrag: () => boolean;
|
|
104
124
|
private readonly childrenComponent: ComponentType;
|
|
105
125
|
private mirror: Readonly<Data>;
|
|
@@ -117,6 +137,18 @@ export function createReactBlock<Data = BlockToolData>(
|
|
|
117
137
|
const config = (options.config ?? {}) as Record<string, unknown>;
|
|
118
138
|
|
|
119
139
|
this.registry = config[BLOK_PORTAL_REGISTRY_CONFIG_KEY] as BlockPortalRegistry | undefined;
|
|
140
|
+
const toolName = config[BLOK_TOOL_NAME_CONFIG_KEY];
|
|
141
|
+
|
|
142
|
+
this.toolName = typeof toolName === 'string' ? toolName : undefined;
|
|
143
|
+
|
|
144
|
+
const publicConfig: Record<string, unknown> = {};
|
|
145
|
+
|
|
146
|
+
for (const [key, value] of Object.entries(config)) {
|
|
147
|
+
if (!INTERNAL_CONFIG_KEYS.includes(key)) {
|
|
148
|
+
publicConfig[key] = value;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
this.toolConfig = Object.freeze(publicConfig) as Readonly<Partial<Config>>;
|
|
120
152
|
|
|
121
153
|
// Read the LIVE pointer-drag flag so a mid-drag commit can be deferred
|
|
122
154
|
// (core silently drops a dispatchChange while a drag is active).
|
|
@@ -160,6 +192,7 @@ export function createReactBlock<Data = BlockToolData>(
|
|
|
160
192
|
hostEl: host,
|
|
161
193
|
component: spec.component as unknown as ComponentType<Record<string, unknown>>,
|
|
162
194
|
props: this.buildProps(),
|
|
195
|
+
toolName: this.toolName,
|
|
163
196
|
});
|
|
164
197
|
|
|
165
198
|
// Returned synchronously; React flushes the portal on its next commit.
|
|
@@ -224,11 +257,12 @@ export function createReactBlock<Data = BlockToolData>(
|
|
|
224
257
|
|
|
225
258
|
/** The full entry props handed to the component on (re-)register. */
|
|
226
259
|
private buildProps(): Record<string, unknown> {
|
|
227
|
-
const props: ReactBlockRenderProps<Data> = {
|
|
260
|
+
const props: ReactBlockRenderProps<Data, Config> = {
|
|
228
261
|
data: this.mirror,
|
|
229
262
|
commit: this.commit,
|
|
230
263
|
block: this.blockApi,
|
|
231
264
|
readOnly: this.readOnly,
|
|
265
|
+
config: this.toolConfig,
|
|
232
266
|
BlockChildren: this.childrenComponent,
|
|
233
267
|
};
|
|
234
268
|
|
|
@@ -262,6 +296,14 @@ export function createReactBlock<Data = BlockToolData>(
|
|
|
262
296
|
...(patch as Record<string, unknown>),
|
|
263
297
|
});
|
|
264
298
|
|
|
299
|
+
// Idempotent: a patch that changes nothing is a full no-op — no props
|
|
300
|
+
// push, no dispatchChange. This is what makes an effect that echoes the
|
|
301
|
+
// current value back through commit safe without a consumer-side guard
|
|
302
|
+
// (an unguarded echo would otherwise loop commit → render → effect).
|
|
303
|
+
if (deepEqual(next, this.mirror)) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
265
307
|
this.mirror = next;
|
|
266
308
|
this.lastRendered = next;
|
|
267
309
|
// No flushSync here: commit is called from React event handlers (inside a
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type {
|
|
|
15
15
|
export {
|
|
16
16
|
createBlockPortalRegistry,
|
|
17
17
|
BLOK_PORTAL_REGISTRY_CONFIG_KEY,
|
|
18
|
+
BLOK_TOOL_NAME_CONFIG_KEY,
|
|
18
19
|
} from './block-portal-registry';
|
|
19
20
|
export type { BlockPortalRegistry, BlockPortalEntry } from './block-portal-registry';
|
|
20
21
|
export { BlockPortalHost } from './BlockPortalHost';
|
package/src/live-tool-config.ts
CHANGED
|
@@ -38,6 +38,48 @@ const resolveAtPath = (root: unknown, path: readonly (string | number)[]): unkno
|
|
|
38
38
|
return undefined;
|
|
39
39
|
}, root);
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Build the component-facing `config` for a react block from the LATEST render's
|
|
43
|
+
* raw config, preferring the stable live wrapper from `wrappedConfig` wherever
|
|
44
|
+
* both sides hold a function at the same path. The result carries the newest
|
|
45
|
+
* non-function VALUES while keeping function identities stable across renders
|
|
46
|
+
* (wrappers already delegate to the latest closure), so a deep-equal dedupe of
|
|
47
|
+
* successive results only fires when a value genuinely changed.
|
|
48
|
+
*/
|
|
49
|
+
export const buildLiveBlockConfig = (
|
|
50
|
+
wrappedConfig: unknown,
|
|
51
|
+
latestConfig: unknown
|
|
52
|
+
): Record<string, unknown> => {
|
|
53
|
+
const merge = (latest: unknown, wrapped: unknown): unknown => {
|
|
54
|
+
if (typeof latest === 'function') {
|
|
55
|
+
return typeof wrapped === 'function' ? wrapped : latest;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (Array.isArray(latest)) {
|
|
59
|
+
const wrappedArray = Array.isArray(wrapped) ? wrapped : [];
|
|
60
|
+
|
|
61
|
+
return latest.map((item, index) => merge(item, wrappedArray[index]));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (isPlainObject(latest)) {
|
|
65
|
+
const wrappedObject = isPlainObject(wrapped) ? wrapped : {};
|
|
66
|
+
const result: Record<string, unknown> = {};
|
|
67
|
+
|
|
68
|
+
for (const [key, value] of Object.entries(latest)) {
|
|
69
|
+
result[key] = merge(value, wrappedObject[key]);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return latest;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const merged = merge(latestConfig, wrappedConfig);
|
|
79
|
+
|
|
80
|
+
return isPlainObject(merged) ? merged : {};
|
|
81
|
+
};
|
|
82
|
+
|
|
41
83
|
/**
|
|
42
84
|
* Return a copy of `tools` where every function inside a tool's `config` is
|
|
43
85
|
* replaced by a stable wrapper that calls the function found at the same path
|
package/src/useBlok.ts
CHANGED
|
@@ -6,10 +6,11 @@ import { BlokDefaultsContext, mergeBlokDefaults } from './provide-blok';
|
|
|
6
6
|
import {
|
|
7
7
|
createBlockPortalRegistry,
|
|
8
8
|
BLOK_PORTAL_REGISTRY_CONFIG_KEY,
|
|
9
|
+
BLOK_TOOL_NAME_CONFIG_KEY,
|
|
9
10
|
type BlockPortalRegistry,
|
|
10
11
|
} from './block-portal-registry';
|
|
11
12
|
import { setRegistry, removeRegistry } from './registry-map';
|
|
12
|
-
import { bindLiveToolConfigFunctions } from './live-tool-config';
|
|
13
|
+
import { bindLiveToolConfigFunctions, buildLiveBlockConfig } from './live-tool-config';
|
|
13
14
|
import { normalizeReadOnlyConfig } from '@bloklabs/core/adapters';
|
|
14
15
|
import type { Blok } from '@/types';
|
|
15
16
|
import type { UseBlokConfig } from './types';
|
|
@@ -32,6 +33,15 @@ interface EditorInstanceState {
|
|
|
32
33
|
* CORE, outside any React render, so it cannot read context — this config
|
|
33
34
|
* bridge is how the tool reaches its editor-scoped registry.
|
|
34
35
|
*/
|
|
36
|
+
const isReactBlockEntry = (entry: unknown): boolean => {
|
|
37
|
+
const toolClass = typeof entry === 'function' ? entry : (entry as { class?: unknown })?.class;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
typeof toolClass === 'function' &&
|
|
41
|
+
(toolClass as { __isBlokReactBlock?: boolean }).__isBlokReactBlock === true
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
35
45
|
const injectPortalRegistry = (tools: unknown, registry: BlockPortalRegistry): unknown => {
|
|
36
46
|
if (tools === null || typeof tools !== 'object') {
|
|
37
47
|
return tools;
|
|
@@ -40,12 +50,7 @@ const injectPortalRegistry = (tools: unknown, registry: BlockPortalRegistry): un
|
|
|
40
50
|
const result: Record<string, unknown> = {};
|
|
41
51
|
|
|
42
52
|
for (const [name, entry] of Object.entries(tools as Record<string, unknown>)) {
|
|
43
|
-
|
|
44
|
-
const isReactBlock =
|
|
45
|
-
typeof toolClass === 'function' &&
|
|
46
|
-
(toolClass as { __isBlokReactBlock?: boolean }).__isBlokReactBlock === true;
|
|
47
|
-
|
|
48
|
-
if (!isReactBlock) {
|
|
53
|
+
if (!isReactBlockEntry(entry)) {
|
|
49
54
|
result[name] = entry;
|
|
50
55
|
|
|
51
56
|
continue;
|
|
@@ -57,6 +62,7 @@ const injectPortalRegistry = (tools: unknown, registry: BlockPortalRegistry): un
|
|
|
57
62
|
base.config = {
|
|
58
63
|
...((base.config as Record<string, unknown> | undefined) ?? {}),
|
|
59
64
|
[BLOK_PORTAL_REGISTRY_CONFIG_KEY]: registry,
|
|
65
|
+
[BLOK_TOOL_NAME_CONFIG_KEY]: name,
|
|
60
66
|
};
|
|
61
67
|
result[name] = base;
|
|
62
68
|
}
|
|
@@ -122,6 +128,12 @@ export function useBlok(configInput: UseBlokConfig, deps?: DependencyList): Blok
|
|
|
122
128
|
// success baseline — so a failed render can't strand the baseline on content
|
|
123
129
|
// the editor never actually showed.
|
|
124
130
|
const pendingDataRef = useRef<UseBlokConfig['data']>(undefined);
|
|
131
|
+
// Live block-config channel (see the sync effect below): the current editor's
|
|
132
|
+
// portal registry, its construction-time wrapped tools (stable function
|
|
133
|
+
// wrappers), and the last config pushed per tool name (dedupe baseline).
|
|
134
|
+
const liveRegistryRef = useRef<BlockPortalRegistry | null>(null);
|
|
135
|
+
const wrappedToolsRef = useRef<unknown>(undefined);
|
|
136
|
+
const pushedBlockConfigsRef = useRef<Map<string, Record<string, unknown>>>(new Map());
|
|
125
137
|
|
|
126
138
|
// Main lifecycle effect
|
|
127
139
|
useEffect(() => {
|
|
@@ -191,13 +203,17 @@ export function useBlok(configInput: UseBlokConfig, deps?: DependencyList): Blok
|
|
|
191
203
|
// wrappers that always call the latest render's closure — so consumers
|
|
192
204
|
// never need to freeze identities or recreate the editor to update them.
|
|
193
205
|
const registry = createBlockPortalRegistry();
|
|
194
|
-
const
|
|
206
|
+
const wrappedTools =
|
|
195
207
|
currentConfig.tools === undefined
|
|
196
208
|
? undefined
|
|
197
|
-
:
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
209
|
+
: bindLiveToolConfigFunctions(currentConfig.tools, () => configRef.current.tools);
|
|
210
|
+
const liveTools = wrappedTools === undefined ? undefined : injectPortalRegistry(wrappedTools, registry);
|
|
211
|
+
|
|
212
|
+
// Reset the live block-config channel for this editor: the sync effect below
|
|
213
|
+
// reads these to push changed non-function config VALUES to mounted blocks.
|
|
214
|
+
liveRegistryRef.current = registry;
|
|
215
|
+
wrappedToolsRef.current = wrappedTools;
|
|
216
|
+
pushedBlockConfigsRef.current = new Map();
|
|
201
217
|
|
|
202
218
|
const blokConfig = {
|
|
203
219
|
...currentConfig,
|
|
@@ -277,6 +293,58 @@ export function useBlok(configInput: UseBlokConfig, deps?: DependencyList): Blok
|
|
|
277
293
|
};
|
|
278
294
|
}, [depsToken]);
|
|
279
295
|
|
|
296
|
+
// Live tool-config VALUES for react blocks. Function slots are already live
|
|
297
|
+
// via the stable wrappers, but non-function values (permissions, URLs,
|
|
298
|
+
// locale…) were snapshotted at construction — which forced consumers to put
|
|
299
|
+
// them in `deps` and recreate the whole editor to change them. Instead, this
|
|
300
|
+
// effect runs on every render, rebuilds each react-block tool's
|
|
301
|
+
// component-facing config from the LATEST render's values (keeping wrapper
|
|
302
|
+
// identities for functions), and pushes it through the portal registry when
|
|
303
|
+
// it genuinely changed — mounted blocks re-render in place, future blocks
|
|
304
|
+
// start from the latest config.
|
|
305
|
+
useEffect(() => {
|
|
306
|
+
const registry = liveRegistryRef.current;
|
|
307
|
+
const state = stateRef.current;
|
|
308
|
+
|
|
309
|
+
if (registry === null || state.editor === null || state.isDestroyed) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const latestTools = configRef.current.tools as Record<string, unknown> | undefined;
|
|
314
|
+
|
|
315
|
+
if (latestTools === null || typeof latestTools !== 'object') {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const wrappedTools = wrappedToolsRef.current as Record<string, unknown> | undefined;
|
|
320
|
+
|
|
321
|
+
for (const [name, entry] of Object.entries(latestTools)) {
|
|
322
|
+
if (!isReactBlockEntry(entry)) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const latestConfig =
|
|
327
|
+
typeof entry === 'function' ? {} : ((entry as { config?: unknown }).config ?? {});
|
|
328
|
+
const wrappedEntry = wrappedTools?.[name];
|
|
329
|
+
const wrappedConfig =
|
|
330
|
+
wrappedEntry !== null && typeof wrappedEntry === 'object'
|
|
331
|
+
? (wrappedEntry as { config?: unknown }).config
|
|
332
|
+
: undefined;
|
|
333
|
+
|
|
334
|
+
const candidate = buildLiveBlockConfig(wrappedConfig, latestConfig);
|
|
335
|
+
const pushed = pushedBlockConfigsRef.current.get(name);
|
|
336
|
+
|
|
337
|
+
if (pushed !== undefined && deepEqual(candidate, pushed)) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const frozen = Object.freeze(candidate);
|
|
342
|
+
|
|
343
|
+
pushedBlockConfigsRef.current.set(name, frozen);
|
|
344
|
+
registry.setToolConfig(name, frozen);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
280
348
|
// Reactive: readOnly (object form normalized so the effect dep is a stable boolean)
|
|
281
349
|
const readOnlyEnabled = normalizeReadOnlyConfig(config.readOnly).enabled;
|
|
282
350
|
useEffect(() => {
|
package/types/index.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export interface BlokContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
39
39
|
* React hook that creates and manages a Blok editor instance.
|
|
40
40
|
*
|
|
41
41
|
* @param config - Editor configuration (all BlokConfig props except `holder`)
|
|
42
|
-
* @param deps - Optional dependency array. When any dep changes, the editor is destroyed and recreated. Keep each value referentially stable (primitives or useMemo-stable objects) so the editor isn't recreated every render.
|
|
42
|
+
* @param deps - Optional dependency array. When any dep changes, the editor is destroyed and recreated. Keep each value referentially stable (primitives or useMemo-stable objects) so the editor isn't recreated every render. Reserve it for true identity changes (e.g. the document id): tool-config functions are re-bound to the latest render's closure automatically, and non-function config values of `createReactBlock` tools are pushed to mounted blocks in place — neither belongs in deps.
|
|
43
43
|
* @returns The Blok editor instance, or null during SSR / before initialization.
|
|
44
44
|
*
|
|
45
45
|
* @example
|
|
@@ -81,6 +81,8 @@ export interface BlokEditorProps
|
|
|
81
81
|
* When any value changes, the editor is destroyed and recreated. Keep each
|
|
82
82
|
* value referentially stable (primitives or useMemo-stable objects) — a dep
|
|
83
83
|
* whose identity changes every render recreates the editor each time.
|
|
84
|
+
* Reserve it for true identity changes (e.g. the document id): tool-config
|
|
85
|
+
* functions and `createReactBlock` config values stay live without it.
|
|
84
86
|
*/
|
|
85
87
|
deps?: React.DependencyList;
|
|
86
88
|
/** Test id forwarded to the editor container element (via data-testid). */
|
|
@@ -555,10 +557,14 @@ export interface PropSchemaEntry {
|
|
|
555
557
|
export type PropSchema = Record<string, PropSchemaEntry>;
|
|
556
558
|
|
|
557
559
|
/** Props handed to a React block's `component` (the only data write path is `commit`). */
|
|
558
|
-
export interface ReactBlockRenderProps<Data
|
|
560
|
+
export interface ReactBlockRenderProps<Data, Config = Record<string, unknown>> {
|
|
559
561
|
/** Frozen snapshot of the block data. Re-rendered with a new value on change; never mutate. */
|
|
560
562
|
data: Readonly<Data>;
|
|
561
|
-
/**
|
|
563
|
+
/**
|
|
564
|
+
* The ONLY data write path: merge a partial patch and sync once. Idempotent —
|
|
565
|
+
* a patch that changes nothing is a full no-op (no re-render, no change
|
|
566
|
+
* event), so effects may safely echo current values without a guard.
|
|
567
|
+
*/
|
|
562
568
|
commit: (patch: Partial<Data>) => void;
|
|
563
569
|
/** This block's per-block API. */
|
|
564
570
|
block: BlockAPI;
|
|
@@ -568,16 +574,27 @@ export interface ReactBlockRenderProps<Data> {
|
|
|
568
574
|
* interactive when the editor is read-only.
|
|
569
575
|
*/
|
|
570
576
|
readOnly: boolean;
|
|
577
|
+
/**
|
|
578
|
+
* The tool's `config` from the consumer's `tools` map (adapter-internal keys
|
|
579
|
+
* stripped) — the first-class channel for host props (permissions, CDN/upload
|
|
580
|
+
* URLs, locale…). LIVE under `useBlok`/`BlokEditor`: functions always call
|
|
581
|
+
* the latest render's closure, and changed non-function values are pushed to
|
|
582
|
+
* mounted blocks in place — config values never belong in `deps`.
|
|
583
|
+
*/
|
|
584
|
+
config: Readonly<Partial<Config>>;
|
|
571
585
|
/** Engine-owned child slot — render `<BlockChildren />` for a container block. */
|
|
572
586
|
BlockChildren: React.ComponentType;
|
|
573
587
|
}
|
|
574
588
|
|
|
575
589
|
/** Spec for {@link createReactBlock}. */
|
|
576
|
-
export interface CreateReactBlockSpec<
|
|
590
|
+
export interface CreateReactBlockSpec<
|
|
591
|
+
Data extends BlockToolData = BlockToolData,
|
|
592
|
+
Config = Record<string, unknown>
|
|
593
|
+
> {
|
|
577
594
|
type: string;
|
|
578
595
|
toolbox?: ToolboxConfig;
|
|
579
596
|
propSchema: PropSchema;
|
|
580
|
-
component: React.ComponentType<ReactBlockRenderProps<Data>>;
|
|
597
|
+
component: React.ComponentType<ReactBlockRenderProps<Data, Config>>;
|
|
581
598
|
onRendered?: (block: BlockAPI) => void;
|
|
582
599
|
onMoved?: (block: BlockAPI) => void;
|
|
583
600
|
onRemoved?: (block: BlockAPI) => void;
|
|
@@ -602,9 +619,10 @@ export interface CreateReactBlockSpec<Data extends BlockToolData = BlockToolData
|
|
|
602
619
|
* });
|
|
603
620
|
* ```
|
|
604
621
|
*/
|
|
605
|
-
export declare function createReactBlock<
|
|
606
|
-
|
|
607
|
-
|
|
622
|
+
export declare function createReactBlock<
|
|
623
|
+
Data extends BlockToolData = BlockToolData,
|
|
624
|
+
Config = Record<string, unknown>
|
|
625
|
+
>(spec: CreateReactBlockSpec<Data, Config>): BlockToolConstructable;
|
|
608
626
|
|
|
609
627
|
/**
|
|
610
628
|
* Tool-config key carrying the editor's portal registry into a
|
|
@@ -613,11 +631,20 @@ export declare function createReactBlock<Data extends BlockToolData = BlockToolD
|
|
|
613
631
|
*/
|
|
614
632
|
export declare const BLOK_PORTAL_REGISTRY_CONFIG_KEY: '__blokPortalRegistry';
|
|
615
633
|
|
|
634
|
+
/**
|
|
635
|
+
* Tool-config key carrying the name a react-block tool is registered under in
|
|
636
|
+
* the consumer's `tools` map. Injected automatically by `useBlok`; routes live
|
|
637
|
+
* tool-config updates to the tool's mounted blocks.
|
|
638
|
+
*/
|
|
639
|
+
export declare const BLOK_TOOL_NAME_CONFIG_KEY: '__blokToolName';
|
|
640
|
+
|
|
616
641
|
/** One mounted React block in the portal registry. */
|
|
617
642
|
export interface BlockPortalEntry {
|
|
618
643
|
hostEl: HTMLElement;
|
|
619
644
|
component: React.ComponentType<Record<string, unknown>>;
|
|
620
645
|
props: Record<string, unknown>;
|
|
646
|
+
/** Name the tool is registered under — routes per-tool live config updates. */
|
|
647
|
+
toolName?: string;
|
|
621
648
|
}
|
|
622
649
|
|
|
623
650
|
/**
|
|
@@ -630,6 +657,11 @@ export interface BlockPortalRegistry {
|
|
|
630
657
|
register(id: string, entry: BlockPortalEntry): void;
|
|
631
658
|
unregister(id: string): void;
|
|
632
659
|
setProps(id: string, props: Record<string, unknown>): void;
|
|
660
|
+
/**
|
|
661
|
+
* Replace the `config` prop of every entry registered under `toolName`, and
|
|
662
|
+
* remember it so entries registered later start from the latest config.
|
|
663
|
+
*/
|
|
664
|
+
setToolConfig(toolName: string, config: Record<string, unknown>): void;
|
|
633
665
|
subscribe(listener: () => void): () => void;
|
|
634
666
|
getSnapshot(): ReadonlyMap<string, BlockPortalEntry>;
|
|
635
667
|
}
|