esm_e(h,p[g])),b=Mn(dist_esm_H),c=Dt(b),P=b!==c&&esm_Ue(b);qn(()=>{s.current++,i.ctrls=u.current;let{queue:h}=i;h.length&&(i.queue=[],Ye(h,g=>g())),Ye(u.current,(g,x)=>{o?.add(g),P&&g.start({default:b});let S=p[x];S&&(esm_he(g,S.ref),g.ref?g.queue.push(S):g.start(S))})}),Nn(()=>()=>{Ye(i.ctrls,h=>h.stop(!0))});let l=m.map(h=>({...h}));return o?[l,o]:l}function esm_J(t,e){let n=Qn.fun(t),[[r],o]=esm_He(1,n?t:[t],n?e||[]:e);return n||arguments.length==2?[r,o]:r}var Gn=()=>esm_fe(),Xo=()=>zn(Gn)[0];var Wo=(t,e)=>{let n=Bn(()=>new esm_ue(t,e));return Kn(()=>()=>{n.stop()}),n};function esm_Qt(t,e,n){let r=qt.fun(e)&&e;r&&!n&&(n=[]);let o=!0,s,a=esm_He(t,(i,u)=>{let p=r?r(i,u):e;return s=p.ref,o=o&&p.reverse,p},n||[{}]);if(Yn(()=>{Xn(a[1].current,(i,u)=>{let p=a[1].current[u+(o?1:-1)];if(esm_he(i,s),i.ref){p&&i.update({to:p.springs});return}p?i.start({to:p.springs}):i.start()})},n),r||arguments.length==3){let i=s??a[1];return i._getProps=(u,p,f)=>{let d=qt.fun(u)?u(f,p):u;if(d){let m=i.current[f+(d.reverse?1:-1)];return m&&(d.to=m.springs),d}},a}return a[0]}function esm_Gt(t,e,n){let r=G.fun(e)&&e,{reset:o,sort:s,trail:a=0,expires:i=!0,exitBeforeEnter:u=!1,onDestroyed:p,ref:f,config:d}=r?r():e,m=Jn(()=>r||arguments.length==3?esm_fe():void 0,[]),b=zt(t),c=[],P=lt(null),l=o?null:P.current;Je(()=>{P.current=c}),$n(()=>(j(c,y=>{m?.add(y.ctrl),y.ctrl.ref=m}),()=>{j(P.current,y=>{y.expired&&clearTimeout(y.expirationId),esm_xe(y.ctrl,m),y.ctrl.stop(!0)})}));let h=tr(b,r?r():e,l),g=o&&P.current||[];Je(()=>j(g,({ctrl:y,item:T,key:F})=>{esm_xe(y,m),dist_esm_I(p,T,F)}));let x=[];if(l&&j(l,(y,T)=>{y.expired?(clearTimeout(y.expirationId),g.push(y)):(T=x[T]=h.indexOf(y.key),~T&&(c[T]=y))}),j(b,(y,T)=>{c[T]||(c[T]={key:h[T],item:y,phase:"mount",ctrl:new esm_le},c[T].ctrl.item=y)}),x.length){let y=-1,{leave:T}=r?r():e;j(x,(F,k)=>{let O=l[k];~F?(y=c.indexOf(O),c[y]={...O,item:b[F]}):T&&c.splice(++y,0,O)})}G.fun(s)&&c.sort((y,T)=>s(y.item,T.item));let S=-a,A=Wn(),V=dist_esm_ne(e),_=new Map,v=lt(new Map),w=lt(!1);j(c,(y,T)=>{let F=y.key,k=y.phase,O=r?r():e,U,D,Jt=dist_esm_I(O.delay||0,F);if(k=="mount")U=O.enter,D="enter";else{let M=h.indexOf(F)<0;if(k!="leave")if(M)U=O.leave,D="leave";else if(U=O.update)D="update";else return;else if(!M)U=O.enter,D="enter";else return}if(U=dist_esm_I(U,y.item,T),U=G.obj(U)?esm_de(U):{to:U},!U.config){let M=d||V.config;U.config=dist_esm_I(M,y.item,T,D)}S+=a;let Z={...V,delay:Jt+S,ref:f,immediate:O.immediate,reset:!1,...U};if(D=="enter"&&G.und(Z.from)){let M=r?r():e,Te=G.und(M.initial)||l?M.from:M.initial;Z.from=dist_esm_I(Te,y.item,T)}let{onResolve:Wt}=Z;Z.onResolve=M=>{dist_esm_I(Wt,M);let Te=P.current,B=Te.find(Fe=>Fe.key===F);if(!!B&&!(M.cancelled&&B.phase!="update")&&B.ctrl.idle){let Fe=Te.every(ee=>ee.ctrl.idle);if(B.phase=="leave"){let ee=dist_esm_I(i,B.item);if(ee!==!1){let Ze=ee===!0?0:ee;if(B.expired=!0,!Fe&&Ze>0){Ze<=2147483647&&(B.expirationId=setTimeout(A,Ze));return}}}Fe&&Te.some(ee=>ee.expired)&&(v.current.delete(B),u&&(w.current=!0),A())}};let ft=esm_e(y.ctrl,Z);D==="leave"&&u?v.current.set(y,{phase:D,springs:ft,payload:Z}):_.set(y,{phase:D,springs:ft,payload:Z})});let C=Hn(dist_esm_H),$=Zn(C),L=C!==$&&esm_Ue(C);Je(()=>{L&&j(c,y=>{y.ctrl.start({default:C})})},[C]),j(_,(y,T)=>{if(v.current.size){let F=c.findIndex(k=>k.key===T.key);c.splice(F,1)}}),Je(()=>{j(v.current.size?v.current:_,({phase:y,payload:T},F)=>{let{ctrl:k}=F;F.phase=y,m?.add(k),L&&y=="enter"&&k.start({default:C}),T&&(esm_he(k,T.ref),(k.ref||m)&&!w.current?k.update(T):(k.start(T),w.current&&(w.current=!1)))})},o?void 0:n);let N=y=>Oe.createElement(Oe.Fragment,null,c.map((T,F)=>{let{springs:k}=_.get(T)||T.ctrl,O=y({...k},T.item,T,F);return O&&O.type?Oe.createElement(O.type,{...O.props,key:G.str(T.key)||G.num(T.key)?T.key:T.ctrl.id,ref:O.ref}):O}));return m?[N,m]:N}var esm_er=1;function tr(t,{key:e,keys:n=e},r){if(n===null){let o=new Set;return t.map(s=>{let a=r&&r.find(i=>i.item===s&&i.phase!=="leave"&&!o.has(i));return a?(o.add(a),a.key):esm_er++})}return G.und(n)?t:G.fun(n)?t.map(n):zt(n)}var hs=({container:t,...e}={})=>{let[n,r]=esm_J(()=>({scrollX:0,scrollY:0,scrollXProgress:0,scrollYProgress:0,...e}),[]);return or(()=>{let o=rr(({x:s,y:a})=>{r.start({scrollX:s.current,scrollXProgress:s.progress,scrollY:a.current,scrollYProgress:a.progress})},{container:t?.current||void 0});return()=>{nr(Object.values(n),s=>s.stop()),o()}},[]),n};var Ps=({container:t,...e})=>{let[n,r]=esm_J(()=>({width:0,height:0,...e}),[]);return ar(()=>{let o=sr(({width:s,height:a})=>{r.start({width:s,height:a,immediate:n.width.get()===0||n.height.get()===0})},{container:t?.current||void 0});return()=>{ir(Object.values(n),s=>s.stop()),o()}},[]),n};var cr={any:0,all:1};function Cs(t,e){let[n,r]=pr(!1),o=ur(),s=Bt.fun(t)&&t,a=s?s():{},{to:i={},from:u={},...p}=a,f=s?e:t,[d,m]=esm_J(()=>({from:u,...p}),[]);return lr(()=>{let b=o.current,{root:c,once:P,amount:l="any",...h}=f??{};if(!b||P&&n||typeof IntersectionObserver>"u")return;let g=new WeakMap,x=()=>(i&&m.start(i),r(!0),P?void 0:()=>{u&&m.start(u),r(!1)}),S=V=>{V.forEach(_=>{let v=g.get(_.target);if(_.isIntersecting!==Boolean(v))if(_.isIntersecting){let w=x();Bt.fun(w)?g.set(_.target,w):A.unobserve(_.target)}else v&&(v(),g.delete(_.target))})},A=new IntersectionObserver(S,{root:c&&c.current||void 0,threshold:typeof l=="number"||Array.isArray(l)?l:cr[l],...h});return A.observe(b),()=>A.unobserve(b)},[f]),s?[o,d]:[o,n]}function qs({children:t,...e}){return t(esm_J(e))}function Bs({items:t,children:e,...n}){let r=esm_Qt(t.length,n);return t.map((o,s)=>{let a=e(o,s);return fr.fun(a)?a(r[s]):a})}function Ys({items:t,children:e,...n}){return esm_Gt(t,n)(e)}var esm_W=class extends esm_X{constructor(n,r){super();this.source=n;this.calc=W(...r);let o=this._get(),s=esm_Le(o);esm_D(this,s.create(o))}key;idle=!0;calc;_active=new Set;advance(n){let r=this._get(),o=this.get();bt(r,o)||(dist_esm_k(this).setValue(r),this._onChange(r,this.idle)),!this.idle&&Yt(this._active)&&esm_ct(this)}_get(){let n=dist_esm_l.arr(this.source)?this.source.map(ve):ht(ve(this.source));return this.calc(...n)}_start(){this.idle&&!Yt(this._active)&&(this.idle=!1,esm_Ve(F(this),n=>{n.done=!1}),dist_esm_p.skipAnimation?(esm_n.batchedUpdates(()=>this.advance()),esm_ct(this)):qe.start(this))}_attach(){let n=1;esm_Ve(ht(this.source),r=>{Pt(r)&&Gt(r,this),esm_Re(r)&&(r.idle||this._active.add(r),n=Math.max(n,r.priority+1))}),this.priority=n,this._start()}_detach(){esm_Ve(ht(this.source),n=>{Pt(n)&&Qt(n,this)}),this._active.clear(),esm_ct(this)}eventObserved(n){n.type=="change"?n.idle?this.advance():(this._active.add(n.parent),this._start()):n.type=="idle"?this._active.delete(n.parent):n.type=="priority"&&(this.priority=ht(this.source).reduce((r,o)=>Math.max(r,(esm_Re(o)?o.priority:0)+1),0))}};function vr(t){return t.idle!==!1}function Yt(t){return!t.size||Array.from(t).every(vr)}function esm_ct(t){t.idle||(t.idle=!0,esm_Ve(F(t),e=>{e.done=!0}),$t(t,{type:"idle",parent:t}))}var esm_ui=(t,...e)=>new esm_W(t,e),pi=(t,...e)=>(Cr(),new esm_W(t,e));dist_esm_p.assign({createStringInterpolator:Xt,to:(t,e)=>new esm_W(t,e)});var di=qe.advance;
-;// CONCATENATED MODULE: external "ReactDOM"
+;// external "ReactDOM"
const external_ReactDOM_namespaceObject = window["ReactDOM"];
-;// CONCATENATED MODULE: ./node_modules/@react-spring/web/dist/esm/index.js
+;// ./node_modules/@react-spring/web/dist/esm/index.js
var web_dist_esm_k=/^--/;function web_dist_esm_I(t,e){return e==null||typeof e=="boolean"||e===""?"":typeof e=="number"&&e!==0&&!web_dist_esm_k.test(t)&&!(web_dist_esm_c.hasOwnProperty(t)&&web_dist_esm_c[t])?e+"px":(""+e).trim()}var web_dist_esm_v={};function esm_V(t,e){if(!t.nodeType||!t.setAttribute)return!1;let r=t.nodeName==="filter"||t.parentNode&&t.parentNode.nodeName==="filter",{style:i,children:s,scrollTop:u,scrollLeft:l,viewBox:a,...n}=e,d=Object.values(n),m=Object.keys(n).map(o=>r||t.hasAttribute(o)?o:web_dist_esm_v[o]||(web_dist_esm_v[o]=o.replace(/([A-Z])/g,p=>"-"+p.toLowerCase())));s!==void 0&&(t.textContent=s);for(let o in i)if(i.hasOwnProperty(o)){let p=web_dist_esm_I(o,i[o]);web_dist_esm_k.test(o)?t.style.setProperty(o,p):t.style[o]=p}m.forEach((o,p)=>{t.setAttribute(o,d[p])}),u!==void 0&&(t.scrollTop=u),l!==void 0&&(t.scrollLeft=l),a!==void 0&&t.setAttribute("viewBox",a)}var web_dist_esm_c={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},esm_F=(t,e)=>t+e.charAt(0).toUpperCase()+e.substring(1),esm_L=["Webkit","Ms","Moz","O"];web_dist_esm_c=Object.keys(web_dist_esm_c).reduce((t,e)=>(esm_L.forEach(r=>t[esm_F(r,e)]=t[e]),t),web_dist_esm_c);var esm_=/^(matrix|translate|scale|rotate|skew)/,dist_esm_$=/^(translate)/,dist_esm_G=/^(rotate|skew)/,web_dist_esm_y=(t,e)=>dist_esm_l.num(t)&&t!==0?t+e:t,web_dist_esm_h=(t,e)=>dist_esm_l.arr(t)?t.every(r=>web_dist_esm_h(r,e)):dist_esm_l.num(t)?t===e:parseFloat(t)===e,dist_esm_g=class extends animated_dist_esm_u{constructor({x:e,y:r,z:i,...s}){let u=[],l=[];(e||r||i)&&(u.push([e||0,r||0,i||0]),l.push(a=>[`translate3d(${a.map(n=>web_dist_esm_y(n,"px")).join(",")})`,web_dist_esm_h(a,0)])),xt(s,(a,n)=>{if(n==="transform")u.push([a||""]),l.push(d=>[d,d===""]);else if(esm_.test(n)){if(delete s[n],dist_esm_l.und(a))return;let d=dist_esm_$.test(n)?"px":dist_esm_G.test(n)?"deg":"";u.push(ht(a)),l.push(n==="rotate3d"?([m,o,p,O])=>[`rotate3d(${m},${o},${p},${web_dist_esm_y(O,d)})`,web_dist_esm_h(O,0)]:m=>[`${n}(${m.map(o=>web_dist_esm_y(o,d)).join(",")})`,web_dist_esm_h(m,n.startsWith("scale")?1:0)])}}),u.length&&(s.transform=new web_dist_esm_x(u,l)),super(s)}},web_dist_esm_x=class extends esm_ge{constructor(r,i){super();this.inputs=r;this.transforms=i}_value=null;get(){return this._value||(this._value=this._get())}_get(){let r="",i=!0;return esm_Ve(this.inputs,(s,u)=>{let l=ve(s[0]),[a,n]=this.transforms[u](dist_esm_l.arr(l)?l:s.map(ve));r+=" "+a,i=i&&n}),i?"none":r}observerAdded(r){r==1&&esm_Ve(this.inputs,i=>esm_Ve(i,s=>Pt(s)&&Gt(s,this)))}observerRemoved(r){r==0&&esm_Ve(this.inputs,i=>esm_Ve(i,s=>Pt(s)&&Qt(s,this)))}eventObserved(r){r.type=="change"&&(this._value=null),$t(this,r)}};var esm_C=["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link","main","map","mark","menu","menuitem","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","circle","clipPath","defs","ellipse","foreignObject","g","image","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","svg","text","tspan"];dist_esm_p.assign({batchedUpdates:external_ReactDOM_namespaceObject.unstable_batchedUpdates,createStringInterpolator:Xt,colors:It});var dist_esm_q=dist_esm_Ke(esm_C,{applyAnimatedValues:esm_V,createAnimatedStyle:t=>new dist_esm_g(t),getComponentProps:({scrollTop:t,scrollLeft:e,...r})=>r}),dist_esm_it=dist_esm_q.animated;
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/use-moving-animation/index.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/use-moving-animation/index.js
/**
* External dependencies
*/
@@ -39792,7 +40318,8 @@
isBlockSelected,
isFirstMultiSelectedBlock,
isBlockMultiSelected,
- isAncestorMultiSelected
+ isAncestorMultiSelected,
+ isDraggingBlocks
} = (0,external_wp_data_namespaceObject.useSelect)(store);
// Whenever the trigger changes, we need to take a snapshot of the current
@@ -39803,9 +40330,7 @@
} = (0,external_wp_element_namespaceObject.useMemo)(() => ({
previous: ref.current && getAbsolutePosition(ref.current),
prevRect: ref.current && ref.current.getBoundingClientRect()
- }),
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [triggerAnimationOnChange]);
+ }), [triggerAnimationOnChange]);
(0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
if (!previous || !ref.current) {
return;
@@ -39813,7 +40338,12 @@
const scrollContainer = (0,external_wp_dom_namespaceObject.getScrollContainer)(ref.current);
const isSelected = isBlockSelected(clientId);
const adjustScrolling = isSelected || isFirstMultiSelectedBlock(clientId);
+ const isDragging = isDraggingBlocks();
function preserveScrollPosition() {
+ // The user already scrolled when dragging blocks.
+ if (isDragging) {
+ return;
+ }
if (adjustScrolling && prevRect) {
const blockRect = ref.current.getBoundingClientRect();
const diff = blockRect.top - prevRect.top;
@@ -39827,7 +40357,7 @@
// motion, if the user is typing (insertion by Enter), or if the block
// count exceeds the threshold (insertion caused all the blocks that
// follow to animate).
- // To do: consider enableing the _moving_ animation even for large
+ // To do: consider enabling the _moving_ animation even for large
// posts, while only disabling the _insertion_ animation?
const disableAnimation = window.matchMedia('(prefers-reduced-motion: reduce)').matches || isTyping() || getGlobalBlockCount() > BLOCK_ANIMATION_THRESHOLD;
if (disableAnimation) {
@@ -39837,6 +40367,13 @@
return;
}
const isPartOfSelection = isSelected || isBlockMultiSelected(clientId) || isAncestorMultiSelected(clientId);
+
+ // The user already dragged the blocks to the new position, so don't
+ // animate the dragged blocks.
+ if (isPartOfSelection && isDragging) {
+ return;
+ }
+
// Make sure the other blocks move under the selected block(s).
const zIndex = isPartOfSelection ? '1' : '';
const controller = new esm_le({
@@ -39886,77 +40423,23 @@
y: 0
});
};
- }, [previous, prevRect, clientId, isTyping, getGlobalBlockCount, isBlockSelected, isFirstMultiSelectedBlock, isBlockMultiSelected, isAncestorMultiSelected]);
+ }, [previous, prevRect, clientId, isTyping, getGlobalBlockCount, isBlockSelected, isFirstMultiSelectedBlock, isBlockMultiSelected, isAncestorMultiSelected, isDraggingBlocks]);
return ref;
}
/* harmony default export */ const use_moving_animation = (useMovingAnimation);
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/utils/dom.js
-const BLOCK_SELECTOR = '.block-editor-block-list__block';
-const APPENDER_SELECTOR = '.block-list-appender';
-const BLOCK_APPENDER_CLASS = '.block-editor-button-block-appender';
-
-/**
- * Returns true if two elements are contained within the same block.
- *
- * @param {Element} a First element.
- * @param {Element} b Second element.
- *
- * @return {boolean} Whether elements are in the same block.
- */
-function isInSameBlock(a, b) {
- return a.closest(BLOCK_SELECTOR) === b.closest(BLOCK_SELECTOR);
-}
-
-/**
- * Returns true if an element is considered part of the block and not its inner
- * blocks or appender.
- *
- * @param {Element} blockElement Block container element.
- * @param {Element} element Element.
- *
- * @return {boolean} Whether an element is considered part of the block and not
- * its inner blocks or appender.
- */
-function isInsideRootBlock(blockElement, element) {
- const parentBlock = element.closest([BLOCK_SELECTOR, APPENDER_SELECTOR, BLOCK_APPENDER_CLASS].join(','));
- return parentBlock === blockElement;
-}
-
-/**
- * Finds the block client ID given any DOM node inside the block.
- *
- * @param {Node?} node DOM node.
- *
- * @return {string|undefined} Client ID or undefined if the node is not part of
- * a block.
- */
-function getBlockClientId(node) {
- while (node && node.nodeType !== node.ELEMENT_NODE) {
- node = node.parentNode;
- }
- if (!node) {
- return;
- }
- const elementNode = /** @type {Element} */node;
- const blockNode = elementNode.closest(BLOCK_SELECTOR);
- if (!blockNode) {
- return;
- }
- return blockNode.id.slice('block-'.length);
-}
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-focus-first-element.js
-/**
- * WordPress dependencies
- */
-
-
-
-
-/**
- * Internal dependencies
- */
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-focus-first-element.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
@@ -39978,11 +40461,11 @@
const {
isBlockSelected,
isMultiSelecting,
- __unstableGetEditorMode
- } = (0,external_wp_data_namespaceObject.useSelect)(store);
+ isZoomOut
+ } = unlock((0,external_wp_data_namespaceObject.useSelect)(store));
(0,external_wp_element_namespaceObject.useEffect)(() => {
// Check if the block is still selected at the time this effect runs.
- if (!isBlockSelected(clientId) || isMultiSelecting() || __unstableGetEditorMode() === 'zoom-out') {
+ if (!isBlockSelected(clientId) || isMultiSelecting() || isZoomOut()) {
return;
}
if (initialPosition === undefined || initialPosition === null) {
@@ -40026,25 +40509,41 @@
return ref;
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-is-hovered.js
-/**
- * WordPress dependencies
- */
-
-function listener(event) {
- if (event.defaultPrevented) {
- return;
- }
- const action = event.type === 'mouseover' ? 'add' : 'remove';
- event.preventDefault();
- event.currentTarget.classList[action]('is-hovered');
-}
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-is-hovered.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+/**
+ * Internal dependencies
+ */
+
/*
* Adds `is-hovered` class when the block is hovered and in navigation or
* outline mode.
*/
-function useIsHovered() {
+function useIsHovered({
+ clientId
+}) {
+ const {
+ hoverBlock
+ } = (0,external_wp_data_namespaceObject.useDispatch)(store);
+ function listener(event) {
+ if (event.defaultPrevented) {
+ return;
+ }
+ const action = event.type === 'mouseover' ? 'add' : 'remove';
+ event.preventDefault();
+ event.currentTarget.classList[action]('is-hovered');
+ if (action === 'add') {
+ hoverBlock(clientId);
+ } else {
+ hoverBlock(null);
+ }
+ }
return (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
node.addEventListener('mouseout', listener);
node.addEventListener('mouseover', listener);
@@ -40054,11 +40553,12 @@
// Remove class in case it lingers.
node.classList.remove('is-hovered');
+ hoverBlock(null);
};
}, []);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-focus-handler.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-focus-handler.js
/**
* WordPress dependencies
*/
@@ -40110,7 +40610,7 @@
return;
}
- // If an inner block is focussed, that block is resposible for
+ // If an inner block is focussed, that block is responsible for
// setting the selected block.
if (!isInsideRootBlock(node, event.target)) {
return;
@@ -40124,18 +40624,87 @@
}, [isBlockSelected, selectBlock]);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js
-/**
- * WordPress dependencies
- */
-
-
-
-
-
-/**
- * Internal dependencies
- */
+;// ./node_modules/@wordpress/icons/build-module/library/drag-handle.js
+/**
+ * WordPress dependencies
+ */
+
+
+const dragHandle = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.SVG, {
+ width: "24",
+ height: "24",
+ xmlns: "http://www.w3.org/2000/svg",
+ viewBox: "0 0 24 24",
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.Path, {
+ d: "M8 7h2V5H8v2zm0 6h2v-2H8v2zm0 6h2v-2H8v2zm6-14v2h2V5h-2zm0 8h2v-2h-2v2zm0 6h2v-2h-2v2z"
+ })
+});
+/* harmony default export */ const drag_handle = (dragHandle);
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-draggable/draggable-chip.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+function BlockDraggableChip({
+ count,
+ icon,
+ isPattern,
+ fadeWhenDisabled
+}) {
+ const patternLabel = isPattern && (0,external_wp_i18n_namespaceObject.__)('Pattern');
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
+ className: "block-editor-block-draggable-chip-wrapper",
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
+ className: "block-editor-block-draggable-chip",
+ "data-testid": "block-draggable-chip",
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.Flex, {
+ justify: "center",
+ className: "block-editor-block-draggable-chip__content",
+ children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.FlexItem, {
+ children: icon ? /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(block_icon, {
+ icon: icon
+ }) : patternLabel || (0,external_wp_i18n_namespaceObject.sprintf)(/* translators: %d: Number of blocks. */
+ (0,external_wp_i18n_namespaceObject._n)('%d block', '%d blocks', count), count)
+ }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.FlexItem, {
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(block_icon, {
+ icon: drag_handle
+ })
+ }), fadeWhenDisabled && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.FlexItem, {
+ className: "block-editor-block-draggable-chip__disabled",
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("span", {
+ className: "block-editor-block-draggable-chip__disabled-icon"
+ })
+ })]
+ })
+ })
+ });
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
/**
@@ -40146,18 +40715,27 @@
*
* @param {string} clientId Block client ID.
*/
+
function useEventHandlers({
clientId,
isSelected
}) {
const {
+ getBlockType
+ } = (0,external_wp_data_namespaceObject.useSelect)(external_wp_blocks_namespaceObject.store);
+ const {
getBlockRootClientId,
- getBlockIndex
- } = (0,external_wp_data_namespaceObject.useSelect)(store);
+ isZoomOut,
+ hasMultiSelection,
+ getBlockName
+ } = unlock((0,external_wp_data_namespaceObject.useSelect)(store));
const {
insertAfterBlock,
- removeBlock
- } = (0,external_wp_data_namespaceObject.useDispatch)(store);
+ removeBlock,
+ resetZoomLevel,
+ startDraggingBlocks,
+ stopDraggingBlocks
+ } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
return (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
if (!isSelected) {
return;
@@ -40184,7 +40762,9 @@
return;
}
event.preventDefault();
- if (keyCode === external_wp_keycodes_namespaceObject.ENTER) {
+ if (keyCode === external_wp_keycodes_namespaceObject.ENTER && isZoomOut()) {
+ resetZoomLevel();
+ } else if (keyCode === external_wp_keycodes_namespaceObject.ENTER) {
insertAfterBlock(clientId);
} else {
removeBlock(clientId);
@@ -40198,7 +40778,89 @@
* @param {DragEvent} event Drag event.
*/
function onDragStart(event) {
- event.preventDefault();
+ if (node !== event.target || node.isContentEditable || node.ownerDocument.activeElement !== node || hasMultiSelection()) {
+ event.preventDefault();
+ return;
+ }
+ const data = JSON.stringify({
+ type: 'block',
+ srcClientIds: [clientId],
+ srcRootClientId: getBlockRootClientId(clientId)
+ });
+ event.dataTransfer.effectAllowed = 'move'; // remove "+" cursor
+ event.dataTransfer.clearData();
+ event.dataTransfer.setData('wp-blocks', data);
+ const {
+ ownerDocument
+ } = node;
+ const {
+ defaultView
+ } = ownerDocument;
+ const selection = defaultView.getSelection();
+ selection.removeAllRanges();
+ const domNode = document.createElement('div');
+ const root = (0,external_wp_element_namespaceObject.createRoot)(domNode);
+ root.render(/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(BlockDraggableChip, {
+ icon: getBlockType(getBlockName(clientId)).icon
+ }));
+ document.body.appendChild(domNode);
+ domNode.style.position = 'absolute';
+ domNode.style.top = '0';
+ domNode.style.left = '0';
+ domNode.style.zIndex = '1000';
+ domNode.style.pointerEvents = 'none';
+
+ // Setting the drag chip as the drag image actually works, but
+ // the behaviour is slightly different in every browser. In
+ // Safari, it animates, in Firefox it's slightly transparent...
+ // So we set a fake drag image and have to reposition it
+ // ourselves.
+ const dragElement = ownerDocument.createElement('div');
+ // Chrome will show a globe icon if the drag element does not
+ // have dimensions.
+ dragElement.style.width = '1px';
+ dragElement.style.height = '1px';
+ dragElement.style.position = 'fixed';
+ dragElement.style.visibility = 'hidden';
+ ownerDocument.body.appendChild(dragElement);
+ event.dataTransfer.setDragImage(dragElement, 0, 0);
+ let offset = {
+ x: 0,
+ y: 0
+ };
+ if (document !== ownerDocument) {
+ const frame = defaultView.frameElement;
+ if (frame) {
+ const rect = frame.getBoundingClientRect();
+ offset = {
+ x: rect.left,
+ y: rect.top
+ };
+ }
+ }
+
+ // chip handle offset
+ offset.x -= 58;
+ function over(e) {
+ domNode.style.transform = `translate( ${e.clientX + offset.x}px, ${e.clientY + offset.y}px )`;
+ }
+ over(event);
+ function end() {
+ ownerDocument.removeEventListener('dragover', over);
+ ownerDocument.removeEventListener('dragend', end);
+ domNode.remove();
+ dragElement.remove();
+ stopDraggingBlocks();
+ document.body.classList.remove('is-dragging-components-draggable');
+ ownerDocument.documentElement.classList.remove('is-dragging');
+ }
+ ownerDocument.addEventListener('dragover', over);
+ ownerDocument.addEventListener('dragend', end);
+ ownerDocument.addEventListener('drop', end);
+ startDraggingBlocks([clientId]);
+ // Important because it hides the block toolbar.
+ document.body.classList.add('is-dragging-components-draggable');
+ ownerDocument.documentElement.classList.add('is-dragging');
}
node.addEventListener('keydown', onKeyDown);
node.addEventListener('dragstart', onDragStart);
@@ -40206,59 +40868,10 @@
node.removeEventListener('keydown', onKeyDown);
node.removeEventListener('dragstart', onDragStart);
};
- }, [clientId, isSelected, getBlockRootClientId, getBlockIndex, insertAfterBlock, removeBlock]);
-}
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-nav-mode-exit.js
-/**
- * WordPress dependencies
- */
-
-
-
-/**
- * Internal dependencies
- */
-
-
-/**
- * Allows navigation mode to be exited by clicking in the selected block.
- *
- * @param {string} clientId Block client ID.
- */
-function useNavModeExit(clientId) {
- const {
- isNavigationMode,
- isBlockSelected
- } = (0,external_wp_data_namespaceObject.useSelect)(store);
- const {
- setNavigationMode,
- selectBlock
- } = (0,external_wp_data_namespaceObject.useDispatch)(store);
- return (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
- function onMouseDown(event) {
- // Don't select a block if it's already handled by a child
- // block.
- if (isNavigationMode() && !event.defaultPrevented) {
- // Prevent focus from moving to the block.
- event.preventDefault();
-
- // When clicking on a selected block, exit navigation mode.
- if (isBlockSelected(clientId)) {
- setNavigationMode(false);
- } else {
- selectBlock(clientId);
- }
- }
- }
- node.addEventListener('mousedown', onMouseDown);
- return () => {
- node.removeEventListener('mousedown', onMouseDown);
- };
- }, [clientId, isNavigationMode, isBlockSelected, setNavigationMode]);
-}
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-intersection-observer.js
+ }, [clientId, isSelected, getBlockRootClientId, insertAfterBlock, removeBlock, isZoomOut, resetZoomLevel, hasMultiSelection, startDraggingBlocks, stopDraggingBlocks]);
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-intersection-observer.js
/**
* WordPress dependencies
*/
@@ -40281,7 +40894,7 @@
}, [observer]);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-scroll-into-view.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-scroll-into-view.js
/**
* WordPress dependencies
*/
@@ -40319,7 +40932,7 @@
}, [isSelected]);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/use-flash-editable-blocks/index.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/use-flash-editable-blocks/index.js
/**
* WordPress dependencies
*/
@@ -40373,7 +40986,91 @@
}, [isEnabled]);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/index.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/use-firefox-draggable-compatibility.js
+/**
+ * WordPress dependencies
+ */
+
+const nodesByDocument = new Map();
+function add(doc, node) {
+ let set = nodesByDocument.get(doc);
+ if (!set) {
+ set = new Set();
+ nodesByDocument.set(doc, set);
+ doc.addEventListener('pointerdown', down);
+ }
+ set.add(node);
+}
+function remove(doc, node) {
+ const set = nodesByDocument.get(doc);
+ if (set) {
+ set.delete(node);
+ restore(node);
+ if (set.size === 0) {
+ nodesByDocument.delete(doc);
+ doc.removeEventListener('pointerdown', down);
+ }
+ }
+}
+function restore(node) {
+ const prevDraggable = node.getAttribute('data-draggable');
+ if (prevDraggable) {
+ node.removeAttribute('data-draggable');
+ // Only restore if `draggable` is still removed. It could have been
+ // changed by React in the meantime.
+ if (prevDraggable === 'true' && !node.getAttribute('draggable')) {
+ node.setAttribute('draggable', 'true');
+ }
+ }
+}
+function down(event) {
+ const {
+ target
+ } = event;
+ const {
+ ownerDocument,
+ isContentEditable,
+ tagName
+ } = target;
+ const isInputOrTextArea = ['INPUT', 'TEXTAREA'].includes(tagName);
+ const nodes = nodesByDocument.get(ownerDocument);
+ if (isContentEditable || isInputOrTextArea) {
+ // Whenever an editable element or an input or textarea is clicked,
+ // check which draggable blocks contain this element, and temporarily
+ // disable draggability.
+ for (const node of nodes) {
+ if (node.getAttribute('draggable') === 'true' && node.contains(target)) {
+ node.removeAttribute('draggable');
+ node.setAttribute('data-draggable', 'true');
+ }
+ }
+ } else {
+ // Whenever a non-editable element or an input or textarea is clicked,
+ // re-enable draggability for any blocks that were previously disabled.
+ for (const node of nodes) {
+ restore(node);
+ }
+ }
+}
+
+/**
+ * In Firefox, the `draggable` and `contenteditable` or `input` or `textarea`
+ * elements don't play well together. When these elements are within a
+ * `draggable` element, selection doesn't get set in the right place. The only
+ * solution is to temporarily remove the `draggable` attribute clicking inside
+ * these elements.
+ * @return {Function} Cleanup function.
+ */
+function useFirefoxDraggableCompatibility() {
+ return (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
+ add(node.ownerDocument, node);
+ return () => {
+ remove(node.ownerDocument, node);
+ };
+ }, []);
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-block-props/index.js
/**
* External dependencies
*/
@@ -40422,13 +41119,13 @@
*
* export default function Edit() {
*
- * const blockProps = useBlockProps(
+ * const blockProps = useBlockProps( {
* className: 'my-custom-class',
* style: {
* color: '#222222',
* backgroundColor: '#eeeeee'
* }
- * )
+ * } )
*
* return (
*
@@ -40471,35 +41168,37 @@
isReusable,
isDragging,
hasChildSelected,
- isBlockMovingMode,
- canInsertMovingBlock,
isEditingDisabled,
hasEditableOutline,
isTemporarilyEditingAsBlocks,
defaultClassName,
- templateLock
+ isSectionBlock,
+ canMove
} = (0,external_wp_element_namespaceObject.useContext)(PrivateBlockContext);
// translators: %s: Type of block (i.e. Text, Image etc)
const blockLabel = (0,external_wp_i18n_namespaceObject.sprintf)((0,external_wp_i18n_namespaceObject.__)('Block: %s'), blockTitle);
const htmlSuffix = mode === 'html' && !__unstableIsHtml ? '-visual' : '';
+ const ffDragRef = useFirefoxDraggableCompatibility();
const mergedRefs = (0,external_wp_compose_namespaceObject.useMergeRefs)([props.ref, useFocusFirstElement({
clientId,
initialPosition
}), useBlockRefProvider(clientId), useFocusHandler(clientId), useEventHandlers({
clientId,
isSelected
- }), useNavModeExit(clientId), useIsHovered(), useIntersectionObserver(), use_moving_animation({
+ }), useIsHovered({
+ clientId
+ }), useIntersectionObserver(), use_moving_animation({
triggerAnimationOnChange: index,
clientId
}), (0,external_wp_compose_namespaceObject.useDisabled)({
isDisabled: !hasOverlay
}), useFlashEditableBlocks({
clientId,
- isEnabled: name === 'core/block' || templateLock === 'contentOnly'
+ isEnabled: isSectionBlock
}), useScrollIntoView({
isSelected
- })]);
+ }), canMove ? ffDragRef : undefined]);
const blockEditContext = useBlockEditContext();
const hasBlockBindings = !!blockEditContext[blockBindingsKey];
const bindingsStyle = hasBlockBindings && canBindBlock(name) ? {
@@ -40517,6 +41216,7 @@
}
return {
tabIndex: blockEditingMode === 'disabled' ? -1 : 0,
+ draggable: canMove && !hasChildSelected ? true : undefined,
...wrapperProps,
...props,
ref: mergedRefs,
@@ -40538,8 +41238,6 @@
'is-reusable': isReusable,
'is-dragging': isDragging,
'has-child-selected': hasChildSelected,
- 'is-block-moving-mode': isBlockMovingMode,
- 'can-insert-moving-block': canInsertMovingBlock,
'is-editing-disabled': isEditingDisabled,
'has-editable-outline': hasEditableOutline,
'has-negative-margin': hasNegativeMargin,
@@ -40560,7 +41258,7 @@
*/
use_block_props_useBlockProps.save = external_wp_blocks_namespaceObject.__unstableGetBlockProps;
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-list/block.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/block.js
/**
* External dependencies
*/
@@ -40599,8 +41297,6 @@
* @return {Object} Merged props.
*/
-
-
function mergeWrapperProps(propsA, propsB) {
const newProps = {
...propsA,
@@ -40649,6 +41345,7 @@
wrapperProps,
setAttributes,
onReplace,
+ onRemove,
onInsertBlocksAfter,
onMerge,
toggleSelection
@@ -40660,10 +41357,6 @@
themeSupportsLayout,
...context
} = (0,external_wp_element_namespaceObject.useContext)(PrivateBlockContext);
- const {
- removeBlock
- } = (0,external_wp_data_namespaceObject.useDispatch)(store);
- const onRemove = (0,external_wp_element_namespaceObject.useCallback)(() => removeBlock(clientId), [clientId, removeBlock]);
const parentLayout = useLayout() || {};
// We wrap the BlockEdit component in a div that hides it when editing in
@@ -40845,6 +41538,7 @@
function switchToDefaultOrRemove() {
const block = getBlock(clientId);
const defaultBlockName = (0,external_wp_blocks_namespaceObject.getDefaultBlockName)();
+ const defaultBlockType = (0,external_wp_blocks_namespaceObject.getBlockType)(defaultBlockName);
if (getBlockName(clientId) !== defaultBlockName) {
const replacement = (0,external_wp_blocks_namespaceObject.switchToBlockType)(block, defaultBlockName);
if (replacement && replacement.length) {
@@ -40858,6 +41552,9 @@
selectBlock(nextBlockClientId);
});
}
+ } else if (defaultBlockType.merge) {
+ const attributes = defaultBlockType.merge({}, block.attributes);
+ replaceBlocks([clientId], [(0,external_wp_blocks_namespaceObject.createBlock)(defaultBlockName, attributes)]);
}
}
@@ -40871,12 +41568,15 @@
* to the moved block.
*/
function moveFirstItemUp(_clientId, changeSelection = true) {
+ const wrapperBlockName = getBlockName(_clientId);
+ const wrapperBlockType = (0,external_wp_blocks_namespaceObject.getBlockType)(wrapperBlockName);
+ const isTextualWrapper = wrapperBlockType.category === 'text';
const targetRootClientId = getBlockRootClientId(_clientId);
const blockOrder = getBlockOrder(_clientId);
const [firstClientId] = blockOrder;
if (blockOrder.length === 1 && (0,external_wp_blocks_namespaceObject.isUnmodifiedBlock)(getBlock(firstClientId))) {
removeBlock(_clientId);
- } else {
+ } else if (isTextualWrapper) {
registry.batch(() => {
if (canInsertBlockType(getBlockName(firstClientId), targetRootClientId)) {
moveBlocksToPosition([firstClientId], _clientId, targetRootClientId, getBlockIndex(_clientId));
@@ -40893,6 +41593,8 @@
removeBlock(_clientId, false);
}
});
+ } else {
+ switchToDefaultOrRemove();
}
}
@@ -40964,6 +41666,9 @@
const replacementBlocks = blocks?.length === 1 && Array.isArray(blocks[0]) ? blocks[0] : blocks;
replaceBlocks([ownProps.clientId], replacementBlocks, indexToSelect, initialPosition);
},
+ onRemove() {
+ removeBlock(ownProps.clientId);
+ },
toggleSelection(selectionEnabled) {
toggleSelection(selectionEnabled);
}
@@ -40991,6 +41696,7 @@
getBlockMode,
isSelectionEnabled,
getTemplateLock,
+ isSectionBlock: _isSectionBlock,
getBlockWithoutAttributes,
getBlockAttributes,
canRemoveBlock,
@@ -41011,10 +41717,7 @@
__unstableSelectionHasUnmergeableBlock,
isBlockBeingDragged,
isDragging,
- hasBlockMovingClientId,
- canInsertBlockType,
__unstableHasActiveBlockOverlayActive,
- __unstableGetEditorMode,
getSelectedBlocksInitialCaretPosition
} = unlock(select(store));
const blockWithoutAttributes = getBlockWithoutAttributes(clientId);
@@ -41038,7 +41741,7 @@
const blockType = (0,external_wp_blocks_namespaceObject.getBlockType)(blockName);
const {
supportsLayout,
- __unstableIsPreviewMode: isPreviewMode
+ isPreviewMode
} = getSettings();
const hasLightBlockWrapper = blockType?.apiVersion > 1;
const previewContext = {
@@ -41067,7 +41770,6 @@
const isMultiSelected = isBlockMultiSelected(clientId);
const checkDeep = true;
const isAncestorOfSelectedBlock = hasSelectedInnerBlock(clientId, checkDeep);
- const movingClientId = hasBlockMovingClientId();
const blockEditingMode = getBlockEditingMode(clientId);
const multiple = (0,external_wp_blocks_namespaceObject.hasBlockSupport)(blockName, 'multiple', true);
@@ -41080,7 +41782,7 @@
mode: getBlockMode(clientId),
isSelectionEnabled: isSelectionEnabled(),
isLocked: !!getTemplateLock(rootClientId),
- templateLock: getTemplateLock(clientId),
+ isSectionBlock: _isSectionBlock(clientId),
canRemove,
canMove,
isSelected: _isSelected,
@@ -41092,15 +41794,12 @@
blockTitle: match?.title || blockType?.title,
isSubtreeDisabled: blockEditingMode === 'disabled' && isBlockSubtreeDisabled(clientId),
hasOverlay: __unstableHasActiveBlockOverlayActive(clientId) && !isDragging(),
- initialPosition: _isSelected && (__unstableGetEditorMode() === 'edit' || __unstableGetEditorMode() === 'zoom-out') // Don't recalculate the initialPosition when toggling in/out of zoom-out mode
- ? getSelectedBlocksInitialCaretPosition() : undefined,
+ initialPosition: _isSelected ? getSelectedBlocksInitialCaretPosition() : undefined,
isHighlighted: isBlockHighlighted(clientId),
isMultiSelected,
isPartiallySelected: isMultiSelected && !__unstableIsFullySelected() && !__unstableSelectionHasUnmergeableBlock(),
isDragging: isBlockBeingDragged(clientId),
hasChildSelected: isAncestorOfSelectedBlock,
- isBlockMovingMode: !!movingClientId,
- canInsertMovingBlock: movingClientId && canInsertBlockType(getBlockName(movingClientId), rootClientId),
isEditingDisabled: blockEditingMode === 'disabled',
hasEditableOutline: blockEditingMode !== 'disabled' && getBlockEditingMode(rootClientId) === 'disabled',
originalBlockClientId: isInvalid ? blocksWithSameName[0] : false
@@ -41137,9 +41836,7 @@
isReusable,
isDragging,
hasChildSelected,
- isBlockMovingMode,
- canInsertMovingBlock,
- templateLock,
+ isSectionBlock,
isEditingDisabled,
hasEditableOutline,
className,
@@ -41182,9 +41879,7 @@
isReusable,
isDragging,
hasChildSelected,
- isBlockMovingMode,
- canInsertMovingBlock,
- templateLock,
+ isSectionBlock,
isEditingDisabled,
hasEditableOutline,
isTemporarilyEditingAsBlocks,
@@ -41192,7 +41887,8 @@
mayDisplayControls,
mayDisplayParentControls,
originalBlockClientId,
- themeSupportsLayout
+ themeSupportsLayout,
+ canMove
};
// Here we separate between the props passed to BlockListBlock and any other
@@ -41225,680 +41921,831 @@
})
});
}
-/* harmony default export */ const block_list_block = ((0,external_wp_element_namespaceObject.memo)(BlockListBlockProvider));
-
-;// CONCATENATED MODULE: external ["wp","htmlEntities"]
+/* harmony default export */ const block = ((0,external_wp_element_namespaceObject.memo)(BlockListBlockProvider));
+
+;// external ["wp","htmlEntities"]
const external_wp_htmlEntities_namespaceObject = window["wp"]["htmlEntities"];
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/inserter/tips.js
-/**
- * WordPress dependencies
- */
-
-
-
-
-const globalTips = [(0,external_wp_element_namespaceObject.createInterpolateElement)((0,external_wp_i18n_namespaceObject.__)('While writing, you can press / to quickly insert new blocks.'), {
- kbd: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("kbd", {})
-}), (0,external_wp_element_namespaceObject.createInterpolateElement)((0,external_wp_i18n_namespaceObject.__)('Indent a list by pressing space at the beginning of a line.'), {
- kbd: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("kbd", {})
-}), (0,external_wp_element_namespaceObject.createInterpolateElement)((0,external_wp_i18n_namespaceObject.__)('Outdent a list by pressing backspace at the beginning of a line.'), {
- kbd: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("kbd", {})
-}), (0,external_wp_i18n_namespaceObject.__)('Drag files into the editor to automatically insert media blocks.'), (0,external_wp_i18n_namespaceObject.__)("Change a block's type by pressing the block icon on the toolbar.")];
-function Tips() {
- const [randomIndex] = (0,external_wp_element_namespaceObject.useState)(
- // Disable Reason: I'm not generating an HTML id.
- // eslint-disable-next-line no-restricted-syntax
- Math.floor(Math.random() * globalTips.length));
- return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Tip, {
- children: globalTips[randomIndex]
- });
-}
-/* harmony default export */ const tips = (Tips);
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/icons/build-module/library/chevron-right.js
-/**
- * WordPress dependencies
- */
-
-
-const chevronRight = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.SVG, {
- xmlns: "http://www.w3.org/2000/svg",
- viewBox: "0 0 24 24",
- children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.Path, {
- d: "M10.6 6L9.4 7l4.6 5-4.6 5 1.2 1 5.4-6z"
- })
-});
-/* harmony default export */ const chevron_right = (chevronRight);
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/icons/build-module/library/chevron-left.js
-/**
- * WordPress dependencies
- */
-
-
-const chevronLeft = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.SVG, {
- xmlns: "http://www.w3.org/2000/svg",
- viewBox: "0 0 24 24",
- children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.Path, {
- d: "M14.6 7l-1.2-1L8 12l5.4 6 1.2-1-4.6-5z"
- })
-});
-/* harmony default export */ const chevron_left = (chevronLeft);
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-card/index.js
-/**
- * External dependencies
- */
-
-
-/**
- * WordPress dependencies
- */
-
-
-
-
-
-
-/**
- * Internal dependencies
- */
-
-
-
-
-function BlockCard({
- title,
- icon,
- description,
- blockType,
- className
-}) {
- if (blockType) {
- external_wp_deprecated_default()('`blockType` property in `BlockCard component`', {
- since: '5.7',
- alternative: '`title, icon and description` properties'
- });
- ({
- title,
- icon,
- description
- } = blockType);
- }
- const {
- parentNavBlockClientId
+;// ./node_modules/@wordpress/block-editor/build-module/components/default-block-appender/index.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+/**
+ * Zero width non-breaking space, used as padding for the paragraph when it is
+ * empty.
+ */
+
+const ZWNBSP = '\ufeff';
+function DefaultBlockAppender({
+ rootClientId
+}) {
+ const {
+ showPrompt,
+ isLocked,
+ placeholder,
+ isManualGrid
} = (0,external_wp_data_namespaceObject.useSelect)(select => {
const {
- getSelectedBlockClientId,
- getBlockParentsByBlockName
+ getBlockCount,
+ getSettings,
+ getTemplateLock,
+ getBlockAttributes
+ } = select(store);
+ const isEmpty = !getBlockCount(rootClientId);
+ const {
+ bodyPlaceholder
+ } = getSettings();
+ return {
+ showPrompt: isEmpty,
+ isLocked: !!getTemplateLock(rootClientId),
+ placeholder: bodyPlaceholder,
+ isManualGrid: getBlockAttributes(rootClientId)?.layout?.isManualPlacement
+ };
+ }, [rootClientId]);
+ const {
+ insertDefaultBlock,
+ startTyping
+ } = (0,external_wp_data_namespaceObject.useDispatch)(store);
+ if (isLocked || isManualGrid) {
+ return null;
+ }
+ const value = (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(placeholder) || (0,external_wp_i18n_namespaceObject.__)('Type / to choose a block');
+ const onAppend = () => {
+ insertDefaultBlock(undefined, rootClientId);
+ startTyping();
+ };
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)("div", {
+ "data-root-client-id": rootClientId || '',
+ className: dist_clsx('block-editor-default-block-appender', {
+ 'has-visible-prompt': showPrompt
+ }),
+ children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("p", {
+ tabIndex: "0"
+ // We want this element to be styled as a paragraph by themes.
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
+ ,
+ role: "button",
+ "aria-label": (0,external_wp_i18n_namespaceObject.__)('Add default block')
+ // A wrapping container for this one already has the wp-block className.
+ ,
+ className: "block-editor-default-block-appender__content",
+ onKeyDown: event => {
+ if (external_wp_keycodes_namespaceObject.ENTER === event.keyCode || external_wp_keycodes_namespaceObject.SPACE === event.keyCode) {
+ onAppend();
+ }
+ },
+ onClick: () => onAppend(),
+ onFocus: () => {
+ if (showPrompt) {
+ onAppend();
+ }
+ },
+ children: showPrompt ? value : ZWNBSP
+ }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(inserter, {
+ rootClientId: rootClientId,
+ position: "bottom right",
+ isAppender: true,
+ __experimentalIsQuick: true
+ })]
+ });
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list-appender/index.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+
+function DefaultAppender({
+ rootClientId
+}) {
+ const canInsertDefaultBlock = (0,external_wp_data_namespaceObject.useSelect)(select => select(store).canInsertBlockType((0,external_wp_blocks_namespaceObject.getDefaultBlockName)(), rootClientId));
+ if (canInsertDefaultBlock) {
+ // Render the default block appender if the context supports use
+ // of the default appender.
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(DefaultBlockAppender, {
+ rootClientId: rootClientId
+ });
+ }
+
+ // Fallback in case the default block can't be inserted.
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(button_block_appender, {
+ rootClientId: rootClientId,
+ className: "block-list-appender__toggle"
+ });
+}
+function BlockListAppender({
+ rootClientId,
+ CustomAppender,
+ className,
+ tagName: TagName = 'div'
+}) {
+ const isDragOver = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ getBlockInsertionPoint,
+ isBlockInsertionPointVisible,
+ getBlockCount
} = select(store);
- const _selectedBlockClientId = getSelectedBlockClientId();
- return {
- parentNavBlockClientId: getBlockParentsByBlockName(_selectedBlockClientId, 'core/navigation', true)[0]
+ const insertionPoint = getBlockInsertionPoint();
+ // Ideally we should also check for `isDragging` but currently it
+ // requires a lot more setup. We can revisit this once we refactor
+ // the DnD utility hooks.
+ return isBlockInsertionPointVisible() && rootClientId === insertionPoint?.rootClientId && getBlockCount(rootClientId) === 0;
+ }, [rootClientId]);
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(TagName
+ // A `tabIndex` is used on the wrapping `div` element in order to
+ // force a focus event to occur when an appender `button` element
+ // is clicked. In some browsers (Firefox, Safari), button clicks do
+ // not emit a focus event, which could cause this event to propagate
+ // unexpectedly. The `tabIndex` ensures that the interaction is
+ // captured as a focus, without also adding an extra tab stop.
+ //
+ // See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus
+ , {
+ tabIndex: -1,
+ className: dist_clsx('block-list-appender wp-block', className, {
+ 'is-drag-over': isDragOver
+ })
+ // Needed in case the whole editor is content editable (for multi
+ // selection). It fixes an edge case where ArrowDown and ArrowRight
+ // should collapse the selection to the end of that selection and
+ // not into the appender.
+ ,
+ contentEditable: false
+ // The appender exists to let you add the first Paragraph before
+ // any is inserted. To that end, this appender should visually be
+ // presented as a block. That means theme CSS should style it as if
+ // it were an empty paragraph block. That means a `wp-block` class to
+ // ensure the width is correct, and a [data-block] attribute to ensure
+ // the correct margin is applied, especially for classic themes which
+ // have commonly targeted that attribute for margins.
+ ,
+ "data-block": true,
+ children: CustomAppender ? /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CustomAppender, {}) : /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(DefaultAppender, {
+ rootClientId: rootClientId
+ })
+ });
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-popover/inbetween.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+
+const inbetween_MAX_POPOVER_RECOMPUTE_COUNTER = Number.MAX_SAFE_INTEGER;
+const InsertionPointOpenRef = (0,external_wp_element_namespaceObject.createContext)();
+function BlockPopoverInbetween({
+ previousClientId,
+ nextClientId,
+ children,
+ __unstablePopoverSlot,
+ __unstableContentRef,
+ operation = 'insert',
+ nearestSide = 'right',
+ ...props
+}) {
+ // This is a temporary hack to get the inbetween inserter to recompute properly.
+ const [popoverRecomputeCounter, forcePopoverRecompute] = (0,external_wp_element_namespaceObject.useReducer)(
+ // Module is there to make sure that the counter doesn't overflow.
+ s => (s + 1) % inbetween_MAX_POPOVER_RECOMPUTE_COUNTER, 0);
+ const {
+ orientation,
+ rootClientId,
+ isVisible
+ } = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ getBlockListSettings,
+ getBlockRootClientId,
+ isBlockVisible
+ } = select(store);
+ const _rootClientId = getBlockRootClientId(previousClientId !== null && previousClientId !== void 0 ? previousClientId : nextClientId);
+ return {
+ orientation: getBlockListSettings(_rootClientId)?.orientation || 'vertical',
+ rootClientId: _rootClientId,
+ isVisible: isBlockVisible(previousClientId) && isBlockVisible(nextClientId)
+ };
+ }, [previousClientId, nextClientId]);
+ const previousElement = useBlockElement(previousClientId);
+ const nextElement = useBlockElement(nextClientId);
+ const isVertical = orientation === 'vertical';
+ const popoverAnchor = (0,external_wp_element_namespaceObject.useMemo)(() => {
+ if (
+ // popoverRecomputeCounter is by definition always equal or greater than 0.
+ // This check is only there to satisfy the correctness of the
+ // exhaustive-deps rule for the `useMemo` hook.
+ popoverRecomputeCounter < 0 || !previousElement && !nextElement || !isVisible) {
+ return undefined;
+ }
+ const contextElement = operation === 'group' ? nextElement || previousElement : previousElement || nextElement;
+ return {
+ contextElement,
+ getBoundingClientRect() {
+ const previousRect = previousElement ? previousElement.getBoundingClientRect() : null;
+ const nextRect = nextElement ? nextElement.getBoundingClientRect() : null;
+ let left = 0;
+ let top = 0;
+ let width = 0;
+ let height = 0;
+ if (operation === 'group') {
+ const targetRect = nextRect || previousRect;
+ top = targetRect.top;
+ // No spacing is likely around blocks in this operation.
+ // So width of the inserter containing rect is set to 0.
+ width = 0;
+ height = targetRect.bottom - targetRect.top;
+ // Popover calculates its distance from mid-block so some
+ // adjustments are needed to make it appear in the right place.
+ left = nearestSide === 'left' ? targetRect.left - 2 : targetRect.right - 2;
+ } else if (isVertical) {
+ // vertical
+ top = previousRect ? previousRect.bottom : nextRect.top;
+ width = previousRect ? previousRect.width : nextRect.width;
+ height = nextRect && previousRect ? nextRect.top - previousRect.bottom : 0;
+ left = previousRect ? previousRect.left : nextRect.left;
+ } else {
+ top = previousRect ? previousRect.top : nextRect.top;
+ height = previousRect ? previousRect.height : nextRect.height;
+ if ((0,external_wp_i18n_namespaceObject.isRTL)()) {
+ // non vertical, rtl
+ left = nextRect ? nextRect.right : previousRect.left;
+ width = previousRect && nextRect ? previousRect.left - nextRect.right : 0;
+ } else {
+ // non vertical, ltr
+ left = previousRect ? previousRect.right : nextRect.left;
+ width = previousRect && nextRect ? nextRect.left - previousRect.right : 0;
+ }
+
+ // Avoid a negative width which happens when the next rect
+ // is on the next line.
+ width = Math.max(width, 0);
+ }
+ return new window.DOMRect(left, top, width, height);
+ }
+ };
+ }, [previousElement, nextElement, popoverRecomputeCounter, isVertical, isVisible, operation, nearestSide]);
+ const popoverScrollRef = use_popover_scroll(__unstableContentRef);
+
+ // This is only needed for a smooth transition when moving blocks.
+ // When blocks are moved up/down, their position can be set by
+ // updating the `transform` property manually (i.e. without using CSS
+ // transitions or animations). The animation, which can also scroll the block
+ // editor, can sometimes cause the position of the Popover to get out of sync.
+ // A MutationObserver is therefore used to make sure that changes to the
+ // selectedElement's attribute (i.e. `transform`) can be tracked and used to
+ // trigger the Popover to rerender.
+ (0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
+ if (!previousElement) {
+ return;
+ }
+ const observer = new window.MutationObserver(forcePopoverRecompute);
+ observer.observe(previousElement, {
+ attributes: true
+ });
+ return () => {
+ observer.disconnect();
+ };
+ }, [previousElement]);
+ (0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
+ if (!nextElement) {
+ return;
+ }
+ const observer = new window.MutationObserver(forcePopoverRecompute);
+ observer.observe(nextElement, {
+ attributes: true
+ });
+ return () => {
+ observer.disconnect();
+ };
+ }, [nextElement]);
+ (0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
+ if (!previousElement) {
+ return;
+ }
+ previousElement.ownerDocument.defaultView.addEventListener('resize', forcePopoverRecompute);
+ return () => {
+ previousElement.ownerDocument.defaultView?.removeEventListener('resize', forcePopoverRecompute);
+ };
+ }, [previousElement]);
+
+ // If there's either a previous or a next element, show the inbetween popover.
+ // Note that drag and drop uses the inbetween popover to show the drop indicator
+ // before the first block and after the last block.
+ if (!previousElement && !nextElement || !isVisible) {
+ return null;
+ }
+
+ /* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
+ // While ideally it would be enough to capture the
+ // bubbling focus event from the Inserter, due to the
+ // characteristics of click focusing of `button`s in
+ // Firefox and Safari, it is not reliable.
+ //
+ // See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Popover, {
+ ref: popoverScrollRef,
+ animate: false,
+ anchor: popoverAnchor,
+ focusOnMount: false
+ // Render in the old slot if needed for backward compatibility,
+ // otherwise render in place (not in the default popover slot).
+ ,
+ __unstableSlotName: __unstablePopoverSlot,
+ inline: !__unstablePopoverSlot
+ // Forces a remount of the popover when its position changes
+ // This makes sure the popover doesn't animate from its previous position.
+ ,
+ ...props,
+ className: dist_clsx('block-editor-block-popover', 'block-editor-block-popover__inbetween', props.className),
+ resize: false,
+ flip: false,
+ placement: "overlay",
+ variant: "unstyled",
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
+ className: "block-editor-block-popover__inbetween-container",
+ children: children
+ })
+ }, nextClientId + '--' + rootClientId);
+ /* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
+}
+/* harmony default export */ const inbetween = (BlockPopoverInbetween);
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-popover/drop-zone.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+const animateVariants = {
+ hide: {
+ opacity: 0,
+ scaleY: 0.75
+ },
+ show: {
+ opacity: 1,
+ scaleY: 1
+ },
+ exit: {
+ opacity: 0,
+ scaleY: 0.9
+ }
+};
+function BlockDropZonePopover({
+ __unstablePopoverSlot,
+ __unstableContentRef
+}) {
+ const {
+ clientId
+ } = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ getBlockOrder,
+ getBlockInsertionPoint
+ } = select(store);
+ const insertionPoint = getBlockInsertionPoint();
+ const order = getBlockOrder(insertionPoint.rootClientId);
+ if (!order.length) {
+ return {};
+ }
+ return {
+ clientId: order[insertionPoint.index]
};
}, []);
- const {
- selectBlock
+ const reducedMotion = (0,external_wp_compose_namespaceObject.useReducedMotion)();
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(cover, {
+ clientId: clientId,
+ __unstablePopoverSlot: __unstablePopoverSlot,
+ __unstableContentRef: __unstableContentRef,
+ className: "block-editor-block-popover__drop-zone",
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__unstableMotion.div, {
+ "data-testid": "block-popover-drop-zone",
+ initial: reducedMotion ? animateVariants.show : animateVariants.hide,
+ animate: animateVariants.show,
+ exit: reducedMotion ? animateVariants.show : animateVariants.exit,
+ className: "block-editor-block-popover__drop-zone-foreground"
+ })
+ });
+}
+/* harmony default export */ const drop_zone = (BlockDropZonePopover);
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-tools/insertion-point.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+
+
+
+const insertion_point_InsertionPointOpenRef = (0,external_wp_element_namespaceObject.createContext)();
+function InbetweenInsertionPointPopover({
+ __unstablePopoverSlot,
+ __unstableContentRef,
+ operation = 'insert',
+ nearestSide = 'right'
+}) {
+ const {
+ selectBlock,
+ hideInsertionPoint
} = (0,external_wp_data_namespaceObject.useDispatch)(store);
- return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)("div", {
- className: dist_clsx('block-editor-block-card', className),
- children: [parentNavBlockClientId &&
- /*#__PURE__*/
- // This is only used by the Navigation block for now. It's not ideal having Navigation block specific code here.
- (0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.Button, {
- onClick: () => selectBlock(parentNavBlockClientId),
- label: (0,external_wp_i18n_namespaceObject.__)('Go to parent Navigation block'),
- style:
- // TODO: This style override is also used in ToolsPanelHeader.
- // It should be supported out-of-the-box by Button.
- {
- minWidth: 24,
- padding: 0
- },
- icon: (0,external_wp_i18n_namespaceObject.isRTL)() ? chevron_right : chevron_left,
- size: "small"
- }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(block_icon, {
- icon: icon,
- showColors: true
- }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__experimentalVStack, {
- spacing: 1,
- children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("h2", {
- className: "block-editor-block-card__title",
- children: title
- }), description && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__experimentalText, {
- className: "block-editor-block-card__description",
- children: description
- })]
- })]
- });
-}
-/* harmony default export */ const block_card = (BlockCard);
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/provider/with-registry-provider.js
-/**
- * WordPress dependencies
- */
-
-
-
-
-/**
- * Internal dependencies
- */
-
-
-
-function getSubRegistry(subRegistries, registry, useSubRegistry) {
- if (!useSubRegistry) {
- return registry;
- }
- let subRegistry = subRegistries.get(registry);
- if (!subRegistry) {
- subRegistry = (0,external_wp_data_namespaceObject.createRegistry)({}, registry);
- subRegistry.registerStore(STORE_NAME, storeConfig);
- subRegistries.set(registry, subRegistry);
- }
- return subRegistry;
-}
-const withRegistryProvider = (0,external_wp_compose_namespaceObject.createHigherOrderComponent)(WrappedComponent => ({
- useSubRegistry = true,
- ...props
-}) => {
- const registry = (0,external_wp_data_namespaceObject.useRegistry)();
- const [subRegistries] = (0,external_wp_element_namespaceObject.useState)(() => new WeakMap());
- const subRegistry = getSubRegistry(subRegistries, registry, useSubRegistry);
- if (subRegistry === registry) {
- return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(WrappedComponent, {
- registry: registry,
- ...props
- });
- }
- return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_data_namespaceObject.RegistryProvider, {
- value: subRegistry,
- children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(WrappedComponent, {
- registry: subRegistry,
- ...props
- })
- });
-}, 'withRegistryProvider');
-/* harmony default export */ const with_registry_provider = (withRegistryProvider);
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/provider/use-block-sync.js
-/**
- * WordPress dependencies
- */
-
-
-
-
-/**
- * Internal dependencies
- */
-
-
-const use_block_sync_noop = () => {};
-
-/**
- * A function to call when the block value has been updated in the block-editor
- * store.
- *
- * @callback onBlockUpdate
- * @param {Object[]} blocks The updated blocks.
- * @param {Object} options The updated block options, such as selectionStart
- * and selectionEnd.
- */
-
-/**
- * useBlockSync is a side effect which handles bidirectional sync between the
- * block-editor store and a controlling data source which provides blocks. This
- * is most commonly used by the BlockEditorProvider to synchronize the contents
- * of the block-editor store with the root entity, like a post.
- *
- * Another example would be the template part block, which provides blocks from
- * a separate entity data source than a root entity. This hook syncs edits to
- * the template part in the block editor back to the entity and vice-versa.
- *
- * Here are some of its basic functions:
- * - Initalizes the block-editor store for the given clientID to the blocks
- * given via props.
- * - Adds incoming changes (like undo) to the block-editor store.
- * - Adds outgoing changes (like editing content) to the controlling entity,
- * determining if a change should be considered persistent or not.
- * - Handles edge cases and race conditions which occur in those operations.
- * - Ignores changes which happen to other entities (like nested inner block
- * controllers.
- * - Passes selection state from the block-editor store to the controlling entity.
- *
- * @param {Object} props Props for the block sync hook
- * @param {string} props.clientId The client ID of the inner block controller.
- * If none is passed, then it is assumed to be a
- * root controller rather than an inner block
- * controller.
- * @param {Object[]} props.value The control value for the blocks. This value
- * is used to initalize the block-editor store
- * and for resetting the blocks to incoming
- * changes like undo.
- * @param {Object} props.selection The selection state responsible to restore the selection on undo/redo.
- * @param {onBlockUpdate} props.onChange Function to call when a persistent
- * change has been made in the block-editor blocks
- * for the given clientId. For example, after
- * this function is called, an entity is marked
- * dirty because it has changes to save.
- * @param {onBlockUpdate} props.onInput Function to call when a non-persistent
- * change has been made in the block-editor blocks
- * for the given clientId. When this is called,
- * controlling sources do not become dirty.
- */
-function useBlockSync({
- clientId = null,
- value: controlledBlocks,
- selection: controlledSelection,
- onChange = use_block_sync_noop,
- onInput = use_block_sync_noop
-}) {
- const registry = (0,external_wp_data_namespaceObject.useRegistry)();
- const {
- resetBlocks,
- resetSelection,
- replaceInnerBlocks,
- setHasControlledInnerBlocks,
- __unstableMarkNextChangeAsNotPersistent
- } = registry.dispatch(store);
- const {
- getBlockName,
- getBlocks,
- getSelectionStart,
- getSelectionEnd
- } = registry.select(store);
- const isControlled = (0,external_wp_data_namespaceObject.useSelect)(select => {
- return !clientId || select(store).areInnerBlocksControlled(clientId);
- }, [clientId]);
- const pendingChanges = (0,external_wp_element_namespaceObject.useRef)({
- incoming: null,
- outgoing: []
- });
- const subscribed = (0,external_wp_element_namespaceObject.useRef)(false);
- const setControlledBlocks = () => {
- if (!controlledBlocks) {
- return;
- }
-
- // We don't need to persist this change because we only replace
- // controlled inner blocks when the change was caused by an entity,
- // and so it would already be persisted.
- __unstableMarkNextChangeAsNotPersistent();
- if (clientId) {
- // It is important to batch here because otherwise,
- // as soon as `setHasControlledInnerBlocks` is called
- // the effect to restore might be triggered
- // before the actual blocks get set properly in state.
- registry.batch(() => {
- setHasControlledInnerBlocks(clientId, true);
- const storeBlocks = controlledBlocks.map(block => (0,external_wp_blocks_namespaceObject.cloneBlock)(block));
- if (subscribed.current) {
- pendingChanges.current.incoming = storeBlocks;
- }
- __unstableMarkNextChangeAsNotPersistent();
- replaceInnerBlocks(clientId, storeBlocks);
- });
- } else {
- if (subscribed.current) {
- pendingChanges.current.incoming = controlledBlocks;
- }
- resetBlocks(controlledBlocks);
- }
- };
-
- // Clean up the changes made by setControlledBlocks() when the component
- // containing useBlockSync() unmounts.
- const unsetControlledBlocks = () => {
- __unstableMarkNextChangeAsNotPersistent();
- if (clientId) {
- setHasControlledInnerBlocks(clientId, false);
- __unstableMarkNextChangeAsNotPersistent();
- replaceInnerBlocks(clientId, []);
- } else {
- resetBlocks([]);
- }
- };
-
- // Add a subscription to the block-editor registry to detect when changes
- // have been made. This lets us inform the data source of changes. This
- // is an effect so that the subscriber can run synchronously without
- // waiting for React renders for changes.
- const onInputRef = (0,external_wp_element_namespaceObject.useRef)(onInput);
- const onChangeRef = (0,external_wp_element_namespaceObject.useRef)(onChange);
- (0,external_wp_element_namespaceObject.useEffect)(() => {
- onInputRef.current = onInput;
- onChangeRef.current = onChange;
- }, [onInput, onChange]);
-
- // Determine if blocks need to be reset when they change.
- (0,external_wp_element_namespaceObject.useEffect)(() => {
- if (pendingChanges.current.outgoing.includes(controlledBlocks)) {
- // Skip block reset if the value matches expected outbound sync
- // triggered by this component by a preceding change detection.
- // Only skip if the value matches expectation, since a reset should
- // still occur if the value is modified (not equal by reference),
- // to allow that the consumer may apply modifications to reflect
- // back on the editor.
- if (pendingChanges.current.outgoing[pendingChanges.current.outgoing.length - 1] === controlledBlocks) {
- pendingChanges.current.outgoing = [];
- }
- } else if (getBlocks(clientId) !== controlledBlocks) {
- // Reset changing value in all other cases than the sync described
- // above. Since this can be reached in an update following an out-
- // bound sync, unset the outbound value to avoid considering it in
- // subsequent renders.
- pendingChanges.current.outgoing = [];
- setControlledBlocks();
- if (controlledSelection) {
- resetSelection(controlledSelection.selectionStart, controlledSelection.selectionEnd, controlledSelection.initialPosition);
- }
- }
- }, [controlledBlocks, clientId]);
- const isMounted = (0,external_wp_element_namespaceObject.useRef)(false);
- (0,external_wp_element_namespaceObject.useEffect)(() => {
- // On mount, controlled blocks are already set in the effect above.
- if (!isMounted.current) {
- isMounted.current = true;
- return;
- }
-
- // When the block becomes uncontrolled, it means its inner state has been reset
- // we need to take the blocks again from the external value property.
- if (!isControlled) {
- pendingChanges.current.outgoing = [];
- setControlledBlocks();
- }
- }, [isControlled]);
- (0,external_wp_element_namespaceObject.useEffect)(() => {
- const {
- getSelectedBlocksInitialCaretPosition,
- isLastBlockChangePersistent,
- __unstableIsLastBlockChangeIgnored,
- areInnerBlocksControlled
- } = registry.select(store);
- let blocks = getBlocks(clientId);
- let isPersistent = isLastBlockChangePersistent();
- let previousAreBlocksDifferent = false;
- subscribed.current = true;
- const unsubscribe = registry.subscribe(() => {
- // Sometimes, when changing block lists, lingering subscriptions
- // might trigger before they are cleaned up. If the block for which
- // the subscription runs is no longer in the store, this would clear
- // its parent entity's block list. To avoid this, we bail out if
- // the subscription is triggering for a block (`clientId !== null`)
- // and its block name can't be found because it's not on the list.
- // (`getBlockName( clientId ) === null`).
- if (clientId !== null && getBlockName(clientId) === null) {
- return;
- }
-
- // When RESET_BLOCKS on parent blocks get called, the controlled blocks
- // can reset to uncontrolled, in these situations, it means we need to populate
- // the blocks again from the external blocks (the value property here)
- // and we should stop triggering onChange
- const isStillControlled = !clientId || areInnerBlocksControlled(clientId);
- if (!isStillControlled) {
- return;
- }
- const newIsPersistent = isLastBlockChangePersistent();
- const newBlocks = getBlocks(clientId);
- const areBlocksDifferent = newBlocks !== blocks;
- blocks = newBlocks;
- if (areBlocksDifferent && (pendingChanges.current.incoming || __unstableIsLastBlockChangeIgnored())) {
- pendingChanges.current.incoming = null;
- isPersistent = newIsPersistent;
- return;
- }
-
- // Since we often dispatch an action to mark the previous action as
- // persistent, we need to make sure that the blocks changed on the
- // previous action before committing the change.
- const didPersistenceChange = previousAreBlocksDifferent && !areBlocksDifferent && newIsPersistent && !isPersistent;
- if (areBlocksDifferent || didPersistenceChange) {
- isPersistent = newIsPersistent;
- // We know that onChange/onInput will update controlledBlocks.
- // We need to be aware that it was caused by an outgoing change
- // so that we do not treat it as an incoming change later on,
- // which would cause a block reset.
- pendingChanges.current.outgoing.push(blocks);
-
- // Inform the controlling entity that changes have been made to
- // the block-editor store they should be aware about.
- const updateParent = isPersistent ? onChangeRef.current : onInputRef.current;
- const undoIgnore = undoIgnoreBlocks.has(blocks);
- if (undoIgnore) {
- undoIgnoreBlocks.delete(blocks);
- }
- updateParent(blocks, {
- selection: {
- selectionStart: getSelectionStart(),
- selectionEnd: getSelectionEnd(),
- initialPosition: getSelectedBlocksInitialCaretPosition()
- },
- undoIgnore
- });
- }
- previousAreBlocksDifferent = areBlocksDifferent;
- }, store);
- return () => {
- subscribed.current = false;
- unsubscribe();
- };
- }, [registry, clientId]);
- (0,external_wp_element_namespaceObject.useEffect)(() => {
- return () => {
- unsetControlledBlocks();
+ const openRef = (0,external_wp_element_namespaceObject.useContext)(insertion_point_InsertionPointOpenRef);
+ const ref = (0,external_wp_element_namespaceObject.useRef)();
+ const {
+ orientation,
+ previousClientId,
+ nextClientId,
+ rootClientId,
+ isInserterShown,
+ isDistractionFree,
+ isZoomOutMode
+ } = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ getBlockOrder,
+ getBlockListSettings,
+ getBlockInsertionPoint,
+ isBlockBeingDragged,
+ getPreviousBlockClientId,
+ getNextBlockClientId,
+ getSettings,
+ isZoomOut
+ } = unlock(select(store));
+ const insertionPoint = getBlockInsertionPoint();
+ const order = getBlockOrder(insertionPoint.rootClientId);
+ if (!order.length) {
+ return {};
+ }
+ let _previousClientId = order[insertionPoint.index - 1];
+ let _nextClientId = order[insertionPoint.index];
+ while (isBlockBeingDragged(_previousClientId)) {
+ _previousClientId = getPreviousBlockClientId(_previousClientId);
+ }
+ while (isBlockBeingDragged(_nextClientId)) {
+ _nextClientId = getNextBlockClientId(_nextClientId);
+ }
+ const settings = getSettings();
+ return {
+ previousClientId: _previousClientId,
+ nextClientId: _nextClientId,
+ orientation: getBlockListSettings(insertionPoint.rootClientId)?.orientation || 'vertical',
+ rootClientId: insertionPoint.rootClientId,
+ isDistractionFree: settings.isDistractionFree,
+ isInserterShown: insertionPoint?.__unstableWithInserter,
+ isZoomOutMode: isZoomOut()
};
}, []);
-}
-
-;// CONCATENATED MODULE: external ["wp","keyboardShortcuts"]
-const external_wp_keyboardShortcuts_namespaceObject = window["wp"]["keyboardShortcuts"];
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/keyboard-shortcuts/index.js
-/**
- * WordPress dependencies
- */
-
-
-
-
-function KeyboardShortcuts() {
- return null;
-}
-function KeyboardShortcutsRegister() {
- // Registering the shortcuts.
- const {
- registerShortcut
- } = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_keyboardShortcuts_namespaceObject.store);
- (0,external_wp_element_namespaceObject.useEffect)(() => {
- registerShortcut({
- name: 'core/block-editor/duplicate',
- category: 'block',
- description: (0,external_wp_i18n_namespaceObject.__)('Duplicate the selected block(s).'),
- keyCombination: {
- modifier: 'primaryShift',
- character: 'd'
- }
- });
- registerShortcut({
- name: 'core/block-editor/remove',
- category: 'block',
- description: (0,external_wp_i18n_namespaceObject.__)('Remove the selected block(s).'),
- keyCombination: {
- modifier: 'access',
- character: 'z'
- }
- });
- registerShortcut({
- name: 'core/block-editor/insert-before',
- category: 'block',
- description: (0,external_wp_i18n_namespaceObject.__)('Insert a new block before the selected block(s).'),
- keyCombination: {
- modifier: 'primaryAlt',
- character: 't'
- }
- });
- registerShortcut({
- name: 'core/block-editor/insert-after',
- category: 'block',
- description: (0,external_wp_i18n_namespaceObject.__)('Insert a new block after the selected block(s).'),
- keyCombination: {
- modifier: 'primaryAlt',
- character: 'y'
- }
- });
- registerShortcut({
- name: 'core/block-editor/delete-multi-selection',
- category: 'block',
- description: (0,external_wp_i18n_namespaceObject.__)('Delete selection.'),
- keyCombination: {
- character: 'del'
- },
- aliases: [{
- character: 'backspace'
- }]
- });
- registerShortcut({
- name: 'core/block-editor/select-all',
- category: 'selection',
- description: (0,external_wp_i18n_namespaceObject.__)('Select all text when typing. Press again to select all blocks.'),
- keyCombination: {
- modifier: 'primary',
- character: 'a'
- }
- });
- registerShortcut({
- name: 'core/block-editor/unselect',
- category: 'selection',
- description: (0,external_wp_i18n_namespaceObject.__)('Clear selection.'),
- keyCombination: {
- character: 'escape'
- }
- });
- registerShortcut({
- name: 'core/block-editor/multi-text-selection',
- category: 'selection',
- description: (0,external_wp_i18n_namespaceObject.__)('Select text across multiple blocks.'),
- keyCombination: {
- modifier: 'shift',
- character: 'arrow'
- }
- });
- registerShortcut({
- name: 'core/block-editor/focus-toolbar',
- category: 'global',
- description: (0,external_wp_i18n_namespaceObject.__)('Navigate to the nearest toolbar.'),
- keyCombination: {
- modifier: 'alt',
- character: 'F10'
- }
- });
- registerShortcut({
- name: 'core/block-editor/move-up',
- category: 'block',
- description: (0,external_wp_i18n_namespaceObject.__)('Move the selected block(s) up.'),
- keyCombination: {
- modifier: 'secondary',
- character: 't'
- }
- });
- registerShortcut({
- name: 'core/block-editor/move-down',
- category: 'block',
- description: (0,external_wp_i18n_namespaceObject.__)('Move the selected block(s) down.'),
- keyCombination: {
- modifier: 'secondary',
- character: 'y'
- }
- });
-
- // List view shortcuts.
- registerShortcut({
- name: 'core/block-editor/collapse-list-view',
- category: 'list-view',
- description: (0,external_wp_i18n_namespaceObject.__)('Collapse all other items.'),
- keyCombination: {
- modifier: 'alt',
- character: 'l'
- }
- });
- registerShortcut({
- name: 'core/block-editor/group',
- category: 'block',
- description: (0,external_wp_i18n_namespaceObject.__)('Create a group block from the selected multiple blocks.'),
- keyCombination: {
- modifier: 'primary',
- character: 'g'
- }
- });
- }, [registerShortcut]);
- return null;
-}
-KeyboardShortcuts.Register = KeyboardShortcutsRegister;
-/* harmony default export */ const keyboard_shortcuts = (KeyboardShortcuts);
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/provider/index.js
-/**
- * WordPress dependencies
- */
-
-
-
-
-/**
- * Internal dependencies
- */
-
-
-
-
-
-
-
-/** @typedef {import('@wordpress/data').WPDataRegistry} WPDataRegistry */
-
-
-const ExperimentalBlockEditorProvider = with_registry_provider(props => {
- const {
- children,
- settings,
- stripExperimentalSettings = false
- } = props;
- const {
- __experimentalUpdateSettings
- } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
- (0,external_wp_element_namespaceObject.useEffect)(() => {
- __experimentalUpdateSettings({
- ...settings,
- __internalIsInitialized: true
- }, {
- stripExperimentalSettings,
- reset: true
- });
- }, [settings, stripExperimentalSettings, __experimentalUpdateSettings]);
-
- // Syncs the entity provider with changes in the block-editor store.
- useBlockSync(props);
- return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.SlotFillProvider, {
- passthrough: true,
- children: [!settings?.__unstableIsPreviewMode && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(keyboard_shortcuts.Register, {}), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(BlockRefsProvider, {
- children: children
- })]
- });
-});
-const BlockEditorProvider = props => {
- return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(ExperimentalBlockEditorProvider, {
- ...props,
- stripExperimentalSettings: true,
- children: props.children
- });
-};
-/* harmony default export */ const provider = (BlockEditorProvider);
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-selection-clearer/index.js
+ const {
+ getBlockEditingMode
+ } = (0,external_wp_data_namespaceObject.useSelect)(store);
+ const disableMotion = (0,external_wp_compose_namespaceObject.useReducedMotion)();
+ function onClick(event) {
+ if (event.target === ref.current && nextClientId && getBlockEditingMode(nextClientId) !== 'disabled') {
+ selectBlock(nextClientId, -1);
+ }
+ }
+ function maybeHideInserterPoint(event) {
+ // Only hide the inserter if it's triggered on the wrapper,
+ // and the inserter is not open.
+ if (event.target === ref.current && !openRef.current) {
+ hideInsertionPoint();
+ }
+ }
+ function onFocus(event) {
+ // Only handle click on the wrapper specifically, and not an event
+ // bubbled from the inserter itself.
+ if (event.target !== ref.current) {
+ openRef.current = true;
+ }
+ }
+ const lineVariants = {
+ // Initial position starts from the center and invisible.
+ start: {
+ opacity: 0,
+ scale: 0
+ },
+ // The line expands to fill the container. If the inserter is visible it
+ // is delayed so it appears orchestrated.
+ rest: {
+ opacity: 1,
+ scale: 1,
+ transition: {
+ delay: isInserterShown ? 0.5 : 0,
+ type: 'tween'
+ }
+ },
+ hover: {
+ opacity: 1,
+ scale: 1,
+ transition: {
+ delay: 0.5,
+ type: 'tween'
+ }
+ }
+ };
+ const inserterVariants = {
+ start: {
+ scale: disableMotion ? 1 : 0
+ },
+ rest: {
+ scale: 1,
+ transition: {
+ delay: 0.4,
+ type: 'tween'
+ }
+ }
+ };
+ if (isDistractionFree) {
+ return null;
+ }
+
+ // Zoom out mode should only show the insertion point for the insert operation.
+ // Other operations such as "group" are when the editor tries to create a row
+ // block by grouping the block being dragged with the block it's being dropped
+ // onto.
+ if (isZoomOutMode && operation !== 'insert') {
+ return null;
+ }
+ const orientationClassname = orientation === 'horizontal' || operation === 'group' ? 'is-horizontal' : 'is-vertical';
+ const className = dist_clsx('block-editor-block-list__insertion-point', orientationClassname);
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(inbetween, {
+ previousClientId: previousClientId,
+ nextClientId: nextClientId,
+ __unstablePopoverSlot: __unstablePopoverSlot,
+ __unstableContentRef: __unstableContentRef,
+ operation: operation,
+ nearestSide: nearestSide,
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_components_namespaceObject.__unstableMotion.div, {
+ layout: !disableMotion,
+ initial: disableMotion ? 'rest' : 'start',
+ animate: "rest",
+ whileHover: "hover",
+ whileTap: "pressed",
+ exit: "start",
+ ref: ref,
+ tabIndex: -1,
+ onClick: onClick,
+ onFocus: onFocus,
+ className: dist_clsx(className, {
+ 'is-with-inserter': isInserterShown
+ }),
+ onHoverEnd: maybeHideInserterPoint,
+ children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__unstableMotion.div, {
+ variants: lineVariants,
+ className: "block-editor-block-list__insertion-point-indicator",
+ "data-testid": "block-list-insertion-point-indicator"
+ }), isInserterShown && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__unstableMotion.div, {
+ variants: inserterVariants,
+ className: dist_clsx('block-editor-block-list__insertion-point-inserter'),
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(inserter, {
+ position: "bottom center",
+ clientId: nextClientId,
+ rootClientId: rootClientId,
+ __experimentalIsQuick: true,
+ onToggle: isOpen => {
+ openRef.current = isOpen;
+ },
+ onSelectOrClose: () => {
+ openRef.current = false;
+ }
+ })
+ })]
+ })
+ });
+}
+function InsertionPoint(props) {
+ const {
+ insertionPoint,
+ isVisible,
+ isBlockListEmpty
+ } = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ getBlockInsertionPoint,
+ isBlockInsertionPointVisible,
+ getBlockCount
+ } = select(store);
+ const blockInsertionPoint = getBlockInsertionPoint();
+ return {
+ insertionPoint: blockInsertionPoint,
+ isVisible: isBlockInsertionPointVisible(),
+ isBlockListEmpty: getBlockCount(blockInsertionPoint?.rootClientId) === 0
+ };
+ }, []);
+ if (!isVisible ||
+ // Don't render the insertion point if the block list is empty.
+ // The insertion point will be represented by the appender instead.
+ isBlockListEmpty) {
+ return null;
+ }
+
+ /**
+ * Render a popover that overlays the block when the desired operation is to replace it.
+ * Otherwise, render a popover in between blocks for the indication of inserting between them.
+ */
+ return insertionPoint.operation === 'replace' ? /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(drop_zone
+ // Force remount to trigger the animation.
+ , {
+ ...props
+ }, `${insertionPoint.rootClientId}-${insertionPoint.index}`) : /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(InbetweenInsertionPointPopover, {
+ operation: insertionPoint.operation,
+ nearestSide: insertionPoint.nearestSide,
+ ...props
+ });
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/use-in-between-inserter.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+function useInBetweenInserter() {
+ const openRef = (0,external_wp_element_namespaceObject.useContext)(insertion_point_InsertionPointOpenRef);
+ const isInBetweenInserterDisabled = (0,external_wp_data_namespaceObject.useSelect)(select => select(store).getSettings().isDistractionFree || unlock(select(store)).isZoomOut(), []);
+ const {
+ getBlockListSettings,
+ getBlockIndex,
+ isMultiSelecting,
+ getSelectedBlockClientIds,
+ getSettings,
+ getTemplateLock,
+ __unstableIsWithinBlockOverlay,
+ getBlockEditingMode,
+ getBlockName,
+ getBlockAttributes,
+ getParentSectionBlock
+ } = unlock((0,external_wp_data_namespaceObject.useSelect)(store));
+ const {
+ showInsertionPoint,
+ hideInsertionPoint
+ } = (0,external_wp_data_namespaceObject.useDispatch)(store);
+ return (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
+ if (isInBetweenInserterDisabled) {
+ return;
+ }
+ function onMouseMove(event) {
+ // openRef is the reference to the insertion point between blocks.
+ // If the reference is not set or the insertion point is already open, return.
+ if (openRef === undefined || openRef.current) {
+ return;
+ }
+
+ // Ignore text nodes sometimes detected in FireFox.
+ if (event.target.nodeType === event.target.TEXT_NODE) {
+ return;
+ }
+ if (isMultiSelecting()) {
+ return;
+ }
+ if (!event.target.classList.contains('block-editor-block-list__layout')) {
+ hideInsertionPoint();
+ return;
+ }
+ let rootClientId;
+ if (!event.target.classList.contains('is-root-container')) {
+ const blockElement = !!event.target.getAttribute('data-block') ? event.target : event.target.closest('[data-block]');
+ rootClientId = blockElement.getAttribute('data-block');
+ }
+ if (getTemplateLock(rootClientId) || getBlockEditingMode(rootClientId) === 'disabled' || getBlockName(rootClientId) === 'core/block' || rootClientId && getBlockAttributes(rootClientId).layout?.isManualPlacement) {
+ return;
+ }
+ const blockListSettings = getBlockListSettings(rootClientId);
+ const orientation = blockListSettings?.orientation || 'vertical';
+ const captureToolbars = !!blockListSettings?.__experimentalCaptureToolbars;
+ const offsetTop = event.clientY;
+ const offsetLeft = event.clientX;
+ const children = Array.from(event.target.children);
+ let element = children.find(blockEl => {
+ const blockElRect = blockEl.getBoundingClientRect();
+ return blockEl.classList.contains('wp-block') && orientation === 'vertical' && blockElRect.top > offsetTop || blockEl.classList.contains('wp-block') && orientation === 'horizontal' && ((0,external_wp_i18n_namespaceObject.isRTL)() ? blockElRect.right < offsetLeft : blockElRect.left > offsetLeft);
+ });
+ if (!element) {
+ hideInsertionPoint();
+ return;
+ }
+
+ // The block may be in an alignment wrapper, so check the first direct
+ // child if the element has no ID.
+ if (!element.id) {
+ element = element.firstElementChild;
+ if (!element) {
+ hideInsertionPoint();
+ return;
+ }
+ }
+
+ // Don't show the insertion point if a parent block has an "overlay"
+ // See https://github.com/WordPress/gutenberg/pull/34012#pullrequestreview-727762337
+ const clientId = element.id.slice('block-'.length);
+ if (!clientId || __unstableIsWithinBlockOverlay(clientId) || !!getParentSectionBlock(clientId)) {
+ return;
+ }
+
+ // Don't show the inserter if the following conditions are met,
+ // as it conflicts with the block toolbar:
+ // 1. when hovering above or inside selected block(s)
+ // 2. when the orientation is vertical
+ // 3. when the __experimentalCaptureToolbars is not enabled
+ // 4. when the Top Toolbar is not disabled
+ if (getSelectedBlockClientIds().includes(clientId) && orientation === 'vertical' && !captureToolbars && !getSettings().hasFixedToolbar) {
+ return;
+ }
+ const elementRect = element.getBoundingClientRect();
+ if (orientation === 'horizontal' && (event.clientY > elementRect.bottom || event.clientY < elementRect.top) || orientation === 'vertical' && (event.clientX > elementRect.right || event.clientX < elementRect.left)) {
+ hideInsertionPoint();
+ return;
+ }
+ const index = getBlockIndex(clientId);
+
+ // Don't show the in-between inserter before the first block in
+ // the list (preserves the original behaviour).
+ if (index === 0) {
+ hideInsertionPoint();
+ return;
+ }
+ showInsertionPoint(rootClientId, index, {
+ __unstableWithInserter: true
+ });
+ }
+ node.addEventListener('mousemove', onMouseMove);
+ return () => {
+ node.removeEventListener('mousemove', onMouseMove);
+ };
+ }, [openRef, getBlockListSettings, getBlockIndex, isMultiSelecting, showInsertionPoint, hideInsertionPoint, getSelectedBlockClientIds, isInBetweenInserterDisabled]);
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-selection-clearer/index.js
/**
* WordPress dependencies
*/
@@ -41958,7 +42805,1924 @@
});
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-multi-selection.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/inner-blocks/button-block-appender.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+function ButtonBlockAppender({
+ showSeparator,
+ isFloating,
+ onAddBlock,
+ isToggle
+}) {
+ const {
+ clientId
+ } = useBlockEditContext();
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(button_block_appender, {
+ className: dist_clsx({
+ 'block-list-appender__toggle': isToggle
+ }),
+ rootClientId: clientId,
+ showSeparator: showSeparator,
+ isFloating: isFloating,
+ onAddBlock: onAddBlock
+ });
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/inner-blocks/default-block-appender.js
+/**
+ * Internal dependencies
+ */
+
+
+
+function default_block_appender_DefaultBlockAppender() {
+ const {
+ clientId
+ } = useBlockEditContext();
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(DefaultBlockAppender, {
+ rootClientId: clientId
+ });
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/inner-blocks/use-nested-settings-update.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+/** @typedef {import('../../selectors').WPDirectInsertBlock } WPDirectInsertBlock */
+
+const pendingSettingsUpdates = new WeakMap();
+
+// Creates a memoizing caching function that remembers the last value and keeps returning it
+// as long as the new values are shallowly equal. Helps keep dependencies stable.
+function createShallowMemo() {
+ let value;
+ return newValue => {
+ if (value === undefined || !external_wp_isShallowEqual_default()(value, newValue)) {
+ value = newValue;
+ }
+ return value;
+ };
+}
+function useShallowMemo(value) {
+ const [memo] = (0,external_wp_element_namespaceObject.useState)(createShallowMemo);
+ return memo(value);
+}
+
+/**
+ * This hook is a side effect which updates the block-editor store when changes
+ * happen to inner block settings. The given props are transformed into a
+ * settings object, and if that is different from the current settings object in
+ * the block-editor store, then the store is updated with the new settings which
+ * came from props.
+ *
+ * @param {string} clientId The client ID of the block to update.
+ * @param {string} parentLock
+ * @param {string[]} allowedBlocks An array of block names which are permitted
+ * in inner blocks.
+ * @param {string[]} prioritizedInserterBlocks Block names and/or block variations to be prioritized in the inserter, in the format {blockName}/{variationName}.
+ * @param {?WPDirectInsertBlock} defaultBlock The default block to insert: [ blockName, { blockAttributes } ].
+ * @param {?boolean} directInsert If a default block should be inserted directly by the appender.
+ *
+ * @param {?WPDirectInsertBlock} __experimentalDefaultBlock A deprecated prop for the default block to insert: [ blockName, { blockAttributes } ]. Use `defaultBlock` instead.
+ *
+ * @param {?boolean} __experimentalDirectInsert A deprecated prop for whether a default block should be inserted directly by the appender. Use `directInsert` instead.
+ *
+ * @param {string} [templateLock] The template lock specified for the inner
+ * blocks component. (e.g. "all")
+ * @param {boolean} captureToolbars Whether or children toolbars should be shown
+ * in the inner blocks component rather than on
+ * the child block.
+ * @param {string} orientation The direction in which the block
+ * should face.
+ * @param {Object} layout The layout object for the block container.
+ */
+function useNestedSettingsUpdate(clientId, parentLock, allowedBlocks, prioritizedInserterBlocks, defaultBlock, directInsert, __experimentalDefaultBlock, __experimentalDirectInsert, templateLock, captureToolbars, orientation, layout) {
+ // Instead of adding a useSelect mapping here, please add to the useSelect
+ // mapping in InnerBlocks! Every subscription impacts performance.
+
+ const registry = (0,external_wp_data_namespaceObject.useRegistry)();
+
+ // Implementors often pass a new array on every render,
+ // and the contents of the arrays are just strings, so the entire array
+ // can be passed as dependencies but We need to include the length of the array,
+ // otherwise if the arrays change length but the first elements are equal the comparison,
+ // does not works as expected.
+ const _allowedBlocks = useShallowMemo(allowedBlocks);
+ const _prioritizedInserterBlocks = useShallowMemo(prioritizedInserterBlocks);
+ const _templateLock = templateLock === undefined || parentLock === 'contentOnly' ? parentLock : templateLock;
+ (0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
+ const newSettings = {
+ allowedBlocks: _allowedBlocks,
+ prioritizedInserterBlocks: _prioritizedInserterBlocks,
+ templateLock: _templateLock
+ };
+
+ // These values are not defined for RN, so only include them if they
+ // are defined.
+ if (captureToolbars !== undefined) {
+ newSettings.__experimentalCaptureToolbars = captureToolbars;
+ }
+
+ // Orientation depends on layout,
+ // ideally the separate orientation prop should be deprecated.
+ if (orientation !== undefined) {
+ newSettings.orientation = orientation;
+ } else {
+ const layoutType = getLayoutType(layout?.type);
+ newSettings.orientation = layoutType.getOrientation(layout);
+ }
+ if (__experimentalDefaultBlock !== undefined) {
+ external_wp_deprecated_default()('__experimentalDefaultBlock', {
+ alternative: 'defaultBlock',
+ since: '6.3',
+ version: '6.4'
+ });
+ newSettings.defaultBlock = __experimentalDefaultBlock;
+ }
+ if (defaultBlock !== undefined) {
+ newSettings.defaultBlock = defaultBlock;
+ }
+ if (__experimentalDirectInsert !== undefined) {
+ external_wp_deprecated_default()('__experimentalDirectInsert', {
+ alternative: 'directInsert',
+ since: '6.3',
+ version: '6.4'
+ });
+ newSettings.directInsert = __experimentalDirectInsert;
+ }
+ if (directInsert !== undefined) {
+ newSettings.directInsert = directInsert;
+ }
+ if (newSettings.directInsert !== undefined && typeof newSettings.directInsert !== 'boolean') {
+ external_wp_deprecated_default()('Using `Function` as a `directInsert` argument', {
+ alternative: '`boolean` values',
+ since: '6.5'
+ });
+ }
+
+ // Batch updates to block list settings to avoid triggering cascading renders
+ // for each container block included in a tree and optimize initial render.
+ // To avoid triggering updateBlockListSettings for each container block
+ // causing X re-renderings for X container blocks,
+ // we batch all the updatedBlockListSettings in a single "data" batch
+ // which results in a single re-render.
+ if (!pendingSettingsUpdates.get(registry)) {
+ pendingSettingsUpdates.set(registry, {});
+ }
+ pendingSettingsUpdates.get(registry)[clientId] = newSettings;
+ window.queueMicrotask(() => {
+ const settings = pendingSettingsUpdates.get(registry);
+ if (Object.keys(settings).length) {
+ const {
+ updateBlockListSettings
+ } = registry.dispatch(store);
+ updateBlockListSettings(settings);
+ pendingSettingsUpdates.set(registry, {});
+ }
+ });
+ }, [clientId, _allowedBlocks, _prioritizedInserterBlocks, _templateLock, defaultBlock, directInsert, __experimentalDefaultBlock, __experimentalDirectInsert, captureToolbars, orientation, layout, registry]);
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/inner-blocks/use-inner-block-template-sync.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+/**
+ * This hook makes sure that a block's inner blocks stay in sync with the given
+ * block "template". The template is a block hierarchy to which inner blocks must
+ * conform. If the blocks get "out of sync" with the template and the template
+ * is meant to be locked (e.g. templateLock = "all" or templateLock = "contentOnly"),
+ * then we replace the inner blocks with the correct value after synchronizing it with the template.
+ *
+ * @param {string} clientId The block client ID.
+ * @param {Object} template The template to match.
+ * @param {string} templateLock The template lock state for the inner blocks. For
+ * example, if the template lock is set to "all",
+ * then the inner blocks will stay in sync with the
+ * template. If not defined or set to false, then
+ * the inner blocks will not be synchronized with
+ * the given template.
+ * @param {boolean} templateInsertUpdatesSelection Whether or not to update the
+ * block-editor selection state when inner blocks
+ * are replaced after template synchronization.
+ */
+function useInnerBlockTemplateSync(clientId, template, templateLock, templateInsertUpdatesSelection) {
+ // Instead of adding a useSelect mapping here, please add to the useSelect
+ // mapping in InnerBlocks! Every subscription impacts performance.
+ const registry = (0,external_wp_data_namespaceObject.useRegistry)();
+
+ // Maintain a reference to the previous value so we can do a deep equality check.
+ const existingTemplateRef = (0,external_wp_element_namespaceObject.useRef)(null);
+ (0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
+ let isCancelled = false;
+ const {
+ getBlocks,
+ getSelectedBlocksInitialCaretPosition,
+ isBlockSelected
+ } = registry.select(store);
+ const {
+ replaceInnerBlocks,
+ __unstableMarkNextChangeAsNotPersistent
+ } = registry.dispatch(store);
+
+ // There's an implicit dependency between useInnerBlockTemplateSync and useNestedSettingsUpdate
+ // The former needs to happen after the latter and since the latter is using microtasks to batch updates (performance optimization),
+ // we need to schedule this one in a microtask as well.
+ // Example: If you remove queueMicrotask here, ctrl + click to insert quote block won't close the inserter.
+ window.queueMicrotask(() => {
+ if (isCancelled) {
+ return;
+ }
+
+ // Only synchronize innerBlocks with template if innerBlocks are empty
+ // or a locking "all" or "contentOnly" exists directly on the block.
+ const currentInnerBlocks = getBlocks(clientId);
+ const shouldApplyTemplate = currentInnerBlocks.length === 0 || templateLock === 'all' || templateLock === 'contentOnly';
+ const hasTemplateChanged = !es6_default()(template, existingTemplateRef.current);
+ if (!shouldApplyTemplate || !hasTemplateChanged) {
+ return;
+ }
+ existingTemplateRef.current = template;
+ const nextBlocks = (0,external_wp_blocks_namespaceObject.synchronizeBlocksWithTemplate)(currentInnerBlocks, template);
+ if (!es6_default()(nextBlocks, currentInnerBlocks)) {
+ __unstableMarkNextChangeAsNotPersistent();
+ replaceInnerBlocks(clientId, nextBlocks, currentInnerBlocks.length === 0 && templateInsertUpdatesSelection && nextBlocks.length !== 0 && isBlockSelected(clientId),
+ // This ensures the "initialPosition" doesn't change when applying the template
+ // If we're supposed to focus the block, we'll focus the first inner block
+ // otherwise, we won't apply any auto-focus.
+ // This ensures for instance that the focus stays in the inserter when inserting the "buttons" block.
+ getSelectedBlocksInitialCaretPosition());
+ }
+ });
+ return () => {
+ isCancelled = true;
+ };
+ }, [template, templateLock, clientId, registry, templateInsertUpdatesSelection]);
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/inner-blocks/use-block-context.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+/**
+ * Returns a context object for a given block.
+ *
+ * @param {string} clientId The block client ID.
+ *
+ * @return {Record} Context value.
+ */
+function useBlockContext(clientId) {
+ return (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const block = select(store).getBlock(clientId);
+ if (!block) {
+ return undefined;
+ }
+ const blockType = select(external_wp_blocks_namespaceObject.store).getBlockType(block.name);
+ if (!blockType) {
+ return undefined;
+ }
+ if (Object.keys(blockType.providesContext).length === 0) {
+ return undefined;
+ }
+ return Object.fromEntries(Object.entries(blockType.providesContext).map(([contextName, attributeName]) => [contextName, block.attributes[attributeName]]));
+ }, [clientId]);
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/use-on-block-drop/index.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+/** @typedef {import('react').SyntheticEvent} SyntheticEvent */
+/** @typedef {import('./types').WPDropOperation} WPDropOperation */
+
+/**
+ * Retrieve the data for a block drop event.
+ *
+ * @param {SyntheticEvent} event The drop event.
+ *
+ * @return {Object} An object with block drag and drop data.
+ */
+function parseDropEvent(event) {
+ let result = {
+ srcRootClientId: null,
+ srcClientIds: null,
+ srcIndex: null,
+ type: null,
+ blocks: null
+ };
+ if (!event.dataTransfer) {
+ return result;
+ }
+ try {
+ result = Object.assign(result, JSON.parse(event.dataTransfer.getData('wp-blocks')));
+ } catch (err) {
+ return result;
+ }
+ return result;
+}
+
+/**
+ * A function that returns an event handler function for block drop events.
+ *
+ * @param {string} targetRootClientId The root client id where the block(s) will be inserted.
+ * @param {number} targetBlockIndex The index where the block(s) will be inserted.
+ * @param {Function} getBlockIndex A function that gets the index of a block.
+ * @param {Function} getClientIdsOfDescendants A function that gets the client ids of descendant blocks.
+ * @param {Function} moveBlocks A function that moves blocks.
+ * @param {Function} insertOrReplaceBlocks A function that inserts or replaces blocks.
+ * @param {Function} clearSelectedBlock A function that clears block selection.
+ * @param {string} operation The type of operation to perform on drop. Could be `insert` or `replace` or `group`.
+ * @param {Function} getBlock A function that returns a block given its client id.
+ * @return {Function} The event handler for a block drop event.
+ */
+function onBlockDrop(targetRootClientId, targetBlockIndex, getBlockIndex, getClientIdsOfDescendants, moveBlocks, insertOrReplaceBlocks, clearSelectedBlock, operation, getBlock) {
+ return event => {
+ const {
+ srcRootClientId: sourceRootClientId,
+ srcClientIds: sourceClientIds,
+ type: dropType,
+ blocks
+ } = parseDropEvent(event);
+
+ // If the user is inserting a block.
+ if (dropType === 'inserter') {
+ clearSelectedBlock();
+ const blocksToInsert = blocks.map(block => (0,external_wp_blocks_namespaceObject.cloneBlock)(block));
+ insertOrReplaceBlocks(blocksToInsert, true, null);
+ }
+
+ // If the user is moving a block.
+ if (dropType === 'block') {
+ const sourceBlockIndex = getBlockIndex(sourceClientIds[0]);
+
+ // If the user is dropping to the same position, return early.
+ if (sourceRootClientId === targetRootClientId && sourceBlockIndex === targetBlockIndex) {
+ return;
+ }
+
+ // If the user is attempting to drop a block within its own
+ // nested blocks, return early as this would create infinite
+ // recursion.
+ if (sourceClientIds.includes(targetRootClientId) || getClientIdsOfDescendants(sourceClientIds).some(id => id === targetRootClientId)) {
+ return;
+ }
+
+ // If the user is dropping a block over another block, replace both blocks
+ // with a group block containing them
+ if (operation === 'group') {
+ const blocksToInsert = sourceClientIds.map(clientId => getBlock(clientId));
+ insertOrReplaceBlocks(blocksToInsert, true, null, sourceClientIds);
+ return;
+ }
+ const isAtSameLevel = sourceRootClientId === targetRootClientId;
+ const draggedBlockCount = sourceClientIds.length;
+
+ // If the block is kept at the same level and moved downwards,
+ // subtract to take into account that the blocks being dragged
+ // were removed from the block list above the insertion point.
+ const insertIndex = isAtSameLevel && sourceBlockIndex < targetBlockIndex ? targetBlockIndex - draggedBlockCount : targetBlockIndex;
+ moveBlocks(sourceClientIds, sourceRootClientId, insertIndex);
+ }
+ };
+}
+
+/**
+ * A function that returns an event handler function for block-related file drop events.
+ *
+ * @param {string} targetRootClientId The root client id where the block(s) will be inserted.
+ * @param {Function} getSettings A function that gets the block editor settings.
+ * @param {Function} updateBlockAttributes A function that updates a block's attributes.
+ * @param {Function} canInsertBlockType A function that returns checks whether a block type can be inserted.
+ * @param {Function} insertOrReplaceBlocks A function that inserts or replaces blocks.
+ *
+ * @return {Function} The event handler for a block-related file drop event.
+ */
+function onFilesDrop(targetRootClientId, getSettings, updateBlockAttributes, canInsertBlockType, insertOrReplaceBlocks) {
+ return files => {
+ if (!getSettings().mediaUpload) {
+ return;
+ }
+ const transformation = (0,external_wp_blocks_namespaceObject.findTransform)((0,external_wp_blocks_namespaceObject.getBlockTransforms)('from'), transform => transform.type === 'files' && canInsertBlockType(transform.blockName, targetRootClientId) && transform.isMatch(files));
+ if (transformation) {
+ const blocks = transformation.transform(files, updateBlockAttributes);
+ insertOrReplaceBlocks(blocks);
+ }
+ };
+}
+
+/**
+ * A function that returns an event handler function for block-related HTML drop events.
+ *
+ * @param {Function} insertOrReplaceBlocks A function that inserts or replaces blocks.
+ *
+ * @return {Function} The event handler for a block-related HTML drop event.
+ */
+function onHTMLDrop(insertOrReplaceBlocks) {
+ return HTML => {
+ const blocks = (0,external_wp_blocks_namespaceObject.pasteHandler)({
+ HTML,
+ mode: 'BLOCKS'
+ });
+ if (blocks.length) {
+ insertOrReplaceBlocks(blocks);
+ }
+ };
+}
+
+/**
+ * A React hook for handling block drop events.
+ *
+ * @param {string} targetRootClientId The root client id where the block(s) will be inserted.
+ * @param {number} targetBlockIndex The index where the block(s) will be inserted.
+ * @param {Object} options The optional options.
+ * @param {WPDropOperation} [options.operation] The type of operation to perform on drop. Could be `insert` or `replace` for now.
+ *
+ * @return {Function} A function to be passed to the onDrop handler.
+ */
+function useOnBlockDrop(targetRootClientId, targetBlockIndex, options = {}) {
+ const {
+ operation = 'insert',
+ nearestSide = 'right'
+ } = options;
+ const {
+ canInsertBlockType,
+ getBlockIndex,
+ getClientIdsOfDescendants,
+ getBlockOrder,
+ getBlocksByClientId,
+ getSettings,
+ getBlock
+ } = (0,external_wp_data_namespaceObject.useSelect)(store);
+ const {
+ getGroupingBlockName
+ } = (0,external_wp_data_namespaceObject.useSelect)(external_wp_blocks_namespaceObject.store);
+ const {
+ insertBlocks,
+ moveBlocksToPosition,
+ updateBlockAttributes,
+ clearSelectedBlock,
+ replaceBlocks,
+ removeBlocks
+ } = (0,external_wp_data_namespaceObject.useDispatch)(store);
+ const registry = (0,external_wp_data_namespaceObject.useRegistry)();
+ const insertOrReplaceBlocks = (0,external_wp_element_namespaceObject.useCallback)((blocks, updateSelection = true, initialPosition = 0, clientIdsToReplace = []) => {
+ if (!Array.isArray(blocks)) {
+ blocks = [blocks];
+ }
+ const clientIds = getBlockOrder(targetRootClientId);
+ const clientId = clientIds[targetBlockIndex];
+ if (operation === 'replace') {
+ replaceBlocks(clientId, blocks, undefined, initialPosition);
+ } else if (operation === 'group') {
+ const targetBlock = getBlock(clientId);
+ if (nearestSide === 'left') {
+ blocks.push(targetBlock);
+ } else {
+ blocks.unshift(targetBlock);
+ }
+ const groupInnerBlocks = blocks.map(block => {
+ return (0,external_wp_blocks_namespaceObject.createBlock)(block.name, block.attributes, block.innerBlocks);
+ });
+ const areAllImages = blocks.every(block => {
+ return block.name === 'core/image';
+ });
+ const galleryBlock = canInsertBlockType('core/gallery', targetRootClientId);
+ const wrappedBlocks = (0,external_wp_blocks_namespaceObject.createBlock)(areAllImages && galleryBlock ? 'core/gallery' : getGroupingBlockName(), {
+ layout: {
+ type: 'flex',
+ flexWrap: areAllImages && galleryBlock ? null : 'nowrap'
+ }
+ }, groupInnerBlocks);
+ // Need to make sure both the target block and the block being dragged are replaced
+ // otherwise the dragged block will be duplicated.
+ replaceBlocks([clientId, ...clientIdsToReplace], wrappedBlocks, undefined, initialPosition);
+ } else {
+ insertBlocks(blocks, targetBlockIndex, targetRootClientId, updateSelection, initialPosition);
+ }
+ }, [getBlockOrder, targetRootClientId, targetBlockIndex, operation, replaceBlocks, getBlock, nearestSide, canInsertBlockType, getGroupingBlockName, insertBlocks]);
+ const moveBlocks = (0,external_wp_element_namespaceObject.useCallback)((sourceClientIds, sourceRootClientId, insertIndex) => {
+ if (operation === 'replace') {
+ const sourceBlocks = getBlocksByClientId(sourceClientIds);
+ const targetBlockClientIds = getBlockOrder(targetRootClientId);
+ const targetBlockClientId = targetBlockClientIds[targetBlockIndex];
+ registry.batch(() => {
+ // Remove the source blocks.
+ removeBlocks(sourceClientIds, false);
+ // Replace the target block with the source blocks.
+ replaceBlocks(targetBlockClientId, sourceBlocks, undefined, 0);
+ });
+ } else {
+ moveBlocksToPosition(sourceClientIds, sourceRootClientId, targetRootClientId, insertIndex);
+ }
+ }, [operation, getBlockOrder, getBlocksByClientId, moveBlocksToPosition, registry, removeBlocks, replaceBlocks, targetBlockIndex, targetRootClientId]);
+ const _onDrop = onBlockDrop(targetRootClientId, targetBlockIndex, getBlockIndex, getClientIdsOfDescendants, moveBlocks, insertOrReplaceBlocks, clearSelectedBlock, operation, getBlock);
+ const _onFilesDrop = onFilesDrop(targetRootClientId, getSettings, updateBlockAttributes, canInsertBlockType, insertOrReplaceBlocks);
+ const _onHTMLDrop = onHTMLDrop(insertOrReplaceBlocks);
+ return event => {
+ const files = (0,external_wp_dom_namespaceObject.getFilesFromDataTransfer)(event.dataTransfer);
+ const html = event.dataTransfer.getData('text/html');
+
+ /**
+ * From Windows Chrome 96, the `event.dataTransfer` returns both file object and HTML.
+ * The order of the checks is important to recognise the HTML drop.
+ */
+ if (html) {
+ _onHTMLDrop(html);
+ } else if (files.length) {
+ _onFilesDrop(files);
+ } else {
+ _onDrop(event);
+ }
+ };
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/utils/math.js
+/**
+ * A string representing the name of an edge.
+ *
+ * @typedef {'top'|'right'|'bottom'|'left'} WPEdgeName
+ */
+
+/**
+ * @typedef {Object} WPPoint
+ * @property {number} x The horizontal position.
+ * @property {number} y The vertical position.
+ */
+
+/**
+ * Given a point, a DOMRect and the name of an edge, returns the distance to
+ * that edge of the rect.
+ *
+ * This function works for edges that are horizontal or vertical (e.g. not
+ * rotated), the following terms are used so that the function works in both
+ * orientations:
+ *
+ * - Forward, meaning the axis running horizontally when an edge is vertical
+ * and vertically when an edge is horizontal.
+ * - Lateral, meaning the axis running vertically when an edge is vertical
+ * and horizontally when an edge is horizontal.
+ *
+ * @param {WPPoint} point The point to measure distance from.
+ * @param {DOMRect} rect A DOM Rect containing edge positions.
+ * @param {WPEdgeName} edge The edge to measure to.
+ */
+function getDistanceFromPointToEdge(point, rect, edge) {
+ const isHorizontal = edge === 'top' || edge === 'bottom';
+ const {
+ x,
+ y
+ } = point;
+ const pointLateralPosition = isHorizontal ? x : y;
+ const pointForwardPosition = isHorizontal ? y : x;
+ const edgeStart = isHorizontal ? rect.left : rect.top;
+ const edgeEnd = isHorizontal ? rect.right : rect.bottom;
+ const edgeForwardPosition = rect[edge];
+
+ // Measure the straight line distance to the edge of the rect, when the
+ // point is adjacent to the edge.
+ // Else, if the point is positioned diagonally to the edge of the rect,
+ // measure diagonally to the nearest corner that the edge meets.
+ let edgeLateralPosition;
+ if (pointLateralPosition >= edgeStart && pointLateralPosition <= edgeEnd) {
+ edgeLateralPosition = pointLateralPosition;
+ } else if (pointLateralPosition < edgeEnd) {
+ edgeLateralPosition = edgeStart;
+ } else {
+ edgeLateralPosition = edgeEnd;
+ }
+ return Math.sqrt((pointLateralPosition - edgeLateralPosition) ** 2 + (pointForwardPosition - edgeForwardPosition) ** 2);
+}
+
+/**
+ * Given a point, a DOMRect and a list of allowed edges returns the name of and
+ * distance to the nearest edge.
+ *
+ * @param {WPPoint} point The point to measure distance from.
+ * @param {DOMRect} rect A DOM Rect containing edge positions.
+ * @param {WPEdgeName[]} allowedEdges A list of the edges included in the
+ * calculation. Defaults to all edges.
+ *
+ * @return {[number, string]} An array where the first value is the distance
+ * and a second is the edge name.
+ */
+function getDistanceToNearestEdge(point, rect, allowedEdges = ['top', 'bottom', 'left', 'right']) {
+ let candidateDistance;
+ let candidateEdge;
+ allowedEdges.forEach(edge => {
+ const distance = getDistanceFromPointToEdge(point, rect, edge);
+ if (candidateDistance === undefined || distance < candidateDistance) {
+ candidateDistance = distance;
+ candidateEdge = edge;
+ }
+ });
+ return [candidateDistance, candidateEdge];
+}
+
+/**
+ * Is the point contained by the rectangle.
+ *
+ * @param {WPPoint} point The point.
+ * @param {DOMRect} rect The rectangle.
+ *
+ * @return {boolean} True if the point is contained by the rectangle, false otherwise.
+ */
+function isPointContainedByRect(point, rect) {
+ return rect.left <= point.x && rect.right >= point.x && rect.top <= point.y && rect.bottom >= point.y;
+}
+
+/**
+ * Is the point within the top and bottom boundaries of the rectangle.
+ *
+ * @param {WPPoint} point The point.
+ * @param {DOMRect} rect The rectangle.
+ *
+ * @return {boolean} True if the point is within top and bottom of rectangle, false otherwise.
+ */
+function isPointWithinTopAndBottomBoundariesOfRect(point, rect) {
+ return rect.top <= point.y && rect.bottom >= point.y;
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/use-block-drop-zone/index.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+
+const THRESHOLD_DISTANCE = 30;
+const MINIMUM_HEIGHT_FOR_THRESHOLD = 120;
+const MINIMUM_WIDTH_FOR_THRESHOLD = 120;
+
+/** @typedef {import('../../utils/math').WPPoint} WPPoint */
+/** @typedef {import('../use-on-block-drop/types').WPDropOperation} WPDropOperation */
+
+/**
+ * The orientation of a block list.
+ *
+ * @typedef {'horizontal'|'vertical'|undefined} WPBlockListOrientation
+ */
+
+/**
+ * The insert position when dropping a block.
+ *
+ * @typedef {'before'|'after'} WPInsertPosition
+ */
+
+/**
+ * @typedef {Object} WPBlockData
+ * @property {boolean} isUnmodifiedDefaultBlock Is the block unmodified default block.
+ * @property {() => DOMRect} getBoundingClientRect Get the bounding client rect of the block.
+ * @property {number} blockIndex The index of the block.
+ */
+
+/**
+ * Get the drop target position from a given drop point and the orientation.
+ *
+ * @param {WPBlockData[]} blocksData The block data list.
+ * @param {WPPoint} position The position of the item being dragged.
+ * @param {WPBlockListOrientation} orientation The orientation of the block list.
+ * @param {Object} options Additional options.
+ * @return {[number, WPDropOperation]} The drop target position.
+ */
+function getDropTargetPosition(blocksData, position, orientation = 'vertical', options = {}) {
+ const allowedEdges = orientation === 'horizontal' ? ['left', 'right'] : ['top', 'bottom'];
+ let nearestIndex = 0;
+ let insertPosition = 'before';
+ let minDistance = Infinity;
+ let targetBlockIndex = null;
+ let nearestSide = 'right';
+ const {
+ dropZoneElement,
+ parentBlockOrientation,
+ rootBlockIndex = 0
+ } = options;
+
+ // Allow before/after when dragging over the top/bottom edges of the drop zone.
+ if (dropZoneElement && parentBlockOrientation !== 'horizontal') {
+ const rect = dropZoneElement.getBoundingClientRect();
+ const [distance, edge] = getDistanceToNearestEdge(position, rect, ['top', 'bottom']);
+
+ // If dragging over the top or bottom of the drop zone, insert the block
+ // before or after the parent block. This only applies to blocks that use
+ // a drop zone element, typically container blocks such as Group or Cover.
+ if (rect.height > MINIMUM_HEIGHT_FOR_THRESHOLD && distance < THRESHOLD_DISTANCE) {
+ if (edge === 'top') {
+ return [rootBlockIndex, 'before'];
+ }
+ if (edge === 'bottom') {
+ return [rootBlockIndex + 1, 'after'];
+ }
+ }
+ }
+ const isRightToLeft = (0,external_wp_i18n_namespaceObject.isRTL)();
+
+ // Allow before/after when dragging over the left/right edges of the drop zone.
+ if (dropZoneElement && parentBlockOrientation === 'horizontal') {
+ const rect = dropZoneElement.getBoundingClientRect();
+ const [distance, edge] = getDistanceToNearestEdge(position, rect, ['left', 'right']);
+
+ // If dragging over the left or right of the drop zone, insert the block
+ // before or after the parent block. This only applies to blocks that use
+ // a drop zone element, typically container blocks such as Group.
+ if (rect.width > MINIMUM_WIDTH_FOR_THRESHOLD && distance < THRESHOLD_DISTANCE) {
+ if (isRightToLeft && edge === 'right' || !isRightToLeft && edge === 'left') {
+ return [rootBlockIndex, 'before'];
+ }
+ if (isRightToLeft && edge === 'left' || !isRightToLeft && edge === 'right') {
+ return [rootBlockIndex + 1, 'after'];
+ }
+ }
+ }
+ blocksData.forEach(({
+ isUnmodifiedDefaultBlock,
+ getBoundingClientRect,
+ blockIndex,
+ blockOrientation
+ }) => {
+ const rect = getBoundingClientRect();
+ let [distance, edge] = getDistanceToNearestEdge(position, rect, allowedEdges);
+ // If the the point is close to a side, prioritize that side.
+ const [sideDistance, sideEdge] = getDistanceToNearestEdge(position, rect, ['left', 'right']);
+ const isPointInsideRect = isPointContainedByRect(position, rect);
+
+ // Prioritize the element if the point is inside of an unmodified default block.
+ if (isUnmodifiedDefaultBlock && isPointInsideRect) {
+ distance = 0;
+ } else if (orientation === 'vertical' && blockOrientation !== 'horizontal' && (isPointInsideRect && sideDistance < THRESHOLD_DISTANCE || !isPointInsideRect && isPointWithinTopAndBottomBoundariesOfRect(position, rect))) {
+ /**
+ * This condition should only apply when the layout is vertical (otherwise there's
+ * no need to create a Row) and dropzones should only activate when the block is
+ * either within and close to the sides of the target block or on its outer sides.
+ */
+ targetBlockIndex = blockIndex;
+ nearestSide = sideEdge;
+ }
+ if (distance < minDistance) {
+ // Where the dropped block will be inserted on the nearest block.
+ insertPosition = edge === 'bottom' || !isRightToLeft && edge === 'right' || isRightToLeft && edge === 'left' ? 'after' : 'before';
+
+ // Update the currently known best candidate.
+ minDistance = distance;
+ nearestIndex = blockIndex;
+ }
+ });
+ const adjacentIndex = nearestIndex + (insertPosition === 'after' ? 1 : -1);
+ const isNearestBlockUnmodifiedDefaultBlock = !!blocksData[nearestIndex]?.isUnmodifiedDefaultBlock;
+ const isAdjacentBlockUnmodifiedDefaultBlock = !!blocksData[adjacentIndex]?.isUnmodifiedDefaultBlock;
+
+ // If the target index is set then group with the block at that index.
+ if (targetBlockIndex !== null) {
+ return [targetBlockIndex, 'group', nearestSide];
+ }
+ // If both blocks are not unmodified default blocks then just insert between them.
+ if (!isNearestBlockUnmodifiedDefaultBlock && !isAdjacentBlockUnmodifiedDefaultBlock) {
+ // If the user is dropping to the trailing edge of the block
+ // add 1 to the index to represent dragging after.
+ const insertionIndex = insertPosition === 'after' ? nearestIndex + 1 : nearestIndex;
+ return [insertionIndex, 'insert'];
+ }
+
+ // Otherwise, replace the nearest unmodified default block.
+ return [isNearestBlockUnmodifiedDefaultBlock ? nearestIndex : adjacentIndex, 'replace'];
+}
+
+/**
+ * Check if the dragged blocks can be dropped on the target.
+ * @param {Function} getBlockType
+ * @param {Object[]} allowedBlocks
+ * @param {string[]} draggedBlockNames
+ * @param {string} targetBlockName
+ * @return {boolean} Whether the dragged blocks can be dropped on the target.
+ */
+function isDropTargetValid(getBlockType, allowedBlocks, draggedBlockNames, targetBlockName) {
+ // At root level allowedBlocks is undefined and all blocks are allowed.
+ // Otherwise, check if all dragged blocks are allowed.
+ let areBlocksAllowed = true;
+ if (allowedBlocks) {
+ const allowedBlockNames = allowedBlocks?.map(({
+ name
+ }) => name);
+ areBlocksAllowed = draggedBlockNames.every(name => allowedBlockNames?.includes(name));
+ }
+
+ // Work out if dragged blocks have an allowed parent and if so
+ // check target block matches the allowed parent.
+ const draggedBlockTypes = draggedBlockNames.map(name => getBlockType(name));
+ const targetMatchesDraggedBlockParents = draggedBlockTypes.every(block => {
+ const [allowedParentName] = block?.parent || [];
+ if (!allowedParentName) {
+ return true;
+ }
+ return allowedParentName === targetBlockName;
+ });
+ return areBlocksAllowed && targetMatchesDraggedBlockParents;
+}
+
+/**
+ * Checks if the given element is an insertion point.
+ *
+ * @param {EventTarget|null} targetToCheck - The element to check.
+ * @param {Document} ownerDocument - The owner document of the element.
+ * @return {boolean} True if the element is a insertion point, false otherwise.
+ */
+function isInsertionPoint(targetToCheck, ownerDocument) {
+ const {
+ defaultView
+ } = ownerDocument;
+ return !!(defaultView && targetToCheck instanceof defaultView.HTMLElement && targetToCheck.closest('[data-is-insertion-point]'));
+}
+
+/**
+ * @typedef {Object} WPBlockDropZoneConfig
+ * @property {?HTMLElement} dropZoneElement Optional element to be used as the drop zone.
+ * @property {string} rootClientId The root client id for the block list.
+ */
+
+/**
+ * A React hook that can be used to make a block list handle drag and drop.
+ *
+ * @param {WPBlockDropZoneConfig} dropZoneConfig configuration data for the drop zone.
+ */
+function useBlockDropZone({
+ dropZoneElement,
+ // An undefined value represents a top-level block. Default to an empty
+ // string for this so that `targetRootClientId` can be easily compared to
+ // values returned by the `getRootBlockClientId` selector, which also uses
+ // an empty string to represent top-level blocks.
+ rootClientId: targetRootClientId = '',
+ parentClientId: parentBlockClientId = '',
+ isDisabled = false
+} = {}) {
+ const registry = (0,external_wp_data_namespaceObject.useRegistry)();
+ const [dropTarget, setDropTarget] = (0,external_wp_element_namespaceObject.useState)({
+ index: null,
+ operation: 'insert'
+ });
+ const {
+ getBlockType,
+ getBlockVariations,
+ getGroupingBlockName
+ } = (0,external_wp_data_namespaceObject.useSelect)(external_wp_blocks_namespaceObject.store);
+ const {
+ canInsertBlockType,
+ getBlockListSettings,
+ getBlocks,
+ getBlockIndex,
+ getDraggedBlockClientIds,
+ getBlockNamesByClientId,
+ getAllowedBlocks,
+ isDragging,
+ isGroupable,
+ isZoomOut,
+ getSectionRootClientId,
+ getBlockParents
+ } = unlock((0,external_wp_data_namespaceObject.useSelect)(store));
+ const {
+ showInsertionPoint,
+ hideInsertionPoint,
+ startDragging,
+ stopDragging
+ } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
+ const onBlockDrop = useOnBlockDrop(dropTarget.operation === 'before' || dropTarget.operation === 'after' ? parentBlockClientId : targetRootClientId, dropTarget.index, {
+ operation: dropTarget.operation,
+ nearestSide: dropTarget.nearestSide
+ });
+ const throttled = (0,external_wp_compose_namespaceObject.useThrottle)((0,external_wp_element_namespaceObject.useCallback)((event, ownerDocument) => {
+ if (!isDragging()) {
+ // When dragging from the desktop, no drag start event is fired.
+ // So, ensure that the drag state is set when the user drags over a drop zone.
+ startDragging();
+ }
+ const draggedBlockClientIds = getDraggedBlockClientIds();
+ const targetParents = [targetRootClientId, ...getBlockParents(targetRootClientId, true)];
+
+ // Check if the target is within any of the dragged blocks.
+ const isTargetWithinDraggedBlocks = draggedBlockClientIds.some(clientId => targetParents.includes(clientId));
+ if (isTargetWithinDraggedBlocks) {
+ return;
+ }
+ const allowedBlocks = getAllowedBlocks(targetRootClientId);
+ const targetBlockName = getBlockNamesByClientId([targetRootClientId])[0];
+ const draggedBlockNames = getBlockNamesByClientId(draggedBlockClientIds);
+ const isBlockDroppingAllowed = isDropTargetValid(getBlockType, allowedBlocks, draggedBlockNames, targetBlockName);
+ if (!isBlockDroppingAllowed) {
+ return;
+ }
+ const sectionRootClientId = getSectionRootClientId();
+
+ // In Zoom Out mode, if the target is not the section root provided by settings then
+ // do not allow dropping as the drop target is not within the root (that which is
+ // treated as "the content" by Zoom Out Mode).
+ if (isZoomOut() && sectionRootClientId !== targetRootClientId) {
+ return;
+ }
+ const blocks = getBlocks(targetRootClientId);
+
+ // The block list is empty, don't show the insertion point but still allow dropping.
+ if (blocks.length === 0) {
+ registry.batch(() => {
+ setDropTarget({
+ index: 0,
+ operation: 'insert'
+ });
+ showInsertionPoint(targetRootClientId, 0, {
+ operation: 'insert'
+ });
+ });
+ return;
+ }
+ const blocksData = blocks.map(block => {
+ const clientId = block.clientId;
+ return {
+ isUnmodifiedDefaultBlock: (0,external_wp_blocks_namespaceObject.isUnmodifiedDefaultBlock)(block),
+ getBoundingClientRect: () => ownerDocument.getElementById(`block-${clientId}`).getBoundingClientRect(),
+ blockIndex: getBlockIndex(clientId),
+ blockOrientation: getBlockListSettings(clientId)?.orientation
+ };
+ });
+ const dropTargetPosition = getDropTargetPosition(blocksData, {
+ x: event.clientX,
+ y: event.clientY
+ }, getBlockListSettings(targetRootClientId)?.orientation, {
+ dropZoneElement,
+ parentBlockClientId,
+ parentBlockOrientation: parentBlockClientId ? getBlockListSettings(parentBlockClientId)?.orientation : undefined,
+ rootBlockIndex: getBlockIndex(targetRootClientId)
+ });
+ const [targetIndex, operation, nearestSide] = dropTargetPosition;
+ const isTargetIndexEmptyDefaultBlock = blocksData[targetIndex]?.isUnmodifiedDefaultBlock;
+ if (isZoomOut() && !isTargetIndexEmptyDefaultBlock && operation !== 'insert') {
+ return;
+ }
+ if (operation === 'group') {
+ const targetBlock = blocks[targetIndex];
+ const areAllImages = [targetBlock.name, ...draggedBlockNames].every(name => name === 'core/image');
+ const canInsertGalleryBlock = canInsertBlockType('core/gallery', targetRootClientId);
+ const areGroupableBlocks = isGroupable([targetBlock.clientId, getDraggedBlockClientIds()]);
+ const groupBlockVariations = getBlockVariations(getGroupingBlockName(), 'block');
+ const canInsertRow = groupBlockVariations && groupBlockVariations.find(({
+ name
+ }) => name === 'group-row');
+
+ // If the dragged blocks and the target block are all images,
+ // check if it is creatable either a Row variation or a Gallery block.
+ if (areAllImages && !canInsertGalleryBlock && (!areGroupableBlocks || !canInsertRow)) {
+ return;
+ }
+ // If the dragged blocks and the target block are not all images,
+ // check if it is creatable a Row variation.
+ if (!areAllImages && (!areGroupableBlocks || !canInsertRow)) {
+ return;
+ }
+ }
+ registry.batch(() => {
+ setDropTarget({
+ index: targetIndex,
+ operation,
+ nearestSide
+ });
+ const insertionPointClientId = ['before', 'after'].includes(operation) ? parentBlockClientId : targetRootClientId;
+ showInsertionPoint(insertionPointClientId, targetIndex, {
+ operation,
+ nearestSide
+ });
+ });
+ }, [isDragging, getAllowedBlocks, targetRootClientId, getBlockNamesByClientId, getDraggedBlockClientIds, getBlockType, getSectionRootClientId, isZoomOut, getBlocks, getBlockListSettings, dropZoneElement, parentBlockClientId, getBlockIndex, registry, startDragging, showInsertionPoint, canInsertBlockType, isGroupable, getBlockVariations, getGroupingBlockName]), 200);
+ return (0,external_wp_compose_namespaceObject.__experimentalUseDropZone)({
+ dropZoneElement,
+ isDisabled,
+ onDrop: onBlockDrop,
+ onDragOver(event) {
+ // `currentTarget` is only available while the event is being
+ // handled, so get it now and pass it to the thottled function.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
+ throttled(event, event.currentTarget.ownerDocument);
+ },
+ onDragLeave(event) {
+ const {
+ ownerDocument
+ } = event.currentTarget;
+
+ // If the drag event is leaving the drop zone and entering an insertion point,
+ // do not hide the insertion point as it is conceptually within the dropzone.
+ if (isInsertionPoint(event.relatedTarget, ownerDocument) || isInsertionPoint(event.target, ownerDocument)) {
+ return;
+ }
+ throttled.cancel();
+ hideInsertionPoint();
+ },
+ onDragEnd() {
+ throttled.cancel();
+ stopDragging();
+ hideInsertionPoint();
+ }
+ });
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/inner-blocks/index.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+const EMPTY_OBJECT = {};
+function BlockContext({
+ children,
+ clientId
+}) {
+ const context = useBlockContext(clientId);
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(BlockContextProvider, {
+ value: context,
+ children: children
+ });
+}
+const BlockListItemsMemo = (0,external_wp_element_namespaceObject.memo)(BlockListItems);
+
+/**
+ * InnerBlocks is a component which allows a single block to have multiple blocks
+ * as children. The UncontrolledInnerBlocks component is used whenever the inner
+ * blocks are not controlled by another entity. In other words, it is normally
+ * used for inner blocks in the post editor
+ *
+ * @param {Object} props The component props.
+ */
+function UncontrolledInnerBlocks(props) {
+ const {
+ clientId,
+ allowedBlocks,
+ prioritizedInserterBlocks,
+ defaultBlock,
+ directInsert,
+ __experimentalDefaultBlock,
+ __experimentalDirectInsert,
+ template,
+ templateLock,
+ wrapperRef,
+ templateInsertUpdatesSelection,
+ __experimentalCaptureToolbars: captureToolbars,
+ __experimentalAppenderTagName,
+ renderAppender,
+ orientation,
+ placeholder,
+ layout,
+ name,
+ blockType,
+ parentLock,
+ defaultLayout
+ } = props;
+ useNestedSettingsUpdate(clientId, parentLock, allowedBlocks, prioritizedInserterBlocks, defaultBlock, directInsert, __experimentalDefaultBlock, __experimentalDirectInsert, templateLock, captureToolbars, orientation, layout);
+ useInnerBlockTemplateSync(clientId, template, templateLock, templateInsertUpdatesSelection);
+ const defaultLayoutBlockSupport = (0,external_wp_blocks_namespaceObject.getBlockSupport)(name, 'layout') || (0,external_wp_blocks_namespaceObject.getBlockSupport)(name, '__experimentalLayout') || EMPTY_OBJECT;
+ const {
+ allowSizingOnChildren = false
+ } = defaultLayoutBlockSupport;
+ const usedLayout = layout || defaultLayoutBlockSupport;
+ const memoedLayout = (0,external_wp_element_namespaceObject.useMemo)(() => ({
+ // Default layout will know about any content/wide size defined by the theme.
+ ...defaultLayout,
+ ...usedLayout,
+ ...(allowSizingOnChildren && {
+ allowSizingOnChildren: true
+ })
+ }), [defaultLayout, usedLayout, allowSizingOnChildren]);
+
+ // For controlled inner blocks, we don't want a change in blocks to
+ // re-render the blocks list.
+ const items = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(BlockListItemsMemo, {
+ rootClientId: clientId,
+ renderAppender: renderAppender,
+ __experimentalAppenderTagName: __experimentalAppenderTagName,
+ layout: memoedLayout,
+ wrapperRef: wrapperRef,
+ placeholder: placeholder
+ });
+ if (!blockType?.providesContext || Object.keys(blockType.providesContext).length === 0) {
+ return items;
+ }
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(BlockContext, {
+ clientId: clientId,
+ children: items
+ });
+}
+
+/**
+ * The controlled inner blocks component wraps the uncontrolled inner blocks
+ * component with the blockSync hook. This keeps the innerBlocks of the block in
+ * the block-editor store in sync with the blocks of the controlling entity. An
+ * example of an inner block controller is a template part block, which provides
+ * its own blocks from the template part entity data source.
+ *
+ * @param {Object} props The component props.
+ */
+function ControlledInnerBlocks(props) {
+ useBlockSync(props);
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(UncontrolledInnerBlocks, {
+ ...props
+ });
+}
+const ForwardedInnerBlocks = (0,external_wp_element_namespaceObject.forwardRef)((props, ref) => {
+ const innerBlocksProps = useInnerBlocksProps({
+ ref
+ }, props);
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
+ className: "block-editor-inner-blocks",
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
+ ...innerBlocksProps
+ })
+ });
+});
+
+/**
+ * This hook is used to lightly mark an element as an inner blocks wrapper
+ * element. Call this hook and pass the returned props to the element to mark as
+ * an inner blocks wrapper, automatically rendering inner blocks as children. If
+ * you define a ref for the element, it is important to pass the ref to this
+ * hook, which the hook in turn will pass to the component through the props it
+ * returns. Optionally, you can also pass any other props through this hook, and
+ * they will be merged and returned.
+ *
+ * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inner-blocks/README.md
+ *
+ * @param {Object} props Optional. Props to pass to the element. Must contain
+ * the ref if one is defined.
+ * @param {Object} options Optional. Inner blocks options.
+ */
+function useInnerBlocksProps(props = {}, options = {}) {
+ const {
+ __unstableDisableLayoutClassNames,
+ __unstableDisableDropZone,
+ dropZoneElement
+ } = options;
+ const {
+ clientId,
+ layout = null,
+ __unstableLayoutClassNames: layoutClassNames = ''
+ } = useBlockEditContext();
+ const selected = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ getBlockName,
+ isZoomOut,
+ getTemplateLock,
+ getBlockRootClientId,
+ getBlockEditingMode,
+ getBlockSettings,
+ getSectionRootClientId
+ } = unlock(select(store));
+ if (!clientId) {
+ const sectionRootClientId = getSectionRootClientId();
+ // Disable the root drop zone when zoomed out and the section root client id
+ // is not the root block list (represented by an empty string).
+ // This avoids drag handling bugs caused by having two block lists acting as
+ // drop zones - the actual 'root' block list and the section root.
+ return {
+ isDropZoneDisabled: isZoomOut() && sectionRootClientId !== ''
+ };
+ }
+ const {
+ hasBlockSupport,
+ getBlockType
+ } = select(external_wp_blocks_namespaceObject.store);
+ const blockName = getBlockName(clientId);
+ const blockEditingMode = getBlockEditingMode(clientId);
+ const parentClientId = getBlockRootClientId(clientId);
+ const [defaultLayout] = getBlockSettings(clientId, 'layout');
+ let _isDropZoneDisabled = blockEditingMode === 'disabled';
+ if (isZoomOut()) {
+ // In zoom out mode, we want to disable the drop zone for the sections.
+ // The inner blocks belonging to the section drop zone is
+ // already disabled by the blocks themselves being disabled.
+ const sectionRootClientId = getSectionRootClientId();
+ _isDropZoneDisabled = clientId !== sectionRootClientId;
+ }
+ return {
+ __experimentalCaptureToolbars: hasBlockSupport(blockName, '__experimentalExposeControlsToChildren', false),
+ name: blockName,
+ blockType: getBlockType(blockName),
+ parentLock: getTemplateLock(parentClientId),
+ parentClientId,
+ isDropZoneDisabled: _isDropZoneDisabled,
+ defaultLayout
+ };
+ }, [clientId]);
+ const {
+ __experimentalCaptureToolbars,
+ name,
+ blockType,
+ parentLock,
+ parentClientId,
+ isDropZoneDisabled,
+ defaultLayout
+ } = selected;
+ const blockDropZoneRef = useBlockDropZone({
+ dropZoneElement,
+ rootClientId: clientId,
+ parentClientId
+ });
+ const ref = (0,external_wp_compose_namespaceObject.useMergeRefs)([props.ref, __unstableDisableDropZone || isDropZoneDisabled || layout?.isManualPlacement && window.__experimentalEnableGridInteractivity ? null : blockDropZoneRef]);
+ const innerBlocksProps = {
+ __experimentalCaptureToolbars,
+ layout,
+ name,
+ blockType,
+ parentLock,
+ defaultLayout,
+ ...options
+ };
+ const InnerBlocks = innerBlocksProps.value && innerBlocksProps.onChange ? ControlledInnerBlocks : UncontrolledInnerBlocks;
+ return {
+ ...props,
+ ref,
+ className: dist_clsx(props.className, 'block-editor-block-list__layout', __unstableDisableLayoutClassNames ? '' : layoutClassNames),
+ children: clientId ? /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(InnerBlocks, {
+ ...innerBlocksProps,
+ clientId: clientId
+ }) : /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(BlockListItems, {
+ ...options
+ })
+ };
+}
+useInnerBlocksProps.save = external_wp_blocks_namespaceObject.__unstableGetInnerBlocksProps;
+
+// Expose default appender placeholders as components.
+ForwardedInnerBlocks.DefaultBlockAppender = default_block_appender_DefaultBlockAppender;
+ForwardedInnerBlocks.ButtonBlockAppender = ButtonBlockAppender;
+ForwardedInnerBlocks.Content = () => useInnerBlocksProps.save().children;
+
+/**
+ * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inner-blocks/README.md
+ */
+/* harmony default export */ const inner_blocks = (ForwardedInnerBlocks);
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/observe-typing/index.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+/**
+ * Set of key codes upon which typing is to be initiated on a keydown event.
+ *
+ * @type {Set}
+ */
+
+const KEY_DOWN_ELIGIBLE_KEY_CODES = new Set([external_wp_keycodes_namespaceObject.UP, external_wp_keycodes_namespaceObject.RIGHT, external_wp_keycodes_namespaceObject.DOWN, external_wp_keycodes_namespaceObject.LEFT, external_wp_keycodes_namespaceObject.ENTER, external_wp_keycodes_namespaceObject.BACKSPACE]);
+
+/**
+ * Returns true if a given keydown event can be inferred as intent to start
+ * typing, or false otherwise. A keydown is considered eligible if it is a
+ * text navigation without shift active.
+ *
+ * @param {KeyboardEvent} event Keydown event to test.
+ *
+ * @return {boolean} Whether event is eligible to start typing.
+ */
+function isKeyDownEligibleForStartTyping(event) {
+ const {
+ keyCode,
+ shiftKey
+ } = event;
+ return !shiftKey && KEY_DOWN_ELIGIBLE_KEY_CODES.has(keyCode);
+}
+
+/**
+ * Removes the `isTyping` flag when the mouse moves in the document of the given
+ * element.
+ */
+function useMouseMoveTypingReset() {
+ const isTyping = (0,external_wp_data_namespaceObject.useSelect)(select => select(store).isTyping(), []);
+ const {
+ stopTyping
+ } = (0,external_wp_data_namespaceObject.useDispatch)(store);
+ return (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
+ if (!isTyping) {
+ return;
+ }
+ const {
+ ownerDocument
+ } = node;
+ let lastClientX;
+ let lastClientY;
+
+ /**
+ * On mouse move, unset typing flag if user has moved cursor.
+ *
+ * @param {MouseEvent} event Mousemove event.
+ */
+ function stopTypingOnMouseMove(event) {
+ const {
+ clientX,
+ clientY
+ } = event;
+
+ // We need to check that the mouse really moved because Safari
+ // triggers mousemove events when shift or ctrl are pressed.
+ if (lastClientX && lastClientY && (lastClientX !== clientX || lastClientY !== clientY)) {
+ stopTyping();
+ }
+ lastClientX = clientX;
+ lastClientY = clientY;
+ }
+ ownerDocument.addEventListener('mousemove', stopTypingOnMouseMove);
+ return () => {
+ ownerDocument.removeEventListener('mousemove', stopTypingOnMouseMove);
+ };
+ }, [isTyping, stopTyping]);
+}
+
+/**
+ * Sets and removes the `isTyping` flag based on user actions:
+ *
+ * - Sets the flag if the user types within the given element.
+ * - Removes the flag when the user selects some text, focuses a non-text
+ * field, presses ESC or TAB, or moves the mouse in the document.
+ */
+function useTypingObserver() {
+ const {
+ isTyping
+ } = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ isTyping: _isTyping
+ } = select(store);
+ return {
+ isTyping: _isTyping()
+ };
+ }, []);
+ const {
+ startTyping,
+ stopTyping
+ } = (0,external_wp_data_namespaceObject.useDispatch)(store);
+ const ref1 = useMouseMoveTypingReset();
+ const ref2 = (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
+ const {
+ ownerDocument
+ } = node;
+ const {
+ defaultView
+ } = ownerDocument;
+ const selection = defaultView.getSelection();
+
+ // Listeners to stop typing should only be added when typing.
+ // Listeners to start typing should only be added when not typing.
+ if (isTyping) {
+ let timerId;
+
+ /**
+ * Stops typing when focus transitions to a non-text field element.
+ *
+ * @param {FocusEvent} event Focus event.
+ */
+ function stopTypingOnNonTextField(event) {
+ const {
+ target
+ } = event;
+
+ // Since focus to a non-text field via arrow key will trigger
+ // before the keydown event, wait until after current stack
+ // before evaluating whether typing is to be stopped. Otherwise,
+ // typing will re-start.
+ timerId = defaultView.setTimeout(() => {
+ if (!(0,external_wp_dom_namespaceObject.isTextField)(target)) {
+ stopTyping();
+ }
+ });
+ }
+
+ /**
+ * Unsets typing flag if user presses Escape while typing flag is
+ * active.
+ *
+ * @param {KeyboardEvent} event Keypress or keydown event to
+ * interpret.
+ */
+ function stopTypingOnEscapeKey(event) {
+ const {
+ keyCode
+ } = event;
+ if (keyCode === external_wp_keycodes_namespaceObject.ESCAPE || keyCode === external_wp_keycodes_namespaceObject.TAB) {
+ stopTyping();
+ }
+ }
+
+ /**
+ * On selection change, unset typing flag if user has made an
+ * uncollapsed (shift) selection.
+ */
+ function stopTypingOnSelectionUncollapse() {
+ if (!selection.isCollapsed) {
+ stopTyping();
+ }
+ }
+ node.addEventListener('focus', stopTypingOnNonTextField);
+ node.addEventListener('keydown', stopTypingOnEscapeKey);
+ ownerDocument.addEventListener('selectionchange', stopTypingOnSelectionUncollapse);
+ return () => {
+ defaultView.clearTimeout(timerId);
+ node.removeEventListener('focus', stopTypingOnNonTextField);
+ node.removeEventListener('keydown', stopTypingOnEscapeKey);
+ ownerDocument.removeEventListener('selectionchange', stopTypingOnSelectionUncollapse);
+ };
+ }
+
+ /**
+ * Handles a keypress or keydown event to infer intention to start
+ * typing.
+ *
+ * @param {KeyboardEvent} event Keypress or keydown event to interpret.
+ */
+ function startTypingInTextField(event) {
+ const {
+ type,
+ target
+ } = event;
+
+ // Abort early if already typing, or key press is incurred outside a
+ // text field (e.g. arrow-ing through toolbar buttons).
+ // Ignore typing if outside the current DOM container
+ if (!(0,external_wp_dom_namespaceObject.isTextField)(target) || !node.contains(target)) {
+ return;
+ }
+
+ // Special-case keydown because certain keys do not emit a keypress
+ // event. Conversely avoid keydown as the canonical event since
+ // there are many keydown which are explicitly not targeted for
+ // typing.
+ if (type === 'keydown' && !isKeyDownEligibleForStartTyping(event)) {
+ return;
+ }
+ startTyping();
+ }
+ node.addEventListener('keypress', startTypingInTextField);
+ node.addEventListener('keydown', startTypingInTextField);
+ return () => {
+ node.removeEventListener('keypress', startTypingInTextField);
+ node.removeEventListener('keydown', startTypingInTextField);
+ };
+ }, [isTyping, startTyping, stopTyping]);
+ return (0,external_wp_compose_namespaceObject.useMergeRefs)([ref1, ref2]);
+}
+function ObserveTyping({
+ children
+}) {
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
+ ref: useTypingObserver(),
+ children: children
+ });
+}
+
+/**
+ * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/observe-typing/README.md
+ */
+/* harmony default export */ const observe_typing = (ObserveTyping);
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/zoom-out-separator.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+function ZoomOutSeparator({
+ clientId,
+ rootClientId = '',
+ position = 'top'
+}) {
+ const [isDraggedOver, setIsDraggedOver] = (0,external_wp_element_namespaceObject.useState)(false);
+ const {
+ sectionRootClientId,
+ sectionClientIds,
+ insertionPoint,
+ blockInsertionPointVisible,
+ blockInsertionPoint,
+ blocksBeingDragged
+ } = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ getInsertionPoint,
+ getBlockOrder,
+ getSectionRootClientId,
+ isBlockInsertionPointVisible,
+ getBlockInsertionPoint,
+ getDraggedBlockClientIds
+ } = unlock(select(store));
+ const root = getSectionRootClientId();
+ const sectionRootClientIds = getBlockOrder(root);
+ return {
+ sectionRootClientId: root,
+ sectionClientIds: sectionRootClientIds,
+ blockOrder: getBlockOrder(root),
+ insertionPoint: getInsertionPoint(),
+ blockInsertionPoint: getBlockInsertionPoint(),
+ blockInsertionPointVisible: isBlockInsertionPointVisible(),
+ blocksBeingDragged: getDraggedBlockClientIds()
+ };
+ }, []);
+ const isReducedMotion = (0,external_wp_compose_namespaceObject.useReducedMotion)();
+ if (!clientId) {
+ return;
+ }
+ let isVisible = false;
+ const isSectionBlock = rootClientId === sectionRootClientId && sectionClientIds && sectionClientIds.includes(clientId);
+ if (!isSectionBlock) {
+ return null;
+ }
+ const hasTopInsertionPoint = insertionPoint?.index === 0 && clientId === sectionClientIds[insertionPoint.index];
+ const hasBottomInsertionPoint = insertionPoint && insertionPoint.hasOwnProperty('index') && clientId === sectionClientIds[insertionPoint.index - 1];
+
+ // We want to show the zoom out separator in either of these conditions:
+ // 1. If the inserter has an insertion index set
+ // 2. We are dragging a pattern over an insertion point
+ if (position === 'top') {
+ isVisible = hasTopInsertionPoint || blockInsertionPointVisible && blockInsertionPoint.index === 0 && clientId === sectionClientIds[blockInsertionPoint.index];
+ }
+ if (position === 'bottom') {
+ isVisible = hasBottomInsertionPoint || blockInsertionPointVisible && clientId === sectionClientIds[blockInsertionPoint.index - 1];
+ }
+ const blockBeingDraggedClientId = blocksBeingDragged[0];
+ const isCurrentBlockBeingDragged = blocksBeingDragged.includes(clientId);
+ const blockBeingDraggedIndex = sectionClientIds.indexOf(blockBeingDraggedClientId);
+ const blockBeingDraggedPreviousSiblingClientId = blockBeingDraggedIndex > 0 ? sectionClientIds[blockBeingDraggedIndex - 1] : null;
+ const isCurrentBlockPreviousSiblingOfBlockBeingDragged = blockBeingDraggedPreviousSiblingClientId === clientId;
+
+ // The separators are visually top/bottom of the block, but in actual fact
+ // the "top" separator is the "bottom" separator of the previous block.
+ // Therefore, this logic hides the separator if the current block is being dragged
+ // or if the current block is the previous sibling of the block being dragged.
+ if (isCurrentBlockBeingDragged || isCurrentBlockPreviousSiblingOfBlockBeingDragged) {
+ isVisible = false;
+ }
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__unstableAnimatePresence, {
+ children: isVisible && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__unstableMotion.div, {
+ initial: {
+ height: 0
+ },
+ animate: {
+ // Use a height equal to that of the zoom out frame size.
+ height: 'calc(1 * var(--wp-block-editor-iframe-zoom-out-frame-size) / var(--wp-block-editor-iframe-zoom-out-scale)'
+ },
+ exit: {
+ height: 0
+ },
+ transition: {
+ type: 'tween',
+ duration: isReducedMotion ? 0 : 0.2,
+ ease: [0.6, 0, 0.4, 1]
+ },
+ className: dist_clsx('block-editor-block-list__zoom-out-separator', {
+ 'is-dragged-over': isDraggedOver
+ }),
+ "data-is-insertion-point": "true",
+ onDragOver: () => setIsDraggedOver(true),
+ onDragLeave: () => setIsDraggedOver(false),
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.__unstableMotion.div, {
+ initial: {
+ opacity: 0
+ },
+ animate: {
+ opacity: 1
+ },
+ exit: {
+ opacity: 0,
+ transition: {
+ delay: -0.125
+ }
+ },
+ transition: {
+ ease: 'linear',
+ duration: 0.1,
+ delay: 0.125
+ },
+ children: (0,external_wp_i18n_namespaceObject.__)('Drop pattern.')
+ })
+ })
+ });
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/block-list/index.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+const block_list_IntersectionObserver = (0,external_wp_element_namespaceObject.createContext)();
+const pendingBlockVisibilityUpdatesPerRegistry = new WeakMap();
+function Root({
+ className,
+ ...settings
+}) {
+ const {
+ isOutlineMode,
+ isFocusMode,
+ temporarilyEditingAsBlocks
+ } = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ getSettings,
+ getTemporarilyEditingAsBlocks,
+ isTyping
+ } = unlock(select(store));
+ const {
+ outlineMode,
+ focusMode
+ } = getSettings();
+ return {
+ isOutlineMode: outlineMode && !isTyping(),
+ isFocusMode: focusMode,
+ temporarilyEditingAsBlocks: getTemporarilyEditingAsBlocks()
+ };
+ }, []);
+ const registry = (0,external_wp_data_namespaceObject.useRegistry)();
+ const {
+ setBlockVisibility
+ } = (0,external_wp_data_namespaceObject.useDispatch)(store);
+ const delayedBlockVisibilityUpdates = (0,external_wp_compose_namespaceObject.useDebounce)((0,external_wp_element_namespaceObject.useCallback)(() => {
+ const updates = {};
+ pendingBlockVisibilityUpdatesPerRegistry.get(registry).forEach(([id, isIntersecting]) => {
+ updates[id] = isIntersecting;
+ });
+ setBlockVisibility(updates);
+ }, [registry]), 300, {
+ trailing: true
+ });
+ const intersectionObserver = (0,external_wp_element_namespaceObject.useMemo)(() => {
+ const {
+ IntersectionObserver: Observer
+ } = window;
+ if (!Observer) {
+ return;
+ }
+ return new Observer(entries => {
+ if (!pendingBlockVisibilityUpdatesPerRegistry.get(registry)) {
+ pendingBlockVisibilityUpdatesPerRegistry.set(registry, []);
+ }
+ for (const entry of entries) {
+ const clientId = entry.target.getAttribute('data-block');
+ pendingBlockVisibilityUpdatesPerRegistry.get(registry).push([clientId, entry.isIntersecting]);
+ }
+ delayedBlockVisibilityUpdates();
+ });
+ }, []);
+ const innerBlocksProps = useInnerBlocksProps({
+ ref: (0,external_wp_compose_namespaceObject.useMergeRefs)([useBlockSelectionClearer(), useInBetweenInserter(), useTypingObserver()]),
+ className: dist_clsx('is-root-container', className, {
+ 'is-outline-mode': isOutlineMode,
+ 'is-focus-mode': isFocusMode
+ })
+ }, settings);
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(block_list_IntersectionObserver.Provider, {
+ value: intersectionObserver,
+ children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
+ ...innerBlocksProps
+ }), !!temporarilyEditingAsBlocks && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(StopEditingAsBlocksOnOutsideSelect, {
+ clientId: temporarilyEditingAsBlocks
+ })]
+ });
+}
+function StopEditingAsBlocksOnOutsideSelect({
+ clientId
+}) {
+ const {
+ stopEditingAsBlocks
+ } = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
+ const isBlockOrDescendantSelected = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ isBlockSelected,
+ hasSelectedInnerBlock
+ } = select(store);
+ return isBlockSelected(clientId) || hasSelectedInnerBlock(clientId, true);
+ }, [clientId]);
+ (0,external_wp_element_namespaceObject.useEffect)(() => {
+ if (!isBlockOrDescendantSelected) {
+ stopEditingAsBlocks(clientId);
+ }
+ }, [isBlockOrDescendantSelected, clientId, stopEditingAsBlocks]);
+ return null;
+}
+function BlockList(settings) {
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(Provider, {
+ value: DEFAULT_BLOCK_EDIT_CONTEXT,
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(Root, {
+ ...settings
+ })
+ });
+}
+const block_list_EMPTY_ARRAY = [];
+const block_list_EMPTY_SET = new Set();
+function Items({
+ placeholder,
+ rootClientId,
+ renderAppender: CustomAppender,
+ __experimentalAppenderTagName,
+ layout = defaultLayout
+}) {
+ // Avoid passing CustomAppender to useSelect because it could be a new
+ // function on every render.
+ const hasAppender = CustomAppender !== false;
+ const hasCustomAppender = !!CustomAppender;
+ const {
+ order,
+ isZoomOut,
+ selectedBlocks,
+ visibleBlocks,
+ shouldRenderAppender
+ } = (0,external_wp_data_namespaceObject.useSelect)(select => {
+ const {
+ getSettings,
+ getBlockOrder,
+ getSelectedBlockClientIds,
+ __unstableGetVisibleBlocks,
+ getTemplateLock,
+ getBlockEditingMode,
+ isSectionBlock,
+ isZoomOut: _isZoomOut,
+ canInsertBlockType
+ } = unlock(select(store));
+ const _order = getBlockOrder(rootClientId);
+ if (getSettings().isPreviewMode) {
+ return {
+ order: _order,
+ selectedBlocks: block_list_EMPTY_ARRAY,
+ visibleBlocks: block_list_EMPTY_SET
+ };
+ }
+ const selectedBlockClientIds = getSelectedBlockClientIds();
+ const selectedBlockClientId = selectedBlockClientIds[0];
+ const showRootAppender = !rootClientId && !selectedBlockClientId && (!_order.length || !canInsertBlockType((0,external_wp_blocks_namespaceObject.getDefaultBlockName)(), rootClientId));
+ const hasSelectedRoot = !!(rootClientId && selectedBlockClientId && rootClientId === selectedBlockClientId);
+ return {
+ order: _order,
+ selectedBlocks: selectedBlockClientIds,
+ visibleBlocks: __unstableGetVisibleBlocks(),
+ isZoomOut: _isZoomOut(),
+ shouldRenderAppender: !isSectionBlock(rootClientId) && getBlockEditingMode(rootClientId) !== 'disabled' && !getTemplateLock(rootClientId) && hasAppender && !_isZoomOut() && (hasCustomAppender || hasSelectedRoot || showRootAppender)
+ };
+ }, [rootClientId, hasAppender, hasCustomAppender]);
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(LayoutProvider, {
+ value: layout,
+ children: [order.map(clientId => /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_wp_data_namespaceObject.AsyncModeProvider, {
+ value:
+ // Only provide data asynchronously if the block is
+ // not visible and not selected.
+ !visibleBlocks.has(clientId) && !selectedBlocks.includes(clientId),
+ children: [isZoomOut && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(ZoomOutSeparator, {
+ clientId: clientId,
+ rootClientId: rootClientId,
+ position: "top"
+ }), /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(block, {
+ rootClientId: rootClientId,
+ clientId: clientId
+ }), isZoomOut && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(ZoomOutSeparator, {
+ clientId: clientId,
+ rootClientId: rootClientId,
+ position: "bottom"
+ })]
+ }, clientId)), order.length < 1 && placeholder, shouldRenderAppender && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(BlockListAppender, {
+ tagName: __experimentalAppenderTagName,
+ rootClientId: rootClientId,
+ CustomAppender: CustomAppender
+ })]
+ });
+}
+function BlockListItems(props) {
+ // This component needs to always be synchronous as it's the one changing
+ // the async mode depending on the block selection.
+ return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_data_namespaceObject.AsyncModeProvider, {
+ value: false,
+ children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(Items, {
+ ...props
+ })
+ });
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-multi-selection.js
/**
* WordPress dependencies
*/
@@ -42041,7 +44805,7 @@
}, [hasMultiSelection, isMultiSelecting, multiSelectedBlockClientIds, selectedBlockClientId, initialPosition, isFullSelection]);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-tab-nav.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-tab-nav.js
/**
* WordPress dependencies
*/
@@ -42059,49 +44823,62 @@
function useTabNav() {
- const container = (0,external_wp_element_namespaceObject.useRef)();
+ const containerRef = /** @type {typeof useRef} */(0,external_wp_element_namespaceObject.useRef)();
const focusCaptureBeforeRef = (0,external_wp_element_namespaceObject.useRef)();
const focusCaptureAfterRef = (0,external_wp_element_namespaceObject.useRef)();
const {
hasMultiSelection,
getSelectedBlockClientId,
- getBlockCount
- } = (0,external_wp_data_namespaceObject.useSelect)(store);
- const {
- setNavigationMode,
+ getBlockCount,
+ getBlockOrder,
+ getLastFocus,
+ getSectionRootClientId,
+ isZoomOut
+ } = unlock((0,external_wp_data_namespaceObject.useSelect)(store));
+ const {
setLastFocus
} = unlock((0,external_wp_data_namespaceObject.useDispatch)(store));
- const isNavigationMode = (0,external_wp_data_namespaceObject.useSelect)(select => select(store).isNavigationMode(), []);
- const {
- getLastFocus
- } = unlock((0,external_wp_data_namespaceObject.useSelect)(store));
-
- // Don't allow tabbing to this element in Navigation mode.
- const focusCaptureTabIndex = !isNavigationMode ? '0' : undefined;
// Reference that holds the a flag for enabling or disabling
// capturing on the focus capture elements.
- const noCapture = (0,external_wp_element_namespaceObject.useRef)();
+ const noCaptureRef = (0,external_wp_element_namespaceObject.useRef)();
function onFocusCapture(event) {
+ const canvasElement = containerRef.current.ownerDocument === event.target.ownerDocument ? containerRef.current : containerRef.current.ownerDocument.defaultView.frameElement;
+
// Do not capture incoming focus if set by us in WritingFlow.
- if (noCapture.current) {
- noCapture.current = null;
+ if (noCaptureRef.current) {
+ noCaptureRef.current = null;
} else if (hasMultiSelection()) {
- container.current.focus();
+ containerRef.current.focus();
} else if (getSelectedBlockClientId()) {
if (getLastFocus()?.current) {
getLastFocus().current.focus();
} else {
// Handles when the last focus has not been set yet, or has been cleared by new blocks being added via the inserter.
- container.current.querySelector(`[data-block="${getSelectedBlockClientId()}"]`).focus();
- }
- } else {
- setNavigationMode(true);
- const canvasElement = container.current.ownerDocument === event.target.ownerDocument ? container.current : container.current.ownerDocument.defaultView.frameElement;
+ containerRef.current.querySelector(`[data-block="${getSelectedBlockClientId()}"]`).focus();
+ }
+ }
+ // In "compose" mode without a selected ID, we want to place focus on the section root when tabbing to the canvas.
+ else if (isZoomOut()) {
+ const sectionRootClientId = getSectionRootClientId();
+ const sectionBlocks = getBlockOrder(sectionRootClientId);
+
+ // If we have section within the section root, focus the first one.
+ if (sectionBlocks.length) {
+ containerRef.current.querySelector(`[data-block="${sectionBlocks[0]}"]`).focus();
+ }
+ // If we don't have any section blocks, focus the section root.
+ else if (sectionRootClientId) {
+ containerRef.current.querySelector(`[data-block="${sectionRootClientId}"]`).focus();
+ } else {
+ // If we don't have any section root, focus the canvas.
+ canvasElement.focus();
+ }
+ } else {
const isBefore =
// eslint-disable-next-line no-bitwise
event.target.compareDocumentPosition(canvasElement) & event.target.DOCUMENT_POSITION_FOLLOWING;
- const tabbables = external_wp_dom_namespaceObject.focus.tabbable.find(container.current);
+ const tabbables = external_wp_dom_namespaceObject.focus.tabbable.find(containerRef.current);
if (tabbables.length) {
const next = isBefore ? tabbables[0] : tabbables[tabbables.length - 1];
next.focus();
@@ -42110,12 +44887,12 @@
}
const before = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
ref: focusCaptureBeforeRef,
- tabIndex: focusCaptureTabIndex,
+ tabIndex: "0",
onFocus: onFocusCapture
});
const after = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
ref: focusCaptureAfterRef,
- tabIndex: focusCaptureTabIndex,
+ tabIndex: "0",
onFocus: onFocusCapture
});
const ref = (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
@@ -42123,11 +44900,6 @@
if (event.defaultPrevented) {
return;
}
- if (event.keyCode === external_wp_keycodes_namespaceObject.ESCAPE && !hasMultiSelection()) {
- event.preventDefault();
- setNavigationMode(true);
- return;
- }
// In Edit mode, Tab should focus the first tabbable element after
// the content, which is normally the sidebar (with block controls)
@@ -42138,28 +44910,26 @@
if (event.keyCode !== external_wp_keycodes_namespaceObject.TAB) {
return;
}
- const isShift = event.shiftKey;
+ if (
+ // Bails in case the focus capture elements aren’t present. They
+ // may be omitted to avoid silent tab stops in preview mode.
+ // See: https://github.com/WordPress/gutenberg/pull/59317
+ !focusCaptureAfterRef.current || !focusCaptureBeforeRef.current) {
+ return;
+ }
+ const {
+ target,
+ shiftKey: isShift
+ } = event;
const direction = isShift ? 'findPrevious' : 'findNext';
- if (!hasMultiSelection() && !getSelectedBlockClientId()) {
- // Preserve the behaviour of entering navigation mode when
- // tabbing into the content without a block selection.
- // `onFocusCapture` already did this previously, but we need to
- // do it again here because after clearing block selection,
- // focus land on the writing flow container and pressing Tab
- // will no longer send focus through the focus capture element.
- if (event.target === node) {
- setNavigationMode(true);
- }
- return;
- }
- const nextTabbable = external_wp_dom_namespaceObject.focus.tabbable[direction](event.target);
+ const nextTabbable = external_wp_dom_namespaceObject.focus.tabbable[direction](target);
// We want to constrain the tabbing to the block and its child blocks.
// If the preceding form element is within a different block,
// such as two sibling image blocks in the placeholder state,
// we want shift + tab from the first form element to move to the image
// block toolbar and not the previous image block's form element.
- const currentBlock = event.target.closest('[data-block]');
+ const currentBlock = target.closest('[data-block]');
const isElementPartOfSelectedBlock = currentBlock && nextTabbable && (isInSameBlock(currentBlock, nextTabbable) || isInsideRootBlock(currentBlock, nextTabbable));
// Allow tabbing from the block wrapper to a form element,
@@ -42176,7 +44946,7 @@
// Disable focus capturing on the focus capture element, so it
// doesn't refocus this block and so it allows default behaviour
// (moving focus to the next tabbable element).
- noCapture.current = true;
+ noCaptureRef.current = true;
// Focusing the focus capture element, which is located above and
// below the editor, should not scroll the page all the way up or
@@ -42196,7 +44966,7 @@
// If focus disappears due to there being no blocks, move focus to
// the writing flow wrapper.
- if (!event.relatedTarget && ownerDocument.activeElement === ownerDocument.body && getBlockCount() === 0) {
+ if (!event.relatedTarget && event.target.hasAttribute('data-block') && ownerDocument.activeElement === ownerDocument.body && getBlockCount() === 0) {
node.focus();
}
}
@@ -42216,7 +44986,7 @@
if (event.target?.getAttribute('role') === 'region') {
return;
}
- if (container.current === event.target) {
+ if (containerRef.current === event.target) {
return;
}
const isShift = event.shiftKey;
@@ -42245,11 +45015,11 @@
node.removeEventListener('focusout', onFocusOut);
};
}, []);
- const mergedRefs = (0,external_wp_compose_namespaceObject.useMergeRefs)([container, ref]);
+ const mergedRefs = (0,external_wp_compose_namespaceObject.useMergeRefs)([containerRef, ref]);
return [before, mergedRefs, after];
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-arrow-nav.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-arrow-nav.js
/**
* WordPress dependencies
*/
@@ -42496,7 +45266,7 @@
}, []);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-select-all.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-select-all.js
/**
* WordPress dependencies
*/
@@ -42552,7 +45322,7 @@
}, []);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-drag-selection.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-drag-selection.js
/**
* WordPress dependencies
*/
@@ -42634,11 +45404,21 @@
}
});
}
+ let lastMouseDownTarget;
+ function onMouseDown({
+ target
+ }) {
+ lastMouseDownTarget = target;
+ }
function onMouseLeave({
buttons,
target,
relatedTarget
}) {
+ if (!target.contains(lastMouseDownTarget)) {
+ return;
+ }
+
// If we're moving into a child element, ignore. We're tracking
// the mouse leaving the element to a parent, no a child.
if (target.contains(relatedTarget)) {
@@ -42696,6 +45476,7 @@
setContentEditableWrapper(node, true);
}
node.addEventListener('mouseout', onMouseLeave);
+ node.addEventListener('mousedown', onMouseDown);
return () => {
node.removeEventListener('mouseout', onMouseLeave);
defaultView.removeEventListener('mouseup', onMouseUp);
@@ -42704,10 +45485,11 @@
}, [startMultiSelect, stopMultiSelect, isSelectionEnabled, hasSelectedBlock]);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-selection-observer.js
-/**
- * WordPress dependencies
- */
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-selection-observer.js
+/**
+ * WordPress dependencies
+ */
+
@@ -42760,6 +45542,15 @@
if (focusOffset === focusNode.childNodes.length) {
return focusNode;
}
+
+ // When the selection is forward (the selection ends with the focus node),
+ // the selection may extend into the next element with an offset of 0. This
+ // may trigger multi selection even though the selection does not visually
+ // end in the next block.
+ if (focusOffset === 0 && (0,external_wp_dom_namespaceObject.isSelectionForward)(selection)) {
+ var _focusNode$previousSi;
+ return (_focusNode$previousSi = focusNode.previousSibling) !== null && _focusNode$previousSi !== void 0 ? _focusNode$previousSi : focusNode.parentElement;
+ }
return focusNode.childNodes[focusOffset];
}
function findDepth(a, b) {
@@ -42927,7 +45718,7 @@
}, [multiSelect, selectBlock, selectionChange, getBlockParents]);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-click-selection.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-click-selection.js
/**
* WordPress dependencies
*/
@@ -42980,7 +45771,7 @@
}, [selectBlock, isSelectionEnabled, getBlockSelectionStart, hasMultiSelection]);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-input.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-input.js
/**
* WordPress dependencies
*/
@@ -43129,7 +45920,7 @@
}, []);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/utils/use-notify-copy.js
+;// ./node_modules/@wordpress/block-editor/build-module/utils/use-notify-copy.js
/**
* WordPress dependencies
*/
@@ -43155,28 +45946,36 @@
} = (0,external_wp_data_namespaceObject.useDispatch)(external_wp_notices_namespaceObject.store);
return (0,external_wp_element_namespaceObject.useCallback)((eventType, selectedBlockClientIds) => {
let notice = '';
- if (selectedBlockClientIds.length === 1) {
+ if (eventType === 'copyStyles') {
+ notice = (0,external_wp_i18n_namespaceObject.__)('Styles copied to clipboard.');
+ } else if (selectedBlockClientIds.length === 1) {
const clientId = selectedBlockClientIds[0];
const title = getBlockType(getBlockName(clientId))?.title;
- notice = eventType === 'copy' ? (0,external_wp_i18n_namespaceObject.sprintf)(
- // Translators: Name of the block being copied, e.g. "Paragraph".
- (0,external_wp_i18n_namespaceObject.__)('Copied "%s" to clipboard.'), title) : (0,external_wp_i18n_namespaceObject.sprintf)(
- // Translators: Name of the block being cut, e.g. "Paragraph".
- (0,external_wp_i18n_namespaceObject.__)('Moved "%s" to clipboard.'), title);
- } else {
- notice = eventType === 'copy' ? (0,external_wp_i18n_namespaceObject.sprintf)(
+ if (eventType === 'copy') {
+ notice = (0,external_wp_i18n_namespaceObject.sprintf)(
+ // Translators: Name of the block being copied, e.g. "Paragraph".
+ (0,external_wp_i18n_namespaceObject.__)('Copied "%s" to clipboard.'), title);
+ } else {
+ notice = (0,external_wp_i18n_namespaceObject.sprintf)(
+ // Translators: Name of the block being cut, e.g. "Paragraph".
+ (0,external_wp_i18n_namespaceObject.__)('Moved "%s" to clipboard.'), title);
+ }
+ } else if (eventType === 'copy') {
+ notice = (0,external_wp_i18n_namespaceObject.sprintf)(
// Translators: %d: Number of blocks being copied.
- (0,external_wp_i18n_namespaceObject._n)('Copied %d block to clipboard.', 'Copied %d blocks to clipboard.', selectedBlockClientIds.length), selectedBlockClientIds.length) : (0,external_wp_i18n_namespaceObject.sprintf)(
- // Translators: %d: Number of blocks being cut.
+ (0,external_wp_i18n_namespaceObject._n)('Copied %d block to clipboard.', 'Copied %d blocks to clipboard.', selectedBlockClientIds.length), selectedBlockClientIds.length);
+ } else {
+ notice = (0,external_wp_i18n_namespaceObject.sprintf)(
+ // Translators: %d: Number of blocks being moved.
(0,external_wp_i18n_namespaceObject._n)('Moved %d block to clipboard.', 'Moved %d blocks to clipboard.', selectedBlockClientIds.length), selectedBlockClientIds.length);
}
createSuccessNotice(notice, {
type: 'snackbar'
});
- }, []);
-}
-
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/utils/pasting.js
+ }, [createSuccessNotice, getBlockName, getBlockType]);
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/utils/pasting.js
/**
* WordPress dependencies
*/
@@ -43227,22 +46026,14 @@
}) {
let plainText = '';
let html = '';
-
- // IE11 only supports `Text` as an argument for `getData` and will
- // otherwise throw an invalid argument error, so we try the standard
- // arguments first, then fallback to `Text` if they fail.
try {
plainText = clipboardData.getData('text/plain');
html = clipboardData.getData('text/html');
- } catch (error1) {
- try {
- html = clipboardData.getData('Text');
- } catch (error2) {
- // Some browsers like UC Browser paste plain text by default and
- // don't support clipboardData at all, so allow default
- // behaviour.
- return;
- }
+ } catch (error) {
+ // Some browsers like UC Browser paste plain text by default and
+ // don't support clipboardData at all, so allow default
+ // behaviour.
+ return;
}
// Remove Windows-specific metadata appended within copied HTML text.
@@ -43305,7 +46096,7 @@
return false;
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/utils.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/utils.js
/**
* WordPress dependencies
*/
@@ -43400,7 +46191,7 @@
return plainText.replace(/\n\n+/g, '\n\n');
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-clipboard-handler.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/use-clipboard-handler.js
/**
* WordPress dependencies
*/
@@ -43598,25 +46389,23 @@
}, []);
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/index.js
-/**
- * External dependencies
- */
-
-
-/**
- * WordPress dependencies
- */
-
-
-
-
-
-/**
- * Internal dependencies
- */
-
-
+;// ./node_modules/@wordpress/block-editor/build-module/components/writing-flow/index.js
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
@@ -43633,13 +46422,15 @@
const hasMultiSelection = (0,external_wp_data_namespaceObject.useSelect)(select => select(store).hasMultiSelection(), []);
return [before, (0,external_wp_compose_namespaceObject.useMergeRefs)([ref, useClipboardHandler(), useInput(), useDragSelection(), useSelectionObserver(), useClickSelection(), useMultiSelection(), useSelectAll(), useArrowNav(), (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
node.tabIndex = 0;
+ node.dataset.hasMultiSelection = hasMultiSelection;
if (!hasMultiSelection) {
- return;
- }
- node.classList.add('has-multi-selection');
+ return () => {
+ delete node.dataset.hasMultiSelection;
+ };
+ }
node.setAttribute('aria-label', (0,external_wp_i18n_namespaceObject.__)('Multiple selected blocks'));
return () => {
- node.classList.remove('has-multi-selection');
+ delete node.dataset.hasMultiSelection;
node.removeAttribute('aria-label');
};
}, [hasMultiSelection])]), after];
@@ -43668,12 +46459,12 @@
*/
/* harmony default export */ const writing_flow = ((0,external_wp_element_namespaceObject.forwardRef)(WritingFlow));
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/iframe/get-compatibility-styles.js
+;// ./node_modules/@wordpress/block-editor/build-module/components/iframe/get-compatibility-styles.js
let compatibilityStyles = null;
/**
* Returns a list of stylesheets that target the editor canvas. A stylesheet is
- * considered targetting the editor a canvas if it contains the
+ * considered targeting the editor a canvas if it contains the
* `editor-styles-wrapper`, `wp-block`, or `wp-block-*` class selectors.
*
* Ideally, this hook should be removed in the future and styles should be added
@@ -43708,10 +46499,10 @@
return accumulator;
}
- // Don't try to add the reset styles, which were removed as a dependency
- // from `edit-blocks` for the iframe since we don't need to reset admin
- // styles.
- if (ownerNode.id === 'wp-reset-editor-styles-css') {
+ // Don't try to add core WP styles. We are responsible for adding
+ // them. This compatibility layer is only meant to add styles added
+ // by plugins or themes.
+ if (ownerNode.id.startsWith('wp-')) {
return accumulator;
}
@@ -43762,25 +46553,418 @@
return compatibilityStyles;
}
-;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/iframe/index.js
-/**
- * External dependencies
- */
-
-
-/**
- * WordPress dependencies
- */
-
-
-
-
-
-
-/**
- * Internal dependencies
- */
-
+;// ./node_modules/@wordpress/block-editor/build-module/components/iframe/use-scale-canvas.js
+/**
+ * WordPress dependencies
+ */
+
+
+
+/**
+ * @typedef {Object} TransitionState
+ * @property {number} scaleValue Scale of the canvas.
+ * @property {number} frameSize Size of the frame/offset around the canvas.
+ * @property {number} containerHeight containerHeight of the iframe.
+ * @property {number} scrollTop ScrollTop of the iframe.
+ * @property {number} scrollHeight ScrollHeight of the iframe.
+ */
+
+/**
+ * Calculate the scale of the canvas.
+ *
+ * @param {Object} options Object of options
+ * @param {number} options.frameSize Size of the frame/offset around the canvas
+ * @param {number} options.containerWidth Actual width of the canvas container
+ * @param {number} options.maxContainerWidth Maximum width of the container to use for the scale calculation. This locks the canvas to a maximum width when zooming out.
+ * @param {number} options.scaleContainerWidth Width the of the container wrapping the canvas container
+ * @return {number} Scale value between 0 and/or equal to 1
+ */
+function calculateScale({
+ frameSize,
+ containerWidth,
+ maxContainerWidth,
+ scaleContainerWidth
+}) {
+ return (Math.min(containerWidth, maxContainerWidth) - frameSize * 2) / scaleContainerWidth;
+}
+
+/**
+ * Compute the next scrollHeight based on the transition states.
+ *
+ * @param {TransitionState} transitionFrom Starting point of the transition
+ * @param {TransitionState} transitionTo Ending state of the transition
+ * @return {number} Next scrollHeight based on scale and frame value changes.
+ */
+function computeScrollHeightNext(transitionFrom, transitionTo) {
+ const {
+ scaleValue: prevScale,
+ scrollHeight: prevScrollHeight
+ } = transitionFrom;
+ const {
+ frameSize,
+ scaleValue
+ } = transitionTo;
+ return prevScrollHeight * (scaleValue / prevScale) + frameSize * 2;
+}
+
+/**
+ * Compute the next scrollTop position after scaling the iframe content.
+ *
+ * @param {TransitionState} transitionFrom Starting point of the transition
+ * @param {TransitionState} transitionTo Ending state of the transition
+ * @return {number} Next scrollTop position after scaling the iframe content.
+ */
+function computeScrollTopNext(transitionFrom, transitionTo) {
+ const {
+ containerHeight: prevContainerHeight,
+ frameSize: prevFrameSize,
+ scaleValue: prevScale,
+ scrollTop: prevScrollTop
+ } = transitionFrom;
+ const {
+ containerHeight,
+ frameSize,
+ scaleValue,
+ scrollHeight
+ } = transitionTo;
+ // Step 0: Start with the current scrollTop.
+ let scrollTopNext = prevScrollTop;
+ // Step 1: Undo the effects of the previous scale and frame around the
+ // midpoint of the visible area.
+ scrollTopNext = (scrollTopNext + prevContainerHeight / 2 - prevFrameSize) / prevScale - prevContainerHeight / 2;
+
+ // Step 2: Apply the new scale and frame around the midpoint of the
+ // visible area.
+ scrollTopNext = (scrollTopNext + containerHeight / 2) * scaleValue + frameSize - containerHeight / 2;
+
+ // Step 3: Handle an edge case so that you scroll to the top of the
+ // iframe if the top of the iframe content is visible in the container.
+ // The same edge case for the bottom is skipped because changing content
+ // makes calculating it impossible.
+ scrollTopNext = prevScrollTop <= prevFrameSize ? 0 : scrollTopNext;
+
+ // This is the scrollTop value if you are scrolled to the bottom of the
+ // iframe. We can't just let the browser handle it because we need to
+ // animate the scaling.
+ const maxScrollTop = scrollHeight - containerHeight;
+
+ // Step 4: Clamp the scrollTopNext between the minimum and maximum
+ // possible scrollTop positions. Round the value to avoid subpixel
+ // truncation by the browser which sometimes causes a 1px error.
+ return Math.round(Math.min(Math.max(0, scrollTopNext), Math.max(0, maxScrollTop)));
+}
+
+/**
+ * Generate the keyframes to use for the zoom out animation.
+ *
+ * @param {TransitionState} transitionFrom Starting transition state.
+ * @param {TransitionState} transitionTo Ending transition state.
+ * @return {Object[]} An array of keyframes to use for the animation.
+ */
+function getAnimationKeyframes(transitionFrom, transitionTo) {
+ const {
+ scaleValue: prevScale,
+ frameSize: prevFrameSize,
+ scrollTop
+ } = transitionFrom;
+ const {
+ scaleValue,
+ frameSize,
+ scrollTop: scrollTopNext
+ } = transitionTo;
+ return [{
+ translate: `0 0`,
+ scale: prevScale,
+ paddingTop: `${prevFrameSize / prevScale}px`,
+ paddingBottom: `${prevFrameSize / prevScale}px`
+ }, {
+ translate: `0 ${scrollTop - scrollTopNext}px`,
+ scale: scaleValue,
+ paddingTop: `${frameSize / scaleValue}px`,
+ paddingBottom: `${frameSize / scaleValue}px`
+ }];
+}
+
+/**
+ * @typedef {Object} ScaleCanvasResult
+ * @property {boolean} isZoomedOut A boolean indicating if the canvas is zoomed out.
+ * @property {number} scaleContainerWidth The width of the container used to calculate the scale.
+ * @property {Object} contentResizeListener A resize observer for the content.
+ * @property {Object} containerResizeListener A resize observer for the container.
+ */
+
+/**
+ * Handles scaling the canvas for the zoom out mode and animating between
+ * the states.
+ *
+ * @param {Object} options Object of options.
+ * @param {number} options.frameSize Size of the frame around the content.
+ * @param {Document} options.iframeDocument Document of the iframe.
+ * @param {number} options.maxContainerWidth Max width of the canvas to use as the starting scale point. Defaults to 750.
+ * @param {number|string} options.scale Scale of the canvas. Can be an decimal between 0 and 1, 1, or 'auto-scaled'.
+ * @return {ScaleCanvasResult} Properties of the result.
+ */
+function useScaleCanvas({
+ frameSize,
+ iframeDocument,
+ maxContainerWidth = 750,
+ scale
+}) {
+ const [contentResizeListener, {
+ height: contentHeight
+ }] = (0,external_wp_compose_namespaceObject.useResizeObserver)();
+ const [containerResizeListener, {
+ width: containerWidth,
+ height: containerHeight
+ }] = (0,external_wp_compose_namespaceObject.useResizeObserver)();
+ const initialContainerWidthRef = (0,external_wp_element_namespaceObject.useRef)(0);
+ const isZoomedOut = scale !== 1;
+ const prefersReducedMotion = (0,external_wp_compose_namespaceObject.useReducedMotion)();
+ const isAutoScaled = scale === 'auto-scaled';
+ // Track if the animation should start when the useEffect runs.
+ const startAnimationRef = (0,external_wp_element_namespaceObject.useRef)(false);
+ // Track the animation so we know if we have an animation running,
+ // and can cancel it, reverse it, call a finish event, etc.
+ const animationRef = (0,external_wp_element_namespaceObject.useRef)(null);
+ (0,external_wp_element_namespaceObject.useEffect)(() => {
+ if (!isZoomedOut) {
+ initialContainerWidthRef.current = containerWidth;
+ }
+ }, [containerWidth, isZoomedOut]);
+ const scaleContainerWidth = Math.max(initialContainerWidthRef.current, containerWidth);
+ const scaleValue = isAutoScaled ? calculateScale({
+ frameSize,
+ containerWidth,
+ maxContainerWidth,
+ scaleContainerWidth
+ }) : scale;
+
+ /**
+ * The starting transition state for the zoom out animation.
+ * @type {import('react').RefObject}
+ */
+ const transitionFromRef = (0,external_wp_element_namespaceObject.useRef)({
+ scaleValue,
+ frameSize,
+ containerHeight: 0,
+ scrollTop: 0,
+ scrollHeight: 0
+ });
+
+ /**
+ * The ending transition state for the zoom out animation.
+ * @type {import('react').RefObject}
+ */
+ const transitionToRef = (0,external_wp_element_namespaceObject.useRef)({
+ scaleValue,
+ frameSize,
+ containerHeight: 0,
+ scrollTop: 0,
+ scrollHeight: 0
+ });
+
+ /**
+ * Start the zoom out animation. This sets the necessary CSS variables
+ * for animating the canvas and returns the Animation object.
+ *
+ * @return {Animation} The animation object for the zoom out animation.
+ */
+ const startZoomOutAnimation = (0,external_wp_element_namespaceObject.useCallback)(() => {
+ const {
+ scrollTop
+ } = transitionFromRef.current;
+ const {
+ scrollTop: scrollTopNext
+ } = transitionToRef.current;
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scroll-top', `${scrollTop}px`);
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scroll-top-next', `${scrollTopNext}px`);
+
+ // If the container has a scrolllbar, force a scrollbar to prevent the content from shifting while animating.
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-overflow-behavior', transitionFromRef.current.scrollHeight === transitionFromRef.current.containerHeight ? 'auto' : 'scroll');
+ iframeDocument.documentElement.classList.add('zoom-out-animation');
+ return iframeDocument.documentElement.animate(getAnimationKeyframes(transitionFromRef.current, transitionToRef.current), {
+ easing: 'cubic-bezier(0.46, 0.03, 0.52, 0.96)',
+ duration: 400
+ });
+ }, [iframeDocument]);
+
+ /**
+ * Callback when the zoom out animation is finished.
+ * - Cleans up animations refs.
+ * - Adds final CSS vars for scale and frame size to preserve the state.
+ * - Removes the 'zoom-out-animation' class (which has the fixed positioning).
+ * - Sets the final scroll position after the canvas is no longer in fixed position.
+ * - Removes CSS vars related to the animation.
+ * - Sets the transitionFrom to the transitionTo state to be ready for the next animation.
+ */
+ const finishZoomOutAnimation = (0,external_wp_element_namespaceObject.useCallback)(() => {
+ startAnimationRef.current = false;
+ animationRef.current = null;
+
+ // Add our final scale and frame size now that the animation is done.
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scale', transitionToRef.current.scaleValue);
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-frame-size', `${transitionToRef.current.frameSize}px`);
+ iframeDocument.documentElement.classList.remove('zoom-out-animation');
+
+ // Set the final scroll position that was just animated to.
+ // Disable reason: Eslint isn't smart enough to know that this is a
+ // DOM element. https://github.com/facebook/react/issues/31483
+ // eslint-disable-next-line react-compiler/react-compiler
+ iframeDocument.documentElement.scrollTop = transitionToRef.current.scrollTop;
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-scroll-top');
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-scroll-top-next');
+ iframeDocument.documentElement.style.removeProperty('--wp-block-editor-iframe-zoom-out-overflow-behavior');
+
+ // Update previous values.
+ transitionFromRef.current = transitionToRef.current;
+ }, [iframeDocument]);
+ const previousIsZoomedOut = (0,external_wp_element_namespaceObject.useRef)(false);
+
+ /**
+ * Runs when zoom out mode is toggled, and sets the startAnimation flag
+ * so the animation will start when the next useEffect runs. We _only_
+ * want to animate when the zoom out mode is toggled, not when the scale
+ * changes due to the container resizing.
+ */
+ (0,external_wp_element_namespaceObject.useEffect)(() => {
+ const trigger = iframeDocument && previousIsZoomedOut.current !== isZoomedOut;
+ previousIsZoomedOut.current = isZoomedOut;
+ if (!trigger) {
+ return;
+ }
+ startAnimationRef.current = true;
+ if (!isZoomedOut) {
+ return;
+ }
+ iframeDocument.documentElement.classList.add('is-zoomed-out');
+ return () => {
+ iframeDocument.documentElement.classList.remove('is-zoomed-out');
+ };
+ }, [iframeDocument, isZoomedOut]);
+
+ /**
+ * This handles:
+ * 1. Setting the correct scale and vars of the canvas when zoomed out
+ * 2. If zoom out mode has been toggled, runs the animation of zooming in/out
+ */
+ (0,external_wp_element_namespaceObject.useEffect)(() => {
+ if (!iframeDocument) {
+ return;
+ }
+
+ // We need to update the appropriate scale to exit from. If sidebars have been opened since setting the
+ // original scale, we will snap to a much smaller scale due to the scale container immediately changing sizes when exiting.
+ if (isAutoScaled && transitionFromRef.current.scaleValue !== 1) {
+ // We use containerWidth as the divisor, as scaleContainerWidth will always match the containerWidth when
+ // exiting.
+ transitionFromRef.current.scaleValue = calculateScale({
+ frameSize: transitionFromRef.current.frameSize,
+ containerWidth,
+ maxContainerWidth,
+ scaleContainerWidth: containerWidth
+ });
+ }
+ if (scaleValue < 1) {
+ // If we are not going to animate the transition, set the scale and frame size directly.
+ // If we are animating, these values will be set when the animation is finished.
+ // Example: Opening sidebars that reduce the scale of the canvas, but we don't want to
+ // animate the transition.
+ if (!startAnimationRef.current) {
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scale', scaleValue);
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-frame-size', `${frameSize}px`);
+ }
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-content-height', `${contentHeight}px`);
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-inner-height', `${containerHeight}px`);
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-container-width', `${containerWidth}px`);
+ iframeDocument.documentElement.style.setProperty('--wp-block-editor-iframe-zoom-out-scale-container-width', `${scaleContainerWidth}px`);
+ }
+
+ /**
+ * Handle the zoom out animation:
+ *
+ * - Get the current scrollTop position.
+ * - Calculate where the same scroll position is after scaling.
+ * - Apply fixed positioning to the canvas with a transform offset
+ * to keep the canvas centered.
+ * - Animate the scale and padding to the new scale and frame size.
+ * - After the animation is complete, remove the fixed positioning
+ * and set the scroll position that keeps everything centered.
+ */
+ if (startAnimationRef.current) {
+ // Don't allow a new transition to start again unless it was started by the zoom out mode changing.
+ startAnimationRef.current = false;
+
+ /**
+ * If we already have an animation running, reverse it.
+ */
+ if (animationRef.current) {
+ animationRef.current.reverse();
+ // Swap the transition to/from refs so that we set the correct values when
+ // finishZoomOutAnimation runs.
+ const tempTransitionFrom = transitionFromRef.current;
+ const tempTransitionTo = transitionToRef.current;
+ transitionFromRef.current = tempTransitionTo;
+ transitionToRef.current = tempTransitionFrom;
+ } else {
+ /**
+ * Start a new zoom animation.
+ */
+
+ // We can't trust the set value from contentHeight, as it was measured
+ // before the zoom out mode was changed. After zoom out mode is changed,
+ // appenders may appear or disappear, so we need to get the height from
+ // the iframe at this point when we're about to animate the zoom out.
+ // The iframe scrollTop, scrollHeight, and clientHeight will all be
+ // the most accurate.
+ transitionFromRef.current.scrollTop = iframeDocument.documentElement.scrollTop;
+ transitionFromRef.current.scrollHeight = iframeDocument.documentElement.scrollHeight;
+ // Use containerHeight, as it's the previous container height before the zoom out animation starts.
+ transitionFromRef.current.containerHeight = containerHeight;
+ transitionToRef.current = {
+ scaleValue,
+ frameSize,
+ containerHeight: iframeDocument.documentElement.clientHeight // use clientHeight to get the actual height of the new container after zoom state changes have rendered, as it will be the most up-to-date.
+ };
+ transitionToRef.current.scrollHeight = computeScrollHeightNext(transitionFromRef.current, transitionToRef.current);
+ transitionToRef.current.scrollTop = computeScrollTopNext(transitionFromRef.current, transitionToRef.current);
+ animationRef.current = startZoomOutAnimation();
+
+ // If the user prefers reduced motion, finish the animation immediately and set the final state.
+ if (prefersReducedMotion) {
+ finishZoomOutAnimation();
+ } else {
+ animationRef.current.onfinish = finishZoomOutAnimation;
+ }
+ }
+ }
+ }, [startZoomOutAnimation, finishZoomOutAnimation, prefersReducedMotion, isAutoScaled, scaleValue, frameSize, iframeDocument, contentHeight, containerWidth, containerHeight, maxContainerWidth, scaleContainerWidth]);
+ return {
+ isZoomedOut,
+ scaleContainerWidth,
+ contentResizeListener,
+ containerResizeListener
+ };
+}
+
+;// ./node_modules/@wordpress/block-editor/build-module/components/iframe/index.js
+/* wp:polyfill */
+/**
+ * External dependencies
+ */
+
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
@@ -43876,24 +47060,18 @@
const settings = getSettings();
return {
resolvedAssets: settings.__unstableResolvedAssets,
- isPreviewMode: settings.__unstableIsPreviewMode
+ isPreviewMode: settings.isPreviewMode
};
}, []);
const {
styles = '',
scripts = ''
} = resolvedAssets;
+ /** @type {[Document, import('react').Dispatch]} */
const [iframeDocument, setIframeDocument] = (0,external_wp_element_namespaceObject.useState)();
- const prevContainerWidth = (0,external_wp_element_namespaceObject.useRef)();
const [bodyClasses, setBodyClasses] = (0,external_wp_element_namespaceObject.useState)([]);
const clearerRef = useBlockSelectionClearer();
const [before, writingFlowRef, after] = useWritingFlow();
- const [contentResizeListener, {
- height: contentHeight
- }] = (0,external_wp_compose_namespaceObject.useResizeObserver)();
- const [containerResizeListener, {
- width: containerWidth
- }] = (0,external_wp_compose_namespaceObject.useResizeObserver)();
const setRef = (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
node._load = () => {
setIframeDocument(node.contentDocument);
@@ -43903,10 +47081,17 @@
function preventFileDropDefault(event) {
event.preventDefault();
}
+ const {
+ ownerDocument
+ } = node;
+
+ // Ideally ALL classes that are added through get_body_class should
+ // be added in the editor too, which we'll somehow have to get from
+ // the server in the future (which will run the PHP filters).
+ setBodyClasses(Array.from(ownerDocument.body.classList).filter(name => name.startsWith('admin-color-') || name.startsWith('post-type-') || name === 'wp-embed-responsive'));
function onLoad() {
const {
- contentDocument,
- ownerDocument
+ contentDocument
} = node;
const {
documentElement
@@ -43914,11 +47099,6 @@
iFrameDocument = contentDocument;
documentElement.classList.add('block-editor-iframe__html');
clearerRef(documentElement);
-
- // Ideally ALL classes that are added through get_body_class should
- // be added in the editor too, which we'll somehow have to get from
- // the server in the future (which will run the PHP filters).
- setBodyClasses(Array.from(ownerDocument.body.classList).filter(name => name.startsWith('admin-color-') || name.startsWith('post-type-') || name === 'wp-embed-responsive'));
contentDocument.dir = ownerDocument.dir;
for (const compatStyle of getCompatibilityStyles()) {
if (contentDocument.getElementById(compatStyle.id)) {
@@ -43932,6 +47112,21 @@
}
iFrameDocument.addEventListener('dragover', preventFileDropDefault, false);
iFrameDocument.addEventListener('drop', preventFileDropDefault, false);
+ // Prevent clicks on links from navigating away. Note that links
+ // inside `contenteditable` are already disabled by the browser, so
+ // this is for links in blocks outside of `contenteditable`.
+ iFrameDocument.addEventListener('click', event => {
+ if (event.target.tagName === 'A') {
+ event.preventDefault();
+
+ // Appending a hash to the current URL will not reload the
+ // page. This is useful for e.g. footnotes.
+ const href = event.target.getAttribute('href');
+ if (href?.startsWith('#')) {
+ iFrameDocument.defaultView.location.hash = href.slice(1);
+ }
+ }
+ });
}
node.addEventListener('load', onLoad);
return () => {
@@ -43941,44 +47136,20 @@
iFrameDocument?.removeEventListener('drop', preventFileDropDefault);
};
}, []);
- const [iframeWindowInnerHeight, setIframeWindowInnerHeight] = (0,external_wp_element_namespaceObject.useState)();
- const iframeResizeRef = (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
- const nodeWindow = node.ownerDocument.defaultView;
- setIframeWindowInnerHeight(nodeWindow.innerHeight);
- const onResize = () => {
- setIframeWindowInnerHeight(nodeWindow.innerHeight);
- };
- nodeWindow.addEventListener('resize', onResize);
- return () => {
- nodeWindow.removeEventListener('resize', onResize);
- };
- }, []);
- const [windowInnerWidth, setWindowInnerWidth] = (0,external_wp_element_namespaceObject.useState)();
- const windowResizeRef = (0,external_wp_compose_namespaceObject.useRefEffect)(node => {
- const nodeWindow = node.ownerDocument.defaultView;
- setWindowInnerWidth(nodeWindow.innerWidth);
- const onResize = () => {
- setWindowInnerWidth(nodeWindow.innerWidth);
- };
- nodeWindow.addEventListener('resize', onResize);
- return () => {
- nodeWindow.removeEventListener('resize', onResize);
- };
- }, []);
- const isZoomedOut = scale !== 1;
- (0,external_wp_element_namespaceObject.useEffect)(() => {
- if (!isZoomedOut) {
- prevContainerWidth.current = containerWidth;
- }
- }, [containerWidth, isZoomedOut]);
+ const {
+ contentResizeListener,
+ containerResizeListener,
+ isZoomedOut,
+ scaleContainerWidth
+ } = useScaleCanvas({
+ scale,
+ frameSize: parseInt(frameSize),
+ iframeDocument
+ });
const disabledRef = (0,external_wp_compose_namespaceObject.useDisabled)({
isDisabled: !readonly
});
- const bodyRef = (0,external_wp_compose_namespaceObject.useMergeRefs)([useBubbleEvents(iframeDocument), contentRef, clearerRef, writingFlowRef, disabledRef,
- // Avoid resize listeners when not needed, these will trigger
- // unnecessary re-renders when animating the iframe width, or when
- // expanding preview iframes.
- isZoomedOut ? iframeResizeRef : null]);
+ const bodyRef = (0,external_wp_compose_namespaceObject.useMergeRefs)([useBubbleEvents(iframeDocument), contentRef, clearerRef, writingFlowRef, disabledRef]);
// Correct doctype is required to enable rendering in standards
// mode. Also preload the styles to avoid a flash of unstyled
@@ -43987,6 +47158,7 @@
+