@craftile/preview-client-html 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/html.cdn.js CHANGED
@@ -1 +1 @@
1
- var Te=Object.defineProperty;var Ne=(y,C,v)=>C in y?Te(y,C,{enumerable:!0,configurable:!0,writable:!0,value:v}):y[C]=v;var w=(y,C,v)=>Ne(y,typeof C!="symbol"?C+"":C,v);var HtmlPreviewClient=(function(){"use strict";var y=Object.defineProperty,C=(o,e,t)=>e in o?y(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t,v=(o,e,t)=>C(o,typeof e!="symbol"?e+"":e,t);class ie{constructor(e,t="*"){v(this,"handlers",new Map),v(this,"targetWindow"),v(this,"targetOrigin"),v(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 re(o="*"){if(window.parent===window)throw new Error("Not inside an iframe");return new ie(window.parent,o)}class se{constructor(){v(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 oe{constructor(e){v(this,"active",!0),v(this,"messenger"),v(this,"currentHoveredBlock",null),v(this,"currentSelectedBlock",null),v(this,"overlayButtonHovered",!1),v(this,"resizeObserver",null),v(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)),this.messenger.listen("craftile.editor.select-block",this.handleEditorSelectBlock.bind(this)),this.messenger.listen("craftile.editor.deselect-block",this.handleEditorDeselectBlock.bind(this)),window.addEventListener("scroll",this.handleScroll.bind(this),{passive:!0}),this.setupGlobalEventListeners()}updateTrackedElement(e,t){this.currentHoveredBlock?.dataset.block===e&&(this.currentHoveredBlock=t,this.sendHoveredBlockPosition()),this.currentSelectedBlock?.dataset.block===e&&(this.currentSelectedBlock=t,requestAnimationFrame(()=>{this.sendSelectedBlockPosition(!0)}),this.trackSelectedBlock())}enable(){this.active=!0,document.body.classList.add("craftile-inspector-active"),this.currentSelectedBlock&&this.trackSelectedBlock()}disable(){this.active=!1,document.body.classList.remove("craftile-inspector-active"),this.currentHoveredBlock=null,this.overlayButtonHovered=!1,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null)}handleOverlayButtonEnter(){this.overlayButtonHovered=!0}handleOverlayButtonLeave(e){this.overlayButtonHovered=!1,this.currentHoveredBlock||this.messenger.send("craftile.preview.block-leave")}handleEditorSelectBlock(e){const t=document.querySelector(`[data-block="${e.blockId}"]`);t&&(this.currentSelectedBlock=t,this.sendSelectedBlockPosition(),this.trackSelectedBlock(),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"}))}handleEditorDeselectBlock(){this.currentSelectedBlock=null,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null)}handleScroll(){this.active&&(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),{capture:!0})}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||!t.getAttribute("data-block"))return;this.currentSelectedBlock===t||(e.preventDefault(),e.stopImmediatePropagation(),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){if(!this.currentSelectedBlock)return;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.active&&this.currentSelectedBlock&&this.sendSelectedBlockPosition(!0)}),this.resizeObserver.observe(this.currentSelectedBlock),this.mutationObserver=new MutationObserver(()=>{this.active&&this.currentSelectedBlock&&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 le extends se{constructor(){super(),v(this,"messenger"),v(this,"inspector"),this.messenger=re(window.origin),this.inspector=new oe(this.messenger),this.initialize()}initialize(){window.addEventListener("load",()=>{this.messenger.send("craftile.preview.ready",{}),setTimeout(()=>{this.sendPageData()},0)}),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 q=11;function ce(o,e){var t=e.attributes,n,i,r,s,l;if(!(e.nodeType===q||o.nodeType===q)){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 u=o.attributes,m=u.length-1;m>=0;m--)n=u[m],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 A,ae="http://www.w3.org/1999/xhtml",b=typeof document>"u"?void 0:document,de=!!b&&"content"in b.createElement("template"),he=!!b&&b.createRange&&"createContextualFragment"in b.createRange();function fe(o){var e=b.createElement("template");return e.innerHTML=o,e.content.childNodes[0]}function ue(o){A||(A=b.createRange(),A.selectNode(b.body));var e=A.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(),de?fe(o):he?ue(o):me(o)}function P(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 ve(o,e){return!e||e===ae?b.createElement(o):b.createElementNS(e,o)}function ge(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 X={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}}},N=1,Y=11,J=3,Q=8;function k(){}function be(o){if(o)return o.getAttribute&&o.getAttribute("id")||o.id}function Ce(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===Y&&(n=n.firstElementChild);var s=i.getNodeKey||be,l=i.onBeforeNodeAdded||k,h=i.onNodeAdded||k,u=i.onBeforeElUpdated||k,m=i.onElUpdated||k,Se=i.onBeforeNodeDiscarded||k,L=i.onNodeDiscarded||k,Be=i.onBeforeElChildrenUpdated||k,we=i.skipFromChildren||k,Z=i.addChild||function(c,a){return c.appendChild(a)},z=i.childrenOnly===!0,O=Object.create(null),I=[];function H(c){I.push(c)}function ee(c,a){if(c.nodeType===N)for(var p=c.firstChild;p;){var d=void 0;a&&(d=s(p))?H(d):(L(p),p.firstChild&&ee(p,a)),p=p.nextSibling}}function M(c,a,p){Se(c)!==!1&&(a&&a.removeChild(c),L(c),ee(c,p))}function G(c){if(c.nodeType===N||c.nodeType===Y)for(var a=c.firstChild;a;){var p=s(a);p&&(O[p]=a),G(a),a=a.nextSibling}}G(t);function V(c){h(c);for(var a=c.firstChild;a;){var p=a.nextSibling,d=s(a);if(d){var f=O[d];f&&P(a,f)?(a.parentNode.replaceChild(f,a),D(f,a)):V(a)}else V(a);a=p}}function ye(c,a,p){for(;a;){var d=a.nextSibling;(p=s(a))?H(p):M(a,c,!0),a=d}}function D(c,a,p){var d=s(a);if(d&&delete O[d],!p){var f=u(c,a);if(f===!1||(f instanceof HTMLElement&&(c=f,G(c)),o(c,a),m(c),Be(c,a)===!1))return}c.nodeName!=="TEXTAREA"?Oe(c,a):X.TEXTAREA(c,a)}function Oe(c,a){var p=we(c,a),d=a.firstChild,f=c.firstChild,x,E,T,$,S;e:for(;d;){for($=d.nextSibling,x=s(d);!p&&f;){if(T=f.nextSibling,d.isSameNode&&d.isSameNode(f)){d=$,f=T;continue e}E=s(f);var F=f.nodeType,B=void 0;if(F===d.nodeType&&(F===N?(x?x!==E&&((S=O[x])?T===S?B=!1:(c.insertBefore(S,f),E?H(E):M(f,c,!0),f=S,E=s(f)):B=!1):E&&(B=!1),B=B!==!1&&P(f,d),B&&D(f,d)):(F===J||F==Q)&&(B=!0,f.nodeValue!==d.nodeValue&&(f.nodeValue=d.nodeValue))),B){d=$,f=T;continue e}E?H(E):M(f,c,!0),f=T}if(x&&(S=O[x])&&P(S,d))p||Z(c,S),D(S,d);else{var K=l(d);K!==!1&&(K&&(d=K),d.actualize&&(d=d.actualize(c.ownerDocument||b)),Z(c,d),V(d))}d=$,f=T}ye(c,f,E);var ne=X[c.nodeName];ne&&ne(c,a)}var g=t,R=g.nodeType,te=n.nodeType;if(!z){if(R===N)te===N?P(t,n)||(L(t),g=ge(t,ve(n.nodeName,n.namespaceURI))):g=n;else if(R===J||R===Q){if(te===R)return g.nodeValue!==n.nodeValue&&(g.nodeValue=n.nodeValue),g;g=n}}if(g===n)L(t);else{if(n.isSameNode&&n.isSameNode(g))return;if(D(g,n,z),I)for(var W=0,xe=I.length;W<xe;W++){var j=O[I[W]];j&&M(j,j.parentNode,!1)}}return!z&&g!==t&&t.parentNode&&(g.actualize&&(g=g.actualize(t.ownerDocument||b)),t.parentNode.replaceChild(g,t)),g}}var Ee=Ce(ce);const ke=o=>o.id||o.name;class U{constructor(e,t){w(this,"previewClient");w(this,"morphdomOptions");w(this,"elementCache",new Map);w(this,"regionCommentsCache",new Map);w(this,"childrenCommentsCache",new Map);w(this,"pendingScripts",new Set);w(this,"scriptExecutionCount",{total:0,completed:0,failed:0});this.previewClient=e||new le,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(),this.cacheChildrenComments()}static init(e,t){return new U(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))}}}}cacheChildrenComments(){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 children: ")){const r=i.substring(16);n.set(r,t)}else if(i.startsWith("END children: ")){const r=i.substring(14),s=n.get(r);s&&(this.childrenCommentsCache.set(r,{begin:s,end:t}),n.delete(r))}}}}cacheChildrenCommentsForBlock(e){const t=this.getElementCached(e);if(!t)return;this.childrenCommentsCache.delete(e);const n=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT,null);let i,r=null;for(;i=n.nextNode();){const s=i.textContent?.trim();if(s){if(s===`BEGIN children: ${e}`)r=i;else if(s===`END children: ${e}`&&r){this.childrenCommentsCache.set(e,{begin:r,end:i});break}}}}invalidateCache(e){[...e.updated,...e.removed].forEach(t=>{this.elementCache.delete(t),this.childrenCommentsCache.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}),t.css&&this.handleCssEffects(t.css),t.js&&this.handleJsEffects(t.js))}handleCssEffects(e){for(const t of e)this.injectStyleElement(t)}injectStyleElement(e){const t=document.createElement("div");t.innerHTML=e;const n=t.firstElementChild;if(!n||n.tagName!=="STYLE"&&n.tagName!=="LINK"){console.warn("Invalid CSS element provided:",e);return}const i=n.id;if(i){const r=document.getElementById(i);if(r&&(r.tagName==="STYLE"||r.tagName==="LINK")){r.parentNode?.replaceChild(n,r);return}}if(n.tagName==="STYLE"&&!i){const r=n.textContent?.trim();if(r){const s=document.querySelectorAll("style:not([id])");for(const l of s)if(l.textContent?.trim()===r)return}}if(n.tagName==="LINK"&&!i){const r=n.getAttribute("href"),s=n.getAttribute("rel");if(r){const l=document.querySelectorAll("link:not([id])");for(const h of l)if(h.getAttribute("href")===r&&h.getAttribute("rel")===s)return}}document.head.appendChild(n)}handleJsEffects(e){this.pendingScripts.clear(),this.scriptExecutionCount={total:0,completed:0,failed:0};const t=e.filter(n=>n?.trim());if(this.scriptExecutionCount.total=t.length,t.length===0){this.emitScriptExecutionComplete();return}for(const n of t)this.injectScriptElement(n)}injectScriptElement(e){const t=document.createElement("div");t.innerHTML=e;const n=t.firstElementChild;if(!n||n.tagName!=="SCRIPT"){console.warn("Invalid script element provided:",e),this.onScriptCompleted(!1);return}const i=n.id;if(i){const r=document.getElementById(i);if(r&&r.tagName==="SCRIPT"){this.pendingScripts.delete(r),r.parentNode?.replaceChild(n,r),this.trackScriptExecution(n);return}}if(!n.src&&!i){const r=n.textContent?.trim();if(r){const s=document.querySelectorAll("script:not([src]):not([id])");for(const l of s)if(l.textContent?.trim()===r){this.onScriptCompleted(!0);return}}}if(n.src&&!i){const r=n.src,s=document.querySelectorAll("script[src]:not([id])");for(const l of s)if(l.src===r){this.onScriptCompleted(!0);return}}document.head.appendChild(n),this.trackScriptExecution(n)}trackScriptExecution(e){if(e.src){this.pendingScripts.add(e);const t=()=>{this.pendingScripts.delete(e),this.onScriptCompleted(!0),e.removeEventListener("load",t),e.removeEventListener("error",n)},n=()=>{this.pendingScripts.delete(e),this.onScriptCompleted(!1),e.removeEventListener("load",t),e.removeEventListener("error",n)};e.addEventListener("load",t),e.addEventListener("error",n)}else this.onScriptCompleted(!0)}onScriptCompleted(e){e?this.scriptExecutionCount.completed++:this.scriptExecutionCount.failed++,this.scriptExecutionCount.completed+this.scriptExecutionCount.failed>=this.scriptExecutionCount.total&&this.emitScriptExecutionComplete()}emitScriptExecutionComplete(){this.previewClient.emit("scripts.execution.complete",{total:this.scriptExecutionCount.total,completed:this.scriptExecutionCount.completed,failed:this.scriptExecutionCount.failed,success:this.scriptExecutionCount.failed===0})}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}=t;for(const[r,s]of Object.entries(e)){if(!s)continue;const l=n[r];if(!l){console.warn(`Block data not found for ${r}`);continue}if(l.disabled){console.debug(`Skipping disabled block ${r}`);continue}if(!!this.getElementCached(r))this.updateBlockHtml(l,s);else{const m=this.calculatePosition(l,i,n);this.insertBlock(l,s,m)}}}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 r=t.getAttribute("data-block"),s=r?this.childrenCommentsCache.get(r):null;if(s){const l=this.findPositionBetweenComments(s.begin,s.end,i,n);l.parent.insertBefore(e,l.before)}else{const h=Array.from(t.children).filter(m=>m.getAttribute("data-block")!==n),u=i!==void 0&&i<h.length?h[i]:null;t.insertBefore(e,u)}}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,regionId:s,position:l,afterId:h,beforeId:u}=n;if(r){const m=this.getElementCached(r);if(!m){console.error(`Parent element ${r} not found for block ${e.id}`);return}this.insertElementByPosition(i,m,l,h,u)}else if(s){const m=this.findRegionInsertionPoint(s,l,h,u);if(!m){console.error(`Failed to find insertion point for region: ${s}`);return}m.parent.insertBefore(i,m.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.cacheChildrenCommentsForBlock(e.id),i.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"}),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}),Ee(n,t,this.morphdomOptions),this.elementCache.delete(e.id);const i=this.getElementCached(e.id);if(!i){console.error(`Block element ${e.id} not found after morphdom update`);return}i!==n&&this.previewClient.inspector.updateTrackedElement(e.id,i),this.cacheChildrenCommentsForBlock(e.id),this.previewClient.emit("block.update.after",{blockId:e.id,blockType:e.type,block:e,element:i,html:t})}insertElementByPosition(e,t,n,i,r){const s=t.getAttribute("data-block"),l=s?this.childrenCommentsCache.get(s):null;if(l){let h=null;if(r)h=this.getElementCached(r);else if(i){const u=this.getElementCached(i);u&&u.nextSibling&&(h=u.nextSibling)}else if(typeof n=="number"){const u=this.findPositionBetweenComments(l.begin,l.end,n);l.begin.parentNode.insertBefore(e,u.before);return}h||(h=l.end),l.begin.parentNode.insertBefore(e,h)}else{let h=null;if(r)h=this.getElementCached(r);else if(i){const u=this.getElementCached(i);u&&(h=u.nextElementSibling)}else typeof n=="number"&&(h=Array.from(t.children)[n]||null);t.insertBefore(e,h)}}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 u=null;if(i){const m=this.getElementCached(i);m&&(u=m)}else if(n){const m=this.getElementCached(n);m&&m.nextSibling&&(u=m.nextSibling)}else typeof t=="number"&&(u=this.findPositionInRegion(l,h,t,r));return u||(u=h),{parent:l.parentNode,before:u}}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}findPositionBetweenComments(e,t,n,i){let r=null;if(typeof n=="number"){const s=[];let l=e.nextSibling;for(;l&&l!==t;){if(l.nodeType===Node.ELEMENT_NODE&&l.hasAttribute("data-block")){const h=l.getAttribute("data-block");(!i||h!==i)&&s.push(l)}l=l.nextSibling}r=n<s.length?s[n]:null}return r||(r=t),{parent:e.parentNode,before:r}}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{regionId:ke(i),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 U})();
1
+ var Oe=Object.defineProperty;var Te=(x,C,m)=>C in x?Oe(x,C,{enumerable:!0,configurable:!0,writable:!0,value:m}):x[C]=m;var B=(x,C,m)=>Te(x,typeof C!="symbol"?C+"":C,m);var HtmlPreviewClient=(function(){"use strict";var x=Object.defineProperty,C=(s,e,t)=>e in s?x(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t,m=(s,e,t)=>C(s,typeof e!="symbol"?e+"":e,t);class ie{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 re(s="*"){if(window.parent===window)throw new Error("Not inside an iframe");return new ie(window.parent,s)}class se{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(o){console.error(`Error in event listener for '${String(e)}':`,o)}})}}removeAllListeners(e){e?this.listeners.delete(e):this.listeners.clear()}}class oe{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)),this.messenger.listen("craftile.editor.select-block",this.handleEditorSelectBlock.bind(this)),this.messenger.listen("craftile.editor.deselect-block",this.handleEditorDeselectBlock.bind(this)),window.addEventListener("scroll",this.handleScroll.bind(this),{passive:!0}),this.setupGlobalEventListeners()}updateTrackedElement(e,t){this.currentHoveredBlock?.dataset.block===e&&(this.currentHoveredBlock=t,this.sendHoveredBlockPosition()),this.currentSelectedBlock?.dataset.block===e&&(this.currentSelectedBlock=t,requestAnimationFrame(()=>{this.sendSelectedBlockPosition(!0)}),this.trackSelectedBlock())}enable(){this.active=!0,document.body.classList.add("craftile-inspector-active"),this.currentSelectedBlock&&this.trackSelectedBlock()}disable(){this.active=!1,document.body.classList.remove("craftile-inspector-active"),this.currentHoveredBlock=null,this.overlayButtonHovered=!1,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null)}handleOverlayButtonEnter(){this.overlayButtonHovered=!0}handleOverlayButtonLeave(e){this.overlayButtonHovered=!1,this.currentHoveredBlock||this.messenger.send("craftile.preview.block-leave")}handleEditorSelectBlock(e){const t=document.querySelector(`[data-block="${e.blockId}"]`);t&&(this.currentSelectedBlock=t,this.sendSelectedBlockPosition(),this.trackSelectedBlock(),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"}))}handleEditorDeselectBlock(){this.currentSelectedBlock=null,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null)}handleScroll(){this.active&&(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),{capture:!0})}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||!t.getAttribute("data-block"))return;this.currentSelectedBlock===t||(e.preventDefault(),e.stopImmediatePropagation(),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){if(!this.currentSelectedBlock)return;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.active&&this.currentSelectedBlock&&this.sendSelectedBlockPosition(!0)}),this.resizeObserver.observe(this.currentSelectedBlock),this.mutationObserver=new MutationObserver(()=>{this.active&&this.currentSelectedBlock&&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),o=r&&r!==e?r.getBoundingClientRect():void 0,l=this.getElementFlexDirection(e.parentElement);return{rect:t,parentRect:o,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 le extends se{constructor(){super(),m(this,"messenger"),m(this,"inspector"),this.messenger=re(window.origin),this.inspector=new oe(this.messenger),this.initialize()}initialize(){window.addEventListener("load",()=>{this.messenger.send("craftile.preview.ready",{}),setTimeout(()=>{this.sendPageData()},0)}),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 q=11;function ce(s,e){var t=e.attributes,n,i,r,o,l;if(!(e.nodeType===q||s.nodeType===q)){for(var h=t.length-1;h>=0;h--)n=t[h],i=n.name,r=n.namespaceURI,o=n.value,r?(i=n.localName||i,l=s.getAttributeNS(r,i),l!==o&&(n.prefix==="xmlns"&&(i=n.name),s.setAttributeNS(r,i,o))):(l=s.getAttribute(i),l!==o&&s.setAttribute(i,o));for(var p=s.attributes,g=p.length-1;g>=0;g--)n=p[g],i=n.name,r=n.namespaceURI,r?(i=n.localName||i,e.hasAttributeNS(r,i)||s.removeAttributeNS(r,i)):e.hasAttribute(i)||s.removeAttribute(i)}}var P,ae="http://www.w3.org/1999/xhtml",b=typeof document>"u"?void 0:document,de=!!b&&"content"in b.createElement("template"),he=!!b&&b.createRange&&"createContextualFragment"in b.createRange();function fe(s){var e=b.createElement("template");return e.innerHTML=s,e.content.childNodes[0]}function ue(s){P||(P=b.createRange(),P.selectNode(b.body));var e=P.createContextualFragment(s);return e.childNodes[0]}function me(s){var e=b.createElement("body");return e.innerHTML=s,e.childNodes[0]}function ve(s){return s=s.trim(),de?fe(s):he?ue(s):me(s)}function L(s,e){var t=s.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 pe(s,e){return!e||e===ae?b.createElement(s):b.createElementNS(e,s)}function ge(s,e){for(var t=s.firstChild;t;){var n=t.nextSibling;e.appendChild(t),t=n}return e}function U(s,e,t){s[t]!==e[t]&&(s[t]=e[t],s[t]?s.setAttribute(t,""):s.removeAttribute(t))}var X={OPTION:function(s,e){var t=s.parentNode;if(t){var n=t.nodeName.toUpperCase();n==="OPTGROUP"&&(t=t.parentNode,n=t&&t.nodeName.toUpperCase()),n==="SELECT"&&!t.hasAttribute("multiple")&&(s.hasAttribute("selected")&&!e.selected&&(s.setAttribute("selected","selected"),s.removeAttribute("selected")),t.selectedIndex=-1)}U(s,e,"selected")},INPUT:function(s,e){U(s,e,"checked"),U(s,e,"disabled"),s.value!==e.value&&(s.value=e.value),e.hasAttribute("value")||s.removeAttribute("value")},TEXTAREA:function(s,e){var t=e.value;s.value!==t&&(s.value=t);var n=s.firstChild;if(n){var i=n.nodeValue;if(i==t||!t&&i==s.placeholder)return;n.nodeValue=t}},SELECT:function(s,e){if(!e.hasAttribute("multiple")){for(var t=-1,n=0,i=s.firstChild,r,o;i;)if(o=i.nodeName&&i.nodeName.toUpperCase(),o==="OPTGROUP")r=i,i=r.firstChild,i||(i=r.nextSibling,r=null);else{if(o==="OPTION"){if(i.hasAttribute("selected")){t=n;break}n++}i=i.nextSibling,!i&&r&&(i=r.nextSibling,r=null)}s.selectedIndex=t}}},N=1,Y=11,J=3,Q=8;function E(){}function be(s){if(s)return s.getAttribute&&s.getAttribute("id")||s.id}function Ce(s){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=ve(n);else n.nodeType===Y&&(n=n.firstElementChild);var o=i.getNodeKey||be,l=i.onBeforeNodeAdded||E,h=i.onNodeAdded||E,p=i.onBeforeElUpdated||E,g=i.onElUpdated||E,Ee=i.onBeforeNodeDiscarded||E,A=i.onNodeDiscarded||E,Se=i.onBeforeElChildrenUpdated||E,we=i.skipFromChildren||E,Z=i.addChild||function(c,a){return c.appendChild(a)},z=i.childrenOnly===!0,y=Object.create(null),H=[];function I(c){H.push(c)}function ee(c,a){if(c.nodeType===N)for(var u=c.firstChild;u;){var d=void 0;a&&(d=o(u))?I(d):(A(u),u.firstChild&&ee(u,a)),u=u.nextSibling}}function M(c,a,u){Ee(c)!==!1&&(a&&a.removeChild(c),A(c),ee(c,u))}function G(c){if(c.nodeType===N||c.nodeType===Y)for(var a=c.firstChild;a;){var u=o(a);u&&(y[u]=a),G(a),a=a.nextSibling}}G(t);function V(c){h(c);for(var a=c.firstChild;a;){var u=a.nextSibling,d=o(a);if(d){var f=y[d];f&&L(a,f)?(a.parentNode.replaceChild(f,a),D(f,a)):V(a)}else V(a);a=u}}function Be(c,a,u){for(;a;){var d=a.nextSibling;(u=o(a))?I(u):M(a,c,!0),a=d}}function D(c,a,u){var d=o(a);if(d&&delete y[d],!u){var f=p(c,a);if(f===!1||(f instanceof HTMLElement&&(c=f,G(c)),s(c,a),g(c),Se(c,a)===!1))return}c.nodeName!=="TEXTAREA"?xe(c,a):X.TEXTAREA(c,a)}function xe(c,a){var u=we(c,a),d=a.firstChild,f=c.firstChild,O,k,T,F,S;e:for(;d;){for(F=d.nextSibling,O=o(d);!u&&f;){if(T=f.nextSibling,d.isSameNode&&d.isSameNode(f)){d=F,f=T;continue e}k=o(f);var $=f.nodeType,w=void 0;if($===d.nodeType&&($===N?(O?O!==k&&((S=y[O])?T===S?w=!1:(c.insertBefore(S,f),k?I(k):M(f,c,!0),f=S,k=o(f)):w=!1):k&&(w=!1),w=w!==!1&&L(f,d),w&&D(f,d)):($===J||$==Q)&&(w=!0,f.nodeValue!==d.nodeValue&&(f.nodeValue=d.nodeValue))),w){d=F,f=T;continue e}k?I(k):M(f,c,!0),f=T}if(O&&(S=y[O])&&L(S,d))u||Z(c,S),D(S,d);else{var K=l(d);K!==!1&&(K&&(d=K),d.actualize&&(d=d.actualize(c.ownerDocument||b)),Z(c,d),V(d))}d=F,f=T}Be(c,f,k);var ne=X[c.nodeName];ne&&ne(c,a)}var v=t,R=v.nodeType,te=n.nodeType;if(!z){if(R===N)te===N?L(t,n)||(A(t),v=ge(t,pe(n.nodeName,n.namespaceURI))):v=n;else if(R===J||R===Q){if(te===R)return v.nodeValue!==n.nodeValue&&(v.nodeValue=n.nodeValue),v;v=n}}if(v===n)A(t);else{if(n.isSameNode&&n.isSameNode(v))return;if(D(v,n,z),H)for(var W=0,ye=H.length;W<ye;W++){var j=y[H[W]];j&&M(j,j.parentNode,!1)}}return!z&&v!==t&&t.parentNode&&(v.actualize&&(v=v.actualize(t.ownerDocument||b)),t.parentNode.replaceChild(v,t)),v}}var ke=Ce(ce);class _{constructor(e,t){B(this,"previewClient");B(this,"morphdomOptions");B(this,"elementCache",new Map);B(this,"regionCommentsCache",new Map);B(this,"childrenCommentsCache",new Map);B(this,"pendingScripts",new Set);B(this,"scriptExecutionCount",{total:0,completed:0,failed:0});this.previewClient=e||new le,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(),this.cacheChildrenComments()}static init(e,t){return new _(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),o=n.get(r);o&&(this.regionCommentsCache.set(r,{begin:o,end:t}),n.delete(r))}}}}cacheChildrenComments(){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 children: ")){const r=i.substring(16);n.set(r,t)}else if(i.startsWith("END children: ")){const r=i.substring(14),o=n.get(r);o&&(this.childrenCommentsCache.set(r,{begin:o,end:t}),n.delete(r))}}}}cacheChildrenCommentsForBlock(e){const t=this.getElementCached(e);if(!t)return;this.childrenCommentsCache.delete(e);const n=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT,null);let i,r=null;for(;i=n.nextNode();){const o=i.textContent?.trim();if(o){if(o===`BEGIN children: ${e}`)r=i;else if(o===`END children: ${e}`&&r){this.childrenCommentsCache.set(e,{begin:r,end:i});break}}}}invalidateCache(e){[...e.updated,...e.removed].forEach(t=>{this.elementCache.delete(t),this.childrenCommentsCache.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}),t.css&&this.handleCssEffects(t.css),t.js&&this.handleJsEffects(t.js))}handleCssEffects(e){for(const t of e)this.injectStyleElement(t)}injectStyleElement(e){const t=document.createElement("div");t.innerHTML=e;const n=t.firstElementChild;if(!n||n.tagName!=="STYLE"&&n.tagName!=="LINK"){console.warn("Invalid CSS element provided:",e);return}const i=n.id;if(i){const r=document.getElementById(i);if(r&&(r.tagName==="STYLE"||r.tagName==="LINK")){r.parentNode?.replaceChild(n,r);return}}if(n.tagName==="STYLE"&&!i){const r=n.textContent?.trim();if(r){const o=document.querySelectorAll("style:not([id])");for(const l of o)if(l.textContent?.trim()===r)return}}if(n.tagName==="LINK"&&!i){const r=n.getAttribute("href"),o=n.getAttribute("rel");if(r){const l=document.querySelectorAll("link:not([id])");for(const h of l)if(h.getAttribute("href")===r&&h.getAttribute("rel")===o)return}}document.head.appendChild(n)}handleJsEffects(e){this.pendingScripts.clear(),this.scriptExecutionCount={total:0,completed:0,failed:0};const t=e.filter(n=>n?.trim());if(this.scriptExecutionCount.total=t.length,t.length===0){this.emitScriptExecutionComplete();return}for(const n of t)this.injectScriptElement(n)}injectScriptElement(e){const t=document.createElement("div");t.innerHTML=e;const n=t.firstElementChild;if(!n||n.tagName!=="SCRIPT"){console.warn("Invalid script element provided:",e),this.onScriptCompleted(!1);return}const i=n.id;if(i){const r=document.getElementById(i);if(r&&r.tagName==="SCRIPT"){this.pendingScripts.delete(r),r.parentNode?.replaceChild(n,r),this.trackScriptExecution(n);return}}if(!n.src&&!i){const r=n.textContent?.trim();if(r){const o=document.querySelectorAll("script:not([src]):not([id])");for(const l of o)if(l.textContent?.trim()===r){this.onScriptCompleted(!0);return}}}if(n.src&&!i){const r=n.src,o=document.querySelectorAll("script[src]:not([id])");for(const l of o)if(l.src===r){this.onScriptCompleted(!0);return}}document.head.appendChild(n),this.trackScriptExecution(n)}trackScriptExecution(e){if(e.src){this.pendingScripts.add(e);const t=()=>{this.pendingScripts.delete(e),this.onScriptCompleted(!0),e.removeEventListener("load",t),e.removeEventListener("error",n)},n=()=>{this.pendingScripts.delete(e),this.onScriptCompleted(!1),e.removeEventListener("load",t),e.removeEventListener("error",n)};e.addEventListener("load",t),e.addEventListener("error",n)}else this.onScriptCompleted(!0)}onScriptCompleted(e){e?this.scriptExecutionCount.completed++:this.scriptExecutionCount.failed++,this.scriptExecutionCount.completed+this.scriptExecutionCount.failed>=this.scriptExecutionCount.total&&this.emitScriptExecutionComplete()}emitScriptExecutionComplete(){this.previewClient.emit("scripts.execution.complete",{total:this.scriptExecutionCount.total,completed:this.scriptExecutionCount.completed,failed:this.scriptExecutionCount.failed,success:this.scriptExecutionCount.failed===0})}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 o=t[i],l=n.positions?.[i];this.moveBlockUsingDOM(o,r,l)}}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,changes:i}=t;for(const[r,o]of Object.entries(e)){if(!o)continue;const l=n[r];if(!l){console.warn(`Block data not found for ${r}`);continue}if(l.disabled){console.debug(`Skipping disabled block ${r}`);continue}if(!!this.getElementCached(r))this.updateBlockHtml(l,o);else{const g=i.positions?.[r];if(!g){console.warn(`No position info for block ${r}`);continue}this.insertBlock(l,o,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,n){const i=this.getElementCached(e.id),{toParent:r,toRegion:o,toIndex:l}=t;if(!i){console.warn(`Block element ${e.id} not found for move operation`);return}this.previewClient.emit("block.move.before",{blockId:e.id,blockType:e.type,block:e,element:i,toParent:r,toRegion:o,toIndex:l});const h=n?.afterId,p=n?.beforeId;if(r){const g=this.getElementCached(r);if(!g){console.error(`Parent element ${r} not found for move operation`);return}this.insertElementInParent(i,g,h,p)}else if(o){const g=this.findRegionInsertionPoint(o,h,p);if(!g){console.error(`Failed to find insertion point for region: ${o}`);return}g.parent.insertBefore(i,g.before)}this.previewClient.emit("block.move.after",{blockId:e.id,blockType:e.type,block:e,element:i,toParent:r,toRegion:o,toIndex: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,regionId:o,afterId:l,beforeId:h}=n;if(r){const p=this.getElementCached(r);if(!p){console.error(`Parent element ${r} not found for block ${e.id}`);return}this.insertElementInParent(i,p,l,h)}else if(o){const p=this.findRegionInsertionPoint(o,l,h);if(!p){console.error(`Failed to find insertion point for region: ${o}`);return}p.parent.insertBefore(i,p.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.cacheChildrenCommentsForBlock(e.id),i.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"}),this.previewClient.emit("block.insert.after",{blockId:e.id,blockType:e.type,block:e,element:i,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}),ke(n,t,this.morphdomOptions),this.elementCache.delete(e.id);const i=this.getElementCached(e.id);if(!i){console.error(`Block element ${e.id} not found after morphdom update`);return}i!==n&&this.previewClient.inspector.updateTrackedElement(e.id,i),this.cacheChildrenCommentsForBlock(e.id),this.previewClient.emit("block.update.after",{blockId:e.id,blockType:e.type,block:e,element:i,html:t})}insertElementInParent(e,t,n,i){const r=t.getAttribute("data-block"),o=r?this.childrenCommentsCache.get(r):null;if(o){let l=null;if(i)l=this.getElementCached(i);else if(n){const h=this.getElementCached(n);h&&h.nextSibling&&(l=h.nextSibling)}l||(l=o.end),o.begin.parentNode.insertBefore(e,l)}else{let l=null;if(i)l=this.getElementCached(i);else if(n){const h=this.getElementCached(n);h&&(l=h.nextElementSibling)}t.insertBefore(e,l)}}findRegionInsertionPoint(e,t,n){const i=this.regionCommentsCache.get(e);if(!i)return console.error(`Region comments not found for region: ${e}`),null;const{begin:r,end:o}=i;let l=null;if(n){const h=this.getElementCached(n);h&&(l=h)}else if(t){const h=this.getElementCached(t);h&&h.nextSibling&&(l=h.nextSibling)}return l||(l=o),{parent:r.parentNode,before:l}}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 _})();
package/dist/index.d.ts CHANGED
@@ -36,15 +36,10 @@ export default class RawHtmlRenderer {
36
36
  private isValidMoveInstruction;
37
37
  private removeBlock;
38
38
  private moveBlockUsingDOM;
39
- private insertElementInContainer;
40
39
  private insertBlock;
41
40
  private updateBlockHtml;
42
- private insertElementByPosition;
41
+ private insertElementInParent;
43
42
  private findRegionInsertionPoint;
44
- private findPositionInRegion;
45
- private findPositionBetweenComments;
46
- private calculatePosition;
47
- private findAdjacentSiblings;
48
43
  private parseHtmlElement;
49
44
  }
50
45
  export {};
package/dist/index.js CHANGED
@@ -3,7 +3,6 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { PreviewClient } from "@craftile/preview-client";
5
5
  import morphdom from "morphdom";
6
- const getRegionId = (r) => r.id || r.name;
7
6
  class RawHtmlRenderer {
8
7
  constructor(previewClient, options) {
9
8
  __publicField(this, "previewClient");
@@ -300,7 +299,8 @@ class RawHtmlRenderer {
300
299
  continue;
301
300
  }
302
301
  const block = blocks[blockId];
303
- this.moveBlockUsingDOM(block, moveInstruction);
302
+ const position = changes.positions?.[blockId];
303
+ this.moveBlockUsingDOM(block, moveInstruction, position);
304
304
  }
305
305
  }
306
306
  handleDisabledBlocks(updates) {
@@ -324,7 +324,7 @@ class RawHtmlRenderer {
324
324
  }
325
325
  }
326
326
  handleHtmlEffects(htmlEffects, updates) {
327
- const { blocks, regions } = updates;
327
+ const { blocks, changes } = updates;
328
328
  for (const [blockId, html] of Object.entries(htmlEffects)) {
329
329
  if (!html) {
330
330
  continue;
@@ -341,8 +341,12 @@ class RawHtmlRenderer {
341
341
  const blockElement = this.getElementCached(blockId);
342
342
  const isCurrentlyInDOM = !!blockElement;
343
343
  if (!isCurrentlyInDOM) {
344
- const positionInfo = this.calculatePosition(block, regions, blocks);
345
- this.insertBlock(block, html, positionInfo);
344
+ const position = changes.positions?.[blockId];
345
+ if (!position) {
346
+ console.warn(`No position info for block ${blockId}`);
347
+ continue;
348
+ }
349
+ this.insertBlock(block, html, position);
346
350
  } else {
347
351
  this.updateBlockHtml(block, html);
348
352
  }
@@ -370,7 +374,7 @@ class RawHtmlRenderer {
370
374
  console.warn(`Block ${blockId} not found for removal`);
371
375
  }
372
376
  }
373
- moveBlockUsingDOM(block, moveInstruction) {
377
+ moveBlockUsingDOM(block, moveInstruction, position) {
374
378
  const blockElement = this.getElementCached(block.id);
375
379
  const { toParent, toRegion, toIndex } = moveInstruction;
376
380
  if (!blockElement) {
@@ -386,15 +390,17 @@ class RawHtmlRenderer {
386
390
  toRegion,
387
391
  toIndex
388
392
  });
393
+ const afterId = position?.afterId;
394
+ const beforeId = position?.beforeId;
389
395
  if (toParent) {
390
396
  const parentElement = this.getElementCached(toParent);
391
397
  if (!parentElement) {
392
398
  console.error(`Parent element ${toParent} not found for move operation`);
393
399
  return;
394
400
  }
395
- this.insertElementInContainer(blockElement, parentElement, block.id, toIndex);
401
+ this.insertElementInParent(blockElement, parentElement, afterId, beforeId);
396
402
  } else if (toRegion) {
397
- const insertionPoint = this.findRegionInsertionPoint(toRegion, toIndex, void 0, void 0, block.id);
403
+ const insertionPoint = this.findRegionInsertionPoint(toRegion, afterId, beforeId);
398
404
  if (!insertionPoint) {
399
405
  console.error(`Failed to find insertion point for region: ${toRegion}`);
400
406
  return;
@@ -411,20 +417,7 @@ class RawHtmlRenderer {
411
417
  toIndex
412
418
  });
413
419
  }
414
- insertElementInContainer(element, container, elementId, index) {
415
- const blockId = container.getAttribute("data-block");
416
- const comments = blockId ? this.childrenCommentsCache.get(blockId) : null;
417
- if (comments) {
418
- const insertionPoint = this.findPositionBetweenComments(comments.begin, comments.end, index, elementId);
419
- insertionPoint.parent.insertBefore(element, insertionPoint.before);
420
- } else {
421
- const children = Array.from(container.children);
422
- const otherChildren = children.filter((child) => child.getAttribute("data-block") !== elementId);
423
- const insertBefore = index !== void 0 && index < otherChildren.length ? otherChildren[index] : null;
424
- container.insertBefore(element, insertBefore);
425
- }
426
- }
427
- insertBlock(block, html, positionInfo) {
420
+ insertBlock(block, html, position) {
428
421
  if (this.getElementCached(block.id)) {
429
422
  return;
430
423
  }
@@ -433,22 +426,22 @@ class RawHtmlRenderer {
433
426
  blockType: block.type,
434
427
  block,
435
428
  html,
436
- positionInfo
429
+ positionInfo: position
437
430
  });
438
431
  const newElement = this.parseHtmlElement(html, block.id);
439
432
  if (!newElement) {
440
433
  return;
441
434
  }
442
- const { parentId, regionId, position, afterId, beforeId } = positionInfo;
435
+ const { parentId, regionId, afterId, beforeId } = position;
443
436
  if (parentId) {
444
437
  const parentElement = this.getElementCached(parentId);
445
438
  if (!parentElement) {
446
439
  console.error(`Parent element ${parentId} not found for block ${block.id}`);
447
440
  return;
448
441
  }
449
- this.insertElementByPosition(newElement, parentElement, position, afterId, beforeId);
442
+ this.insertElementInParent(newElement, parentElement, afterId, beforeId);
450
443
  } else if (regionId) {
451
- const insertionPoint = this.findRegionInsertionPoint(regionId, position, afterId, beforeId);
444
+ const insertionPoint = this.findRegionInsertionPoint(regionId, afterId, beforeId);
452
445
  if (!insertionPoint) {
453
446
  console.error(`Failed to find insertion point for region: ${regionId}`);
454
447
  return;
@@ -465,8 +458,9 @@ class RawHtmlRenderer {
465
458
  blockId: block.id,
466
459
  blockType: block.type,
467
460
  block,
461
+ element: newElement,
468
462
  html,
469
- positionInfo
463
+ positionInfo: position
470
464
  });
471
465
  }
472
466
  updateBlockHtml(block, html) {
@@ -505,7 +499,7 @@ class RawHtmlRenderer {
505
499
  html
506
500
  });
507
501
  }
508
- insertElementByPosition(element, parentElement, position, afterId, beforeId) {
502
+ insertElementInParent(element, parentElement, afterId, beforeId) {
509
503
  const blockId = parentElement.getAttribute("data-block");
510
504
  const comments = blockId ? this.childrenCommentsCache.get(blockId) : null;
511
505
  if (comments) {
@@ -517,10 +511,6 @@ class RawHtmlRenderer {
517
511
  if (afterElement && afterElement.nextSibling) {
518
512
  insertBefore = afterElement.nextSibling;
519
513
  }
520
- } else if (typeof position === "number") {
521
- const insertionPoint = this.findPositionBetweenComments(comments.begin, comments.end, position);
522
- comments.begin.parentNode.insertBefore(element, insertionPoint.before);
523
- return;
524
514
  }
525
515
  if (!insertBefore) {
526
516
  insertBefore = comments.end;
@@ -535,14 +525,11 @@ class RawHtmlRenderer {
535
525
  if (afterElement) {
536
526
  insertBefore = afterElement.nextElementSibling;
537
527
  }
538
- } else if (typeof position === "number") {
539
- const children = Array.from(parentElement.children);
540
- insertBefore = children[position] || null;
541
528
  }
542
529
  parentElement.insertBefore(element, insertBefore);
543
530
  }
544
531
  }
545
- findRegionInsertionPoint(regionId, position, afterId, beforeId, excludeBlockId) {
532
+ findRegionInsertionPoint(regionId, afterId, beforeId) {
546
533
  const regionComments = this.regionCommentsCache.get(regionId);
547
534
  if (!regionComments) {
548
535
  console.error(`Region comments not found for region: ${regionId}`);
@@ -560,46 +547,6 @@ class RawHtmlRenderer {
560
547
  if (afterElement && afterElement.nextSibling) {
561
548
  insertBefore = afterElement.nextSibling;
562
549
  }
563
- } else if (typeof position === "number") {
564
- insertBefore = this.findPositionInRegion(beginComment, endComment, position, excludeBlockId);
565
- }
566
- if (!insertBefore) {
567
- insertBefore = endComment;
568
- }
569
- return {
570
- parent: beginComment.parentNode,
571
- before: insertBefore
572
- };
573
- }
574
- findPositionInRegion(beginComment, endComment, position, excludeBlockId) {
575
- const regionBlocks = [];
576
- let currentNode = beginComment.nextSibling;
577
- while (currentNode && currentNode !== endComment) {
578
- if (currentNode.nodeType === Node.ELEMENT_NODE && currentNode.hasAttribute("data-block")) {
579
- const blockId = currentNode.getAttribute("data-block");
580
- if (!excludeBlockId || blockId !== excludeBlockId) {
581
- regionBlocks.push(currentNode);
582
- }
583
- }
584
- currentNode = currentNode.nextSibling;
585
- }
586
- return position < regionBlocks.length ? regionBlocks[position] : null;
587
- }
588
- findPositionBetweenComments(beginComment, endComment, index, excludeBlockId) {
589
- let insertBefore = null;
590
- if (typeof index === "number") {
591
- const blocks = [];
592
- let currentNode = beginComment.nextSibling;
593
- while (currentNode && currentNode !== endComment) {
594
- if (currentNode.nodeType === Node.ELEMENT_NODE && currentNode.hasAttribute("data-block")) {
595
- const blockId = currentNode.getAttribute("data-block");
596
- if (!excludeBlockId || blockId !== excludeBlockId) {
597
- blocks.push(currentNode);
598
- }
599
- }
600
- currentNode = currentNode.nextSibling;
601
- }
602
- insertBefore = index < blocks.length ? blocks[index] : null;
603
550
  }
604
551
  if (!insertBefore) {
605
552
  insertBefore = endComment;
@@ -609,59 +556,6 @@ class RawHtmlRenderer {
609
556
  before: insertBefore
610
557
  };
611
558
  }
612
- calculatePosition(block, regions, blocks) {
613
- if (block.parentId) {
614
- const parentBlock = blocks[block.parentId];
615
- if (!parentBlock) {
616
- console.warn(`Block data not found for block ${block.id}`);
617
- }
618
- const position = parentBlock.children.indexOf(block.id);
619
- if (position === -1) {
620
- console.warn(`Block ${block.id} not found in parent ${block.parentId} children`);
621
- return { parentId: block.parentId };
622
- }
623
- const { afterId, beforeId } = this.findAdjacentSiblings(parentBlock.children, position, blocks);
624
- return {
625
- parentId: block.parentId,
626
- position,
627
- afterId,
628
- beforeId
629
- };
630
- } else {
631
- for (const region of regions) {
632
- const position = region.blocks.indexOf(block.id);
633
- if (position !== -1) {
634
- const { afterId, beforeId } = this.findAdjacentSiblings(region.blocks, position, blocks);
635
- return {
636
- regionId: getRegionId(region),
637
- position,
638
- afterId,
639
- beforeId
640
- };
641
- }
642
- }
643
- return {};
644
- }
645
- }
646
- findAdjacentSiblings(siblings, currentIndex, blocks) {
647
- let afterId;
648
- let beforeId;
649
- for (let i = currentIndex - 1; i >= 0; i--) {
650
- const siblingBlock = blocks[siblings[i]];
651
- if (siblingBlock && !siblingBlock.disabled) {
652
- afterId = siblings[i];
653
- break;
654
- }
655
- }
656
- for (let i = currentIndex + 1; i < siblings.length; i++) {
657
- const siblingBlock = blocks[siblings[i]];
658
- if (siblingBlock && !siblingBlock.disabled) {
659
- beforeId = siblings[i];
660
- break;
661
- }
662
- }
663
- return { afterId, beforeId };
664
- }
665
559
  parseHtmlElement(html, blockId) {
666
560
  if (!html.trim()) {
667
561
  console.error(`Empty HTML provided for block ${blockId}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@craftile/preview-client-html",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "HTML preview client for static block rendering in Craftile",
5
5
  "keywords": [
6
6
  "craftile",
@@ -39,8 +39,8 @@
39
39
  "vite": "^7.0.0",
40
40
  "vite-plugin-dts": "^4.5.4",
41
41
  "vitest": "^3.2.4",
42
- "@craftile/preview-client": "1.0.2",
43
- "@craftile/types": "1.0.2"
42
+ "@craftile/preview-client": "1.0.4",
43
+ "@craftile/types": "1.0.4"
44
44
  },
45
45
  "repository": {
46
46
  "type": "git",