@bloklabs/react 1.2.5 → 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)},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)}}),()=>{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.onEnter.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;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)(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;
@@ -272,18 +275,18 @@ function J(e, t) {
272
275
  (t = (n = u.current).onAfterRender) == null || t.call(n, ...e);
273
276
  });
274
277
  let c = new d(s);
275
- 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(() => {
276
279
  e.editor === c && !e.isDestroyed && (e.isEditorReady = !0, o(c));
277
280
  }).catch(() => {
278
281
  if (e.editor === c && !e.isDestroyed) {
279
- D(c), U(c);
282
+ E(c), V(c);
280
283
  try {
281
284
  c.destroy();
282
285
  } catch (e) {}
283
286
  e.editor = null, e.holder = null, e.isDestroyed = !0, e.isEditorReady = !1, o(null);
284
287
  }
285
288
  }), () => {
286
- Y(e, o);
289
+ J(e, o);
287
290
  };
288
291
  }, [p]), a(() => {
289
292
  let e = x.current, t = f.current;
@@ -293,8 +296,8 @@ function J(e, t) {
293
296
  let r = S.current;
294
297
  for (let [t, a] of Object.entries(n)) {
295
298
  var i;
296
- if (!q(a)) continue;
297
- 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);
298
301
  if (c !== void 0 && g(s, c)) continue;
299
302
  let l = Object.freeze(s);
300
303
  C.current.set(t, l), e.setToolConfig(t, l);
@@ -304,43 +307,43 @@ function J(e, t) {
304
307
  a(() => {
305
308
  r !== null && r.readOnly.set(w);
306
309
  }, [r, w]);
307
- 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;
308
315
  a(() => {
309
- r === null || !E || r.focus();
310
- }, [r, E]);
311
- let { theme: O } = n;
316
+ r === null || D === void 0 || r.theme.set(D);
317
+ }, [r, D]);
318
+ let { width: O } = n;
312
319
  a(() => {
313
- r === null || O === void 0 || r.theme.set(O);
320
+ r === null || O === void 0 || r.width.set(O);
314
321
  }, [r, O]);
315
- let { width: k } = n;
322
+ let { placeholder: k } = n;
316
323
  a(() => {
317
- r === null || k === void 0 || r.width.set(k);
324
+ r === null || k === void 0 || r.placeholder.set(k);
318
325
  }, [r, k]);
319
- let { placeholder: A } = n;
320
- a(() => {
321
- r === null || A === void 0 || r.placeholder.set(A);
322
- }, [r, A]);
323
- let { data: j } = n;
326
+ let { data: A } = n;
324
327
  return a(() => {
325
- if (r === null || j === void 0) return;
328
+ if (r === null || A === void 0) return;
326
329
  let e = f.current;
327
330
  if (!(e.editor !== r || e.isDestroyed)) {
328
- if (h.current !== r && (h.current = r, b.current = void 0, g(j, _.current))) {
329
- m.current = j;
331
+ if (h.current !== r && (h.current = r, b.current = void 0, g(A, _.current))) {
332
+ m.current = A;
330
333
  return;
331
334
  }
332
- g(j, m.current) || g(j, b.current) || (b.current = j, v.current = v.current.catch(() => void 0).then(() => r.render(j)).then(() => {
333
- 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;
334
337
  }, () => {}).then(() => {
335
- b.current === j && (b.current = void 0);
338
+ b.current === A && (b.current = void 0);
336
339
  }));
337
340
  }
338
- }, [r, j]), r;
341
+ }, [r, A]), r;
339
342
  }
