@jackuait/blok 0.23.4 → 0.23.5

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.
@@ -1,5 +1,5 @@
1
1
  import { i as e, t } from "./chunk-5O_1xk2F.mjs";
2
- import { $ as n, $n as r, $r as i, $t as a, Ai as o, An as s, Ar as c, At as l, B as u, Bn as d, Br as f, Bt as p, C as m, Ci as h, Cn as g, Cr as _, Ct as v, Dn as y, Dr as b, Dt as x, Ea as S, Ei as C, En as w, Er as T, Et as E, F as D, Fn as ee, Fr as O, Ft as k, G as A, Gn as te, Gr as j, Gt as M, H as N, Hn as ne, Hr as P, Ht as re, I as F, In as ie, Ir as ae, It as I, J as oe, Jn as L, Jr as se, Jt as ce, Kn as le, Kr as ue, Kt as de, L as R, Ln as fe, Lr as pe, Lt as me, Ma as z, Mn as he, Mr as ge, Mt as _e, Na as ve, Ni as ye, Nn as be, Nr as xe, Nt as Se, On as Ce, Or as we, Ot as Te, P as Ee, Pi as De, Pn as Oe, Pr as ke, Pt as Ae, Q as je, Qn as Me, Qr as Ne, Qt as Pe, R as Fe, Rn as Ie, Rr as Le, Rt as Re, S as ze, Si as Be, Sn as Ve, Sr as He, St as Ue, T as We, Ti as Ge, Tn as Ke, Tr as qe, Tt as Je, U as Ye, Un as Xe, Ur as Ze, Ut as Qe, Vn as $e, Vr as et, Vt as tt, W as B, Wn as nt, Wr as rt, Wt as it, X as at, Xn as ot, Xr as st, Xt as ct, Y as lt, Yn as ut, Yr as dt, Yt as ft, Z as pt, Zi as mt, Zn as ht, Zt as gt, _ as _t, _n as vt, _r as yt, _t as bt, a as xt, ai as St, ar as Ct, at as wt, b as Tt, bi as V, bn as Et, br as Dt, bt as Ot, c as kt, cn as At, cr as jt, ct as Mt, d as Nt, di as Pt, dn as Ft, dr as It, dt as Lt, ei as Rt, en as zt, er as Bt, et as Vt, f as Ht, fn as Ut, fr as Wt, ft as Gt, g as Kt, gi as qt, gn as Jt, gr as Yt, gt as Xt, h as Zt, hn as Qt, hr as $t, ht as en, i as tn, ia as nn, ii as rn, in as an, ir as on, it as sn, jn as cn, jr as ln, jt as un, ki as H, kn as dn, kr as fn, kt as pn, l as mn, li as hn, ln as gn, lr as _n, lt as vn, mn as yn, mr as bn, mt as xn, n as Sn, ni as Cn, nn as wn, nr as Tn, nt as En, o as Dn, oa as On, oi as kn, on as An, or as jn, ot as Mn, p as Nn, pi as Pn, pn as Fn, pr as In, pt as Ln, q as Rn, qr as zn, qt as Bn, r as Vn, ri as Hn, rr as Un, rt as Wn, s as Gn, si as Kn, sn as qn, sr as Jn, st as Yn, t as Xn, ti as Zn, tr as Qn, u as U, ui as $n, un as er, ur as tr, ut as nr, v as rr, vn as ir, vr as ar, vt as or, wi as sr, wn as cr, wr as lr, wt as ur, x as dr, xi as fr, xn as pr, xr as mr, xt as hr, y as gr, yn as _r, yr as vr, yt as yr, z as br, zn as xr, zr as Sr, zt as Cr } from "./constants-DZtdGLlr.mjs";
2
+ import { $ as n, $n as r, $r as i, $t as a, Ai as o, An as s, Ar as c, At as l, B as u, Bn as d, Br as f, Bt as p, C as m, Ci as h, Cn as g, Cr as _, Ct as v, Dn as y, Dr as b, Dt as x, Ea as S, Ei as C, En as w, Er as T, Et as E, F as D, Fn as ee, Fr as O, Ft as k, G as A, Gn as te, Gr as j, Gt as M, H as N, Hn as ne, Hr as P, Ht as re, I as F, In as ie, Ir as ae, It as I, J as oe, Jn as L, Jr as se, Jt as ce, Kn as le, Kr as ue, Kt as de, L as R, Ln as fe, Lr as pe, Lt as me, Ma as z, Mn as he, Mr as ge, Mt as _e, Na as ve, Ni as ye, Nn as be, Nr as xe, Nt as Se, On as Ce, Or as we, Ot as Te, P as Ee, Pi as De, Pn as Oe, Pr as ke, Pt as Ae, Q as je, Qn as Me, Qr as Ne, Qt as Pe, R as Fe, Rn as Ie, Rr as Le, Rt as Re, S as ze, Si as Be, Sn as Ve, Sr as He, St as Ue, T as We, Ti as Ge, Tn as Ke, Tr as qe, Tt as Je, U as Ye, Un as Xe, Ur as Ze, Ut as Qe, Vn as $e, Vr as et, Vt as tt, W as B, Wn as nt, Wr as rt, Wt as it, X as at, Xn as ot, Xr as st, Xt as ct, Y as lt, Yn as ut, Yr as dt, Yt as ft, Z as pt, Zi as mt, Zn as ht, Zt as gt, _ as _t, _n as vt, _r as yt, _t as bt, a as xt, ai as St, ar as Ct, at as wt, b as Tt, bi as V, bn as Et, br as Dt, bt as Ot, c as kt, cn as At, cr as jt, ct as Mt, d as Nt, di as Pt, dn as Ft, dr as It, dt as Lt, ei as Rt, en as zt, er as Bt, et as Vt, f as Ht, fn as Ut, fr as Wt, ft as Gt, g as Kt, gi as qt, gn as Jt, gr as Yt, gt as Xt, h as Zt, hn as Qt, hr as $t, ht as en, i as tn, ia as nn, ii as rn, in as an, ir as on, it as sn, jn as cn, jr as ln, jt as un, ki as H, kn as dn, kr as fn, kt as pn, l as mn, li as hn, ln as gn, lr as _n, lt as vn, mn as yn, mr as bn, mt as xn, n as Sn, ni as Cn, nn as wn, nr as Tn, nt as En, o as Dn, oa as On, oi as kn, on as An, or as jn, ot as Mn, p as Nn, pi as Pn, pn as Fn, pr as In, pt as Ln, q as Rn, qr as zn, qt as Bn, r as Vn, ri as Hn, rr as Un, rt as Wn, s as Gn, si as Kn, sn as qn, sr as Jn, st as Yn, t as Xn, ti as Zn, tr as Qn, u as U, ui as $n, un as er, ur as tr, ut as nr, v as rr, vn as ir, vr as ar, vt as or, wi as sr, wn as cr, wr as lr, wt as ur, x as dr, xi as fr, xn as pr, xr as mr, xt as hr, y as gr, yn as _r, yr as vr, yt as yr, z as br, zn as xr, zr as Sr, zt as Cr } from "./constants-DpIX_GOn.mjs";
3
3
  import { t as W } from "./objectSpread2-jlBcdYeb.mjs";
