@picked/react 0.0.1-dev.1785287094311 → 0.0.1-dev.1785305085063

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.
@@ -13,6 +13,15 @@ interface HtmlRenderProps {
13
13
  * client-only mount or a later content change attaches and writes the shadow root imperatively
14
14
  * instead. A non-matching value or a `null` content renders nothing.
15
15
  *
16
+ * Inside a Picked live-preview session the update path changes: content arrives at typing speed, so
17
+ * after the first render the shadow root is **morphed** rather than rewritten, and page scripts are
18
+ * **frozen** — nothing re-executes. The two are one behaviour and must never be separated. Freezing
19
+ * is what stops a customer's analytics and third-party pixels firing once per keystroke from the
20
+ * dashboard; morphing is what keeps the page alive without them, since a wholesale rewrite would
21
+ * detach every listener with nothing left to re-bind it. Markup inserted during a preview morph has
22
+ * its scripts neutralised, so a newly-added section renders but has no behaviour until the next full
23
+ * load — reported to the embedder so the editor can say so.
24
+ *
16
25
  * @param {HtmlRenderProps} props - The component props.
17
26
  * @returns {React.JSX.Element} The shadow-root host element.
18
27
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"HtmlRender.d.ts","sourceRoot":"","sources":["../../src/experience/HtmlRender.tsx"],"names":[],"mappings":"AAAA,8GAA8G;AAC9G,OAAO,KAA4B,MAAM,OAAO,CAAA;AAQhD,UAAU,eAAe;IACvB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB;AAED;;;;;;;;;;;;;;GAcG;AACH,iBAAS,UAAU,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAgChE;AAED,eAAe,UAAU,CAAA"}
1
+ {"version":3,"file":"HtmlRender.d.ts","sourceRoot":"","sources":["../../src/experience/HtmlRender.tsx"],"names":[],"mappings":"AAAA,8GAA8G;AAC9G,OAAO,KAA4B,MAAM,OAAO,CAAA;AAWhD,UAAU,eAAe;IACvB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,iBAAS,UAAU,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAuChE;AAED,eAAe,UAAU,CAAA"}
@@ -1 +1 @@
1
- import{useEffect as e,useRef as t}from"react";import{isHtmlAssetValue as n,rehydrateScripts as r,supportsShadowRoot as i,supportsWindow as a}from"@picked/client";import{jsx as o}from"react/jsx-runtime";function s({html:s}){let c=(n(s)?s:null)?.content??``,l=t(null),u=t(!1);return e(()=>{let e=l.current;if(!i()||!e)return;let t=e.shadowRoot,n=!u.current;if(u.current=!0,t&&n){c&&r(t);return}let a=t??e.attachShadow({mode:`open`});a.innerHTML=c,c&&r(a)},[c]),a()?o(`div`,{ref:l,suppressHydrationWarning:!0}):o(`div`,{ref:l,suppressHydrationWarning:!0,dangerouslySetInnerHTML:{__html:`<template shadowrootmode="open">${c}</template>`}})}export{s as default};
1
+ import{morphInto as e}from"./morph.js";import{useEffect as t,useRef as n}from"react";import{isHtmlAssetValue as r,isPreviewSession as i,rehydrateScripts as a,reportInertScriptSubtrees as o,supportsShadowRoot as s,supportsWindow as c}from"@picked/client";import{jsx as l}from"react/jsx-runtime";function u({html:u}){let d=(r(u)?u:null)?.content??``,f=n(null),p=n(!1);return t(()=>{let t=f.current;if(!s()||!t)return;let n=t.shadowRoot,r=!p.current;if(p.current=!0,n&&r){d&&a(n);return}let c=n??t.attachShadow({mode:`open`});if(!r&&i()){let{inertScriptSubtrees:t}=e(c,d);o(t);return}c.innerHTML=d,d&&a(c)},[d]),c()?l(`div`,{ref:f,suppressHydrationWarning:!0}):l(`div`,{ref:f,suppressHydrationWarning:!0,dangerouslySetInnerHTML:{__html:`<template shadowrootmode="open">${d}</template>`}})}export{u as default};
@@ -0,0 +1,26 @@
1
+ /** Outcome of a morph pass. Returned by {@link morphInto}. */
2
+ interface MorphResult {
3
+ /**
4
+ * How many inserted subtrees contained at least one `<script>`. Those scripts are neutralised
5
+ * before insertion, so the markup renders but has no behaviour until the next full load. The
6
+ * dashboard surfaces this count so an author who adds a section understands why its carousel is
7
+ * inert, instead of filing it as a bug.
8
+ */
9
+ inertScriptSubtrees: number;
10
+ }
11
+ /**
12
+ * Morphs a root's children to match `markup`, preserving every node the new markup did not change.
13
+ *
14
+ * Scripts are never executed: existing ones are left untouched (mutating a script's text does not
15
+ * re-run it) and inserted ones are neutralised before they reach the document. The returned count
16
+ * reports how many inserted subtrees were affected, so the editor can say so.
17
+ *
18
+ * @param {ParentNode & Node} root - The live root — typically a shadow root — to update.
19
+ * @param {string} markup - The desired markup.
20
+ * @returns {MorphResult} How many inserted subtrees had their scripts neutralised.
21
+ * @example
22
+ * const { inertScriptSubtrees } = morphInto(shadowRoot, '<h1>Hello</h1>')
23
+ */
24
+ export declare function morphInto(root: ParentNode & Node, markup: string): MorphResult;
25
+ export {};
26
+ //# sourceMappingURL=morph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"morph.d.ts","sourceRoot":"","sources":["../../src/experience/morph.ts"],"names":[],"mappings":"AAmBA,8DAA8D;AAC9D,UAAU,WAAW;IACnB;;;;;OAKG;IACH,mBAAmB,EAAE,MAAM,CAAA;CAC5B;AAuHD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAO9E"}
@@ -0,0 +1 @@
1
+ import{PICKED_SCRIPT_TYPE as e}from"@picked/client";var t=`data-picked-hydrated`;function n(t){let n=t.querySelectorAll(`script`),r=t.tagName===`SCRIPT`;if(n.length===0&&!r)return!1;r&&t.setAttribute(`type`,e);for(let t of Array.from(n))t.setAttribute(`type`,e);return!0}function r(e,t,r){let i=t.importNode(e,!0);return i instanceof Element&&n(i)&&(r.inertScriptSubtrees+=1),i}function i(e,n){for(let t of Array.from(n.attributes))e.getAttribute(t.name)!==t.value&&e.setAttribute(t.name,t.value);for(let r of Array.from(e.attributes))r.name!==t&&(n.hasAttribute(r.name)||e.removeAttribute(r.name))}function a(e,t){return e.nodeType===t.nodeType&&e.nodeName===t.nodeName}function o(e,t,n,s){let c=Array.from(e.childNodes),l=Array.from(t.childNodes);for(let[t,u]of l.entries()){let l=c[t];if(!l){e.appendChild(r(u,n,s));continue}if(!a(l,u)){e.replaceChild(r(u,n,s),l);continue}if(l instanceof Element&&u instanceof Element){i(l,u),o(l,u,n,s);continue}l.nodeValue!==u.nodeValue&&(l.nodeValue=u.nodeValue)}for(let e of c.slice(l.length))e.remove()}function s(e,t){let n={inertScriptSubtrees:0},r=e.ownerDocument??globalThis.document,i=r.createElement(`template`);return i.innerHTML=t,o(e,i.content,r,n),n}export{s as morphInto};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picked/react",
3
- "version": "0.0.1-dev.1785287094311",
3
+ "version": "0.0.1-dev.1785305085063",
4
4
  "devDependencies": {
5
5
  "@picked/client": "workspace:*",
6
6
  "@repo/eslint-config": "workspace:*",
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "module": "./dist/index.js",
87
87
  "peerDependencies": {
88
- "@picked/client": "0.0.1-dev.1785287094311",
88
+ "@picked/client": "0.0.1-dev.1785305085063",
89
89
  "effector": "^23.3.0",
90
90
  "react": "19.2.2",
91
91
  "react-dom": "19.2.2"