preact-island
Version:
🏝 Create your own slice of paradise on any website.
2 lines (1 loc) • 4.34 kB
JavaScript
import{render as e,h as t}from"preact";import{useMemo as r,useEffect as o,createPortal as n}from"preact/compat";function s(){return s=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(e[o]=r[o])}return e},s.apply(this,arguments)}const c=e=>e instanceof ShadowRoot,a=e=>{const t=e.getRootNode()instanceof ShadowRoot?e.getRootNode().host:e,{dataset:r}=t,o={};for(var n in r){if(!1===r.hasOwnProperty(n))return;const e=`${(s=n.split(/(props?)/).pop()||"").charAt(0).toLowerCase()}${s.slice(1)}`;e&&(o[e]=r[n])}var s;return o},l=e=>["text/props","application/json"].includes(e.getAttribute("type")||""),i=e=>c(e)?[]:Array.from(e.getElementsByTagName("script")).filter(l),d=e=>Array.from(document.querySelectorAll(e)).filter(l),p=e=>{let t={};return e.forEach(e=>{try{t=s({},t,JSON.parse(e.innerHTML))}catch(e){}}),t},u=(e,t,r={},o)=>{const n=a(t),c=e._executedScript?a(e._executedScript):{},l=p(i(t));return s({},r,n,c,o?p(d(o)):{},l)};function m(e,t){var r=(t=[].concat(t))[t.length-1].nextSibling;function o(t,o){e.insertBefore(t,o||r)}return e.__k={nodeType:1,parentNode:e,firstChild:t[0],childNodes:t,insertBefore:o,appendChild:o,removeChild:function(t){e.removeChild(t)}}}const h=({island:r,widget:o,rootFragment:n,props:s})=>{r.props=s,e(t(o,s),n)},f=t=>{const r={_rootsToObservers:new WeakMap,_roots:[],_executedScript:document.currentScript,props:{},render:({selector:e,clean:o=!1,replace:n=!1,inline:a=!1,initialProps:l={},propsSelector:p,elementName:f})=>{let E=!1;const g=()=>{if(!0===E)return;const g=(({selector:e,inline:t,elementName:r})=>{const o=document.currentScript;if(t&&null!=o&&o.parentNode)return[o.parentNode];const n=null==o?void 0:o.dataset.mountIn;return n?Array.from(document.querySelectorAll(n)).map(e=>{if(null!=r){const t=document.createElement(r),o=e.appendChild(t);return null!=o.shadowRoot?o.shadowRoot:o}return e}):e?Array.from(document.querySelectorAll(e)).map(e=>null!=e.shadowRoot?e.shadowRoot:e):[]})({selector:e,inline:a,elementName:f});if(0===g.length)return;const{rootFragments:y}=(({island:e,widget:t,hostElements:r,clean:o,replace:n,initialProps:a,propsSelector:l})=>{const p=[];return r.forEach(r=>{const f=u(e,r,a,l);let E;if(o&&r.replaceChildren(),n)E=m(r.parentElement||document.body,r);else{const e=document.createElement("div");r.appendChild(e),E=m(r,e)}p.push(E),h({island:e,widget:t,rootFragment:E,props:f});const g=(({island:e,hostElement:t,initialProps:r,onNewProps:o,propsSelector:n})=>{const a=new MutationObserver(function(s){s.forEach(function(){o(u(e,t,r,n))})}),l={attributes:!0,childList:!0,characterData:!0};return e._executedScript&&a.observe(e._executedScript,l),i(t).forEach(e=>{a.observe(e,s({},l,{subtree:!0}))}),n&&d(n).forEach(e=>{a.observe(e,s({},l,{subtree:!0}))}),a.observe(c(t)?t.host:t,l),a})({island:e,hostElement:r,initialProps:a,onNewProps:r=>{h({island:e,widget:t,rootFragment:E,props:r})},propsSelector:l});e._rootsToObservers.set(E,g)}),{rootFragments:p}})({island:r,widget:t,clean:o,hostElements:g,replace:n,initialProps:l,propsSelector:p});r._roots=r._roots.concat(y),E=!0};g(),document.addEventListener("DOMContentLoaded",g),document.addEventListener("load",g)},rerender:e=>{r._roots.forEach(o=>{h({island:r,widget:t,rootFragment:o,props:s({},r.props,e)})})},destroy:()=>{r._roots.forEach(t=>{var o;null==(o=r._rootsToObservers.get(t))||o.disconnect(),e(null,t)})}};return r},E=(e,t)=>{if(null==customElements.get(e)){class t extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}}customElements.define(e,t)}const r=f(t);return s({},r,{render:t=>r.render(s({elementName:e},t)),injectStyles:e=>{r._roots.forEach(t=>{const r=document.createElement("style");r.innerHTML=e,t.parentNode.prepend(r)})}})},g=({name:e,container:t=document.body,children:s,style:c})=>{const a=r(()=>{if(null==customElements.get(e)){class t extends HTMLElement{constructor(){super();const e=this.attachShadow({mode:"open"});if(c)if(c instanceof HTMLStyleElement)e.prepend(c);else{const t=document.createElement("style");t.innerHTML=c,e.prepend(t)}}}customElements.define(e,t)}const r=document.createElement(e);return t.appendChild(r)},[t,c]);return o(()=>()=>{a.remove()},[a]),n(s,a.shadowRoot)};export{g as WebComponentPortal,f as createIsland,E as createIslandWebComponent};