4
4
  import { n as G } from "./tw-DmW6-pCY.mjs";
5
5
  import { n as wr } from "./lightweight-i18n-Cj88c8gl.mjs";
package/dist/full.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./chunks/blok-qwtrt5R3.cjs`),t=require(`./chunks/constants-Y3Af_xZ7.cjs`),n=require(`./chunks/objectSpread2-iNkE6aJh.cjs`),r=require(`./chunks/tools-BmSYWm8L.cjs`);var i={paragraph:{class:r.k,inlineToolbar:!0,config:{preserveBlank:!0}},header:{class:r.O,inlineToolbar:!0},list:{class:r.D,inlineToolbar:!0}},a=n.t(n.t({},i),{},{bold:{class:r.l},italic:{class:r.c},marker:{class:r.o},underline:{class:r.a},strikethrough:{class:r.i},link:{class:r.s}});exports.Blok=e.t,exports.Bold=r.l,exports.DATA_ATTR=t.Ma,exports.Header=r.O,exports.Italic=r.c,exports.Link=r.s,exports.List=r.D,exports.Marker=r.o,exports.Paragraph=r.k,exports.Strikethrough=r.i,exports.Toggle=r.T,exports.Underline=r.a,exports.allTools=a,exports.defaultBlockTools=r.t,exports.defaultInlineTools=r.n,exports.defaultTools=i,exports.version=e.n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./chunks/blok-DixLFA0K.cjs`),t=require(`./chunks/constants-Bze_TXgc.cjs`),n=require(`./chunks/objectSpread2-iNkE6aJh.cjs`),r=require(`./chunks/tools-CRAPWuhj.cjs`);var i={paragraph:{class:r.k,inlineToolbar:!0,config:{preserveBlank:!0}},header:{class:r.O,inlineToolbar:!0},list:{class:r.D,inlineToolbar:!0}},a=n.t(n.t({},i),{},{bold:{class:r.l},italic:{class:r.c},marker:{class:r.o},underline:{class:r.a},strikethrough:{class:r.i},link:{class:r.s}});exports.Blok=e.t,exports.Bold=r.l,exports.DATA_ATTR=t.Ma,exports.Header=r.O,exports.Italic=r.c,exports.Link=r.s,exports.List=r.D,exports.Marker=r.o,exports.Paragraph=r.k,exports.Strikethrough=r.i,exports.Toggle=r.T,exports.Underline=r.a,exports.allTools=a,exports.defaultBlockTools=r.t,exports.defaultInlineTools=r.n,exports.defaultTools=i,exports.version=e.n;
package/dist/full.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { n as e, t } from "./chunks/blok-BydOC-jj.mjs";
2
- import { Ma as n } from "./chunks/constants-DZtdGLlr.mjs";
1
+ import { n as e, t } from "./chunks/blok-TvOrZOjF.mjs";
2
+ import { Ma as n } from "./chunks/constants-DpIX_GOn.mjs";
3
3
  import { t as r } from "./chunks/objectSpread2-jlBcdYeb.mjs";
4
- import { D as i, O as a, T as o, a as s, c, i as l, k as u, l as d, n as f, o as p, s as m, t as h } from "./chunks/tools-DOZaLyYm.mjs";
4
+ import { D as i, O as a, T as o, a as s, c, i as l, k as u, l as d, n as f, o as p, s as m, t as h } from "./chunks/tools-DBb88o-I.mjs";
5
5
  //#region src/full.ts
