@craftile/plugin-static-blocks-renderer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/dist/index.cjs +27 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +93 -0
- package/package.json +54 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Craftile Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";const w='var Te=Object.defineProperty;var Pe=(y,k,m)=>k in y?Te(y,k,{enumerable:!0,configurable:!0,writable:!0,value:m}):y[k]=m;var A=(y,k,m)=>Pe(y,typeof k!="symbol"?k+"":k,m);var HtmlPreviewClient=(function(){"use strict";var y=Object.defineProperty,k=(o,e,t)=>e in o?y(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t,m=(o,e,t)=>k(o,typeof e!="symbol"?e+"":e,t);class re{constructor(e,t="*"){m(this,"handlers",new Map),m(this,"targetWindow"),m(this,"targetOrigin"),m(this,"fallbackHandler"),this.targetWindow=e,this.targetOrigin=t,window.addEventListener("message",this.handleMessage.bind(this))}handleMessage(e){const t=e.data;if(!t.type)return;const n=this.handlers.get(t.type);n?n.forEach(i=>i(t.payload,e)):this.fallbackHandler&&this.fallbackHandler(e.data,e)}send(e,t){const n={type:e,payload:t};this.targetWindow.postMessage(n,this.targetOrigin)}listen(e,t){return this.handlers.has(e)||this.handlers.set(e,[]),this.handlers.get(e).push(t),()=>{const n=this.handlers.get(e);if(n){const i=n.indexOf(t);i>-1&&n.splice(i,1)}}}registerFallbackHandler(e){this.fallbackHandler=e}}function se(o="*"){if(window.parent===window)throw new Error("Not inside an iframe");return new re(window.parent,o)}class oe{constructor(){m(this,"listeners",new Map)}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.off(e,t)}}off(e,t){const n=this.listeners.get(e);n&&(n.delete(t),n.size===0&&this.listeners.delete(e))}once(e,t){const n=i=>{t(i),this.off(e,n)};this.on(e,n)}emit(e,...t){const n=this.listeners.get(e);if(n){const i=t[0];n.forEach(r=>{try{r(i)}catch(s){console.error(`Error in event listener for \'${String(e)}\':`,s)}})}}removeAllListeners(e){e?this.listeners.delete(e):this.listeners.clear()}}class le{constructor(e){m(this,"active",!0),m(this,"messenger"),m(this,"currentHoveredBlock",null),m(this,"currentSelectedBlock",null),m(this,"overlayButtonHovered",!1),m(this,"resizeObserver",null),m(this,"mutationObserver",null),this.messenger=e,this.messenger.listen("craftile.inspector.enable",()=>this.enable()),this.messenger.listen("craftile.inspector.disable",()=>this.disable()),this.messenger.listen("craftile.inspector.overlay-button-enter",this.handleOverlayButtonEnter.bind(this)),this.messenger.listen("craftile.inspector.overlay-button-leave",this.handleOverlayButtonLeave.bind(this)),window.addEventListener("scroll",this.handleScroll.bind(this),{passive:!0}),this.setupGlobalEventListeners()}enable(){this.active=!0,document.body.classList.add("craftile-inspector-active")}disable(){this.active=!1,document.body.classList.remove("craftile-inspector-active"),this.currentHoveredBlock=null,this.currentSelectedBlock=null,this.overlayButtonHovered=!1}handleOverlayButtonEnter(){this.overlayButtonHovered=!0}handleOverlayButtonLeave(e){this.overlayButtonHovered=!1,this.currentHoveredBlock||this.messenger.send("craftile.preview.block-leave")}handleScroll(){this.currentSelectedBlock&&this.sendSelectedBlockPosition(),this.currentHoveredBlock&&this.sendHoveredBlockPosition()}setupGlobalEventListeners(){document.addEventListener("mouseover",this.handleGlobalHover.bind(this)),document.addEventListener("mouseout",this.handleGlobalLeave.bind(this)),document.addEventListener("click",this.handleGlobalClick.bind(this))}handleGlobalHover(e){if(!this.active)return;const t=e.target.closest("[data-block]");t&&(e.stopPropagation(),this.currentHoveredBlock=t,this.sendHoveredBlockPosition())}handleGlobalLeave(e){!this.active||!e.target.closest("[data-block]")||this.overlayButtonHovered||(this.currentHoveredBlock=null,this.messenger.send("craftile.preview.block-leave"))}handleGlobalClick(e){if(this.messenger.send("craftile.preview.click"),!this.active)return;const t=e.target.closest("[data-block]");if(!t)return;e.stopPropagation(),t.getAttribute("data-block")&&(this.currentSelectedBlock=t,this.sendSelectedBlockPosition(),this.trackSelectedBlock())}sendHoveredBlockPosition(){const e=this.computeElementPositioning(this.currentHoveredBlock);this.messenger.send("craftile.preview.block-hover",{blockRect:e.rect,parentRect:e.parentRect,scrollTop:e.scrollTop,scrollLeft:e.scrollLeft,blockId:this.currentHoveredBlock.dataset.block,parentFlexDirection:e.parentFlexDirection})}sendSelectedBlockPosition(e=!1){const t=this.computeElementPositioning(this.currentSelectedBlock);this.messenger.send(e?"craftile.preview.update-selected-block":"craftile.preview.block-select",{blockRect:t.rect,scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,blockId:this.currentSelectedBlock.dataset.block})}trackSelectedBlock(){if(!this.currentSelectedBlock)return;this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null),this.resizeObserver=new ResizeObserver(()=>{this.sendSelectedBlockPosition(!0)}),this.resizeObserver.observe(this.currentSelectedBlock),this.mutationObserver=new MutationObserver(()=>{this.sendSelectedBlockPosition(!0)}),this.mutationObserver.observe(this.currentSelectedBlock,{attributes:!0,subtree:!1});let e=this.currentSelectedBlock.parentElement;for(;e&&(this.mutationObserver.observe(e,{childList:!0,subtree:!1}),e!==document.body);)e=e.parentElement}computeElementPositioning(e){const t=e.getBoundingClientRect(),n=window.pageYOffset||document.documentElement.scrollTop,i=window.pageXOffset||document.documentElement.scrollLeft,r=this.findEldestParentBlock(e),s=r&&r!==e?r.getBoundingClientRect():void 0,l=this.getElementFlexDirection(e.parentElement);return{rect:t,parentRect:s,scrollTop:n,scrollLeft:i,parentFlexDirection:l}}findEldestParentBlock(e){let t=null,n=e.parentElement;for(;n&&n!==document.body;)n.hasAttribute("data-block")&&(t=n),n=n.parentElement;return t}getElementFlexDirection(e){if(!e)return"column";const t=window.getComputedStyle(e),n=t.display.includes("flex")?t.flexDirection:"column";return n==="row"||n==="row-reverse"?"row":"column"}}class ae extends oe{constructor(){super(),m(this,"messenger"),m(this,"inspector"),this.messenger=se(window.origin),this.inspector=new le(this.messenger),this.initialize()}initialize(){window.addEventListener("load",()=>{this.messenger.send("craftile.preview.ready",{})}),document.addEventListener("DOMContentLoaded",()=>{this.sendPageData()}),this.messenger.registerFallbackHandler(e=>{const{type:t,payload:n}=e;this.emit(t,n)})}sendPageData(){const e=document.getElementById("page-data");if(e)try{const t=JSON.parse(e.textContent||"{}");this.messenger.send("craftile.preview.page-data",{pageData:t})}catch(t){console.error("Failed to parse page data:",t)}}}var Y=11;function ce(o,e){var t=e.attributes,n,i,r,s,l;if(!(e.nodeType===Y||o.nodeType===Y)){for(var h=t.length-1;h>=0;h--)n=t[h],i=n.name,r=n.namespaceURI,s=n.value,r?(i=n.localName||i,l=o.getAttributeNS(r,i),l!==s&&(n.prefix==="xmlns"&&(i=n.name),o.setAttributeNS(r,i,s))):(l=o.getAttribute(i),l!==s&&o.setAttribute(i,s));for(var p=o.attributes,v=p.length-1;v>=0;v--)n=p[v],i=n.name,r=n.namespaceURI,r?(i=n.localName||i,e.hasAttributeNS(r,i)||o.removeAttributeNS(r,i)):e.hasAttribute(i)||o.removeAttribute(i)}}var H,de="http://www.w3.org/1999/xhtml",b=typeof document>"u"?void 0:document,fe=!!b&&"content"in b.createElement("template"),he=!!b&&b.createRange&&"createContextualFragment"in b.createRange();function ue(o){var e=b.createElement("template");return e.innerHTML=o,e.content.childNodes[0]}function ve(o){H||(H=b.createRange(),H.selectNode(b.body));var e=H.createContextualFragment(o);return e.childNodes[0]}function me(o){var e=b.createElement("body");return e.innerHTML=o,e.childNodes[0]}function pe(o){return o=o.trim(),fe?ue(o):he?ve(o):me(o)}function I(o,e){var t=o.nodeName,n=e.nodeName,i,r;return t===n?!0:(i=t.charCodeAt(0),r=n.charCodeAt(0),i<=90&&r>=97?t===n.toUpperCase():r<=90&&i>=97?n===t.toUpperCase():!1)}function ge(o,e){return!e||e===de?b.createElement(o):b.createElementNS(e,o)}function be(o,e){for(var t=o.firstChild;t;){var n=t.nextSibling;e.appendChild(t),t=n}return e}function _(o,e,t){o[t]!==e[t]&&(o[t]=e[t],o[t]?o.setAttribute(t,""):o.removeAttribute(t))}var q={OPTION:function(o,e){var t=o.parentNode;if(t){var n=t.nodeName.toUpperCase();n==="OPTGROUP"&&(t=t.parentNode,n=t&&t.nodeName.toUpperCase()),n==="SELECT"&&!t.hasAttribute("multiple")&&(o.hasAttribute("selected")&&!e.selected&&(o.setAttribute("selected","selected"),o.removeAttribute("selected")),t.selectedIndex=-1)}_(o,e,"selected")},INPUT:function(o,e){_(o,e,"checked"),_(o,e,"disabled"),o.value!==e.value&&(o.value=e.value),e.hasAttribute("value")||o.removeAttribute("value")},TEXTAREA:function(o,e){var t=e.value;o.value!==t&&(o.value=t);var n=o.firstChild;if(n){var i=n.nodeValue;if(i==t||!t&&i==o.placeholder)return;n.nodeValue=t}},SELECT:function(o,e){if(!e.hasAttribute("multiple")){for(var t=-1,n=0,i=o.firstChild,r,s;i;)if(s=i.nodeName&&i.nodeName.toUpperCase(),s==="OPTGROUP")r=i,i=r.firstChild,i||(i=r.nextSibling,r=null);else{if(s==="OPTION"){if(i.hasAttribute("selected")){t=n;break}n++}i=i.nextSibling,!i&&r&&(i=r.nextSibling,r=null)}o.selectedIndex=t}}},P=1,J=11,Q=3,Z=8;function B(){}function ke(o){if(o)return o.getAttribute&&o.getAttribute("id")||o.id}function we(o){return function(t,n,i){if(i||(i={}),typeof n=="string")if(t.nodeName==="#document"||t.nodeName==="HTML"||t.nodeName==="BODY"){var r=n;n=b.createElement("html"),n.innerHTML=r}else n=pe(n);else n.nodeType===J&&(n=n.firstElementChild);var s=i.getNodeKey||ke,l=i.onBeforeNodeAdded||B,h=i.onNodeAdded||B,p=i.onBeforeElUpdated||B,v=i.onElUpdated||B,G=i.onBeforeNodeDiscarded||B,N=i.onNodeDiscarded||B,Ee=i.onBeforeElChildrenUpdated||B,Ce=i.skipFromChildren||B,ee=i.addChild||function(a,c){return a.appendChild(c)},V=i.childrenOnly===!0,S=Object.create(null),L=[];function M(a){L.push(a)}function te(a,c){if(a.nodeType===P)for(var u=a.firstChild;u;){var d=void 0;c&&(d=s(u))?M(d):(N(u),u.firstChild&&te(u,c)),u=u.nextSibling}}function x(a,c,u){G(a)!==!1&&(c&&c.removeChild(a),N(a),te(a,u))}function z(a){if(a.nodeType===P||a.nodeType===J)for(var c=a.firstChild;c;){var u=s(c);u&&(S[u]=c),z(c),c=c.nextSibling}}z(t);function W(a){h(a);for(var c=a.firstChild;c;){var u=c.nextSibling,d=s(c);if(d){var f=S[d];f&&I(c,f)?(c.parentNode.replaceChild(f,c),D(f,c)):W(c)}else W(c);c=u}}function ye(a,c,u){for(;c;){var d=c.nextSibling;(u=s(c))?M(u):x(c,a,!0),c=d}}function D(a,c,u){var d=s(c);if(d&&delete S[d],!u){var f=p(a,c);if(f===!1||(f instanceof HTMLElement&&(a=f,z(a)),o(a,c),v(a),Ee(a,c)===!1))return}a.nodeName!=="TEXTAREA"?Se(a,c):q.TEXTAREA(a,c)}function Se(a,c){var u=Ce(a,c),d=c.firstChild,f=a.firstChild,O,w,T,$,E;e:for(;d;){for($=d.nextSibling,O=s(d);!u&&f;){if(T=f.nextSibling,d.isSameNode&&d.isSameNode(f)){d=$,f=T;continue e}w=s(f);var U=f.nodeType,C=void 0;if(U===d.nodeType&&(U===P?(O?O!==w&&((E=S[O])?T===E?C=!1:(a.insertBefore(E,f),w?M(w):x(f,a,!0),f=E,w=s(f)):C=!1):w&&(C=!1),C=C!==!1&&I(f,d),C&&D(f,d)):(U===Q||U==Z)&&(C=!0,f.nodeValue!==d.nodeValue&&(f.nodeValue=d.nodeValue))),C){d=$,f=T;continue e}w?M(w):x(f,a,!0),f=T}if(O&&(E=S[O])&&I(E,d))u||ee(a,E),D(E,d);else{var j=l(d);j!==!1&&(j&&(d=j),d.actualize&&(d=d.actualize(a.ownerDocument||b)),ee(a,d),W(d))}d=$,f=T}ye(a,f,w);var ie=q[a.nodeName];ie&&ie(a,c)}var g=t,R=g.nodeType,ne=n.nodeType;if(!V){if(R===P)ne===P?I(t,n)||(N(t),g=be(t,ge(n.nodeName,n.namespaceURI))):g=n;else if(R===Q||R===Z){if(ne===R)return g.nodeValue!==n.nodeValue&&(g.nodeValue=n.nodeValue),g;g=n}}if(g===n)N(t);else{if(n.isSameNode&&n.isSameNode(g))return;if(D(g,n,V),L)for(var X=0,Oe=L.length;X<Oe;X++){var K=S[L[X]];K&&x(K,K.parentNode,!1)}}return!V&&g!==t&&t.parentNode&&(g.actualize&&(g=g.actualize(t.ownerDocument||b)),t.parentNode.replaceChild(g,t)),g}}var Be=we(ce);class F{constructor(e,t){A(this,"previewClient");A(this,"morphdomOptions");A(this,"elementCache",new Map);A(this,"regionCommentsCache",new Map);this.previewClient=e||new ae,this.morphdomOptions=t?.morphdom||{},this.previewClient.on("updates.effects",this.handleEffects.bind(this)),this.previewClient.on("craftile.editor.updates",this.handleDirectUpdates.bind(this)),this.cacheRegionComments()}static init(e,t){return new F(e,t)}getElementCached(e){if(this.elementCache.has(e)){const n=this.elementCache.get(e);if(n.isConnected)return n;this.elementCache.delete(e)}const t=document.querySelector(`[data-block="${e}"]`);return t&&this.elementCache.set(e,t),t}cacheRegionComments(){const e=document.createTreeWalker(document.body,NodeFilter.SHOW_COMMENT,null);let t;const n=new Map;for(;t=e.nextNode();){const i=t.textContent?.trim();if(i){if(i.startsWith("BEGIN region: ")){const r=i.substring(14);n.set(r,t)}else if(i.startsWith("END region: ")){const r=i.substring(12),s=n.get(r);s&&(this.regionCommentsCache.set(r,{begin:s,end:t}),n.delete(r))}}}}invalidateCache(e){[...e.updated,...e.removed].forEach(t=>{this.elementCache.delete(t)})}handleEffects(e){const{effects:t,blocks:n,regions:i,changes:r}=e;t&&(this.invalidateCache(r),t.html&&this.handleHtmlEffects(t.html,{blocks:n,regions:i,changes:r}))}handleDirectUpdates(e){const{changes:t}=e;t.moved&&this.handleMoves(e),t.updated.length>0&&this.handleDisabledBlocks(e),t.removed.length>0&&this.handleRemoves(e)}handleMoves(e){const{blocks:t,changes:n}=e;for(const[i,r]of Object.entries(e.changes.moved)){if(r?.toParent&&n.updated?.includes(r?.toParent))continue;if(!this.isValidMoveInstruction(r)){console.warn(`Invalid move instruction for block ${i}:`,r);continue}const s=t[i];this.moveBlockUsingDOM(s,r)}}handleDisabledBlocks(e){const{blocks:t,changes:n}=e;for(const i of n.updated){const r=t[i];if(!r)continue;const l=!!this.getElementCached(i);r.disabled&&l?this.removeBlock(r.id):r.disabled}}handleRemoves(e){const{changes:t}=e;for(const n of t.removed)this.removeBlock(n)}handleHtmlEffects(e,t){const{blocks:n,regions:i,changes:r}=t;for(const s of r.added){const l=e[s];if(!l)continue;const h=n[s];if(!h){console.warn(`Block data not found for ${s}`);continue}if(h.disabled){console.debug(`Skipping disabled block ${s} during add operation`);continue}const p=this.calculatePosition(h,i,n);this.insertBlock(h,l,p)}for(const s of r.updated){const l=e[s];if(!l)continue;const h=n[s];if(!h){console.warn(`Block data not found for ${s}`);continue}if(h.disabled)continue;if(!!this.getElementCached(s))this.updateBlockHtml(h,l);else{const G=this.calculatePosition(h,i,n);this.insertBlock(h,l,G)}}}isValidMoveInstruction(e){const t=!!(e.toParent||e.toRegion),n=e.toIndex===void 0||e.toIndex>=0;return t&&n}removeBlock(e){const t=this.getElementCached(e);t?(this.previewClient.emit("block.remove.before",{blockId:e,element:t}),t.remove(),this.elementCache.delete(e),this.previewClient.emit("block.remove.after",{blockId:e,element:t})):console.warn(`Block ${e} not found for removal`)}moveBlockUsingDOM(e,t){const n=this.getElementCached(e.id),{toParent:i,toRegion:r,toIndex:s}=t;if(!n){console.warn(`Block element ${e.id} not found for move operation`);return}if(this.previewClient.emit("block.move.before",{blockId:e.id,blockType:e.type,block:e,element:n,toParent:i,toRegion:r,toIndex:s}),i){const l=this.getElementCached(i);if(!l){console.error(`Parent element ${i} not found for move operation`);return}this.insertElementInContainer(n,l,e.id,s)}else if(r){const l=this.findRegionInsertionPoint(r,s,void 0,void 0,e.id);if(!l){console.error(`Failed to find insertion point for region: ${r}`);return}l.parent.insertBefore(n,l.before)}this.previewClient.emit("block.move.after",{blockId:e.id,blockType:e.type,block:e,element:n,toParent:i,toRegion:r,toIndex:s})}insertElementInContainer(e,t,n,i){const s=Array.from(t.children).filter(h=>h.getAttribute("data-block")!==n),l=i!==void 0&&i<s.length?s[i]:null;t.insertBefore(e,l)}insertBlock(e,t,n){if(this.getElementCached(e.id))return;this.previewClient.emit("block.insert.before",{blockId:e.id,blockType:e.type,block:e,html:t,positionInfo:n});const i=this.parseHtmlElement(t,e.id);if(!i)return;const{parentId:r,regionName:s,position:l,afterId:h,beforeId:p}=n;if(r){const v=this.getElementCached(r);if(!v){console.error(`Parent element ${r} not found for block ${e.id}`);return}this.insertElementByPosition(i,v,l,h,p)}else if(s){const v=this.findRegionInsertionPoint(s,l,h,p);if(!v){console.error(`Failed to find insertion point for region: ${s}`);return}v.parent.insertBefore(i,v.before)}else console.warn(`No parent or region specified for block ${e.id}, inserting into body`),document.body.appendChild(i);this.elementCache.set(e.id,i),this.previewClient.emit("block.insert.after",{blockId:e.id,blockType:e.type,block:e,html:t,positionInfo:n})}updateBlockHtml(e,t){if(!t){console.warn(`No HTML provided for block ${e.id}`);return}const n=this.getElementCached(e.id);if(!n){console.warn(`Block element ${e.id} not found for HTML update`);return}this.previewClient.emit("block.update.before",{blockId:e.id,blockType:e.type,block:e,element:n,html:t}),Be(n,t,this.morphdomOptions),this.elementCache.delete(e.id),this.previewClient.emit("block.update.after",{blockId:e.id,blockType:e.type,block:e,element:n,html:t})}insertElementByPosition(e,t,n,i,r){let s=null;if(r)s=this.getElementCached(r);else if(i){const l=this.getElementCached(i);l&&(s=l.nextElementSibling)}else typeof n=="number"&&(s=Array.from(t.children)[n]||null);t.insertBefore(e,s)}findRegionInsertionPoint(e,t,n,i,r){const s=this.regionCommentsCache.get(e);if(!s)return console.error(`Region comments not found for region: ${e}`),null;const{begin:l,end:h}=s;let p=null;if(i){const v=this.getElementCached(i);v&&(p=v)}else if(n){const v=this.getElementCached(n);v&&v.nextSibling&&(p=v.nextSibling)}else typeof t=="number"&&(p=this.findPositionInRegion(l,h,t,r));return p||(p=h),{parent:l.parentNode,before:p}}findPositionInRegion(e,t,n,i){const r=[];let s=e.nextSibling;for(;s&&s!==t;){if(s.nodeType===Node.ELEMENT_NODE&&s.hasAttribute("data-block")){const l=s.getAttribute("data-block");(!i||l!==i)&&r.push(s)}s=s.nextSibling}return n<r.length?r[n]:null}calculatePosition(e,t,n){if(e.parentId){const i=n[e.parentId];i||console.warn(`Block data not found for block ${e.id}`);const r=i.children.indexOf(e.id);if(r===-1)return console.warn(`Block ${e.id} not found in parent ${e.parentId} children`),{parentId:e.parentId};const{afterId:s,beforeId:l}=this.findAdjacentSiblings(i.children,r,n);return{parentId:e.parentId,position:r,afterId:s,beforeId:l}}else{for(const i of t){const r=i.blocks.indexOf(e.id);if(r!==-1){const{afterId:s,beforeId:l}=this.findAdjacentSiblings(i.blocks,r,n);return{regionName:i.name,position:r,afterId:s,beforeId:l}}}return{}}}findAdjacentSiblings(e,t,n){let i,r;for(let s=t-1;s>=0;s--){const l=n[e[s]];if(l&&!l.disabled){i=e[s];break}}for(let s=t+1;s<e.length;s++){const l=n[e[s]];if(l&&!l.disabled){r=e[s];break}}return{afterId:i,beforeId:r}}parseHtmlElement(e,t){if(!e.trim())return console.error(`Empty HTML provided for block ${t}`),null;const n=document.createElement("div");n.innerHTML=e;const i=n.firstElementChild;return i||(console.error(`Invalid HTML for block ${t}: no element found`),null)}}return F})();\n',E=(d={})=>({editor:l})=>{const a=new Map;l.events.on("updates",v),u();function f(e){return`data-block="${e}"`}function u(){l.preview.loadFromHtml(m(l.engine.getPage()))}function h(e,n){const i=`${e.id}:${JSON.stringify(e.properties)}:${e.children.join(",")}`;if(a.has(i))return a.get(i);let o;if(d.blockRenderers?.[e.type])o=d.blockRenderers[e.type];else{const r=l.engine.getBlockSchema(e.type);o=typeof r?.meta?.render=="function"?r.meta.render:({block:k,editorAttributes:C})=>`<div ${C}><em>Unknown block type: ${k.type}</em></div>`}const t=Array.isArray(e.children)?e.children.map(r=>h(n[r],n)).join(""):"",s=f(e.id);let c;try{c=o({id:e.id,props:e.properties,block:e,editorAttributes:s,children:t})}catch(r){console.warn(`Render error for block ${e.id}:`,r),c=`<div ${s} class="render-error">
|
|
2
|
+
<em>⚠️ Render Error: ${r instanceof Error?r.message:"Unknown error"}</em>
|
|
3
|
+
</div>`}return a.set(i,c),c}function m(e){const n=(e.regions??[]).map(t=>{const s=t.blocks.map(c=>h(e.blocks[c],e.blocks)).join(`
|
|
4
|
+
`);return`<!--BEGIN region: ${t.name}-->
|
|
5
|
+
${s}
|
|
6
|
+
<!--END region: ${t.name}-->`}).join(`
|
|
7
|
+
`),i=(d.styles||[]).map(t=>` <link rel="stylesheet" href="${t}" />`).join(`
|
|
8
|
+
`),o=(d.scripts||[]).map(t=>`<script src="${t}"><\/script>`).join(`
|
|
9
|
+
`);return`
|
|
10
|
+
<!DOCTYPE html>
|
|
11
|
+
<html lang="en">
|
|
12
|
+
<head>
|
|
13
|
+
<meta charset="UTF-8" />
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
15
|
+
${i}
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
${n}
|
|
19
|
+
|
|
20
|
+
${o}
|
|
21
|
+
<script>
|
|
22
|
+
${w}
|
|
23
|
+
window.HtmlPreviewClient.init();
|
|
24
|
+
<\/script>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|
|
27
|
+
`.trim()}function p(e){return e.changes.added.length>0||e.changes.updated.length>0||e.changes.removed.length>0||Object.keys(e.changes.moved||{}).length>0}function v(e){if(!p(e))return;const n=b(e);l.preview.sendMessage("updates.effects",{...e,effects:n})}function b(e){const n=[...e.changes.added,...e.changes.updated];if(n.length===0)return{html:{}};const i=l.engine.getPage().blocks,o={html:{}};return e.changes.removed.forEach(t=>{g(t)}),n.forEach(t=>{const s=i[t];s&&(o.html[t]=h(s,i))}),o}function g(e){for(const n of a.keys())n.startsWith(`${e}:`)&&a.delete(n)}};module.exports=E;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CraftileEditorPlugin } from '@craftile/editor';
|
|
2
|
+
import { Block } from '@craftile/types';
|
|
3
|
+
export interface BlockRenderer {
|
|
4
|
+
(props: {
|
|
5
|
+
id: string;
|
|
6
|
+
props: Record<string, any>;
|
|
7
|
+
block: Block;
|
|
8
|
+
editorAttributes: string;
|
|
9
|
+
children: string;
|
|
10
|
+
}): string;
|
|
11
|
+
}
|
|
12
|
+
export interface StaticBlocksRendererOptions {
|
|
13
|
+
styles?: string[];
|
|
14
|
+
scripts?: string[];
|
|
15
|
+
blockRenderers?: Record<string, BlockRenderer>;
|
|
16
|
+
}
|
|
17
|
+
declare const _default: (options?: StaticBlocksRendererOptions) => CraftileEditorPlugin;
|
|
18
|
+
export default _default;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const w = 'var Te=Object.defineProperty;var Pe=(y,k,m)=>k in y?Te(y,k,{enumerable:!0,configurable:!0,writable:!0,value:m}):y[k]=m;var A=(y,k,m)=>Pe(y,typeof k!="symbol"?k+"":k,m);var HtmlPreviewClient=(function(){"use strict";var y=Object.defineProperty,k=(o,e,t)=>e in o?y(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t,m=(o,e,t)=>k(o,typeof e!="symbol"?e+"":e,t);class re{constructor(e,t="*"){m(this,"handlers",new Map),m(this,"targetWindow"),m(this,"targetOrigin"),m(this,"fallbackHandler"),this.targetWindow=e,this.targetOrigin=t,window.addEventListener("message",this.handleMessage.bind(this))}handleMessage(e){const t=e.data;if(!t.type)return;const n=this.handlers.get(t.type);n?n.forEach(i=>i(t.payload,e)):this.fallbackHandler&&this.fallbackHandler(e.data,e)}send(e,t){const n={type:e,payload:t};this.targetWindow.postMessage(n,this.targetOrigin)}listen(e,t){return this.handlers.has(e)||this.handlers.set(e,[]),this.handlers.get(e).push(t),()=>{const n=this.handlers.get(e);if(n){const i=n.indexOf(t);i>-1&&n.splice(i,1)}}}registerFallbackHandler(e){this.fallbackHandler=e}}function se(o="*"){if(window.parent===window)throw new Error("Not inside an iframe");return new re(window.parent,o)}class oe{constructor(){m(this,"listeners",new Map)}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.off(e,t)}}off(e,t){const n=this.listeners.get(e);n&&(n.delete(t),n.size===0&&this.listeners.delete(e))}once(e,t){const n=i=>{t(i),this.off(e,n)};this.on(e,n)}emit(e,...t){const n=this.listeners.get(e);if(n){const i=t[0];n.forEach(r=>{try{r(i)}catch(s){console.error(`Error in event listener for \'${String(e)}\':`,s)}})}}removeAllListeners(e){e?this.listeners.delete(e):this.listeners.clear()}}class le{constructor(e){m(this,"active",!0),m(this,"messenger"),m(this,"currentHoveredBlock",null),m(this,"currentSelectedBlock",null),m(this,"overlayButtonHovered",!1),m(this,"resizeObserver",null),m(this,"mutationObserver",null),this.messenger=e,this.messenger.listen("craftile.inspector.enable",()=>this.enable()),this.messenger.listen("craftile.inspector.disable",()=>this.disable()),this.messenger.listen("craftile.inspector.overlay-button-enter",this.handleOverlayButtonEnter.bind(this)),this.messenger.listen("craftile.inspector.overlay-button-leave",this.handleOverlayButtonLeave.bind(this)),window.addEventListener("scroll",this.handleScroll.bind(this),{passive:!0}),this.setupGlobalEventListeners()}enable(){this.active=!0,document.body.classList.add("craftile-inspector-active")}disable(){this.active=!1,document.body.classList.remove("craftile-inspector-active"),this.currentHoveredBlock=null,this.currentSelectedBlock=null,this.overlayButtonHovered=!1}handleOverlayButtonEnter(){this.overlayButtonHovered=!0}handleOverlayButtonLeave(e){this.overlayButtonHovered=!1,this.currentHoveredBlock||this.messenger.send("craftile.preview.block-leave")}handleScroll(){this.currentSelectedBlock&&this.sendSelectedBlockPosition(),this.currentHoveredBlock&&this.sendHoveredBlockPosition()}setupGlobalEventListeners(){document.addEventListener("mouseover",this.handleGlobalHover.bind(this)),document.addEventListener("mouseout",this.handleGlobalLeave.bind(this)),document.addEventListener("click",this.handleGlobalClick.bind(this))}handleGlobalHover(e){if(!this.active)return;const t=e.target.closest("[data-block]");t&&(e.stopPropagation(),this.currentHoveredBlock=t,this.sendHoveredBlockPosition())}handleGlobalLeave(e){!this.active||!e.target.closest("[data-block]")||this.overlayButtonHovered||(this.currentHoveredBlock=null,this.messenger.send("craftile.preview.block-leave"))}handleGlobalClick(e){if(this.messenger.send("craftile.preview.click"),!this.active)return;const t=e.target.closest("[data-block]");if(!t)return;e.stopPropagation(),t.getAttribute("data-block")&&(this.currentSelectedBlock=t,this.sendSelectedBlockPosition(),this.trackSelectedBlock())}sendHoveredBlockPosition(){const e=this.computeElementPositioning(this.currentHoveredBlock);this.messenger.send("craftile.preview.block-hover",{blockRect:e.rect,parentRect:e.parentRect,scrollTop:e.scrollTop,scrollLeft:e.scrollLeft,blockId:this.currentHoveredBlock.dataset.block,parentFlexDirection:e.parentFlexDirection})}sendSelectedBlockPosition(e=!1){const t=this.computeElementPositioning(this.currentSelectedBlock);this.messenger.send(e?"craftile.preview.update-selected-block":"craftile.preview.block-select",{blockRect:t.rect,scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,blockId:this.currentSelectedBlock.dataset.block})}trackSelectedBlock(){if(!this.currentSelectedBlock)return;this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null),this.resizeObserver=new ResizeObserver(()=>{this.sendSelectedBlockPosition(!0)}),this.resizeObserver.observe(this.currentSelectedBlock),this.mutationObserver=new MutationObserver(()=>{this.sendSelectedBlockPosition(!0)}),this.mutationObserver.observe(this.currentSelectedBlock,{attributes:!0,subtree:!1});let e=this.currentSelectedBlock.parentElement;for(;e&&(this.mutationObserver.observe(e,{childList:!0,subtree:!1}),e!==document.body);)e=e.parentElement}computeElementPositioning(e){const t=e.getBoundingClientRect(),n=window.pageYOffset||document.documentElement.scrollTop,i=window.pageXOffset||document.documentElement.scrollLeft,r=this.findEldestParentBlock(e),s=r&&r!==e?r.getBoundingClientRect():void 0,l=this.getElementFlexDirection(e.parentElement);return{rect:t,parentRect:s,scrollTop:n,scrollLeft:i,parentFlexDirection:l}}findEldestParentBlock(e){let t=null,n=e.parentElement;for(;n&&n!==document.body;)n.hasAttribute("data-block")&&(t=n),n=n.parentElement;return t}getElementFlexDirection(e){if(!e)return"column";const t=window.getComputedStyle(e),n=t.display.includes("flex")?t.flexDirection:"column";return n==="row"||n==="row-reverse"?"row":"column"}}class ae extends oe{constructor(){super(),m(this,"messenger"),m(this,"inspector"),this.messenger=se(window.origin),this.inspector=new le(this.messenger),this.initialize()}initialize(){window.addEventListener("load",()=>{this.messenger.send("craftile.preview.ready",{})}),document.addEventListener("DOMContentLoaded",()=>{this.sendPageData()}),this.messenger.registerFallbackHandler(e=>{const{type:t,payload:n}=e;this.emit(t,n)})}sendPageData(){const e=document.getElementById("page-data");if(e)try{const t=JSON.parse(e.textContent||"{}");this.messenger.send("craftile.preview.page-data",{pageData:t})}catch(t){console.error("Failed to parse page data:",t)}}}var Y=11;function ce(o,e){var t=e.attributes,n,i,r,s,l;if(!(e.nodeType===Y||o.nodeType===Y)){for(var h=t.length-1;h>=0;h--)n=t[h],i=n.name,r=n.namespaceURI,s=n.value,r?(i=n.localName||i,l=o.getAttributeNS(r,i),l!==s&&(n.prefix==="xmlns"&&(i=n.name),o.setAttributeNS(r,i,s))):(l=o.getAttribute(i),l!==s&&o.setAttribute(i,s));for(var p=o.attributes,v=p.length-1;v>=0;v--)n=p[v],i=n.name,r=n.namespaceURI,r?(i=n.localName||i,e.hasAttributeNS(r,i)||o.removeAttributeNS(r,i)):e.hasAttribute(i)||o.removeAttribute(i)}}var H,de="http://www.w3.org/1999/xhtml",b=typeof document>"u"?void 0:document,fe=!!b&&"content"in b.createElement("template"),he=!!b&&b.createRange&&"createContextualFragment"in b.createRange();function ue(o){var e=b.createElement("template");return e.innerHTML=o,e.content.childNodes[0]}function ve(o){H||(H=b.createRange(),H.selectNode(b.body));var e=H.createContextualFragment(o);return e.childNodes[0]}function me(o){var e=b.createElement("body");return e.innerHTML=o,e.childNodes[0]}function pe(o){return o=o.trim(),fe?ue(o):he?ve(o):me(o)}function I(o,e){var t=o.nodeName,n=e.nodeName,i,r;return t===n?!0:(i=t.charCodeAt(0),r=n.charCodeAt(0),i<=90&&r>=97?t===n.toUpperCase():r<=90&&i>=97?n===t.toUpperCase():!1)}function ge(o,e){return!e||e===de?b.createElement(o):b.createElementNS(e,o)}function be(o,e){for(var t=o.firstChild;t;){var n=t.nextSibling;e.appendChild(t),t=n}return e}function _(o,e,t){o[t]!==e[t]&&(o[t]=e[t],o[t]?o.setAttribute(t,""):o.removeAttribute(t))}var q={OPTION:function(o,e){var t=o.parentNode;if(t){var n=t.nodeName.toUpperCase();n==="OPTGROUP"&&(t=t.parentNode,n=t&&t.nodeName.toUpperCase()),n==="SELECT"&&!t.hasAttribute("multiple")&&(o.hasAttribute("selected")&&!e.selected&&(o.setAttribute("selected","selected"),o.removeAttribute("selected")),t.selectedIndex=-1)}_(o,e,"selected")},INPUT:function(o,e){_(o,e,"checked"),_(o,e,"disabled"),o.value!==e.value&&(o.value=e.value),e.hasAttribute("value")||o.removeAttribute("value")},TEXTAREA:function(o,e){var t=e.value;o.value!==t&&(o.value=t);var n=o.firstChild;if(n){var i=n.nodeValue;if(i==t||!t&&i==o.placeholder)return;n.nodeValue=t}},SELECT:function(o,e){if(!e.hasAttribute("multiple")){for(var t=-1,n=0,i=o.firstChild,r,s;i;)if(s=i.nodeName&&i.nodeName.toUpperCase(),s==="OPTGROUP")r=i,i=r.firstChild,i||(i=r.nextSibling,r=null);else{if(s==="OPTION"){if(i.hasAttribute("selected")){t=n;break}n++}i=i.nextSibling,!i&&r&&(i=r.nextSibling,r=null)}o.selectedIndex=t}}},P=1,J=11,Q=3,Z=8;function B(){}function ke(o){if(o)return o.getAttribute&&o.getAttribute("id")||o.id}function we(o){return function(t,n,i){if(i||(i={}),typeof n=="string")if(t.nodeName==="#document"||t.nodeName==="HTML"||t.nodeName==="BODY"){var r=n;n=b.createElement("html"),n.innerHTML=r}else n=pe(n);else n.nodeType===J&&(n=n.firstElementChild);var s=i.getNodeKey||ke,l=i.onBeforeNodeAdded||B,h=i.onNodeAdded||B,p=i.onBeforeElUpdated||B,v=i.onElUpdated||B,G=i.onBeforeNodeDiscarded||B,N=i.onNodeDiscarded||B,Ee=i.onBeforeElChildrenUpdated||B,Ce=i.skipFromChildren||B,ee=i.addChild||function(a,c){return a.appendChild(c)},V=i.childrenOnly===!0,S=Object.create(null),L=[];function M(a){L.push(a)}function te(a,c){if(a.nodeType===P)for(var u=a.firstChild;u;){var d=void 0;c&&(d=s(u))?M(d):(N(u),u.firstChild&&te(u,c)),u=u.nextSibling}}function x(a,c,u){G(a)!==!1&&(c&&c.removeChild(a),N(a),te(a,u))}function z(a){if(a.nodeType===P||a.nodeType===J)for(var c=a.firstChild;c;){var u=s(c);u&&(S[u]=c),z(c),c=c.nextSibling}}z(t);function W(a){h(a);for(var c=a.firstChild;c;){var u=c.nextSibling,d=s(c);if(d){var f=S[d];f&&I(c,f)?(c.parentNode.replaceChild(f,c),D(f,c)):W(c)}else W(c);c=u}}function ye(a,c,u){for(;c;){var d=c.nextSibling;(u=s(c))?M(u):x(c,a,!0),c=d}}function D(a,c,u){var d=s(c);if(d&&delete S[d],!u){var f=p(a,c);if(f===!1||(f instanceof HTMLElement&&(a=f,z(a)),o(a,c),v(a),Ee(a,c)===!1))return}a.nodeName!=="TEXTAREA"?Se(a,c):q.TEXTAREA(a,c)}function Se(a,c){var u=Ce(a,c),d=c.firstChild,f=a.firstChild,O,w,T,$,E;e:for(;d;){for($=d.nextSibling,O=s(d);!u&&f;){if(T=f.nextSibling,d.isSameNode&&d.isSameNode(f)){d=$,f=T;continue e}w=s(f);var U=f.nodeType,C=void 0;if(U===d.nodeType&&(U===P?(O?O!==w&&((E=S[O])?T===E?C=!1:(a.insertBefore(E,f),w?M(w):x(f,a,!0),f=E,w=s(f)):C=!1):w&&(C=!1),C=C!==!1&&I(f,d),C&&D(f,d)):(U===Q||U==Z)&&(C=!0,f.nodeValue!==d.nodeValue&&(f.nodeValue=d.nodeValue))),C){d=$,f=T;continue e}w?M(w):x(f,a,!0),f=T}if(O&&(E=S[O])&&I(E,d))u||ee(a,E),D(E,d);else{var j=l(d);j!==!1&&(j&&(d=j),d.actualize&&(d=d.actualize(a.ownerDocument||b)),ee(a,d),W(d))}d=$,f=T}ye(a,f,w);var ie=q[a.nodeName];ie&&ie(a,c)}var g=t,R=g.nodeType,ne=n.nodeType;if(!V){if(R===P)ne===P?I(t,n)||(N(t),g=be(t,ge(n.nodeName,n.namespaceURI))):g=n;else if(R===Q||R===Z){if(ne===R)return g.nodeValue!==n.nodeValue&&(g.nodeValue=n.nodeValue),g;g=n}}if(g===n)N(t);else{if(n.isSameNode&&n.isSameNode(g))return;if(D(g,n,V),L)for(var X=0,Oe=L.length;X<Oe;X++){var K=S[L[X]];K&&x(K,K.parentNode,!1)}}return!V&&g!==t&&t.parentNode&&(g.actualize&&(g=g.actualize(t.ownerDocument||b)),t.parentNode.replaceChild(g,t)),g}}var Be=we(ce);class F{constructor(e,t){A(this,"previewClient");A(this,"morphdomOptions");A(this,"elementCache",new Map);A(this,"regionCommentsCache",new Map);this.previewClient=e||new ae,this.morphdomOptions=t?.morphdom||{},this.previewClient.on("updates.effects",this.handleEffects.bind(this)),this.previewClient.on("craftile.editor.updates",this.handleDirectUpdates.bind(this)),this.cacheRegionComments()}static init(e,t){return new F(e,t)}getElementCached(e){if(this.elementCache.has(e)){const n=this.elementCache.get(e);if(n.isConnected)return n;this.elementCache.delete(e)}const t=document.querySelector(`[data-block="${e}"]`);return t&&this.elementCache.set(e,t),t}cacheRegionComments(){const e=document.createTreeWalker(document.body,NodeFilter.SHOW_COMMENT,null);let t;const n=new Map;for(;t=e.nextNode();){const i=t.textContent?.trim();if(i){if(i.startsWith("BEGIN region: ")){const r=i.substring(14);n.set(r,t)}else if(i.startsWith("END region: ")){const r=i.substring(12),s=n.get(r);s&&(this.regionCommentsCache.set(r,{begin:s,end:t}),n.delete(r))}}}}invalidateCache(e){[...e.updated,...e.removed].forEach(t=>{this.elementCache.delete(t)})}handleEffects(e){const{effects:t,blocks:n,regions:i,changes:r}=e;t&&(this.invalidateCache(r),t.html&&this.handleHtmlEffects(t.html,{blocks:n,regions:i,changes:r}))}handleDirectUpdates(e){const{changes:t}=e;t.moved&&this.handleMoves(e),t.updated.length>0&&this.handleDisabledBlocks(e),t.removed.length>0&&this.handleRemoves(e)}handleMoves(e){const{blocks:t,changes:n}=e;for(const[i,r]of Object.entries(e.changes.moved)){if(r?.toParent&&n.updated?.includes(r?.toParent))continue;if(!this.isValidMoveInstruction(r)){console.warn(`Invalid move instruction for block ${i}:`,r);continue}const s=t[i];this.moveBlockUsingDOM(s,r)}}handleDisabledBlocks(e){const{blocks:t,changes:n}=e;for(const i of n.updated){const r=t[i];if(!r)continue;const l=!!this.getElementCached(i);r.disabled&&l?this.removeBlock(r.id):r.disabled}}handleRemoves(e){const{changes:t}=e;for(const n of t.removed)this.removeBlock(n)}handleHtmlEffects(e,t){const{blocks:n,regions:i,changes:r}=t;for(const s of r.added){const l=e[s];if(!l)continue;const h=n[s];if(!h){console.warn(`Block data not found for ${s}`);continue}if(h.disabled){console.debug(`Skipping disabled block ${s} during add operation`);continue}const p=this.calculatePosition(h,i,n);this.insertBlock(h,l,p)}for(const s of r.updated){const l=e[s];if(!l)continue;const h=n[s];if(!h){console.warn(`Block data not found for ${s}`);continue}if(h.disabled)continue;if(!!this.getElementCached(s))this.updateBlockHtml(h,l);else{const G=this.calculatePosition(h,i,n);this.insertBlock(h,l,G)}}}isValidMoveInstruction(e){const t=!!(e.toParent||e.toRegion),n=e.toIndex===void 0||e.toIndex>=0;return t&&n}removeBlock(e){const t=this.getElementCached(e);t?(this.previewClient.emit("block.remove.before",{blockId:e,element:t}),t.remove(),this.elementCache.delete(e),this.previewClient.emit("block.remove.after",{blockId:e,element:t})):console.warn(`Block ${e} not found for removal`)}moveBlockUsingDOM(e,t){const n=this.getElementCached(e.id),{toParent:i,toRegion:r,toIndex:s}=t;if(!n){console.warn(`Block element ${e.id} not found for move operation`);return}if(this.previewClient.emit("block.move.before",{blockId:e.id,blockType:e.type,block:e,element:n,toParent:i,toRegion:r,toIndex:s}),i){const l=this.getElementCached(i);if(!l){console.error(`Parent element ${i} not found for move operation`);return}this.insertElementInContainer(n,l,e.id,s)}else if(r){const l=this.findRegionInsertionPoint(r,s,void 0,void 0,e.id);if(!l){console.error(`Failed to find insertion point for region: ${r}`);return}l.parent.insertBefore(n,l.before)}this.previewClient.emit("block.move.after",{blockId:e.id,blockType:e.type,block:e,element:n,toParent:i,toRegion:r,toIndex:s})}insertElementInContainer(e,t,n,i){const s=Array.from(t.children).filter(h=>h.getAttribute("data-block")!==n),l=i!==void 0&&i<s.length?s[i]:null;t.insertBefore(e,l)}insertBlock(e,t,n){if(this.getElementCached(e.id))return;this.previewClient.emit("block.insert.before",{blockId:e.id,blockType:e.type,block:e,html:t,positionInfo:n});const i=this.parseHtmlElement(t,e.id);if(!i)return;const{parentId:r,regionName:s,position:l,afterId:h,beforeId:p}=n;if(r){const v=this.getElementCached(r);if(!v){console.error(`Parent element ${r} not found for block ${e.id}`);return}this.insertElementByPosition(i,v,l,h,p)}else if(s){const v=this.findRegionInsertionPoint(s,l,h,p);if(!v){console.error(`Failed to find insertion point for region: ${s}`);return}v.parent.insertBefore(i,v.before)}else console.warn(`No parent or region specified for block ${e.id}, inserting into body`),document.body.appendChild(i);this.elementCache.set(e.id,i),this.previewClient.emit("block.insert.after",{blockId:e.id,blockType:e.type,block:e,html:t,positionInfo:n})}updateBlockHtml(e,t){if(!t){console.warn(`No HTML provided for block ${e.id}`);return}const n=this.getElementCached(e.id);if(!n){console.warn(`Block element ${e.id} not found for HTML update`);return}this.previewClient.emit("block.update.before",{blockId:e.id,blockType:e.type,block:e,element:n,html:t}),Be(n,t,this.morphdomOptions),this.elementCache.delete(e.id),this.previewClient.emit("block.update.after",{blockId:e.id,blockType:e.type,block:e,element:n,html:t})}insertElementByPosition(e,t,n,i,r){let s=null;if(r)s=this.getElementCached(r);else if(i){const l=this.getElementCached(i);l&&(s=l.nextElementSibling)}else typeof n=="number"&&(s=Array.from(t.children)[n]||null);t.insertBefore(e,s)}findRegionInsertionPoint(e,t,n,i,r){const s=this.regionCommentsCache.get(e);if(!s)return console.error(`Region comments not found for region: ${e}`),null;const{begin:l,end:h}=s;let p=null;if(i){const v=this.getElementCached(i);v&&(p=v)}else if(n){const v=this.getElementCached(n);v&&v.nextSibling&&(p=v.nextSibling)}else typeof t=="number"&&(p=this.findPositionInRegion(l,h,t,r));return p||(p=h),{parent:l.parentNode,before:p}}findPositionInRegion(e,t,n,i){const r=[];let s=e.nextSibling;for(;s&&s!==t;){if(s.nodeType===Node.ELEMENT_NODE&&s.hasAttribute("data-block")){const l=s.getAttribute("data-block");(!i||l!==i)&&r.push(s)}s=s.nextSibling}return n<r.length?r[n]:null}calculatePosition(e,t,n){if(e.parentId){const i=n[e.parentId];i||console.warn(`Block data not found for block ${e.id}`);const r=i.children.indexOf(e.id);if(r===-1)return console.warn(`Block ${e.id} not found in parent ${e.parentId} children`),{parentId:e.parentId};const{afterId:s,beforeId:l}=this.findAdjacentSiblings(i.children,r,n);return{parentId:e.parentId,position:r,afterId:s,beforeId:l}}else{for(const i of t){const r=i.blocks.indexOf(e.id);if(r!==-1){const{afterId:s,beforeId:l}=this.findAdjacentSiblings(i.blocks,r,n);return{regionName:i.name,position:r,afterId:s,beforeId:l}}}return{}}}findAdjacentSiblings(e,t,n){let i,r;for(let s=t-1;s>=0;s--){const l=n[e[s]];if(l&&!l.disabled){i=e[s];break}}for(let s=t+1;s<e.length;s++){const l=n[e[s]];if(l&&!l.disabled){r=e[s];break}}return{afterId:i,beforeId:r}}parseHtmlElement(e,t){if(!e.trim())return console.error(`Empty HTML provided for block ${t}`),null;const n=document.createElement("div");n.innerHTML=e;const i=n.firstElementChild;return i||(console.error(`Invalid HTML for block ${t}: no element found`),null)}}return F})();\n', E = (d = {}) => ({ editor: l }) => {
|
|
2
|
+
const a = /* @__PURE__ */ new Map();
|
|
3
|
+
l.events.on("updates", v), u();
|
|
4
|
+
function f(e) {
|
|
5
|
+
return `data-block="${e}"`;
|
|
6
|
+
}
|
|
7
|
+
function u() {
|
|
8
|
+
l.preview.loadFromHtml(m(l.engine.getPage()));
|
|
9
|
+
}
|
|
10
|
+
function h(e, n) {
|
|
11
|
+
const i = `${e.id}:${JSON.stringify(e.properties)}:${e.children.join(",")}`;
|
|
12
|
+
if (a.has(i))
|
|
13
|
+
return a.get(i);
|
|
14
|
+
let o;
|
|
15
|
+
if (d.blockRenderers?.[e.type])
|
|
16
|
+
o = d.blockRenderers[e.type];
|
|
17
|
+
else {
|
|
18
|
+
const r = l.engine.getBlockSchema(e.type);
|
|
19
|
+
o = typeof r?.meta?.render == "function" ? r.meta.render : ({ block: k, editorAttributes: C }) => `<div ${C}><em>Unknown block type: ${k.type}</em></div>`;
|
|
20
|
+
}
|
|
21
|
+
const t = Array.isArray(e.children) ? e.children.map((r) => h(n[r], n)).join("") : "", s = f(e.id);
|
|
22
|
+
let c;
|
|
23
|
+
try {
|
|
24
|
+
c = o({ id: e.id, props: e.properties, block: e, editorAttributes: s, children: t });
|
|
25
|
+
} catch (r) {
|
|
26
|
+
console.warn(`Render error for block ${e.id}:`, r), c = `<div ${s} class="render-error">
|
|
27
|
+
<em>⚠️ Render Error: ${r instanceof Error ? r.message : "Unknown error"}</em>
|
|
28
|
+
</div>`;
|
|
29
|
+
}
|
|
30
|
+
return a.set(i, c), c;
|
|
31
|
+
}
|
|
32
|
+
function m(e) {
|
|
33
|
+
const n = (e.regions ?? []).map((t) => {
|
|
34
|
+
const s = t.blocks.map((c) => h(e.blocks[c], e.blocks)).join(`
|
|
35
|
+
`);
|
|
36
|
+
return `<!--BEGIN region: ${t.name}-->
|
|
37
|
+
${s}
|
|
38
|
+
<!--END region: ${t.name}-->`;
|
|
39
|
+
}).join(`
|
|
40
|
+
`), i = (d.styles || []).map((t) => ` <link rel="stylesheet" href="${t}" />`).join(`
|
|
41
|
+
`), o = (d.scripts || []).map((t) => `<script src="${t}"><\/script>`).join(`
|
|
42
|
+
`);
|
|
43
|
+
return `
|
|
44
|
+
<!DOCTYPE html>
|
|
45
|
+
<html lang="en">
|
|
46
|
+
<head>
|
|
47
|
+
<meta charset="UTF-8" />
|
|
48
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
49
|
+
${i}
|
|
50
|
+
</head>
|
|
51
|
+
<body>
|
|
52
|
+
${n}
|
|
53
|
+
|
|
54
|
+
${o}
|
|
55
|
+
<script>
|
|
56
|
+
${w}
|
|
57
|
+
window.HtmlPreviewClient.init();
|
|
58
|
+
<\/script>
|
|
59
|
+
</body>
|
|
60
|
+
</html>
|
|
61
|
+
`.trim();
|
|
62
|
+
}
|
|
63
|
+
function p(e) {
|
|
64
|
+
return e.changes.added.length > 0 || e.changes.updated.length > 0 || e.changes.removed.length > 0 || Object.keys(e.changes.moved || {}).length > 0;
|
|
65
|
+
}
|
|
66
|
+
function v(e) {
|
|
67
|
+
if (!p(e))
|
|
68
|
+
return;
|
|
69
|
+
const n = b(e);
|
|
70
|
+
l.preview.sendMessage("updates.effects", { ...e, effects: n });
|
|
71
|
+
}
|
|
72
|
+
function b(e) {
|
|
73
|
+
const n = [...e.changes.added, ...e.changes.updated];
|
|
74
|
+
if (n.length === 0)
|
|
75
|
+
return { html: {} };
|
|
76
|
+
const i = l.engine.getPage().blocks, o = {
|
|
77
|
+
html: {}
|
|
78
|
+
};
|
|
79
|
+
return e.changes.removed.forEach((t) => {
|
|
80
|
+
g(t);
|
|
81
|
+
}), n.forEach((t) => {
|
|
82
|
+
const s = i[t];
|
|
83
|
+
s && (o.html[t] = h(s, i));
|
|
84
|
+
}), o;
|
|
85
|
+
}
|
|
86
|
+
function g(e) {
|
|
87
|
+
for (const n of a.keys())
|
|
88
|
+
n.startsWith(`${e}:`) && a.delete(n);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
export {
|
|
92
|
+
E as default
|
|
93
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@craftile/plugin-static-blocks-renderer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Craftile plugin for static HTML block rendering",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"craftile",
|
|
7
|
+
"plugin",
|
|
8
|
+
"static",
|
|
9
|
+
"rendering",
|
|
10
|
+
"blocks"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"authors": [
|
|
14
|
+
{
|
|
15
|
+
"name": "Eldo Magan",
|
|
16
|
+
"email": "magan.eldo@gmail.com"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "dist/index.cjs",
|
|
21
|
+
"module": "dist/index.js",
|
|
22
|
+
"types": "dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"source": "./src/index.ts",
|
|
27
|
+
"import": "./dist/index.js",
|
|
28
|
+
"require": "./dist/index.cjs"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"typescript": "~5.8.3",
|
|
36
|
+
"vite": "^7.0.0",
|
|
37
|
+
"vite-plugin-dts": "^4.5.4",
|
|
38
|
+
"@craftile/core": "0.1.0",
|
|
39
|
+
"@craftile/editor": "0.1.0",
|
|
40
|
+
"@craftile/preview-client-html": "0.1.0",
|
|
41
|
+
"@craftile/types": "0.1.0"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/craftile/editor.git"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"dev": "tsc && vite build --watch",
|
|
52
|
+
"build": "tsc && vite build"
|
|
53
|
+
}
|
|
54
|
+
}
|