@jackuait/blok 0.23.3 → 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.
- package/README.md +3 -3
- package/dist/blok.cjs +1 -1
- package/dist/blok.iife.js +14 -14
- package/dist/blok.mjs +2 -2
- package/dist/blok.umd.js +6 -6
- package/dist/chunks/{blok-J3Lfa_bK.cjs → blok-DixLFA0K.cjs} +5 -5
- package/dist/chunks/{blok-1H9roBGf.mjs → blok-TvOrZOjF.mjs} +2195 -2170
- package/dist/chunks/{constants-BZUc1kAY.cjs → constants-Bze_TXgc.cjs} +1 -1
- package/dist/chunks/{constants-BJ79cqMa.mjs → constants-DpIX_GOn.mjs} +2 -1
- package/dist/chunks/{tools-OHDv2C7w.cjs → tools-CRAPWuhj.cjs} +1 -1
- package/dist/chunks/{tools-ByOjWADT.mjs → tools-DBb88o-I.mjs} +1 -1
- package/dist/full.cjs +1 -1
- package/dist/full.mjs +3 -3
- package/dist/react.cjs +1 -1
- package/dist/react.mjs +42 -31
- package/dist/tools.cjs +1 -1
- package/dist/tools.mjs +2 -2
- package/package.json +1 -1
- package/src/components/block/index.ts +3 -2
- package/src/components/block/tunes-manager.ts +7 -2
- package/src/components/constants/data-attributes.ts +4 -0
- package/src/components/modules/modificationsObserver.ts +40 -2
- package/src/components/modules/paste/handlers/html-handler.ts +14 -1
- package/src/components/modules/paste/index.ts +1 -1
- package/src/components/modules/renderer.ts +32 -4
- package/src/components/modules/toolbar/blockSettings.ts +15 -2
- package/src/components/utils/apply-link-config.ts +40 -0
- package/src/react/BlokEditor.tsx +10 -2
- package/src/react/config-keys.ts +3 -0
- package/src/react/types.ts +4 -0
- package/src/react/useBlok.ts +45 -6
- package/types/block-tunes/block-tune.d.ts +21 -1
- package/types/configs/blok-config.d.ts +62 -5
- package/types/index.d.ts +1 -1
|
@@ -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-
|
|
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-
|
|
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-
|
|
2
|
-
import { Ma as n } from "./chunks/constants-
|
|
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-
|
|
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-
|
|
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-
|
|
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";
|
|
@@ -35,7 +35,7 @@ function h(e, r) {
|
|
|
35
35
|
destroyTimeout: null,
|
|
36
36
|
isDestroyed: !1,
|
|
37
37
|
depsToken: null
|
|
38
|
-
}), h = o(() => ({}), r == null ? [] : r);
|
|
38
|
+
}), h = o(() => ({}), r == null ? [] : r), _ = s(e.data), v = s(null), y = s(Promise.resolve());
|
|
39
39
|
i(() => {
|
|
40
40
|
if (typeof window > "u") return;
|
|
41
41
|
let e = f.current;
|
|
@@ -51,7 +51,7 @@ function h(e, r) {
|
|
|
51
51
|
}
|
|
52
52
|
let r = document.createElement("div");
|
|
53
53
|
e.holder = r, e.isDestroyed = !1, e.depsToken = h;
|
|
54
|
-
let i = u.current, a =
|
|
54
|
+
let i = u.current, a = n(n({}, i), {}, {
|
|
55
55
|
holder: r,
|
|
56
56
|
onReady: () => {
|
|
57
57
|
var e, t;
|
|
@@ -61,14 +61,25 @@ function h(e, r) {
|
|
|
61
61
|
var t, n;
|
|
62
62
|
(t = (n = u.current).onChange) == null || t.call(n, ...e);
|
|
63
63
|
}
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
});
|
|
65
|
+
i.onSave && (a.onSave = (...e) => {
|
|
66
|
+
var t, n;
|
|
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);
|
|
74
|
+
});
|
|
75
|
+
let o = new t(a);
|
|
76
|
+
return e.editor = o, d(o, r), o.isReady.then(() => {
|
|
77
|
+
e.editor === o && !e.isDestroyed && l(o);
|
|
67
78
|
}).catch(() => {
|
|
68
|
-
if (e.editor ===
|
|
69
|
-
p(
|
|
79
|
+
if (e.editor === o && !e.isDestroyed) {
|
|
80
|
+
p(o);
|
|
70
81
|
try {
|
|
71
|
-
|
|
82
|
+
o.destroy();
|
|
72
83
|
} catch (e) {}
|
|
73
84
|
e.editor = null, e.holder = null, e.isDestroyed = !0, l(null);
|
|
74
85
|
}
|
|
@@ -76,36 +87,36 @@ function h(e, r) {
|
|
|
76
87
|
g(e, l);
|
|
77
88
|
};
|
|
78
89
|
}, [h]);
|
|
79
|
-
let { readOnly:
|
|
90
|
+
let { readOnly: b } = e;
|
|
80
91
|
i(() => {
|
|
81
|
-
a !== null && a.readOnly.set(
|
|
82
|
-
}, [a,
|
|
83
|
-
let { autofocus:
|
|
92
|
+
a !== null && a.readOnly.set(b == null ? !1 : b);
|
|
93
|
+
}, [a, b]);
|
|
94
|
+
let { autofocus: x } = e;
|
|
84
95
|
i(() => {
|
|
85
|
-
a === null || !
|
|
86
|
-
}, [a,
|
|
87
|
-
let { theme:
|
|
96
|
+
a === null || !x || a.focus();
|
|
97
|
+
}, [a, x]);
|
|
98
|
+
let { theme: S } = e;
|
|
88
99
|
i(() => {
|
|
89
|
-
a === null ||
|
|
90
|
-
}, [a,
|
|
91
|
-
let { width:
|
|
100
|
+
a === null || S === void 0 || a.theme.set(S);
|
|
101
|
+
}, [a, S]);
|
|
102
|
+
let { width: C } = e;
|
|
92
103
|
i(() => {
|
|
93
|
-
a === null ||
|
|
94
|
-
}, [a,
|
|
95
|
-
let { placeholder:
|
|
104
|
+
a === null || C === void 0 || a.width.set(C);
|
|
105
|
+
}, [a, C]);
|
|
106
|
+
let { placeholder: w } = e;
|
|
96
107
|
i(() => {
|
|
97
|
-
a === null ||
|
|
98
|
-
}, [a,
|
|
99
|
-
let { data:
|
|
108
|
+
a === null || w === void 0 || a.placeholder.set(w);
|
|
109
|
+
}, [a, w]);
|
|
110
|
+
let { data: T } = e;
|
|
100
111
|
return i(() => {
|
|
101
|
-
if (!(a === null ||
|
|
102
|
-
if (
|
|
103
|
-
|
|
112
|
+
if (!(a === null || T === void 0)) {
|
|
113
|
+
if (v.current !== a) {
|
|
114
|
+
v.current = a, _.current = T;
|
|
104
115
|
return;
|
|
105
116
|
}
|
|
106
|
-
m(
|
|
117
|
+
m(T, _.current) || (_.current = T, y.current = y.current.catch(() => void 0).then(() => a.render(T)));
|
|
107
118
|
}
|
|
108
|
-
}, [a,
|
|
119
|
+
}, [a, T]), a;
|
|
109
120
|
}
|
|
110
121
|
function g(e, t) {
|
|
111
122
|
e.destroyTimeout = setTimeout(() => {
|
|
@@ -135,7 +146,7 @@ var _ = ["editor"], v = r(function(t, r) {
|
|
|
135
146
|
t.current = e;
|
|
136
147
|
}
|
|
137
148
|
} }, o));
|
|
138
|
-
}), y = /* @__PURE__ */ "autofocus.defaultBlock.dataModel.placeholder.sanitizer.hideToolbar.maxHistoryLength.historyDebounceTime.newGroupDelay.globalUndoRedo.tools.data.minHeight.logLevel.readOnly.i18n.link.linkPaste.onBeforePaste.onReady.onChange.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) {
|
|
139
150
|
let { deps: o, onReady: c } = t, u = e(t, b), d = {}, f = {};
|
|
140
151
|
for (let e of Object.keys(u)) {
|
|
141
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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(
|
|
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
|
|
@@ -42,6 +42,12 @@ export class ModificationsObserver extends Module {
|
|
|
42
42
|
*/
|
|
43
43
|
private readonly batchTime = modificationsObserverBatchTimeout;
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Set once the module is destroyed so an in-flight serialization (onSave)
|
|
47
|
+
* doesn't call back into a torn-down editor after its promise resolves.
|
|
48
|
+
*/
|
|
49
|
+
private destroyed = false;
|
|
50
|
+
|
|
45
51
|
/**
|
|
46
52
|
* Prepare the module
|
|
47
53
|
* @param options - options used by the modification observer module
|
|
@@ -103,7 +109,7 @@ export class ModificationsObserver extends Module {
|
|
|
103
109
|
* @param event - some of our custom change events
|
|
104
110
|
*/
|
|
105
111
|
private particularBlockChanged(event: BlockMutationEvent): void {
|
|
106
|
-
if (this.disabled || !isFunction(this.config.onChange)) {
|
|
112
|
+
if (this.disabled || (!isFunction(this.config.onChange) && !isFunction(this.config.onSave))) {
|
|
107
113
|
return;
|
|
108
114
|
}
|
|
109
115
|
|
|
@@ -127,14 +133,45 @@ export class ModificationsObserver extends Module {
|
|
|
127
133
|
? queuedEvents[0]
|
|
128
134
|
: queuedEvents;
|
|
129
135
|
|
|
130
|
-
if (this.config.onChange) {
|
|
136
|
+
if (isFunction(this.config.onChange)) {
|
|
131
137
|
this.config.onChange(this.Blok.API.methods, eventsToEmit);
|
|
132
138
|
}
|
|
133
139
|
|
|
140
|
+
if (isFunction(this.config.onSave)) {
|
|
141
|
+
this.emitOnSave();
|
|
142
|
+
}
|
|
143
|
+
|
|
134
144
|
this.batchingOnChangeQueue.clear();
|
|
135
145
|
}, this.batchTime);
|
|
136
146
|
}
|
|
137
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Serializes the editor and delivers the full OutputData to the consumer's
|
|
150
|
+
* `onSave` callback. Invoked once per batched change window, so a burst of
|
|
151
|
+
* edits results in a single serialization. Skips delivery if the module was
|
|
152
|
+
* destroyed while the (async) serialization was in flight.
|
|
153
|
+
*/
|
|
154
|
+
private emitOnSave(): void {
|
|
155
|
+
void this.Blok.Saver.save()
|
|
156
|
+
.then((data) => {
|
|
157
|
+
if (this.destroyed || data === undefined) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const { onSave } = this.config;
|
|
162
|
+
|
|
163
|
+
if (isFunction(onSave)) {
|
|
164
|
+
onSave(data, this.Blok.API.methods);
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
.catch(() => {
|
|
168
|
+
/**
|
|
169
|
+
* Serialization failed — the Saver already surfaces the error via its
|
|
170
|
+
* own channel, so swallow here to avoid an unhandled rejection.
|
|
171
|
+
*/
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
138
175
|
/**
|
|
139
176
|
* Cleans up the module: disconnects the MutationObserver and cancels any
|
|
140
177
|
* pending batching timeout. Called by the editor's destroy() chain so that
|
|
@@ -144,6 +181,7 @@ export class ModificationsObserver extends Module {
|
|
|
144
181
|
*/
|
|
145
182
|
public destroy(): void {
|
|
146
183
|
this.disabled = true;
|
|
184
|
+
this.destroyed = true;
|
|
147
185
|
this.mutationObserver.disconnect();
|
|
148
186
|
|
|
149
187
|
if (this.batchingTimeout !== null) {
|
|
@@ -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
|
-
|
|
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(
|
|
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(
|
|
124
|
-
:
|
|
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()
|
|
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
|
+
}
|
package/src/react/BlokEditor.tsx
CHANGED
|
@@ -24,9 +24,17 @@ import type { UseBlokConfig } from './types';
|
|
|
24
24
|
* mount, changing it to new *content* re-renders the editor via `render()` — no
|
|
25
25
|
* recreation. Updates are deep-equal–deduped (a new reference with identical
|
|
26
26
|
* content is a no-op, so it won't clobber the caret) and serialized (rapid
|
|
27
|
-
* changes can't overlap).
|
|
28
|
-
* (`ref.current.save()`). For ad-hoc reloads you can still call
|
|
27
|
+
* changes can't overlap). For ad-hoc reloads you can still call
|
|
29
28
|
* `ref.current.render(newData)`.
|
|
29
|
+
*
|
|
30
|
+
* Pair `data` with `onSave` for a true controlled component: `onSave` is the
|
|
31
|
+
* output half, firing (debounced) with the full serialized `OutputData` on every
|
|
32
|
+
* content change — no manual `ref.current.save()` polling. Echoing that payload
|
|
33
|
+
* straight back via `onSave={setData}` is safe and caret-stable: the adapter
|
|
34
|
+
* records the editor's own emitted output as the content baseline, so the
|
|
35
|
+
* `onSave → setState → data` round-trip deep-equals that baseline and is deduped
|
|
36
|
+
* to a no-op (no re-render, no caret reset, no recursion). Genuine external `data`
|
|
37
|
+
* changes still re-render in place.
|
|
30
38
|
*/
|
|
31
39
|
export interface BlokEditorProps
|
|
32
40
|
extends Omit<UseBlokConfig, 'onReady'>,
|
package/src/react/config-keys.ts
CHANGED
package/src/react/types.ts
CHANGED
|
@@ -13,6 +13,10 @@ import type { BlokConfig, Blok, EditorWidth } from '@/types';
|
|
|
13
13
|
* - `placeholder` — calls `editor.placeholder.set(value)`
|
|
14
14
|
* - `data` — re-renders via `editor.render(value)` when content changes
|
|
15
15
|
* (deep-equal–deduped and serialized; seeds the initial content at creation)
|
|
16
|
+
*
|
|
17
|
+
* The `onSave` config (inherited from `BlokConfig`) is the controlled output
|
|
18
|
+
* half: it fires with the full serialized `OutputData` on every content change,
|
|
19
|
+
* so `data` + `onSave` form a controlled component without manual `save()` calls.
|
|
16
20
|
*/
|
|
17
21
|
export interface UseBlokConfig extends Omit<BlokConfig, 'holder'> {
|
|
18
22
|
/** Editor content width mode. Synced reactively after mount via `editor.width.set()`. */
|