6
6
  var g = {
7
7
  paragraph: {
package/dist/react.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./chunks/chunk-BL1yB9zm.cjs`);const e=require(`./chunks/blok-qwtrt5R3.cjs`),t=require(`./chunks/objectSpread2-iNkE6aJh.cjs`);let n=require(`react`),r=require(`react/jsx-runtime`);var i=new WeakMap;function a(e,t){i.set(e,t)}function o(e){return i.get(e)}function s(e){i.delete(e)}function c(e,t){if(e===t)return!0;if(typeof e!=`object`||!e||typeof t!=`object`||!t)return!1;let n=Array.isArray(e),r=Array.isArray(t);if(n!==r)return!1;if(n&&r)return e.length===t.length?e.every((e,n)=>c(e,t[n])):!1;let i=e,a=t,o=Object.keys(i),s=Object.keys(a);return o.length===s.length?o.every(e=>Object.prototype.hasOwnProperty.call(a,e)&&c(i[e],a[e])):!1}function l(r,i){let[o,l]=(0,n.useState)(null),d=(0,n.useRef)(r);d.current=r;let f=(0,n.useRef)({editor:null,holder:null,destroyTimeout:null,isDestroyed:!1,depsToken:null}),p=(0,n.useMemo)(()=>({}),i==null?[]:i),m=(0,n.useRef)(r.data),h=(0,n.useRef)(null),g=(0,n.useRef)(Promise.resolve());(0,n.useEffect)(()=>{if(typeof window>`u`)return;let n=f.current;if(n.destroyTimeout!==null&&(clearTimeout(n.destroyTimeout),n.destroyTimeout=null),n.editor!==null&&!n.isDestroyed&&n.depsToken===p)return l(n.editor),()=>{u(n,l)};if(n.editor!==null&&!n.isDestroyed){s(n.editor);try{n.editor.destroy()}catch(e){}n.editor=null,n.holder=null,n.isDestroyed=!0,l(null)}let r=document.createElement(`div`);n.holder=r,n.isDestroyed=!1,n.depsToken=p;let i=d.current,o=t.t(t.t({},i),{},{holder:r,onReady:()=>{var e,t;(e=(t=d.current).onReady)==null||e.call(t)},onChange:(...e)=>{var t,n;(t=(n=d.current).onChange)==null||t.call(n,...e)}});i.onSave&&(o.onSave=(...e)=>{var t,n;m.current=e[0],(t=(n=d.current).onSave)==null||t.call(n,...e)});let c=new e.t(o);return n.editor=c,a(c,r),c.isReady.then(()=>{n.editor===c&&!n.isDestroyed&&l(c)}).catch(()=>{if(n.editor===c&&!n.isDestroyed){s(c);try{c.destroy()}catch(e){}n.editor=null,n.holder=null,n.isDestroyed=!0,l(null)}}),()=>{u(n,l)}},[p]);let{readOnly:_}=r;(0,n.useEffect)(()=>{o!==null&&o.readOnly.set(_==null?!1:_)},[o,_]);let{autofocus:v}=r;(0,n.useEffect)(()=>{o===null||!v||o.focus()},[o,v]);let{theme:y}=r;(0,n.useEffect)(()=>{o===null||y===void 0||o.theme.set(y)},[o,y]);let{width:b}=r;(0,n.useEffect)(()=>{o===null||b===void 0||o.width.set(b)},[o,b]);let{placeholder:x}=r;(0,n.useEffect)(()=>{o===null||x===void 0||o.placeholder.set(x)},[o,x]);let{data:S}=r;return(0,n.useEffect)(()=>{if(!(o===null||S===void 0)){if(h.current!==o){h.current=o,m.current=S;return}c(S,m.current)||(m.current=S,g.current=g.current.catch(()=>void 0).then(()=>o.render(S)))}},[o,S]),o}function u(e,t){e.destroyTimeout=setTimeout(()=>{if(e.editor!==null){s(e.editor);try{e.editor.destroy()}catch(e){}e.editor=null,e.holder=null,e.isDestroyed=!0,e.destroyTimeout=null,t(null)}},0)}var d=[`editor`],f=(0,n.forwardRef)(function(i,a){let{editor:s}=i,c=e.i(i,d),l=(0,n.useRef)(null);return(0,n.useEffect)(()=>{if(s===null||l.current===null)return;let e=o(s);if(e!==void 0)return l.current.appendChild(e),()=>{e.remove()}},[s]),(0,r.jsx)(`div`,t.t({ref:e=>{if(l.current=e,typeof a==`function`)a(e);else if(a!=null){let t=a;t.current=e}}},c))}),p=`autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.onBeforePaste.onReady.onChange.onSave.inlineToolbar.tunes.style.theme.onThemeChange.scrollToBlock.user.resolveUser.notifierPosition.notifier.width`.split(`.`),m=[`deps`,`onReady`],h=new Set(p),g=(0,n.forwardRef)(function(i,a){let{deps:o,onReady:s}=i,c=e.i(i,m),u={},d={};for(let e of Object.keys(c)){let t=c[e];h.has(e)?u[e]=t:d[e]=t}let p=l(u,o);(0,n.useImperativeHandle)(a,()=>p,[p]);let g=(0,n.useRef)(s);return g.current=s,(0,n.useEffect)(()=>{if(p!==null){var e;(e=g.current)==null||e.call(g,p)}},[p]),(0,r.jsx)(f,t.t({editor:p},d))});exports.BlokContent=f,exports.BlokEditor=g,exports.useBlok=l;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./chunks/chunk-BL1yB9zm.cjs`);const e=require(`./chunks/blok-DixLFA0K.cjs`),t=require(`./chunks/objectSpread2-iNkE6aJh.cjs`);let n=require(`react`),r=require(`react/jsx-runtime`);var i=new WeakMap;function a(e,t){i.set(e,t)}function o(e){return i.get(e)}function s(e){i.delete(e)}function c(e,t){if(e===t)return!0;if(typeof e!=`object`||!e||typeof t!=`object`||!t)return!1;let n=Array.isArray(e),r=Array.isArray(t);if(n!==r)return!1;if(n&&r)return e.length===t.length?e.every((e,n)=>c(e,t[n])):!1;let i=e,a=t,o=Object.keys(i),s=Object.keys(a);return o.length===s.length?o.every(e=>Object.prototype.hasOwnProperty.call(a,e)&&c(i[e],a[e])):!1}function l(r,i){let[o,l]=(0,n.useState)(null),d=(0,n.useRef)(r);d.current=r;let f=(0,n.useRef)({editor:null,holder:null,destroyTimeout:null,isDestroyed:!1,depsToken:null}),p=(0,n.useMemo)(()=>({}),i==null?[]:i),m=(0,n.useRef)(r.data),h=(0,n.useRef)(null),g=(0,n.useRef)(Promise.resolve());(0,n.useEffect)(()=>{if(typeof window>`u`)return;let n=f.current;if(n.destroyTimeout!==null&&(clearTimeout(n.destroyTimeout),n.destroyTimeout=null),n.editor!==null&&!n.isDestroyed&&n.depsToken===p)return l(n.editor),()=>{u(n,l)};if(n.editor!==null&&!n.isDestroyed){s(n.editor);try{n.editor.destroy()}catch(e){}n.editor=null,n.holder=null,n.isDestroyed=!0,l(null)}let r=document.createElement(`div`);n.holder=r,n.isDestroyed=!1,n.depsToken=p;let i=d.current,o=t.t(t.t({},i),{},{holder:r,onReady:()=>{var e,t;(e=(t=d.current).onReady)==null||e.call(t)},onChange:(...e)=>{var t,n;(t=(n=d.current).onChange)==null||t.call(n,...e)}});i.onSave&&(o.onSave=(...e)=>{var t,n;m.current=e[0],(t=(n=d.current).onSave)==null||t.call(n,...e)}),i.onBeforeRender&&(o.onBeforeRender=(...e)=>{var t,n,r;return(t=(n=(r=d.current).onBeforeRender)==null?void 0:n.call(r,...e))==null?e[0]:t}),i.onAfterRender&&(o.onAfterRender=(...e)=>{var t,n;(t=(n=d.current).onAfterRender)==null||t.call(n,...e)});let c=new e.t(o);return n.editor=c,a(c,r),c.isReady.then(()=>{n.editor===c&&!n.isDestroyed&&l(c)}).catch(()=>{if(n.editor===c&&!n.isDestroyed){s(c);try{c.destroy()}catch(e){}n.editor=null,n.holder=null,n.isDestroyed=!0,l(null)}}),()=>{u(n,l)}},[p]);let{readOnly:_}=r;(0,n.useEffect)(()=>{o!==null&&o.readOnly.set(_==null?!1:_)},[o,_]);let{autofocus:v}=r;(0,n.useEffect)(()=>{o===null||!v||o.focus()},[o,v]);let{theme:y}=r;(0,n.useEffect)(()=>{o===null||y===void 0||o.theme.set(y)},[o,y]);let{width:b}=r;(0,n.useEffect)(()=>{o===null||b===void 0||o.width.set(b)},[o,b]);let{placeholder:x}=r;(0,n.useEffect)(()=>{o===null||x===void 0||o.placeholder.set(x)},[o,x]);let{data:S}=r;return(0,n.useEffect)(()=>{if(!(o===null||S===void 0)){if(h.current!==o){h.current=o,m.current=S;return}c(S,m.current)||(m.current=S,g.current=g.current.catch(()=>void 0).then(()=>o.render(S)))}},[o,S]),o}function u(e,t){e.destroyTimeout=setTimeout(()=>{if(e.editor!==null){s(e.editor);try{e.editor.destroy()}catch(e){}e.editor=null,e.holder=null,e.isDestroyed=!0,e.destroyTimeout=null,t(null)}},0)}var d=[`editor`],f=(0,n.forwardRef)(function(i,a){let{editor:s}=i,c=e.i(i,d),l=(0,n.useRef)(null);return(0,n.useEffect)(()=>{if(s===null||l.current===null)return;let e=o(s);if(e!==void 0)return l.current.appendChild(e),()=>{e.remove()}},[s]),(0,r.jsx)(`div`,t.t({ref:e=>{if(l.current=e,typeof a==`function`)a(e);else if(a!=null){let t=a;t.current=e}}},c))}),p=`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(`.`),m=[`deps`,`onReady`],h=new Set(p),g=(0,n.forwardRef)(function(i,a){let{deps:o,onReady:s}=i,c=e.i(i,m),u={},d={};for(let e of Object.keys(c)){let t=c[e];h.has(e)?u[e]=t:d[e]=t}let p=l(u,o);(0,n.useImperativeHandle)(a,()=>p,[p]);let g=(0,n.useRef)(s);return g.current=s,(0,n.useEffect)(()=>{if(p!==null){var e;(e=g.current)==null||e.call(g,p)}},[p]),(0,r.jsx)(f,t.t({editor:p},d))});exports.BlokContent=f,exports.BlokEditor=g,exports.useBlok=l;
package/dist/react.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as e, t } from "./chunks/blok-BydOC-jj.mjs";
1
+ import { i as e, t } from "./chunks/blok-TvOrZOjF.mjs";
2
2
  import { t as n } from "./chunks/objectSpread2-jlBcdYeb.mjs";
3
3
  import { forwardRef as r, useEffect as i, useImperativeHandle as a, useMemo as o, useRef as s, useState as c } from "react";
4
4
  import { jsx as l } from "react/jsx-runtime";
@@ -65,6 +65,12 @@ function h(e, r) {
65
65
  i.onSave && (a.onSave = (...e) => {
66
66
  var t, n;
67
67
  _.current = e[0], (t = (n = u.current).onSave) == null || t.call(n, ...e);
68
+ }), i.onBeforeRender && (a.onBeforeRender = (...e) => {
69
+ var t, n, r;
70
+ return (t = (n = (r = u.current).onBeforeRender) == null ? void 0 : n.call(r, ...e)) == null ? e[0] : t;
71
+ }), i.onAfterRender && (a.onAfterRender = (...e) => {
72
+ var t, n;
73
+ (t = (n = u.current).onAfterRender) == null || t.call(n, ...e);
68
74
  });
69
75
  let o = new t(a);
70
76
  return e.editor = o, d(o, r), o.isReady.then(() => {
@@ -140,7 +146,7 @@ var _ = ["editor"], v = r(function(t, r) {
140
146
  t.current = e;
141
147
  }
142
148
  } }, o));
143
- }), y = /* @__PURE__ */ "autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.onBeforePaste.onReady.onChange.onSave.inlineToolbar.tunes.style.theme.onThemeChange.scrollToBlock.user.resolveUser.notifierPosition.notifier.width".split("."), b = ["deps", "onReady"], x = new Set(y), S = r(function(t, r) {
149
+ }), y = /* @__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("."), b = ["deps", "onReady"], x = new Set(y), S = r(function(t, r) {
144
150
  let { deps: o, onReady: c } = t, u = e(t, b), d = {}, f = {};
145
151
  for (let e of Object.keys(u)) {
146
152
  let t = u[e];
package/dist/tools.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./chunks/constants-Y3Af_xZ7.cjs`),t=require(`./chunks/tools-BmSYWm8L.cjs`);exports.Audio=t.g,exports.Bold=t.l,exports.Bookmark=t.u,exports.Callout=t.w,exports.Code=t.y,exports.Column=t.p,exports.ColumnList=t.m,exports.Columns=t.f,exports.Convert=e.m,exports.Database=t.C,exports.DatabaseRow=t.S,exports.Divider=t.x,exports.Embed=t.d,exports.File=t._,exports.Header=t.O,exports.Image=t.v,exports.InlineCode=t.r,exports.Italic=t.c,exports.Link=t.s,exports.List=t.D,exports.Marker=t.o,exports.Paragraph=t.k,exports.Quote=t.b,exports.Strikethrough=t.i,exports.Table=t.E,exports.Toggle=t.T,exports.Underline=t.a,exports.Video=t.h,exports.defaultBlockTools=t.t,exports.defaultInlineTools=t.n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./chunks/constants-Bze_TXgc.cjs`),t=require(`./chunks/tools-CRAPWuhj.cjs`);exports.Audio=t.g,exports.Bold=t.l,exports.Bookmark=t.u,exports.Callout=t.w,exports.Code=t.y,exports.Column=t.p,exports.ColumnList=t.m,exports.Columns=t.f,exports.Convert=e.m,exports.Database=t.C,exports.DatabaseRow=t.S,exports.Divider=t.x,exports.Embed=t.d,exports.File=t._,exports.Header=t.O,exports.Image=t.v,exports.InlineCode=t.r,exports.Italic=t.c,exports.Link=t.s,exports.List=t.D,exports.Marker=t.o,exports.Paragraph=t.k,exports.Quote=t.b,exports.Strikethrough=t.i,exports.Table=t.E,exports.Toggle=t.T,exports.Underline=t.a,exports.Video=t.h,exports.defaultBlockTools=t.t,exports.defaultInlineTools=t.n;
package/dist/tools.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { m as e } from "./chunks/constants-DZtdGLlr.mjs";
2
- import { C as t, D as n, E as r, O as i, S as a, T as o, _ as s, a as c, b as l, c as u, d, f, g as p, h as m, i as h, k as g, l as _, m as v, n as y, o as b, p as x, r as S, s as C, t as w, u as T, v as E, w as D, x as O, y as k } from "./chunks/tools-DOZaLyYm.mjs";
1
+ import { m as e } from "./chunks/constants-DpIX_GOn.mjs";
2
+ import { C as t, D as n, E as r, O as i, S as a, T as o, _ as s, a as c, b as l, c as u, d, f, g as p, h as m, i as h, k as g, l as _, m as v, n as y, o as b, p as x, r as S, s as C, t as w, u as T, v as E, w as D, x as O, y as k } from "./chunks/tools-DBb88o-I.mjs";
3
3
  export { p as Audio, _ as Bold, T as Bookmark, D as Callout, k as Code, x as Column, v as ColumnList, f as Columns, e as Convert, t as Database, a as DatabaseRow, O as Divider, d as Embed, s as File, i as Header, E as Image, S as InlineCode, u as Italic, C as Link, n as List, b as Marker, g as Paragraph, l as Quote, h as Strikethrough, r as Table, o as Toggle, c as Underline, m as Video, w as defaultBlockTools, y as defaultInlineTools };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jackuait/blok",
3
- "version": "0.23.4",
3
+ "version": "0.23.5",
4
4
  "description": "Blok — headless, highly extensible rich text editor built for developers who need to implement a block-based editing experience (similar to Notion) without building it from scratch",
5
5
  "module": "dist/blok.mjs",
6
6
  "main": "./dist/blok.cjs",
@@ -8,6 +8,7 @@ import type {
8
8
  PopoverItemParams
9
9
  } from '../../../types';
10
10
  import type { BlockTuneData } from '../../../types/block-tunes/block-tune-data';
11
+ import type { BlockTuneRenderContext } from '../../../types/block-tunes/block-tune';
11
12
  import type { SavedData } from '../../../types/data-formats';
12
13
  import { Dom as $, toggleEmptyMark } from '../dom';
13
14
  import type { BlokEventMap } from '../events';
@@ -501,14 +502,14 @@ export class Block extends EventsDispatcher<BlockEvents> {
501
502
  * Returns data to render in Block Tunes menu.
502
503
  * Splits block tunes into 2 groups: block specific tunes and common tunes
503
504
  */
504
- public getTunes(): {
505
+ public getTunes(renderContext?: BlockTuneRenderContext): {
505
506
  toolTunes: PopoverItemParams[];
506
507
  commonTunes: PopoverItemParams[];
507
508
  } {
508
509
  /** Tool's tunes: may be defined as return value of optional renderSettings method */
509
510
  const tunesDefinedInTool = typeof this.toolInstance.renderSettings === 'function' ? this.toolInstance.renderSettings() : [];
510
511
 
511
- return this.tunesManager.getMenuConfig(tunesDefinedInTool);
512
+ return this.tunesManager.getMenuConfig(tunesDefinedInTool, renderContext);
512
513
  }
513
514
 
514
515
  /**
@@ -1,4 +1,5 @@
1
1
  import type { BlockTune as IBlockTune } from '../../../types';
2
+ import type { BlockTuneRenderContext } from '../../../types/block-tunes/block-tune';
2
3
  import type { BlockAPI as BlockAPIInterface } from '../../../types/api';
3
4
  import type { BlockTuneData } from '../../../types/block-tunes/block-tune-data';
4
5
  import type { MenuConfigItem } from '../../../types/tools';
@@ -52,9 +53,13 @@ export class TunesManager {
52
53
  * Splits tunes into tool-specific (from tool's renderSettings) and common tunes.
53
54
  *
54
55
  * @param toolRenderSettings - Optional render settings from the tool
56
+ * @param renderContext - Optional context exposing the host tune popover element
55
57
  * @returns Object with toolTunes and commonTunes arrays
56
58
  */
57
- public getMenuConfig(toolRenderSettings?: MenuConfigItem | MenuConfigItem[] | HTMLElement): {
59
+ public getMenuConfig(
60
+ toolRenderSettings?: MenuConfigItem | MenuConfigItem[] | HTMLElement,
61
+ renderContext?: BlockTuneRenderContext
62
+ ): {
58
63
  toolTunes: PopoverItemParams[];
59
64
  commonTunes: PopoverItemParams[];
60
65
  } {
@@ -96,7 +101,7 @@ export class TunesManager {
96
101
  const commonTunes = [
97
102
  ...this.tunesInstances.values(),
98
103
  ...this.defaultTunesInstances.values(),
99
- ].map(tuneInstance => tuneInstance.render());
104
+ ].map(tuneInstance => tuneInstance.render(renderContext));
100
105
 
101
106
  /** Separate custom html from Popover items params for common tunes */
102
107
  commonTunes.forEach(tuneConfig => {
@@ -24,6 +24,10 @@ export const DATA_ATTR = {
24
24
  editor: 'data-blok-editor',
25
25
  /** Redactor zone */
26
26
  redactor: 'data-blok-redactor',
27
+ /** Present on the editor wrapper once a `blocks.render()` batch has finished
28
+ * inserting blocks into the DOM; removed while a re-render is in flight.
29
+ * Acts as a stable render-readiness gate for consumers (e.g. E2E waits). */
30
+ rendered: 'data-blok-rendered',
27
31
 
28
32
  // ============================================
29
33
  // Block Identifiers
@@ -1,8 +1,10 @@
1
+ import type { BlokConfig } from '../../../../../types/configs/blok-config';
1
2
  import type { SanitizerConfig } from '../../../../../types/configs/sanitizer-config';
2
3
  import type { BlokModules } from '../../../../types-internal/blok-modules';
3
4
  import { Dom as dom$ } from '../../../dom';
4
5
  import type { BlockToolAdapter } from '../../../tools/block';
5
6
  import { isObject } from '../../../utils';
7
+ import { applyLinkConfig } from '../../../utils/apply-link-config';
6
8
  import { clean } from '../../../utils/sanitizer';
7
9
  import { SAFE_STRUCTURAL_TAGS, collectTagNames } from '../constants';
8
10
  import type { SanitizerConfigBuilder } from '../sanitizer-config';
@@ -18,12 +20,16 @@ import { BasePasteHandler } from './base';
18
20
  * Handles HTML string content.
19
21
  */
20
22
  export class HtmlHandler extends BasePasteHandler implements PasteHandler {
23
+ private readonly linkConfig?: BlokConfig['link'];
24
+
21
25
  constructor(
22
26
  Blok: BlokModules,
23
27
  toolRegistry: ToolRegistry,
24
- sanitizerBuilder: SanitizerConfigBuilder
28
+ sanitizerBuilder: SanitizerConfigBuilder,
29
+ config?: BlokConfig
25
30
  ) {
26
31
  super(Blok, toolRegistry, sanitizerBuilder);
32
+ this.linkConfig = config?.link;
27
33
  }
28
34
 
29
35
  canHandle(data: unknown): number {
@@ -64,6 +70,13 @@ export class HtmlHandler extends BasePasteHandler implements PasteHandler {
64
70
 
65
71
  wrapper.innerHTML = innerHTML;
66
72
 
73
+ // Apply the editor's `link` config to pasted anchors before they are split
74
+ // into blocks, mirroring the interactive Link inline tool. Pasted `<a>`
75
+ // would otherwise keep their original (foreign) target/rel/href.
76
+ if (this.linkConfig !== undefined) {
77
+ applyLinkConfig(wrapper, this.linkConfig);
78
+ }
79
+
67
80
  const nodes = this.getNodes(wrapper);
68
81
 
69
82
  // Pre-expand DETAILS nodes: extract child elements (non-summary) before
@@ -59,7 +59,7 @@ export class Paste extends Module {
59
59
  new TableCellsHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
60
60
  new FilesHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
61
61
  new PatternHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder, this.config),
62
- new HtmlHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
62
+ new HtmlHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder, this.config),
63
63
  new MarkdownHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
64
64
  new TextHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder, this.config),
65
65
  ];
@@ -13,6 +13,8 @@ import {
13
13
  type DataFormatAnalysis,
14
14
  } from '../utils/data-model-transform';
15
15
  import { migrateMarkColors } from '../utils/color-migration';
16
+ import { applyLinkConfig } from '../utils/apply-link-config';
17
+ import { DATA_ATTR } from '../constants';
16
18
  import { BlocksRendered } from '../events';
17
19
 
18
20
  /**
@@ -86,6 +88,14 @@ export class Renderer extends Module {
86
88
  * @param blocksData - blocks to render
87
89
  */
88
90
  public render(blocksData: OutputBlockData[]): Promise<void> {
91
+ const { wrapper } = this.Blok.UI.nodes;
92
+
93
+ /**
94
+ * Flip the render-readiness gate off synchronously: while a (re-)render is
95
+ * in flight the previously rendered content may already be cleared.
96
+ */
97
+ wrapper.removeAttribute(DATA_ATTR.rendered);
98
+
89
99
  return new Promise((resolve) => {
90
100
  const renderedCount = this.insertRenderedBlocks(blocksData);
91
101
 
@@ -93,7 +103,9 @@ export class Renderer extends Module {
93
103
  * Wait till browser will render inserted Blocks and resolve a promise
94
104
  */
95
105
  window.requestIdleCallback(() => {
106
+ wrapper.setAttribute(DATA_ATTR.rendered, '');
96
107
  this.eventsDispatcher.emit(BlocksRendered, { count: renderedCount });
108
+ this.config.onAfterRender?.(this.Blok.API.methods);
97
109
  resolve();
98
110
  }, { timeout: 2000 });
99
111
  });
@@ -107,7 +119,15 @@ export class Renderer extends Module {
107
119
  private insertRenderedBlocks(blocksData: OutputBlockData[]): number {
108
120
  const { Tools, BlockManager } = this.Blok;
109
121
 
110
- if (blocksData.length === 0) {
122
+ // Give consumers a chance to transform the blocks array before anything is
123
+ // rendered — e.g. to run app-specific legacy-data migrations inside Blok.
124
+ // Runs on the raw saved shape (before format analysis / hierarchical
125
+ // expansion) so the hook sees exactly what was passed to render().
126
+ const sourceBlocks = this.config.onBeforeRender !== undefined
127
+ ? this.config.onBeforeRender(blocksData)
128
+ : blocksData;
129
+
130
+ if (sourceBlocks.length === 0) {
111
131
  BlockManager.insert();
112
132
 
113
133
  return 1;
@@ -115,13 +135,13 @@ export class Renderer extends Module {
115
135
 
116
136
  // Analyze and potentially transform the input data
117
137
  const dataModelConfig = this.config.dataModel || 'auto';
118
- const analysis = analyzeDataFormat(blocksData);
138
+ const analysis = analyzeDataFormat(sourceBlocks);
119
139
  this.detectedInputFormat = analysis.format;
120
140
 
121
141
  // Transform to hierarchical if config requires it
122
142
  const expandedBlocks = shouldExpandToHierarchical(dataModelConfig, analysis.format)
123
- ? expandToHierarchical(blocksData)
124
- : blocksData;
143
+ ? expandToHierarchical(sourceBlocks)
144
+ : sourceBlocks;
125
145
 
126
146
  // Recover migrated cells whose text a pre-fix save detached to root:
127
147
  // re-attach `cell-<row>-<col>`-id orphans back into their empty cell.
@@ -240,6 +260,14 @@ export class Renderer extends Module {
240
260
  BlockManager.insertMany(blocks);
241
261
  migrateMarkColors(this.Blok.UI.nodes.redactor);
242
262
 
263
+ // Apply the editor's `link` config (target / rel / transformHref) to every
264
+ // anchor coming from stored block HTML, mirroring the interactive Link
265
+ // inline tool. Without this, link config only governs links the user
266
+ // creates by hand — anchors from saved articles keep their stored attrs.
267
+ if (this.config.link !== undefined) {
268
+ applyLinkConfig(this.Blok.UI.nodes.redactor, this.config.link);
269
+ }
270
+
243
271
  return blocks.length;
244
272
  }
245
273
 
@@ -1,4 +1,5 @@
1
1
  import type { MenuConfigItem } from '../../../../types/tools';
2
+ import type { BlockTuneRenderContext } from '../../../../types/block-tunes/block-tune';
2
3
  import { Module } from '../../__module';
3
4
  import type { Block } from '../../block';
4
5
  import { BlockAPI } from '../../block/api';
@@ -194,8 +195,19 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
194
195
  this.Blok.BlockSelection.clearCache();
195
196
  }
196
197
 
198
+ /**
199
+ * Expose the (not-yet-created) tune popover element to custom tunes via
200
+ * their render context. The popover is built further down, so the element
201
+ * is filled in after construction; tunes capturing the context resolve it
202
+ * lazily (e.g. when opening a sub-menu) instead of reaching into the DOM.
203
+ */
204
+ const popoverRef: { current: HTMLElement | null } = { current: null };
205
+ const renderContext: BlockTuneRenderContext = {
206
+ getPopoverElement: () => popoverRef.current,
207
+ };
208
+
197
209
  /** Get tool-specific tunes and common tunes (delete, move, etc.) */
198
- const { toolTunes, commonTunes } = block.getTunes();
210
+ const { toolTunes, commonTunes } = block.getTunes(renderContext);
199
211
 
200
212
  const items = await this.getTunesItems(block, commonTunes, toolTunes);
201
213
 
@@ -235,7 +247,8 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
235
247
  }
236
248
 
237
249
  this.popover = new PopoverClass(popoverParams);
238
- this.popover.getElement().setAttribute('data-blok-testid', 'block-tunes-popover');
250
+ popoverRef.current = this.popover.getElement();
251
+ popoverRef.current.setAttribute('data-blok-testid', 'block-tunes-popover');
239
252
 
240
253
  this.popover.on(PopoverEvent.Closed, this.onPopoverClose);
241
254
 
@@ -0,0 +1,40 @@
1
+ import type { BlokConfig } from '../../../types';
2
+
3
+ /**
4
+ * Anchor-building configuration shared by the interactive Link inline tool,
5
+ * the render pipeline and the paste pipeline.
6
+ */
7
+ type LinkConfig = NonNullable<BlokConfig['link']>;
8
+
9
+ /**
10
+ * Applies the editor's `link` config to every anchor inside `root`.
11
+ *
12
+ * Mirrors the behaviour of the interactive Link inline tool so that anchors
13
+ * coming from stored block HTML (render) or pasted markup (paste) receive the
14
+ * same treatment as anchors the user creates by hand:
15
+ *
16
+ * - `target` is forced (default `_blank`),
17
+ * - `rel` is forced (default `nofollow`),
18
+ * - `transformHref` rewrites the existing href when provided.
19
+ *
20
+ * @param root - element (or fragment) whose descendant anchors should be processed
21
+ * @param link - the resolved `link` config from the editor configuration
22
+ */
23
+ export function applyLinkConfig(root: ParentNode, link: LinkConfig): void {
24
+ const target = link.target ?? '_blank';
25
+ const rel = link.rel ?? 'nofollow';
26
+ const { transformHref } = link;
27
+
28
+ root.querySelectorAll('a').forEach((anchor) => {
29
+ if (transformHref !== undefined) {
30
+ const href = anchor.getAttribute('href');
31
+
32
+ if (href !== null) {
33
+ anchor.setAttribute('href', transformHref(href));
34
+ }
35
+ }
36
+
37
+ anchor.setAttribute('target', target);
38
+ anchor.setAttribute('rel', rel);
39
+ });
40
+ }
@@ -31,6 +31,8 @@ export const USE_BLOK_CONFIG_KEYS = [
31
31
  'onReady',
32
32
  'onChange',
33
33
  'onSave',
34
+ 'onBeforeRender',
35
+ 'onAfterRender',
34
36
  'inlineToolbar',
35
37
  'tunes',
36
38
  'style',
@@ -123,6 +123,22 @@ export function useBlok(config: UseBlokConfig, deps?: DependencyList): Blok | nu
123
123
  };
124
124
  }
125
125
 
126
+ // onBeforeRender / onAfterRender are opt-in (absent prop must stay absent so
127
+ // the core skips them). When present, route through the ref so the latest
128
+ // callback is always used without recreating the editor.
129
+ if (currentConfig.onBeforeRender) {
130
+ blokConfig.onBeforeRender = (
131
+ ...args: Parameters<NonNullable<UseBlokConfig['onBeforeRender']>>
132
+ ): ReturnType<NonNullable<UseBlokConfig['onBeforeRender']>> =>
133
+ configRef.current.onBeforeRender?.(...args) ?? args[0];
134
+ }
135
+
136
+ if (currentConfig.onAfterRender) {
137
+ blokConfig.onAfterRender = (...args: Parameters<NonNullable<UseBlokConfig['onAfterRender']>>): void => {
138
+ configRef.current.onAfterRender?.(...args);
139
+ };
140
+ }
141
+
126
142
  const blok = new BlokRuntime(blokConfig) as unknown as Blok;
127
143
  state.editor = blok;
128
144
  setHolder(blok, holder);
@@ -2,6 +2,24 @@ import {API, BlockAPI, ToolConfig} from '../index';
2
2
  import { BlockTuneData } from './block-tune-data';
3
3
  import { BaseToolConstructable, MenuConfig } from '../tools';
4
4
 
5
+ /**
6
+ * Context passed to a Block Tune's `render()` method, giving the tune a handle
7
+ * on the popover it is rendered into — so custom tunes can anchor sub-menus or
8
+ * portals inside Blok's tune popover instead of reaching into the DOM via
9
+ * `closest('[data-blok-popover]')`.
10
+ */
11
+ export interface BlockTuneRenderContext {
12
+ /**
13
+ * Returns the popover element (`[data-blok-popover]`) the tune is rendered
14
+ * into, or `null` when accessed before the popover has mounted.
15
+ *
16
+ * `render()` itself runs *before* the popover exists, so calling this
17
+ * synchronously inside `render()` returns `null`. Capture the context and
18
+ * call this later (e.g. when opening a sub-menu) to get the live element.
19
+ */
20
+ getPopoverElement(): HTMLElement | null;
21
+ }
22
+
5
23
  /**
6
24
  * Describes BLockTune blueprint
7
25
  */
@@ -10,8 +28,10 @@ export interface BlockTune {
10
28
  * Returns BlockTune's UI.
11
29
  * Should return either MenuConfig (recommended)
12
30
  * or an HTMLElement (UI consistency is not guaranteed)
31
+ *
32
+ * @param context - render context exposing the host tune popover element
13
33
  */
14
- render(): HTMLElement | MenuConfig;
34
+ render(context?: BlockTuneRenderContext): HTMLElement | MenuConfig;
15
35
 
16
36
  /**
17
37
  * Method called on Tool render. Pass Tool content as an argument.
@@ -1,6 +1,6 @@
1
1
  import type { ThemeMode, ResolvedTheme } from '../api/theme';
2
2
  import {ToolConstructable, ToolSettings} from '../tools';
3
- import {API, LogLevels, OutputData} from '../index';
3
+ import {API, LogLevels, OutputBlockData, OutputData} from '../index';
4
4
  import {SanitizerConfig} from './sanitizer-config';
5
5
  import {I18nConfig} from './i18n-config';
6
6
  import { BlockMutationEvent } from '../events/block';
@@ -136,8 +136,17 @@ export interface BlokConfig {
136
136
  i18n?: I18nConfig;
137
137
 
138
138
  /**
139
- * Configures how the Link inline tool builds anchor elements, so consumers can
140
- * control the created `<a>` instead of post-processing the rendered DOM.
139
+ * Configures how Blok builds anchor (`<a>`) elements, so consumers can control
140
+ * the created links instead of post-processing the rendered DOM.
141
+ *
142
+ * Applies on every path that produces anchors:
143
+ * - the interactive **Link inline tool** (links the user creates by hand),
144
+ * - **render** — anchors coming from stored block HTML when `blocks.render()`
145
+ * runs (e.g. saved articles whose `<a>` never went through the inline tool),
146
+ * - **paste** — `<a>` arriving via the clipboard.
147
+ *
148
+ * On the render and paste paths `target`/`rel` are forced and `transformHref`
149
+ * rewrites the href, exactly as for hand-created links.
141
150
  */
142
151
  link?: {
143
152
  /**
@@ -154,8 +163,13 @@ export interface BlokConfig {
154
163
 
155
164
  /**
156
165
  * Transforms the href just before it is assigned to the anchor.
157
- * Runs after URL validation/normalization, on the final value.
158
- * @param href - the validated, protocol-normalized href
166
+ *
167
+ * On the inline-tool path it runs after URL validation/normalization, on the
168
+ * final value. On the render and paste paths it runs against each anchor's
169
+ * existing href, so it must be idempotent (re-rendering already-transformed
170
+ * content must not change the result again).
171
+ *
172
+ * @param href - the href to transform
159
173
  * @returns the href to set on the anchor
160
174
  */
161
175
  transformHref?: (href: string) => string;
@@ -204,6 +218,32 @@ export interface BlokConfig {
204
218
  */
205
219
  onSave?(data: OutputData, api: API): void;
206
220
 
221
+ /**
222
+ * Transforms the blocks array just before it is rendered, on every render
223
+ * (the initial render and every `blocks.render()` call). Use it to run
224
+ * app-specific data migrations inside Blok instead of pre-processing the
225
+ * data before handing it to the editor.
226
+ *
227
+ * Receives the raw saved blocks (the exact array passed to render, before any
228
+ * format analysis or hierarchical expansion) and must return the blocks to
229
+ * render. Returning an empty array renders an empty document; returning blocks
230
+ * for an empty input injects them.
231
+ *
232
+ * @param blocks - the blocks about to be rendered
233
+ * @returns the blocks to actually render
234
+ */
235
+ onBeforeRender?(blocks: OutputBlockData[]): OutputBlockData[];
236
+
237
+ /**
238
+ * Fires after a render completes and the blocks are in the DOM — on the
239
+ * initial render and on every `blocks.render()` call. Use it for post-render
240
+ * side effects (scroll restoration, attaching observers, …). Distinct from
241
+ * `onReady`, which fires once when the editor first becomes ready.
242
+ *
243
+ * @param api - blok.js api
244
+ */
245
+ onAfterRender?(api: API): void;
246
+
207
247
  /**
208
248
  * Defines default toolbar for all tools.
209
249
  */
package/types/index.d.ts CHANGED
@@ -72,7 +72,7 @@ export {
72
72
  FilePasteEvent,
73
73
  FilePasteEventDetail,
74
74
  } from './tools';
75
- export {BlockTune, BlockTuneConstructable} from './block-tunes';
75
+ export {BlockTune, BlockTuneConstructable, BlockTuneRenderContext} from './block-tunes';
76
76
  export {
77
77
  BlokConfig,
78
78
  SanitizerConfig,