340
- function Y(e, t) {
343
+ function J(e, t) {
341
344
  e.destroyTimeout = setTimeout(() => {
342
345
  if (e.editor !== null) {
343
- D(e.editor), U(e.editor);
346
+ E(e.editor), V(e.editor);
344
347
  try {
345
348
  e.editor.destroy();
346
349
  } catch (e) {}
@@ -350,7 +353,7 @@ function Y(e, t) {
350
353
  }
351
354
  //#endregion
352
355
  //#region src/BlockPortalHost.tsx
353
- var re = class extends e {
356
+ var Y = class extends e {
354
357
  constructor(...e) {
355
358
  super(...e), this.state = { failed: !1 };
356
359
  }
@@ -366,12 +369,12 @@ function X({ registry: e }) {
366
369
  let t = u(e.subscribe, e.getSnapshot, e.getSnapshot);
367
370
  return /* @__PURE__ */ x(b, { children: Array.from(t.entries()).map(([e, t]) => {
368
371
  let n = t.component;
369
- 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);
370
373
  }) });
371
374
  }
372
375
  //#endregion
373
376
  //#region \0@oxc-project+runtime@0.126.0/helpers/objectWithoutPropertiesLoose.js
374
- function ie(e, t) {
377
+ function ae(e, t) {
375
378
  if (e == null) return {};
376
379
  var n = {};
377
380
  for (var r in e) if ({}.hasOwnProperty.call(e, r)) {
@@ -384,7 +387,7 @@ function ie(e, t) {
384
387
  //#region \0@oxc-project+runtime@0.126.0/helpers/objectWithoutProperties.js
385
388
  function Z(e, t) {
386
389
  if (e == null) return {};
387
- var n, r, i = ie(e, t);
390
+ var n, r, i = ae(e, t);
388
391
  if (Object.getOwnPropertySymbols) {
389
392
  var a = Object.getOwnPropertySymbols(e);
390
393
  for (r = 0; r < a.length; r++) n = a[r], t.includes(n) || {}.propertyIsEnumerable.call(e, n) && (i[n] = e[n]);
@@ -393,8 +396,8 @@ function Z(e, t) {
393
396
  }
394
397
  //#endregion
395
398
  //#region src/BlokContent.tsx
396
- var ae = ["editor"], Q = n(function(e, t) {
397
- 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) => {
398
401
  if (i.current = e, typeof t == "function") t(e);
399
402
  else if (t != null) {
400
403
  let n = t;
@@ -403,25 +406,25 @@ var ae = ["editor"], Q = n(function(e, t) {
403
406
  };
404
407
  a(() => {
405
408
  if (n === null || i.current === null) return;
406
- let e = E(n);
409
+ let e = T(n);
407
410
  if (e !== void 0) return i.current.appendChild(e), () => {
408
411
  e.remove();
409
412
  };
410
413
  }, [n]);
411
- let s = n === null ? void 0 : H(n);
412
- return /* @__PURE__ */ x("div", N(N({ ref: o }, r), {}, { children: s === void 0 ? null : /* @__PURE__ */ x(X, { registry: s }) }));
413
- }), oe = /* @__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("."), 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 = [
414
417
  "deps",
415
418
  "onReady",
416
419
  "onBlocksRendered",
417
420
  "onBlockRendered"
418
- ], ce = new Set(oe), le = n(function(e, t) {
419
- 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 = {};
420
423
  for (let e of Object.keys(l)) {
421
424
  let t = l[e];
422
- ce.has(e) ? u[e] = t : d[e] = t;
425
+ le.has(e) ? u[e] = t : d[e] = t;
423
426
  }
424
- let f = J(u, n);
427
+ let f = q(u, n);
425
428
  o(t, () => f, [f]);
426
429
  let p = c(r);
427
430
  p.current = r;
@@ -461,9 +464,9 @@ var ae = ["editor"], Q = n(function(e, t) {
461
464
  f,
462
465
  _,
463
466
  v
464
- ]), /* @__PURE__ */ x(Q, N({ editor: f }, d));
467
+ ]), /* @__PURE__ */ x(Q, M({ editor: f }, d));
465
468
  }), $ = "block changed";
466
- function ue(e) {
469
+ function de(e) {
467
470
  let t = c(0), n = c(e);
468
471
  n.current !== e && (n.current = e, t.current = 0);
469
472
  let i = r((n) => {
@@ -477,8 +480,8 @@ function ue(e) {
477
480
  }
478
481
  //#endregion
479
482
  //#region src/createReactBlock.tsx
480
- var de = [L, R];
481
- function fe(e) {
483
+ var fe = [F, I];
484
+ function pe(e) {
482
485
  var t;
483
486
  return t = class {
484
487
  static get toolbox() {
@@ -491,15 +494,15 @@ function fe(e) {
491
494
  var n, r;
492
495
  this.hostEl = null, this.pendingDispatch = !1, this.commit = (t) => {
493
496
  var n;
494
- let r = _(e.propSchema, N(N({}, this.mirror), t));
497
+ let r = _(e.propSchema, M(M({}, this.mirror), t));
495
498
  h(r, this.mirror) || (this.mirror = r, this.lastRendered = r, (n = this.registry) == null || n.setProps(this.blockApi.id, { data: r }), this.flushDispatch());
496
499
  }, this.blockApi = t.block;
497
500
  let i = (n = t.config) == null ? {} : n;
498
- this.registry = i[L];
499
- let o = i[R];
501
+ this.registry = i[F];
502
+ let o = i[I];
500
503
  this.toolName = typeof o == "string" ? o : void 0;
501
504
  let s = {};
502
- 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);
503
506
  this.toolConfig = Object.freeze(s);
504
507
  let l = t.api;
505
508
  this.pointerDrag = () => {
@@ -589,4 +592,70 @@ function fe(e) {
589
592
  }, t.__isBlokReactBlock = !0, t;
590
593
  }
591
594
  //#endregion
592
- 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.5",
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.5",
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
  }
@@ -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;
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