@bloklabs/react 1.2.4 → 1.2.6

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 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=`__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=_;
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=>{let t=typeof e==`function`?e:e==null?void 0:e.class;return typeof t==`function`&&t.__isBlokReactInlineTool===!0},M=(e,t)=>{if(typeof e!=`object`||!e)return e;let n={};for(let[i,a]of Object.entries(e)){var r;if(!A(a)&&!j(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 N(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),()=>{P(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:M(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)},onEnter:(...e)=>{var t,n;return(t=(n=u.current).onEnter)==null?void 0: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)}}),()=>{P(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:j}=a;(0,e.useEffect)(()=>{s===null||!j||s.focus()},[s,j]);let{theme:N}=a;(0,e.useEffect)(()=>{s===null||N===void 0||s.theme.set(N)},[s,N]);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 P(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 F=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 I({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)(F,{children:(0,r.jsx)(n,m({},t.props))}),t.hostEl,e)})})}function L(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 R(e,t){if(e==null)return{};var n,r,i=L(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 z=[`editor`],B=(0,e.forwardRef)(function(t,n){let{editor:i}=t,a=R(t,z),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)(I,{registry:l})}))}),V=`autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.onBeforePaste.onReady.onChange.onSave.onEnter.onBeforeRender.onAfterRender.inlineToolbar.tunes.style.theme.onThemeChange.scrollToBlock.user.resolveUser.notifierPosition.notifier.width`.split(`.`),H=[`deps`,`onReady`,`onBlocksRendered`,`onBlockRendered`],U=new Set(V),W=(0,e.forwardRef)(function(t,n){let{deps:i,onReady:a,onBlocksRendered:o,onBlockRendered:s}=t,c=R(t,H),l={},u={};for(let e of Object.keys(c)){let t=c[e];U.has(e)?l[e]=t:u[e]=t}let d=N(l,i);(0,e.useImperativeHandle)(n,()=>d,[d]);let f=(0,e.useRef)(a);f.current=a;let p=(0,e.useRef)(null);(0,e.useEffect)(()=>{if(d!==null&&p.current!==d){var e;p.current=d,(e=f.current)==null||e.call(f,d)}},[d]);let h=(0,e.useRef)(o);h.current=o;let g=(0,e.useRef)(s);g.current=s;let _=!!o,v=!!s;return(0,e.useEffect)(()=>{if(d===null)return;let e=[];if(_){let t=e=>{var t;return(t=h.current)==null?void 0:t.call(h,e)};d.on(`blocks:rendered`,t),e.push([`blocks:rendered`,t])}if(v){let t=e=>{var t;return(t=g.current)==null?void 0:t.call(g,e)};d.on(`block:rendered`,t),e.push([`block:rendered`,t])}return()=>{for(let[t,n]of e)d.off(t,n)}},[d,_,v]),(0,r.jsx)(B,m({editor:d},u))}),G=`block changed`;function K(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(G,n),()=>t.off(G,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 q=[y,b];function J(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))q.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}var Y=[y,b],X=e=>`__blok-inline-tool__:${e}:${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;function Z(e){var t;return t=class{static get title(){return e.title}static get shortcut(){return e.shortcut}static get sanitize(){return e.sanitize}static get isReadOnlySupported(){var t;return(t=e.isReadOnlySupported)==null?!1:t}constructor(t){var n;this.active=!1,this.registered=!1;let r=(n=t==null?void 0:t.config)==null?{}:n;this.registry=r[y];let i=r[b];this.toolName=typeof i==`string`?i:e.type,this.portalKey=X(this.toolName);let a={};for(let[e,t]of Object.entries(r))Y.includes(e)||(a[e]=t);this.toolConfig=Object.freeze(a)}render(){let t=document.createElement(`div`);return t.setAttribute(`data-blok-mutation-free`,`true`),this.registry!==void 0&&(this.registry.register(this.portalKey,{hostEl:t,component:e.component,props:{active:this.active,config:this.toolConfig},toolName:this.toolName}),this.registered=!0),{name:this.toolName,title:e.title,icon:t,onActivate:()=>{if(typeof e.surround!=`function`)return;let t=window.getSelection();!t||t.rangeCount===0||e.surround(t.getRangeAt(0))},isActive:()=>this.refreshActiveState()}}destroy(){var e;this.registered&&(this.registered=!1,(e=this.registry)==null||e.unregister(this.portalKey))}refreshActiveState(){let t=typeof e.checkState==`function`?!!e.checkState(window.getSelection()):!1;if(t!==this.active&&(this.active=t,this.registered)){var n;(n=this.registry)==null||n.setProps(this.portalKey,{active:t})}return t}},t.__isBlokReactInlineTool=!0,t.isInline=!0,t}exports.BLOK_PORTAL_REGISTRY_CONFIG_KEY=y,exports.BLOK_TOOL_NAME_CONFIG_KEY=b,exports.BlockPortalHost=I,exports.BlokContent=B,exports.BlokEditor=W,exports.BlokProvider=g,exports.createBlockPortalRegistry=x,exports.createReactBlock=J,exports.createReactInlineTool=Z,exports.useBlocks=K,exports.useBlok=N,exports.useBlokDefaults=_;
package/dist/index.mjs CHANGED
@@ -5,47 +5,47 @@ import { Fragment as b, jsx as x } from "react/jsx-runtime";
5
5
  import { createPortal as S, flushSync as C } from "react-dom";
6
6
  //#region src/holder-map.ts
7
7
  var w = /* @__PURE__ */ new WeakMap();
8
- function T(e, t) {
8
+ function ee(e, t) {
9
9
  w.set(e, t);
10
10
  }
11
- function E(e) {
11
+ function T(e) {
12
12
  return w.get(e);
13
13
  }
14
- function D(e) {
14
+ function E(e) {
15
15
  w.delete(e);
16
16
  }
17
17
  //#endregion
18
18
  //#region \0@oxc-project+runtime@0.126.0/helpers/typeof.js
19
- function O(e) {
19
+ function D(e) {
20
20
  "@babel/helpers - typeof";
21
- return O = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(e) {
21
+ return D = 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
- }, O(e);
25
+ }, D(e);
26
26
  }
27
27
  //#endregion
28
28
  //#region \0@oxc-project+runtime@0.126.0/helpers/toPrimitive.js
29
- function k(e, t) {
30
- if (O(e) != "object" || !e) return e;
29
+ function O(e, t) {
30
+ if (D(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 (O(r) != "object") return r;
34
+ if (D(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 A(e) {
42
- var t = k(e, "string");
43
- return O(t) == "symbol" ? t : t + "";
41
+ function k(e) {
42
+ var t = O(e, "string");
43
+ return D(t) == "symbol" ? t : t + "";
44
44
  }
45
45
  //#endregion
46
46
  //#region \0@oxc-project+runtime@0.126.0/helpers/defineProperty.js
47
- function j(e, t, n) {
48
- return (t = A(t)) in e ? Object.defineProperty(e, t, {
47
+ function A(e, t, n) {
48
+ return (t = k(t)) in e ? Object.defineProperty(e, t, {
49
49
  value: n,
50
50
  enumerable: !0,
51
51
  configurable: !0,
@@ -54,7 +54,7 @@ function j(e, t, n) {
54
54
  }
55
55
  //#endregion
56
56
  //#region \0@oxc-project+runtime@0.126.0/helpers/objectSpread2.js
57
- function M(e, t) {
57
+ function j(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 M(e, t) {
64
64
  }
65
65
  return n;
66
66
  }
67
- function N(e) {
67
+ function M(e) {
68
68
  for (var t = 1; t < arguments.length; t++) {
69
69
  var n = arguments[t] == null ? {} : arguments[t];
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) {
70
+ t % 2 ? j(Object(n), !0).forEach(function(t) {
71
+ A(e, t, n[t]);
72
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : j(Object(n)).forEach(function(t) {
73
73
  Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(n, t));
74
74
  });
75
75
  }
@@ -77,35 +77,35 @@ function N(e) {
77
77
  }
78
78
  //#endregion
79
79
  //#region src/provide-blok.tsx
80
- var P = t({});
81
- function F({ defaults: e, children: t }) {
82
- return /* @__PURE__ */ x(P.Provider, {
80
+ var N = t({});
81
+ function P({ defaults: e, children: t }) {
82
+ return /* @__PURE__ */ x(N.Provider, {
83
83
  value: e,
84
84
  children: t
85
85
  });
86
86
  }
87
- function I() {
88
- return i(P);
87
+ function te() {
88
+ return i(N);
89
89
  }
90
- function ee(e, t) {
90
+ function ne(e, t) {
91
91
  if (Object.keys(e).length === 0) return t;
92
- let n = N({}, e);
92
+ let n = M({}, 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 = N(N({}, e.tools), t.tools)), n;
97
+ return (e.tools !== void 0 || t.tools !== void 0) && (n.tools = M(M({}, e.tools), t.tools)), n;
98
98
  }
99
99
  //#endregion
100
100
  //#region src/block-portal-registry.ts
101
- var L = "__blokPortalRegistry", R = "__blokToolName", z = () => {
101
+ var F = "__blokPortalRegistry", I = "__blokToolName", L = () => {
102
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
106
  register(t, i) {
107
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);
108
+ a.set(t, o === void 0 ? i : M(M({}, i), {}, { props: M(M({}, i.props), {}, { config: o }) })), r(a);
109
109
  },
110
110
  unregister(t) {
111
111
  if (!e.snapshot.has(t)) return;
@@ -116,14 +116,14 @@ var L = "__blokPortalRegistry", R = "__blokToolName", z = () => {
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, N(N({}, i), {}, { props: N(N({}, i.props), n) })), r(a);
119
+ a.set(t, M(M({}, i), {}, { props: M(M({}, i.props), n) })), r(a);
120
120
  },
121
121
  setToolConfig(t, i) {
122
122
  n.set(t, i);
123
123
  let a = [...e.snapshot].filter(([, e]) => e.toolName === t);
124
124
  if (a.length === 0) return;
125
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 }) }));
126
+ for (let [e, t] of a) o.set(e, M(M({}, t), {}, { props: M(M({}, t.props), {}, { config: i }) }));
127
127
  r(o);
128
128
  },
129
129
  subscribe(e) {
@@ -135,45 +135,45 @@ var L = "__blokPortalRegistry", R = "__blokToolName", z = () => {
135
135
  return e.snapshot;
136
136
  }
137
137
  };
138
- }, B = /* @__PURE__ */ new WeakMap();
139
- function V(e, t) {
140
- B.set(e, t);
138
+ }, R = /* @__PURE__ */ new WeakMap();
139
+ function z(e, t) {
140
+ R.set(e, t);
141
141
  }
142
- function H(e) {
143
- return B.get(e);
142
+ function B(e) {
143
+ return R.get(e);
144
144
  }
145
- function U(e) {
146
- B.delete(e);
145
+ function V(e) {
146
+ R.delete(e);
147
147
  }
148
148
  //#endregion
149
149
  //#region src/live-tool-config.ts
150
- var W = (e) => {
150
+ var H = (e) => {
151
151
  if (typeof e != "object" || !e) return !1;
152
152
  let t = Object.getPrototypeOf(e);
153
153
  return t === Object.prototype || t === null;
154
- }, G = (e, t) => t.reduce((e, t) => {
154
+ }, re = (e, t) => t.reduce((e, t) => {
155
155
  if (Array.isArray(e)) return typeof t == "number" ? e[t] : void 0;
156
- if (W(e)) return e[t];
157
- }, e), K = (e, t) => {
156
+ if (H(e)) return e[t];
157
+ }, e), ie = (e, t) => {
158
158
  let n = (e, t) => {
159
159
  if (typeof e == "function") return typeof t == "function" ? t : e;
160
160
  if (Array.isArray(e)) {
161
161
  let r = Array.isArray(t) ? t : [];
162
162
  return e.map((e, t) => n(e, r[t]));
163
163
  }
164
- if (W(e)) {
165
- let r = W(t) ? t : {}, i = {};
164
+ if (H(e)) {
165
+ let r = H(t) ? t : {}, i = {};
166
166
  for (let [t, a] of Object.entries(e)) i[t] = n(a, r[t]);
167
167
  return i;
168
168
  }
169
169
  return e;
170
170
  }, r = n(t, e);
171
- return W(r) ? r : {};
172
- }, te = (e, t) => {
173
- if (!W(e)) return e;
171
+ return H(r) ? r : {};
172
+ }, U = (e, t) => {
173
+ if (!H(e)) return e;
174
174
  let n = {};
175
175
  for (let [r, i] of Object.entries(e)) {
176
- if (!W(i) || !W(i.config)) {
176
+ if (!H(i) || !H(i.config)) {
177
177
  n[r] = i;
178
178
  continue;
179
179
  }
@@ -181,12 +181,12 @@ var W = (e) => {
181
181
  if (typeof n == "function") {
182
182
  let e = n;
183
183
  return function(...n) {
184
- let a = t(), o = W(a) ? a[r] : void 0, s = G(W(o) ? o.config : void 0, i);
184
+ let a = t(), o = H(a) ? a[r] : void 0, s = re(H(o) ? o.config : void 0, i);
185
185
  return Reflect.apply(typeof s == "function" ? s : e, this, n);
186
186
  };
187
187
  }
188
188
  if (Array.isArray(n)) return e.has(n) ? n : (e.add(n), n.map((e, t) => a(e, [...i, t])));
189
- if (W(n)) {
189
+ if (H(n)) {
190
190
  if (e.has(n)) return n;
191
191
  e.add(n);
192
192
  let t = {};
@@ -195,31 +195,34 @@ var W = (e) => {
195
195
  }
196
196
  return n;
197
197
  };
198
- n[r] = N(N({}, i), {}, { config: a(i.config, []) });
198
+ n[r] = M(M({}, i), {}, { config: a(i.config, []) });
199
199
  }
200
200
  return n;
201
- }, q = (e) => {
201
+ }, W = (e) => {
202
202
  let t = typeof e == "function" ? e : e == null ? void 0 : e.class;
203
203
  return typeof t == "function" && t.__isBlokReactBlock === !0;
204
- }, ne = (e, t) => {
204
+ }, G = (e) => {
205
+ let t = typeof e == "function" ? e : e == null ? void 0 : e.class;
206
+ return typeof t == "function" && t.__isBlokReactInlineTool === !0;
207
+ }, K = (e, t) => {
205
208
  if (typeof e != "object" || !e) return e;
206
209
  let n = {};
207
210
  for (let [i, a] of Object.entries(e)) {
208
211
  var r;
209
- if (!q(a)) {
212
+ if (!W(a) && !G(a)) {
210
213
  n[i] = a;
211
214
  continue;
212
215
  }
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
216
+ let e = typeof a == "function" ? { class: a } : M({}, a);
217
+ e.config = M(M({}, (r = e.config) == null ? {} : r), {}, {
218
+ [F]: t,
219
+ [I]: i
217
220
  }), n[i] = e;
218
221
  }
219
222
  return n;
220
223
  };
221
- function J(e, t) {
222
- let n = ee(i(P), e), [r, o] = l(null), u = c(n);
224
+ function q(e, t) {
225
+ let n = ne(i(N), e), [r, o] = l(null), u = c(n);
223
226
  u.current = n;
224
227
  let f = c({
225
228
  editor: null,
@@ -233,10 +236,10 @@ function J(e, t) {
233
236
  if (typeof window > "u") return;
234
237
  let e = f.current;
235
238
  if (e.destroyTimeout !== null && (clearTimeout(e.destroyTimeout), e.destroyTimeout = null), e.editor !== null && !e.isDestroyed && e.depsToken === p) return e.isEditorReady && o(e.editor), () => {
236
- Y(e, o);
239
+ J(e, o);
237
240
  };
238
241
  if (e.editor !== null && !e.isDestroyed) {
239
- D(e.editor), U(e.editor);
242
+ E(e.editor), V(e.editor);
240
243
  try {
241
244
  e.editor.destroy();
242
245
  } catch (e) {}
@@ -244,9 +247,9 @@ function J(e, t) {
244
247
  }
245
248
  let t = document.createElement("div");
246
249
  e.holder = t, e.isDestroyed = !1, e.isEditorReady = !1, e.depsToken = p;
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);
250
+ let n = u.current, r = L(), i = n.tools === void 0 ? void 0 : U(n.tools, () => u.current.tools), a = i === void 0 ? void 0 : K(i, r);
248
251
  x.current = r, S.current = i, C.current = /* @__PURE__ */ new Map();
249
- let s = N(N(N({}, n), a === void 0 ? {} : { tools: a }), {}, {
252
+ let s = M(M(M({}, n), a === void 0 ? {} : { tools: a }), {}, {
250
253
  holder: t,
251
254
  onReady: (...e) => {
252
255
  var t, n;
@@ -255,6 +258,10 @@ function J(e, t) {
255
258
  onChange: (...e) => {
256
259
  var t, n;
257
260
  (t = (n = u.current).onChange) == null || t.call(n, ...e);
261
+ },
262
+ onEnter: (...e) => {
263
+ var t, n;
264
+ return (t = (n = u.current).onEnter) == null ? void 0 : t.call(n, ...e);
258
265
  }
259
266
  });
260
267
  n.onSave && (s.onSave = (...e) => {
@@ -268,18 +275,18 @@ function J(e, t) {
268
275
  (t = (n = u.current).onAfterRender) == null || t.call(n, ...e);
269
276
  });
270
277
  let c = new d(s);
271
- return e.editor = c, _.current = n.data, T(c, t), V(c, r), c.isReady.then(() => {
278
+ return e.editor = c, _.current = n.data, ee(c, t), z(c, r), c.isReady.then(() => {
272
279
  e.editor === c && !e.isDestroyed && (e.isEditorReady = !0, o(c));
273
280
  }).catch(() => {
274
281
  if (e.editor === c && !e.isDestroyed) {
275
- D(c), U(c);
282
+ E(c), V(c);
276
283
  try {
277
284
  c.destroy();
278
285
  } catch (e) {}
279
286
  e.editor = null, e.holder = null, e.isDestroyed = !0, e.isEditorReady = !1, o(null);
280
287
  }
281
288
  }), () => {
282
- Y(e, o);
289
+ J(e, o);
283
290
  };
284
291
  }, [p]), a(() => {
285
292
  let e = x.current, t = f.current;
@@ -289,8 +296,8 @@ function J(e, t) {
289
296
  let r = S.current;
290
297
  for (let [t, a] of Object.entries(n)) {
291
298
  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);
299
+ if (!W(a)) continue;
300
+ let n = typeof a == "function" || (i = a.config) == null ? {} : i, o = r == null ? void 0 : r[t], s = ie(typeof o == "object" && o ? o.config : void 0, n), c = C.current.get(t);
294
301
  if (c !== void 0 && g(s, c)) continue;
295
302
  let l = Object.freeze(s);
296
303
  C.current.set(t, l), e.setToolConfig(t, l);
@@ -300,43 +307,43 @@ function J(e, t) {
300
307
  a(() => {
301
308
  r !== null && r.readOnly.set(w);
302
309
  }, [r, w]);
303
- let { autofocus: E } = n;
310
+ let { autofocus: T } = n;
311
+ a(() => {
312
+ r === null || !T || r.focus();
313
+ }, [r, T]);
314
+ let { theme: D } = n;
304
315
  a(() => {
305
- r === null || !E || r.focus();
306
- }, [r, E]);
307
- let { theme: O } = n;
316
+ r === null || D === void 0 || r.theme.set(D);
317
+ }, [r, D]);
318
+ let { width: O } = n;
308
319
  a(() => {
309
- r === null || O === void 0 || r.theme.set(O);
320
+ r === null || O === void 0 || r.width.set(O);
310
321
  }, [r, O]);
311
- let { width: k } = n;
322
+ let { placeholder: k } = n;
312
323
  a(() => {
313
- r === null || k === void 0 || r.width.set(k);
324
+ r === null || k === void 0 || r.placeholder.set(k);
314
325
  }, [r, k]);
315
- let { placeholder: A } = n;
316
- a(() => {
317
- r === null || A === void 0 || r.placeholder.set(A);
318
- }, [r, A]);
319
- let { data: j } = n;
326
+ let { data: A } = n;
320
327
  return a(() => {
321
- if (r === null || j === void 0) return;
328
+ if (r === null || A === void 0) return;
322
329
  let e = f.current;
323
330
  if (!(e.editor !== r || e.isDestroyed)) {
324
- if (h.current !== r && (h.current = r, b.current = void 0, g(j, _.current))) {
325
- m.current = j;
331
+ if (h.current !== r && (h.current = r, b.current = void 0, g(A, _.current))) {
332
+ m.current = A;
326
333
  return;
327
334
  }
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;
335
+ g(A, m.current) || g(A, b.current) || (b.current = A, v.current = v.current.catch(() => void 0).then(() => r.render(A)).then(() => {
336
+ m.current = A;
330
337
  }, () => {}).then(() => {
331
- b.current === j && (b.current = void 0);
338
+ b.current === A && (b.current = void 0);
332
339
  }));
333
340
  }
334
- }, [r, j]), r;
341
+ }, [r, A]), r;
335
342
  }
336
- function Y(e, t) {
343
+ function J(e, t) {
337
344
  e.destroyTimeout = setTimeout(() => {
338
345
  if (e.editor !== null) {
339
- D(e.editor), U(e.editor);
346
+ E(e.editor), V(e.editor);
340
347
  try {
341
348
  e.editor.destroy();
342
349
  } catch (e) {}
@@ -346,7 +353,7 @@ function Y(e, t) {
346
353
  }
347
354
  //#endregion
348
355
  //#region src/BlockPortalHost.tsx
349
- var re = class extends e {
356
+ var Y = class extends e {
350
357
  constructor(...e) {
351
358
  super(...e), this.state = { failed: !1 };
352
359
  }
@@ -362,12 +369,12 @@ function X({ registry: e }) {
362
369
  let t = u(e.subscribe, e.getSnapshot, e.getSnapshot);
363
370
  return /* @__PURE__ */ x(b, { children: Array.from(t.entries()).map(([e, t]) => {
364
371
  let n = t.component;
365
- return S(/* @__PURE__ */ x(re, { children: /* @__PURE__ */ x(n, N({}, t.props)) }), t.hostEl, e);
372
+ return S(/* @__PURE__ */ x(Y, { children: /* @__PURE__ */ x(n, M({}, t.props)) }), t.hostEl, e);
366
373
  }) });
367
374
  }
368
375
  //#endregion
369
376
  //#region \0@oxc-project+runtime@0.126.0/helpers/objectWithoutPropertiesLoose.js
370
- function ie(e, t) {
377
+ function ae(e, t) {
371
378
  if (e == null) return {};
372
379
  var n = {};
373
380
  for (var r in e) if ({}.hasOwnProperty.call(e, r)) {
@@ -380,7 +387,7 @@ function ie(e, t) {
380
387
  //#region \0@oxc-project+runtime@0.126.0/helpers/objectWithoutProperties.js
381
388
  function Z(e, t) {
382
389
  if (e == null) return {};
383
- var n, r, i = ie(e, t);
390
+ var n, r, i = ae(e, t);
384
391
  if (Object.getOwnPropertySymbols) {
385
392
  var a = Object.getOwnPropertySymbols(e);
386
393
  for (r = 0; r < a.length; r++) n = a[r], t.includes(n) || {}.propertyIsEnumerable.call(e, n) && (i[n] = e[n]);
@@ -389,8 +396,8 @@ function Z(e, t) {
389
396
  }
390
397
  //#endregion
391
398
  //#region src/BlokContent.tsx
392
- var ae = ["editor"], Q = n(function(e, t) {
393
- let { editor: n } = e, r = Z(e, ae), i = c(null), o = (e) => {
399
+ var oe = ["editor"], Q = n(function(e, t) {
400
+ let { editor: n } = e, r = Z(e, oe), i = c(null), o = (e) => {
394
401
  if (i.current = e, typeof t == "function") t(e);
395
402
  else if (t != null) {
396
403
  let n = t;
@@ -399,52 +406,54 @@ var ae = ["editor"], Q = n(function(e, t) {
399
406
  };
400
407
  a(() => {
401
408
  if (n === null || i.current === null) return;
402
- let e = E(n);
409
+ let e = T(n);
403
410
  if (e !== void 0) return i.current.appendChild(e), () => {
404
411
  e.remove();
405
412
  };
406
413
  }, [n]);
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 = [
414
+ let s = n === null ? void 0 : B(n);
415
+ return /* @__PURE__ */ x("div", M(M({ ref: o }, r), {}, { children: s === void 0 ? null : /* @__PURE__ */ x(X, { registry: s }) }));
416
+ }), se = /* @__PURE__ */ "autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.onBeforePaste.onReady.onChange.onSave.onEnter.onBeforeRender.onAfterRender.inlineToolbar.tunes.style.theme.onThemeChange.scrollToBlock.user.resolveUser.notifierPosition.notifier.width".split("."), ce = [
410
417
  "deps",
411
418
  "onReady",
412
419
  "onBlocksRendered",
413
420
  "onBlockRendered"
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 = {};
421
+ ], le = new Set(se), ue = n(function(e, t) {
422
+ let { deps: n, onReady: r, onBlocksRendered: i, onBlockRendered: s } = e, l = Z(e, ce), u = {}, d = {};
416
423
  for (let e of Object.keys(l)) {
417
424
  let t = l[e];
418
- ce.has(e) ? u[e] = t : d[e] = t;
425
+ le.has(e) ? u[e] = t : d[e] = t;
419
426
  }
420
- let f = J(u, n);
427
+ let f = q(u, n);
421
428
  o(t, () => f, [f]);
422
429
  let p = c(r);
423
- p.current = r, a(() => {
424
- if (f !== null) {
430
+ p.current = r;
431
+ let m = c(null);
432
+ a(() => {
433
+ if (f !== null && m.current !== f) {
425
434
  var e;
426
- (e = p.current) == null || e.call(p, f);
435
+ m.current = f, (e = p.current) == null || e.call(p, f);
427
436
  }
428
437
  }, [f]);
429
- let m = c(i);
430
- m.current = i;
431
- let h = c(s);
432
- h.current = s;
433
- let g = !!i, _ = !!s;
438
+ let h = c(i);
439
+ h.current = i;
440
+ let g = c(s);
441
+ g.current = s;
442
+ let _ = !!i, v = !!s;
434
443
  return a(() => {
435
444
  if (f === null) return;
436
445
  let e = [];
437
- if (g) {
446
+ if (_) {
438
447
  let t = (e) => {
439
448
  var t;
440
- return (t = m.current) == null ? void 0 : t.call(m, e);
449
+ return (t = h.current) == null ? void 0 : t.call(h, e);
441
450
  };
442
451
  f.on("blocks:rendered", t), e.push(["blocks:rendered", t]);
443
452
  }
444
- if (_) {
453
+ if (v) {
445
454
  let t = (e) => {
446
455
  var t;
447
- return (t = h.current) == null ? void 0 : t.call(h, e);
456
+ return (t = g.current) == null ? void 0 : t.call(g, e);
448
457
  };
449
458
  f.on("block:rendered", t), e.push(["block:rendered", t]);
450
459
  }
@@ -453,11 +462,11 @@ var ae = ["editor"], Q = n(function(e, t) {
453
462
  };
454
463
  }, [
455
464
  f,
456
- g,
457
- _
458
- ]), /* @__PURE__ */ x(Q, N({ editor: f }, d));
465
+ _,
466
+ v
467
+ ]), /* @__PURE__ */ x(Q, M({ editor: f }, d));
459
468
  }), $ = "block changed";
460
- function ue(e) {
469
+ function de(e) {
461
470
  let t = c(0), n = c(e);
462
471
  n.current !== e && (n.current = e, t.current = 0);
463
472
  let i = r((n) => {
@@ -471,8 +480,8 @@ function ue(e) {
471
480
  }
472
481
  //#endregion
473
482
  //#region src/createReactBlock.tsx
474
- var de = [L, R];
475
- function fe(e) {
483
+ var fe = [F, I];
484
+ function pe(e) {
476
485
  var t;
477
486
  return t = class {
478
487
  static get toolbox() {
@@ -485,15 +494,15 @@ function fe(e) {
485
494
  var n, r;
486
495
  this.hostEl = null, this.pendingDispatch = !1, this.commit = (t) => {
487
496
  var n;
488
- let r = _(e.propSchema, N(N({}, this.mirror), t));
497
+ let r = _(e.propSchema, M(M({}, this.mirror), t));
489
498
  h(r, this.mirror) || (this.mirror = r, this.lastRendered = r, (n = this.registry) == null || n.setProps(this.blockApi.id, { data: r }), this.flushDispatch());
490
499
  }, this.blockApi = t.block;
491
500
  let i = (n = t.config) == null ? {} : n;
492
- this.registry = i[L];
493
- let o = i[R];
501
+ this.registry = i[F];
502
+ let o = i[I];
494
503
  this.toolName = typeof o == "string" ? o : void 0;
495
504
  let s = {};
496
- for (let [e, t] of Object.entries(i)) de.includes(e) || (s[e] = t);
505
+ for (let [e, t] of Object.entries(i)) fe.includes(e) || (s[e] = t);
497
506
  this.toolConfig = Object.freeze(s);
498
507
  let l = t.api;
499
508
  this.pointerDrag = () => {
@@ -583,4 +592,70 @@ function fe(e) {
583
592
  }, t.__isBlokReactBlock = !0, t;
584
593
  }
585
594
  //#endregion
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 };
595
+ //#region src/createReactInlineTool.tsx
596
+ var me = [F, I], he = (e) => `__blok-inline-tool__:${e}:${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
597
+ function ge(e) {
598
+ var t;
599
+ return t = class {
600
+ static get title() {
601
+ return e.title;
602
+ }
603
+ static get shortcut() {
604
+ return e.shortcut;
605
+ }
606
+ static get sanitize() {
607
+ return e.sanitize;
608
+ }
609
+ static get isReadOnlySupported() {
610
+ var t;
611
+ return (t = e.isReadOnlySupported) == null ? !1 : t;
612
+ }
613
+ constructor(t) {
614
+ var n;
615
+ this.active = !1, this.registered = !1;
616
+ let r = (n = t == null ? void 0 : t.config) == null ? {} : n;
617
+ this.registry = r[F];
618
+ let i = r[I];
619
+ this.toolName = typeof i == "string" ? i : e.type, this.portalKey = he(this.toolName);
620
+ let a = {};
621
+ for (let [e, t] of Object.entries(r)) me.includes(e) || (a[e] = t);
622
+ this.toolConfig = Object.freeze(a);
623
+ }
624
+ render() {
625
+ let t = document.createElement("div");
626
+ return t.setAttribute("data-blok-mutation-free", "true"), this.registry !== void 0 && (this.registry.register(this.portalKey, {
627
+ hostEl: t,
628
+ component: e.component,
629
+ props: {
630
+ active: this.active,
631
+ config: this.toolConfig
632
+ },
633
+ toolName: this.toolName
634
+ }), this.registered = !0), {
635
+ name: this.toolName,
636
+ title: e.title,
637
+ icon: t,
638
+ onActivate: () => {
639
+ if (typeof e.surround != "function") return;
640
+ let t = window.getSelection();
641
+ !t || t.rangeCount === 0 || e.surround(t.getRangeAt(0));
642
+ },
643
+ isActive: () => this.refreshActiveState()
644
+ };
645
+ }
646
+ destroy() {
647
+ var e;
648
+ this.registered && (this.registered = !1, (e = this.registry) == null || e.unregister(this.portalKey));
649
+ }
650
+ refreshActiveState() {
651
+ let t = typeof e.checkState == "function" ? !!e.checkState(window.getSelection()) : !1;
652
+ if (t !== this.active && (this.active = t, this.registered)) {
653
+ var n;
654
+ (n = this.registry) == null || n.setProps(this.portalKey, { active: t });
655
+ }
656
+ return t;
657
+ }
658
+ }, t.__isBlokReactInlineTool = !0, t.isInline = !0, t;
659
+ }
660
+ //#endregion
661
+ export { F as BLOK_PORTAL_REGISTRY_CONFIG_KEY, I as BLOK_TOOL_NAME_CONFIG_KEY, X as BlockPortalHost, Q as BlokContent, ue as BlokEditor, P as BlokProvider, L as createBlockPortalRegistry, pe as createReactBlock, ge as createReactInlineTool, de as useBlocks, q as useBlok, te as useBlokDefaults };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloklabs/react",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
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.4",
36
+ "@bloklabs/core": "^1.2.6",
37
37
  "react": "^18.0.0 || ^19.0.0",
38
38
  "react-dom": "^18.0.0 || ^19.0.0"
39
39
  }
@@ -56,8 +56,13 @@ export interface BlokEditorProps
56
56
  /** Test id forwarded to the editor container element (via data-testid). */
57
57
  'data-testid'?: string;
58
58
  /**
59
- * Called once the editor is ready, with the live Blok instance. Fires after the
59
+ * Called with the live Blok instance once it is ready. Fires after the
60
60
  * forwarded ref is committed, so `ref.current` is also populated at this point.
61
+ *
62
+ * Contract: fires exactly once per editor instance. The editor is recreated
63
+ * only when `deps` change or the component remounts; `data` changes —
64
+ * including transitions to and from empty content — re-render in place and
65
+ * never recreate the editor or re-fire `onReady`.
61
66
  */
62
67
  onReady?: (editor: Blok) => void;
63
68
  /**
@@ -113,8 +118,15 @@ export const BlokEditor = forwardRef<Blok | null, BlokEditorProps>(
113
118
  // are reliably populated.
114
119
  const onReadyRef = useRef(onReady);
115
120
  onReadyRef.current = onReady;
121
+ // Hardening, not a bug fix: today this effect only re-runs when `editor`
122
+ // changes, but future React semantics (Fast Refresh, <Activity>) may re-run
123
+ // an effect with an unchanged value. Tracking the last-notified instance
124
+ // guarantees at-most-once per instance while keeping the per-instance
125
+ // re-fire on recreation (deps change / remount) intact.
126
+ const notifiedEditorRef = useRef<Blok | null>(null);
116
127
  useEffect(() => {
117
- if (editor !== null) {
128
+ if (editor !== null && notifiedEditorRef.current !== editor) {
129
+ notifiedEditorRef.current = editor;
118
130
  onReadyRef.current?.(editor);
119
131
  }
120
132
  }, [editor]);
@@ -31,6 +31,7 @@ export const USE_BLOK_CONFIG_KEYS = [
31
31
  'onReady',
32
32
  'onChange',
33
33
  'onSave',
34
+ 'onEnter',
34
35
  'onBeforeRender',
35
36
  'onAfterRender',
36
37
  'inlineToolbar',
@@ -0,0 +1,214 @@
1
+ import type { ComponentType } from 'react';
2
+ import {
3
+ BLOK_PORTAL_REGISTRY_CONFIG_KEY,
4
+ BLOK_TOOL_NAME_CONFIG_KEY,
5
+ type BlockPortalRegistry,
6
+ } from './block-portal-registry';
7
+ import type { SanitizerConfig } from '@/types';
8
+ import type { InlineTool, InlineToolConstructorOptions, MenuConfig } from '@/types/tools';
9
+
10
+ /** Adapter-internal config keys, stripped before the config reaches the component. */
11
+ const INTERNAL_CONFIG_KEYS: readonly string[] = [
12
+ BLOK_PORTAL_REGISTRY_CONFIG_KEY,
13
+ BLOK_TOOL_NAME_CONFIG_KEY,
14
+ ];
15
+
16
+ /**
17
+ * Unique portal-registry key per tool instance (inline tools have no block id
18
+ * to key on, and multiple instances of the same tool can coexist — e.g. the
19
+ * visible toolbar's instance plus a shortcut render-probe).
20
+ * @param toolName - name the tool is registered under
21
+ */
22
+ const generatePortalKey = (toolName: string): string =>
23
+ `__blok-inline-tool__:${toolName}:${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
24
+
25
+ /** Props handed to a React inline tool's `component` (its toolbar icon/UI). */
26
+ export interface ReactInlineToolRenderProps<Config = Record<string, unknown>> {
27
+ /**
28
+ * Whether the tool's formatting is active for the current selection —
29
+ * derived from the spec's `checkState` every time the toolbar queries it.
30
+ * Pushed IN PLACE (no remount), so the icon restyles live.
31
+ */
32
+ active: boolean;
33
+ /**
34
+ * The tool's `config` from the consumer's `tools` map (adapter-internal
35
+ * keys stripped) — the channel for host props (palette, locale…).
36
+ */
37
+ config: Readonly<Partial<Config>>;
38
+ }
39
+
40
+ /** Spec for {@link createReactInlineTool}. */
41
+ export interface CreateReactInlineToolSpec<Config = Record<string, unknown>> {
42
+ /** Tool type name — the MenuConfig item name (fallback when the tools-map key is unavailable). */
43
+ type: string;
44
+ /** Optional toolbar item title (shown in overflow/search contexts). */
45
+ title?: string;
46
+ /** The component rendered as the tool's toolbar icon/UI. */
47
+ component: ComponentType<ReactInlineToolRenderProps<Config>>;
48
+ /** Applies/removes the formatting on the LIVE selection's range (captured at activation time). */
49
+ surround?: (range: Range) => void;
50
+ /** Reports whether the formatting is active for the given selection. */
51
+ checkState?: (selection: Selection | null) => boolean;
52
+ /** Keyboard shortcut (e.g. `CMD+SHIFT+C`). */
53
+ shortcut?: string;
54
+ /** Inline sanitizer config declaring the markup this tool produces. */
55
+ sanitize?: SanitizerConfig;
56
+ /** Whether the tool stays available in read-only mode. */
57
+ isReadOnlySupported?: boolean;
58
+ }
59
+
60
+ /**
61
+ * Author a first-party React inline tool. Returns an inline-tool constructable
62
+ * registered exactly like a vanilla tool (`tools: { color: createReactInlineTool(...) }`).
63
+ *
64
+ * Mirrors the `createReactBlock` portal pattern: `render()` returns a
65
+ * `MenuConfig` whose `icon` is a Blok-owned host element
66
+ * (`data-blok-mutation-free`) the component is portaled into via the editor's
67
+ * shared `BlockPortalHost` tree — app-level context (themes, styled-components
68
+ * providers) reaches the icon with no consumer-managed `createRoot`, and
69
+ * `destroy()` (called by the inline toolbar on close/teardown) unregisters the
70
+ * portal so the component unmounts deterministically — no leaked React roots.
71
+ *
72
+ * Without an injected registry (vanilla core, no `useBlok`), the tool still
73
+ * renders a valid MenuConfig — the host element just stays empty.
74
+ */
75
+ export function createReactInlineTool<Config = Record<string, unknown>>(
76
+ spec: CreateReactInlineToolSpec<Config>
77
+ ): (new (options: InlineToolConstructorOptions) => InlineTool) & {
78
+ readonly __isBlokReactInlineTool: true;
79
+ readonly isInline: true;
80
+ readonly title: string | undefined;
81
+ readonly shortcut: string | undefined;
82
+ readonly sanitize: SanitizerConfig | undefined;
83
+ readonly isReadOnlySupported: boolean;
84
+ } {
85
+ return class ReactInlineTool implements InlineTool {
86
+ /** Marker so `useBlok` can detect react inline tools and inject the registry. */
87
+ public static readonly __isBlokReactInlineTool = true as const;
88
+ public static readonly isInline = true as const;
89
+
90
+ public static get title(): string | undefined {
91
+ return spec.title;
92
+ }
93
+
94
+ public static get shortcut(): string | undefined {
95
+ return spec.shortcut;
96
+ }
97
+
98
+ public static get sanitize(): SanitizerConfig | undefined {
99
+ return spec.sanitize;
100
+ }
101
+
102
+ public static get isReadOnlySupported(): boolean {
103
+ return spec.isReadOnlySupported ?? false;
104
+ }
105
+
106
+ private readonly registry: BlockPortalRegistry | undefined;
107
+ /** Name this tool is registered under in the consumer's `tools` map. */
108
+ private readonly toolName: string;
109
+ /** Unique portal-registry key — inline tools have no block id. */
110
+ private readonly portalKey: string;
111
+ /** The consumer's tool config with adapter-internal keys stripped. */
112
+ private readonly toolConfig: Readonly<Partial<Config>>;
113
+ /** Last active state pushed to the mounted component (change-dedup baseline). */
114
+ private active = false;
115
+ /** True while this instance owns a registered portal entry. */
116
+ private registered = false;
117
+
118
+ public constructor(options: InlineToolConstructorOptions) {
119
+ const config: Record<string, unknown> = options?.config ?? {};
120
+
121
+ this.registry = config[BLOK_PORTAL_REGISTRY_CONFIG_KEY] as BlockPortalRegistry | undefined;
122
+
123
+ const toolName = config[BLOK_TOOL_NAME_CONFIG_KEY];
124
+
125
+ this.toolName = typeof toolName === 'string' ? toolName : spec.type;
126
+ this.portalKey = generatePortalKey(this.toolName);
127
+
128
+ const publicConfig: Record<string, unknown> = {};
129
+
130
+ for (const [key, value] of Object.entries(config)) {
131
+ if (!INTERNAL_CONFIG_KEYS.includes(key)) {
132
+ publicConfig[key] = value;
133
+ }
134
+ }
135
+ this.toolConfig = Object.freeze(publicConfig) as Readonly<Partial<Config>>;
136
+ }
137
+
138
+ public render(): MenuConfig {
139
+ // The Blok-owned host: React reconciles the icon portaled INTO it, and
140
+ // this attribute makes core's MutationObserver ignore those mutations.
141
+ const host = document.createElement('div');
142
+
143
+ host.setAttribute('data-blok-mutation-free', 'true');
144
+
145
+ if (this.registry !== undefined) {
146
+ this.registry.register(this.portalKey, {
147
+ hostEl: host,
148
+ component: spec.component as unknown as ComponentType<Record<string, unknown>>,
149
+ props: { active: this.active, config: this.toolConfig },
150
+ toolName: this.toolName,
151
+ });
152
+ this.registered = true;
153
+ }
154
+
155
+ return {
156
+ name: this.toolName,
157
+ title: spec.title,
158
+ icon: host,
159
+ onActivate: (): void => {
160
+ if (typeof spec.surround !== 'function') {
161
+ return;
162
+ }
163
+
164
+ // Capture the LIVE selection at activation time (matching
165
+ // wrapLegacyInlineTool) — never a range snapshotted at render.
166
+ const selection = window.getSelection();
167
+
168
+ if (!selection || selection.rangeCount === 0) {
169
+ return;
170
+ }
171
+
172
+ spec.surround(selection.getRangeAt(0));
173
+ },
174
+ isActive: (): boolean => this.refreshActiveState(),
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Idempotent teardown, called by the inline toolbar when this instance is
180
+ * dropped (toolbar close, editor destroy, or a throwaway render probe).
181
+ * Unregisters the portal entry so React unmounts the icon component —
182
+ * the unmount signal consumer-managed `createRoot` hacks never had.
183
+ */
184
+ public destroy(): void {
185
+ if (!this.registered) {
186
+ return;
187
+ }
188
+
189
+ this.registered = false;
190
+ this.registry?.unregister(this.portalKey);
191
+ }
192
+
193
+ /**
194
+ * Recompute the active state from the live selection and push it to the
195
+ * mounted component ONLY when it actually changed (no redundant
196
+ * external-store notifications).
197
+ */
198
+ private refreshActiveState(): boolean {
199
+ const active = typeof spec.checkState === 'function'
200
+ ? Boolean(spec.checkState(window.getSelection()))
201
+ : false;
202
+
203
+ if (active !== this.active) {
204
+ this.active = active;
205
+
206
+ if (this.registered) {
207
+ this.registry?.setProps(this.portalKey, { active });
208
+ }
209
+ }
210
+
211
+ return active;
212
+ }
213
+ };
214
+ }
package/src/index.ts CHANGED
@@ -12,6 +12,11 @@ export type {
12
12
  PropSchema,
13
13
  PropSchemaEntry,
14
14
  } from './createReactBlock';
15
+ export { createReactInlineTool } from './createReactInlineTool';
16
+ export type {
17
+ CreateReactInlineToolSpec,
18
+ ReactInlineToolRenderProps,
19
+ } from './createReactInlineTool';
15
20
  export {
16
21
  createBlockPortalRegistry,
17
22
  BLOK_PORTAL_REGISTRY_CONFIG_KEY,
package/src/useBlok.ts CHANGED
@@ -42,6 +42,16 @@ const isReactBlockEntry = (entry: unknown): boolean => {
42
42
  );
43
43
  };
44
44
 
45
+ /** React inline tools (createReactInlineTool) need the same registry bridge. */
46
+ const isReactInlineToolEntry = (entry: unknown): boolean => {
47
+ const toolClass = typeof entry === 'function' ? entry : (entry as { class?: unknown })?.class;
48
+
49
+ return (
50
+ typeof toolClass === 'function' &&
51
+ (toolClass as { __isBlokReactInlineTool?: boolean }).__isBlokReactInlineTool === true
52
+ );
53
+ };
54
+
45
55
  const injectPortalRegistry = (tools: unknown, registry: BlockPortalRegistry): unknown => {
46
56
  if (tools === null || typeof tools !== 'object') {
47
57
  return tools;
@@ -50,7 +60,7 @@ const injectPortalRegistry = (tools: unknown, registry: BlockPortalRegistry): un
50
60
  const result: Record<string, unknown> = {};
51
61
 
52
62
  for (const [name, entry] of Object.entries(tools as Record<string, unknown>)) {
53
- if (!isReactBlockEntry(entry)) {
63
+ if (!isReactBlockEntry(entry) && !isReactInlineToolEntry(entry)) {
54
64
  result[name] = entry;
55
65
 
56
66
  continue;
@@ -225,6 +235,9 @@ export function useBlok(configInput: UseBlokConfig, deps?: DependencyList): Blok
225
235
  onChange: (...args: Parameters<NonNullable<UseBlokConfig['onChange']>>): void => {
226
236
  configRef.current.onChange?.(...args);
227
237
  },
238
+ // Forward the return value: it is the "handled" signal the core acts on.
239
+ onEnter: (...args: Parameters<NonNullable<UseBlokConfig['onEnter']>>): boolean | void =>
240
+ configRef.current.onEnter?.(...args),
228
241
  };
229
242
 
230
243
  // Only attach onSave when the consumer opted in: its mere presence makes the
package/types/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { BlokConfig, BlockToolData, OutputBlockData, OutputData } from '@bloklabs/core';
2
2
  import type { BlockAPI, BlockToolConstructable, ToolboxConfig } from '@bloklabs/core';
3
+ import type { InlineToolConstructable, SanitizerConfig } from '@bloklabs/core';
3
4
  import type { Blok, EditorWidth, BlockRenderedPayload, BlocksRenderedPayload } from '@bloklabs/core';
4
5
  import type { BlockTuneData } from '@bloklabs/core';
5
6
  import type { MarkdownImportConfig } from '@bloklabs/core/markdown';
@@ -624,6 +625,70 @@ export declare function createReactBlock<
624
625
  Config = Record<string, unknown>
625
626
  >(spec: CreateReactBlockSpec<Data, Config>): BlockToolConstructable;
626
627
 
628
+ // ---------------------------------------------------------------------------
629
+ // Inline-tool authoring (createReactInlineTool)
630
+ // ---------------------------------------------------------------------------
631
+
632
+ /** Props handed to a React inline tool's `component` (its toolbar icon/UI). */
633
+ export interface ReactInlineToolRenderProps<Config = Record<string, unknown>> {
634
+ /**
635
+ * Whether the tool's formatting is active for the current selection —
636
+ * derived from the spec's `checkState` every time the toolbar queries it.
637
+ * Pushed IN PLACE (no remount), so the icon restyles live.
638
+ */
639
+ active: boolean;
640
+ /**
641
+ * The tool's `config` from the consumer's `tools` map (adapter-internal
642
+ * keys stripped) — the channel for host props (palette, locale…).
643
+ */
644
+ config: Readonly<Partial<Config>>;
645
+ }
646
+
647
+ /** Spec for {@link createReactInlineTool}. */
648
+ export interface CreateReactInlineToolSpec<Config = Record<string, unknown>> {
649
+ /** Tool type name — the MenuConfig item name (fallback when the tools-map key is unavailable). */
650
+ type: string;
651
+ /** Optional toolbar item title (shown in overflow/search contexts). */
652
+ title?: string;
653
+ /** The component rendered as the tool's toolbar icon/UI. */
654
+ component: React.ComponentType<ReactInlineToolRenderProps<Config>>;
655
+ /** Applies/removes the formatting on the LIVE selection's range (captured at activation time). */
656
+ surround?: (range: Range) => void;
657
+ /** Reports whether the formatting is active for the given selection. */
658
+ checkState?: (selection: Selection | null) => boolean;
659
+ /** Keyboard shortcut (e.g. `CMD+SHIFT+C`). */
660
+ shortcut?: string;
661
+ /** Inline sanitizer config declaring the markup this tool produces. */
662
+ sanitize?: SanitizerConfig;
663
+ /** Whether the tool stays available in read-only mode. */
664
+ isReadOnlySupported?: boolean;
665
+ }
666
+
667
+ /**
668
+ * Author a first-party React inline tool: returns an inline-tool
669
+ * constructable registered exactly like a vanilla tool
670
+ * (`tools: { color: createReactInlineTool(...) }`). The tool's toolbar icon is
671
+ * a React component portaled through the editor's shared portal host INSIDE
672
+ * the React tree that renders `BlokContent`/`BlokEditor` — app-level context
673
+ * (themes, styled-components providers) reaches the icon with no
674
+ * consumer-managed `createRoot`, and the inline toolbar's teardown unmounts it
675
+ * deterministically (no leaked React roots).
676
+ *
677
+ * @example
678
+ * ```tsx
679
+ * const DescriptionColor = createReactInlineTool({
680
+ * type: 'descriptionColor',
681
+ * title: 'Text color',
682
+ * component: ({ active }) => <FontColorIcon active={active} />,
683
+ * surround: (range) => applyColor(range),
684
+ * checkState: (selection) => hasColor(selection),
685
+ * });
686
+ * ```
687
+ */
688
+ export declare function createReactInlineTool<Config = Record<string, unknown>>(
689
+ spec: CreateReactInlineToolSpec<Config>
690
+ ): InlineToolConstructable;
691
+
627
692
  /**
628
693
  * Tool-config key carrying the editor's portal registry into a
629
694
  * `createReactBlock` tool. Injected automatically by `useBlok`; exposed for