hyperclayjs 1.15.0 → 1.17.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.
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Autosave Debug Utility
3
+ *
4
+ * Provides conditional logging for the autosave system.
5
+ * Enable by setting localStorage.setItem('hyperclay:debug:autosave', 'true')
6
+ *
7
+ * When enabled, dynamically imports a diff library to show exactly
8
+ * what changed between DOM states.
9
+ */
10
+
11
+ const DEBUG_KEY = 'hyperclay:debug:autosave';
12
+
13
+ let diffModule = null;
14
+ let diffLoadPromise = null;
15
+
16
+ /**
17
+ * Check if autosave debug mode is enabled
18
+ */
19
+ export function isDebugEnabled() {
20
+ try {
21
+ return localStorage.getItem(DEBUG_KEY) === 'true';
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Lazily load the diff library only when needed
29
+ * Uses esm.sh for zero-install dynamic import
30
+ */
31
+ async function loadDiff() {
32
+ if (diffModule) return diffModule;
33
+ if (diffLoadPromise) return diffLoadPromise;
34
+
35
+ diffLoadPromise = import('https://esm.sh/diff@5.2.0')
36
+ .then(mod => {
37
+ diffModule = mod;
38
+ return mod;
39
+ })
40
+ .catch(err => {
41
+ console.warn('[autosave-debug] Failed to load diff library:', err);
42
+ return null;
43
+ });
44
+
45
+ return diffLoadPromise;
46
+ }
47
+
48
+ /**
49
+ * Log a brief one-liner for save operations
50
+ */
51
+ export function logSaveCheck(label, matches) {
52
+ if (!isDebugEnabled()) return;
53
+
54
+ const status = matches ? '✓ matches' : '✗ differs';
55
+ console.log(`[autosave] ${label}: ${status}`);
56
+ }
57
+
58
+ /**
59
+ * Log when baseline is captured/updated
60
+ */
61
+ export function logBaseline(event, details = '') {
62
+ if (!isDebugEnabled()) return;
63
+
64
+ console.log(`[autosave] baseline ${event}${details ? `: ${details}` : ''}`);
65
+ }
66
+
67
+ /**
68
+ * Log and diff two HTML strings (async, for unload warning)
69
+ * Returns a promise that resolves when logging is complete
70
+ */
71
+ export async function logUnloadDiff(currentContents, lastSaved) {
72
+ if (!isDebugEnabled()) return;
73
+
74
+ console.group('[autosave] Unload warning triggered - content differs from last save');
75
+ console.log('Current length:', currentContents.length);
76
+ console.log('Last saved length:', lastSaved.length);
77
+ console.log('Difference:', currentContents.length - lastSaved.length, 'characters');
78
+
79
+ const diff = await loadDiff();
80
+
81
+ if (diff) {
82
+ const changes = diff.diffLines(lastSaved, currentContents);
83
+
84
+ console.log('\n--- DIFF (last saved → current) ---');
85
+
86
+ let hasChanges = false;
87
+ changes.forEach(part => {
88
+ if (part.added || part.removed) {
89
+ hasChanges = true;
90
+ const prefix = part.added ? '+++ ' : '--- ';
91
+ const lines = part.value.split('\n').filter(l => l.length > 0);
92
+
93
+ // Truncate very long diffs
94
+ const maxLines = 20;
95
+ const displayLines = lines.slice(0, maxLines);
96
+
97
+ displayLines.forEach(line => {
98
+ // Truncate very long lines
99
+ const displayLine = line.length > 200
100
+ ? line.substring(0, 200) + '...[truncated]'
101
+ : line;
102
+ console.log(prefix + displayLine);
103
+ });
104
+
105
+ if (lines.length > maxLines) {
106
+ console.log(`... and ${lines.length - maxLines} more lines`);
107
+ }
108
+ }
109
+ });
110
+
111
+ if (!hasChanges) {
112
+ console.log('(No line-level differences found - may be whitespace or inline changes)');
113
+ // Fall back to character diff for small differences
114
+ if (Math.abs(currentContents.length - lastSaved.length) < 500) {
115
+ const charChanges = diff.diffChars(lastSaved, currentContents);
116
+ console.log('\n--- CHARACTER DIFF ---');
117
+ charChanges.forEach(part => {
118
+ if (part.added || part.removed) {
119
+ const prefix = part.added ? '+++ ' : '--- ';
120
+ const value = part.value.length > 100
121
+ ? part.value.substring(0, 100) + '...[truncated]'
122
+ : part.value;
123
+ console.log(prefix + JSON.stringify(value));
124
+ }
125
+ });
126
+ }
127
+ }
128
+ } else {
129
+ console.log('(diff library not available - showing raw comparison)');
130
+ console.log('First 500 chars of current:', currentContents.substring(0, 500));
131
+ console.log('First 500 chars of last saved:', lastSaved.substring(0, 500));
132
+ }
133
+
134
+ console.groupEnd();
135
+ }
136
+
137
+ /**
138
+ * Synchronous version for beforeunload (can't await in event handler)
139
+ * Logs what it can immediately, diff loads async but may not complete before unload
140
+ */
141
+ export function logUnloadDiffSync(currentContents, lastSaved) {
142
+ if (!isDebugEnabled()) return;
143
+
144
+ console.group('[autosave] Unload warning triggered - content differs from last save');
145
+ console.log('Current length:', currentContents.length);
146
+ console.log('Last saved length:', lastSaved.length);
147
+ console.log('Difference:', currentContents.length - lastSaved.length, 'characters');
148
+
149
+ // If diff is already loaded, use it synchronously
150
+ if (diffModule) {
151
+ const changes = diffModule.diffLines(lastSaved, currentContents);
152
+
153
+ console.log('\n--- DIFF (last saved → current) ---');
154
+
155
+ let hasChanges = false;
156
+ changes.forEach(part => {
157
+ if (part.added || part.removed) {
158
+ hasChanges = true;
159
+ const prefix = part.added ? '+++ ' : '--- ';
160
+ const lines = part.value.split('\n').filter(l => l.length > 0);
161
+
162
+ const maxLines = 20;
163
+ const displayLines = lines.slice(0, maxLines);
164
+
165
+ displayLines.forEach(line => {
166
+ const displayLine = line.length > 200
167
+ ? line.substring(0, 200) + '...[truncated]'
168
+ : line;
169
+ console.log(prefix + displayLine);
170
+ });
171
+
172
+ if (lines.length > maxLines) {
173
+ console.log(`... and ${lines.length - maxLines} more lines`);
174
+ }
175
+ }
176
+ });
177
+
178
+ if (!hasChanges) {
179
+ console.log('(No line-level differences - checking character diff)');
180
+ if (Math.abs(currentContents.length - lastSaved.length) < 500) {
181
+ const charChanges = diffModule.diffChars(lastSaved, currentContents);
182
+ charChanges.forEach(part => {
183
+ if (part.added || part.removed) {
184
+ const prefix = part.added ? '+++ ' : '--- ';
185
+ const value = part.value.length > 100
186
+ ? part.value.substring(0, 100) + '...[truncated]'
187
+ : part.value;
188
+ console.log(prefix + JSON.stringify(value));
189
+ }
190
+ });
191
+ }
192
+ }
193
+ } else {
194
+ // Kick off async load for next time, show basic info now
195
+ loadDiff();
196
+ console.log('(diff library loading - run localStorage.setItem("hyperclay:debug:autosave", "true") and reload for full diff)');
197
+
198
+ // Find first difference position
199
+ let diffPos = 0;
200
+ const minLen = Math.min(currentContents.length, lastSaved.length);
201
+ while (diffPos < minLen && currentContents[diffPos] === lastSaved[diffPos]) {
202
+ diffPos++;
203
+ }
204
+
205
+ console.log('First difference at position:', diffPos);
206
+ console.log('Context around difference:');
207
+ console.log(' Last saved:', JSON.stringify(lastSaved.substring(Math.max(0, diffPos - 50), diffPos + 100)));
208
+ console.log(' Current:', JSON.stringify(currentContents.substring(Math.max(0, diffPos - 50), diffPos + 100)));
209
+ }
210
+
211
+ console.groupEnd();
212
+ }
213
+
214
+ /**
215
+ * Pre-load the diff library if debug is enabled
216
+ * Call this early to ensure diff is ready for unload events
217
+ */
218
+ export function preloadIfEnabled() {
219
+ if (isDebugEnabled()) {
220
+ loadDiff();
221
+ console.log('[autosave-debug] Debug mode enabled - diff library loading');
222
+ }
223
+ }
@@ -1,8 +1,8 @@
1
1
  /*
2
2
  Lazy-load vendor scripts in edit mode only
3
3
 
4
- Injects a <script save-ignore> tag that loads the vendor script.
5
- The save-ignore attribute ensures it's stripped when the page is saved.
4
+ Injects a <script save-remove> tag that loads the vendor script.
5
+ The save-remove attribute ensures it's stripped when the page is saved.
6
6
 
7
7
  Usage:
8
8
  import { loadVendorScript } from '../utilities/loadVendorScript.js';
@@ -15,7 +15,7 @@
15
15
  */
16
16
 
17
17
  /**
18
- * Load a vendor script via script tag with save-ignore
18
+ * Load a vendor script via script tag with save-remove
19
19
  * @param {string} url - URL to the vendor script
20
20
  * @param {Object} [options] - Options
21
21
  * @param {string} [options.globalName] - Window property to return when loaded (for classic scripts)
@@ -33,7 +33,7 @@ export function loadVendorScript(url, options = {}) {
33
33
  return new Promise((resolve, reject) => {
34
34
  const script = document.createElement('script');
35
35
  script.src = url;
36
- script.setAttribute('save-ignore', '');
36
+ script.setAttribute('save-remove', '');
37
37
  if (isModule) {
38
38
  script.type = 'module';
39
39
  }
@@ -67,8 +67,27 @@ const Mutation = {
67
67
  },
68
68
 
69
69
  _observing: false,
70
+ _paused: false,
70
71
  debug: false,
71
72
 
73
+ /**
74
+ * Pause mutation observation.
75
+ * Use this when making programmatic DOM changes that shouldn't trigger callbacks.
76
+ * Always pair with resume() in a try/finally block.
77
+ */
78
+ pause() {
79
+ this._paused = true;
80
+ this._log('Paused');
81
+ },
82
+
83
+ /**
84
+ * Resume mutation observation after a pause.
85
+ */
86
+ resume() {
87
+ this._paused = false;
88
+ this._log('Resumed');
89
+ },
90
+
72
91
  _log(message, data = null, type = 'log') {
73
92
  if (!this.debug) return;
74
93
 
@@ -173,9 +192,14 @@ const Mutation = {
173
192
  }
174
193
  },
175
194
 
176
- _shouldIgnore(element) {
195
+ _shouldIgnore(node) {
196
+ // For non-element nodes (like text nodes), start from parent
197
+ let element = (node && node.nodeType !== 1) ? node.parentElement : node;
198
+
177
199
  while (element && element.nodeType === 1) {
178
- if (element.hasAttribute?.('mutations-ignore') || element.hasAttribute?.('save-ignore')) {
200
+ if (element.hasAttribute?.('mutations-ignore') ||
201
+ element.hasAttribute?.('save-remove') ||
202
+ element.hasAttribute?.('save-ignore')) {
179
203
  return true;
180
204
  }
181
205
  element = element.parentElement;
@@ -184,8 +208,12 @@ const Mutation = {
184
208
  },
185
209
 
186
210
  _handleMutations(mutations) {
187
- this._log(`Processing ${mutations.length} mutations`, { mutations });
188
-
211
+ // Skip all mutations while paused (e.g., during live-sync morph)
212
+ if (this._paused) {
213
+ this._log(`Skipping ${mutations.length} mutations (paused)`);
214
+ return;
215
+ }
216
+
189
217
  const changes = [];
190
218
  const changesByType = {
191
219
  add: [],
@@ -197,7 +225,6 @@ const Mutation = {
197
225
  for (const mutation of mutations) {
198
226
  // Check if the target or any parent has mutations-ignore attribute
199
227
  if (this._shouldIgnore(mutation.target)) {
200
- this._log('Ignoring mutation due to mutations-ignore attribute', { mutation });
201
228
  continue;
202
229
  }
203
230
 
@@ -244,7 +271,7 @@ const Mutation = {
244
271
  }
245
272
 
246
273
  for (const node of mutation.removedNodes) {
247
- if (node.nodeType === 1 && !node.hasAttribute?.('save-ignore') && !node.hasAttribute?.('mutations-ignore')) {
274
+ if (node.nodeType === 1 && !this._shouldIgnore(node)) {
248
275
  const removedNodes = [node, ...node.querySelectorAll('*')];
249
276
  this._log(`Processing ${removedNodes.length} removed nodes`, { removedNodes });
250
277
 
@@ -309,8 +336,6 @@ const Mutation = {
309
336
  if (changesByType.attribute.length) {
310
337
  this._notify('attribute', changesByType.attribute);
311
338
  }
312
- } else {
313
- this._log('No changes to process after filtering');
314
339
  }
315
340
  },
316
341
 
@@ -0,0 +1,22 @@
1
+ var HyperMorph=(()=>{var V=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var Y=Object.prototype.hasOwnProperty;var J=(s,o)=>{for(var u in o)V(s,u,{get:o[u],enumerable:!0})},Q=(s,o,u,d)=>{if(o&&typeof o=="object"||typeof o=="function")for(let h of G(o))!Y.call(s,h)&&h!==u&&V(s,h,{get:()=>o[h],enumerable:!(d=K(o,h))||d.enumerable});return s};var X=s=>Q(V({},"__esModule",{value:!0}),s);var pe={};J(pe,{HyperMorph:()=>$,default:()=>he,defaults:()=>fe,morph:()=>de});var F={includeClasses:!0,includeAttributes:["href","src","name","type","role","aria-label","alt","title"],excludeAttributePrefixes:["data-morph-","data-hyper-","data-im-"],textHintLength:64,excludeIds:!0,maxPathDepth:4,landmarks:["HEADER","NAV","MAIN","ASIDE","FOOTER","SECTION","ARTICLE"],weights:{signature:100,pathSegment:10,textMatch:20,textMismatch:25,uniqueCandidate:50,positionPenalty:1},minConfidence:101};function Z(s){let o=5381;for(let u=0;u<s.length;u++)o=(o<<5)+o^s.charCodeAt(u);return Math.abs(o).toString(36)}function ee(s){if(s.classList&&s.classList.length>0)return Array.from(s.classList).sort().join(" ");let o=s.getAttribute?.("class");return o?o.split(/\s+/).filter(Boolean).sort().join(" "):""}function te(s,o){let u=[];for(let d of s.attributes||[]){let h=d.name;h==="id"||h==="class"||o.excludeAttributePrefixes.some(y=>h.startsWith(y))||o.includeAttributes.includes(h)&&u.push(`${h}=${d.value}`)}return u.sort().join("|")}function ne(s,o){return(s.textContent||"").replace(/\s+/g," ").trim().slice(0,o.textHintLength)}function re(s,o){let u=[s.tagName];return o.includeClasses&&u.push(ee(s)),u.push(te(s,o)),Z(u.join("|"))}function se(s){let o=s.tagName,u=1,d=s.previousElementSibling;for(;d;)d.tagName===o&&u++,d=d.previousElementSibling;return u}function ie(s,o){return s.id||s.getAttribute?.("role")?!0:o.landmarks.includes(s.tagName)}function ae(s){if(s.id)return`#${s.id}`;let o=s.getAttribute?.("role");return o?`@${o}`:s.tagName}function oe(s,o){let u=[],d=s;for(;d&&d.tagName&&u.length<o.maxPathDepth;){let h=`${d.tagName}:${se(d)}`;if(u.unshift(h),d!==s&&ie(d,o)){u.unshift(ae(d));break}d=d.parentElement}return u}function ue(s,o){let u=0,d=s.length-1,h=o.length-1;for(;d>=0&&h>=0&&s[d]===o[h];)u++,d--,h--;return u}function C(s,o,u){if(u.has(s))return u.get(s);let d={signature:re(s,o),path:oe(s,o),textHint:ne(s,o)};return u.set(s,d),d}function z(s,o,u,d){if(d.has(s))return d.get(s);let h=new Map,y=s.querySelectorAll("*"),H=0;for(let S of y){let I=C(S,o,u);I.domIndex=H++,h.has(I.signature)||h.set(I.signature,[]),h.get(I.signature).push(S)}return d.set(s,h),h}function ce(s,o,u){u.delete(s),o.delete(s);let d=s.querySelectorAll("*");for(let h of d)o.delete(h)}function q(s,o,u,d,h){let y=C(s,u,d),H=C(o,u,d),S=u.weights,I={},E=0;if(y.signature!==H.signature)return{score:0,breakdown:{rejected:"signature mismatch"}};E+=S.signature,I.signature=S.signature;let T=ue(y.path,H.path)*S.pathSegment;E+=T,I.path=T;let k=!0;if(y.textHint&&H.textHint?y.textHint===H.textHint?(E+=S.textMatch,I.text=S.textMatch):(E-=S.textMismatch,I.text=-S.textMismatch,k=!1):y.textHint!==H.textHint&&(E-=S.textMismatch,I.text=-S.textMismatch,k=!1),h.candidateCount===1&&k&&(E+=S.uniqueCandidate,I.unique=S.uniqueCandidate),typeof y.domIndex=="number"&&typeof H.domIndex=="number"){let N=Math.abs(y.domIndex-H.domIndex),R=Math.min(N*S.positionPenalty,20);E-=R,I.drift=-R}return{score:E,breakdown:I}}function D(s,o,u,d,h){if(u.excludeIds&&s.id)return null;let y=z(o,u,d,h),H=C(s,u,d);if(typeof H.domIndex!="number"){let k=0,N=s.previousElementSibling;for(;N;)k++,N=N.previousElementSibling;H.domIndex=k}let S=y.get(H.signature)||[],I=u.excludeIds?S.filter(k=>!k.id):S;if(I.length===0)return null;let E=null,x=0,T=null;for(let k of I){let{score:N,breakdown:R}=q(s,k,u,d,{candidateCount:I.length});N>x&&(x=N,E=k,T=R)}return x<u.minConfidence?null:{element:E,confidence:x,breakdown:T}}function W(s,o,u,d,h){let y=o.querySelectorAll("*"),H=z(s,u,d,h),S=0;for(let T of y){let k=C(T,u,d);k.domIndex=S++}let I=[];for(let T of y){if(u.excludeIds&&T.id)continue;let k=C(T,u,d),N=H.get(k.signature)||[],R=u.excludeIds?N.filter(B=>!B.id):N;for(let B of R){let{score:l,breakdown:A}=q(T,B,u,d,{candidateCount:R.length});l>=u.minConfidence&&I.push({newEl:T,oldEl:B,score:l,breakdown:A})}}I.sort((T,k)=>k.score-T.score);let E=new Map,x=new Set;for(let{newEl:T,oldEl:k}of I)E.has(T)||x.has(k)||(E.set(T,k),x.add(k));return E}function P(s,o,u,d){let h=C(s,u,d),y=C(o,u,d),{score:H,breakdown:S}=q(s,o,u,d,{candidateCount:1});return{matches:H>=u.minConfidence,score:H,breakdown:S,newMeta:{signature:h.signature,path:h.path,textHint:h.textHint},oldMeta:{signature:y.signature,path:y.path,textHint:y.textHint}}}function U(s={}){let o={...F,...s,weights:{...F.weights,...s.weights}},u=new WeakMap,d=new WeakMap;return{findMatch:(h,y)=>D(h,y,o,u,d),computeMatches:(h,y)=>W(h,y,o,u,d),explain:(h,y)=>P(h,y,o,u),invalidate:h=>ce(h,u,d),session:()=>{let h=new WeakMap,y=new WeakMap;return{findMatch:(H,S)=>D(H,S,o,h,y),computeMatches:(H,S)=>W(H,S,o,h,y),explain:(H,S)=>P(H,S,o,h)}},getConfig:()=>({...o})}}var le=U(),$=(function(){"use strict";let s=()=>{};function o(l){if(!(l instanceof Element))return!1;if(l.hasAttribute("save-ignore"))return!0;if(l.tagName==="LINK"||l.tagName==="SCRIPT"){let A=l.getAttribute("src")||l.getAttribute("href")||"";if(A.startsWith("chrome-extension://")||A.startsWith("moz-extension://")||A.startsWith("safari-web-extension://"))return!0}return!1}function u(l,A){if(A!=="smart")return l.outerHTML;let p=l.getAttribute("src"),v=l.getAttribute("type")||"text/javascript";if(p)try{let b=new URL(p,window.location.href);return`ext:${v}:${b.origin}${b.pathname}`}catch{return`ext:${v}:${p}`}else{let b=l.textContent.trim(),g=5381;for(let r=0;r<b.length;r++)g=(g<<5)+g^b.charCodeAt(r);return`inline:${v}:${Math.abs(g).toString(36)}`}}let d={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:s,afterNodeAdded:s,beforeNodeMorphed:s,afterNodeMorphed:s,beforeNodeRemoved:s,afterNodeRemoved:s,beforeAttributeUpdated:s},head:{style:"merge",shouldPreserve:l=>l.getAttribute("im-preserve")==="true",shouldReAppend:l=>l.getAttribute("im-re-append")==="true",shouldRemove:s,afterHeadMorphed:s},scripts:{handle:!1,matchMode:"outerHTML",shouldPreserve:l=>l.getAttribute("im-preserve")==="true",shouldReAppend:l=>l.getAttribute("im-re-append")==="true",shouldRemove:s,afterScriptsHandled:s},restoreFocus:!0},h={computeMatches(l,A){let{computeMatches:p}=le.session();return p(l,A)}};function y(l,A,p={}){l=R(l);let v=B(A),b=N(l,v,p),g=b.scripts.matchMode,r=new Set(Array.from(l.querySelectorAll("script")).map(n=>u(n,g))),c=S(b,()=>x(b,l,v,n=>n.morphStyle==="innerHTML"?(I(n,l,v),Array.from(l.childNodes)):H(n,l,v)));b.pantry.remove();let e=k(l,r,b);return e.length>0?c instanceof Promise?c.then(n=>Promise.all(e).then(()=>n)):Promise.all(e).then(()=>c):c}function H(l,A,p){let v=B(A);return I(l,v,p,A,A.nextSibling),Array.from(v.childNodes)}function S(l,A){if(!l.config.restoreFocus)return A();let p=document.activeElement;if(!(p instanceof HTMLInputElement||p instanceof HTMLTextAreaElement))return A();let{id:v,selectionStart:b,selectionEnd:g}=p,r=A();return v&&v!==document.activeElement?.getAttribute("id")&&(p=l.target.querySelector(`[id="${v}"]`),p?.focus()),p&&!p.selectionEnd&&g!=null&&p.setSelectionRange(b,g),r}let I=(function(){function l(e,n,i,t=null,a=null){n instanceof HTMLTemplateElement&&i instanceof HTMLTemplateElement&&(n=n.content,i=i.content),t||=n.firstChild;for(let f of i.childNodes){if(o(f))continue;if(t&&t!=a){let M=p(e,f,t,a);if(M){M!==t&&b(e,t,M),E(M,f,e),t=M.nextSibling;continue}}if(f instanceof Element){let M=f.getAttribute("id");if(e.persistentIds.has(M)){let w=g(n,M,t,e);E(w,f,e),t=w.nextSibling;continue}if(!e.idMap.has(f)){let w=e.hyperMatches.get(f);if(w&&!e.idMap.has(w)){c(n,w,t),E(w,f,e),t=w.nextSibling;continue}}}let m=A(n,f,t,e);m&&(t=m.nextSibling)}for(;t&&t!=a;){let f=t;t=t.nextSibling,o(f)||v(e,f)}}function A(e,n,i,t){if(t.callbacks.beforeNodeAdded(n)===!1)return null;if(t.idMap.has(n)){let a=document.createElement(n.tagName);return e.insertBefore(a,i),E(a,n,t),t.callbacks.afterNodeAdded(a),a}else{let a=document.importNode(n,!0);return e.insertBefore(a,i),t.callbacks.afterNodeAdded(a),a}}let p=(function(){function e(t,a,f,m){let M=a instanceof Element&&!t.idMap.has(a)?t.hyperMatches.get(a):null,w=null,O=a.nextSibling,j=0,L=f;for(;L&&L!=m;){if(i(L,a)){if(n(t,L,a)||L===M&&!t.idMap.has(L))return L;if(w===null){let _=L instanceof Element&&t.hyperMatchedOldElements.has(L);!t.idMap.has(L)&&!_&&(w=L)}}if(w===null&&O&&i(L,O)&&(j++,O=O.nextSibling,j>=2&&(w=void 0)),t.activeElementAndParents.includes(L))break;L=L.nextSibling}return w||null}function n(t,a,f){let m=t.idMap.get(a),M=t.idMap.get(f);if(!M||!m)return!1;for(let w of m)if(M.has(w))return!0;return!1}function i(t,a){let f=t,m=a;return f.nodeType===m.nodeType&&f.tagName===m.tagName&&(!f.getAttribute?.("id")||f.getAttribute?.("id")===m.getAttribute?.("id"))}return e})();function v(e,n){let i=n instanceof Element&&e.hyperMatchedOldElements.has(n)&&!e.idMap.has(n);if(e.idMap.has(n)||i)c(e.pantry,n,null);else{if(e.callbacks.beforeNodeRemoved(n)===!1)return;n.parentNode?.removeChild(n),e.callbacks.afterNodeRemoved(n)}}function b(e,n,i){let t=n;for(;t&&t!==i;){let a=t;t=t.nextSibling,o(a)||v(e,a)}return t}function g(e,n,i,t){let a=t.target.getAttribute?.("id")===n&&t.target||t.target.querySelector(`[id="${n}"]`)||t.pantry.querySelector(`[id="${n}"]`);return r(a,t),c(e,a,i),a}function r(e,n){let i=e.getAttribute("id");for(;e=e.parentNode;){let t=n.idMap.get(e);t&&(t.delete(i),t.size||n.idMap.delete(e))}}function c(e,n,i){if(e.moveBefore)try{e.moveBefore(n,i)}catch{e.insertBefore(n,i)}else e.insertBefore(n,i)}return l})(),E=(function(){function l(r,c,e){return e.ignoreActive&&r===document.activeElement?null:(e.callbacks.beforeNodeMorphed(r,c)===!1||(r instanceof HTMLHeadElement&&e.head.ignore||(r instanceof HTMLHeadElement&&e.head.style!=="morph"?T(r,c,e):(A(r,c,e),g(r,e)||I(e,r,c))),e.callbacks.afterNodeMorphed(r,c)),r)}function A(r,c,e){let n=c.nodeType;if(n===1){let i=r,t=c,a=i.attributes,f=t.attributes;for(let m of f)b(m.name,i,"update",e)||i.getAttribute(m.name)!==m.value&&i.setAttribute(m.name,m.value);for(let m=a.length-1;0<=m;m--){let M=a[m];if(M&&!t.hasAttribute(M.name)){if(b(M.name,i,"remove",e))continue;i.removeAttribute(M.name)}}g(i,e)||p(i,t,e)}(n===8||n===3)&&r.nodeValue!==c.nodeValue&&(r.nodeValue=c.nodeValue)}function p(r,c,e){if(r instanceof HTMLInputElement&&c instanceof HTMLInputElement&&c.type!=="file"){let n=c.value,i=r.value;v(r,c,"checked",e),v(r,c,"disabled",e),c.hasAttribute("value")?i!==n&&(b("value",r,"update",e)||(r.setAttribute("value",n),r.value=n)):b("value",r,"remove",e)||(r.value="",r.removeAttribute("value"))}else if(r instanceof HTMLOptionElement&&c instanceof HTMLOptionElement)v(r,c,"selected",e);else if(r instanceof HTMLTextAreaElement&&c instanceof HTMLTextAreaElement){let n=c.value,i=r.value;if(b("value",r,"update",e))return;n!==i&&(r.value=n),r.firstChild&&r.firstChild.nodeValue!==n&&(r.firstChild.nodeValue=n)}}function v(r,c,e,n){let i=c[e],t=r[e];if(i!==t){let a=b(e,r,"update",n);a||(r[e]=c[e]),i?a||r.setAttribute(e,""):b(e,r,"remove",n)||r.removeAttribute(e)}}function b(r,c,e,n){return r==="value"&&n.ignoreActiveValue&&c===document.activeElement?!0:n.callbacks.beforeAttributeUpdated(r,c,e)===!1}function g(r,c){return!!c.ignoreActiveValue&&r===document.activeElement&&r!==document.body}return l})();function x(l,A,p,v){if(l.head.block){let b=A.querySelector("head"),g=p.querySelector("head");if(b&&g){let r=T(b,g,l);return Promise.all(r).then(()=>{let c=Object.assign(l,{head:{block:!1,ignore:!0}});return v(c)})}}return v(l)}function T(l,A,p){let v=[],b=[],g=[],r=[],c=p.scripts.matchMode,e=t=>{if(t.tagName==="SCRIPT")return u(t,c);if(t.tagName==="LINK"&&c==="smart"){let a=t.getAttribute("href");if(a)try{let f=new URL(a,window.location.href);return`link:${t.getAttribute("rel")||""}:${f.origin}${f.pathname}`}catch{}}return t.outerHTML},n=new Map;for(let t of A.children)o(t)||n.set(e(t),t);for(let t of l.children){let a=e(t),f=n.has(a),m=p.head.shouldReAppend(t),M=p.head.shouldPreserve(t);f||M?m?b.push(t):(n.delete(a),g.push(t)):p.head.style==="append"?m&&(b.push(t),r.push(t)):p.head.shouldRemove(t)!==!1&&!o(t)&&b.push(t)}r.push(...n.values());let i=[];for(let t of r){let a=document.createRange().createContextualFragment(t.outerHTML).firstChild;if(p.callbacks.beforeNodeAdded(a)!==!1){if("href"in a&&a.href||"src"in a&&a.src){let f,m=new Promise(function(M){f=M});a.addEventListener("load",function(){f()}),i.push(m)}l.appendChild(a),p.callbacks.afterNodeAdded(a),v.push(a)}}for(let t of b)p.callbacks.beforeNodeRemoved(t)!==!1&&(l.removeChild(t),p.callbacks.afterNodeRemoved(t));return p.head.afterHeadMorphed(l,{added:v,kept:g,removed:b}),i}function k(l,A,p){if(!p.scripts.handle)return[];let v=[],b=[],g=[],r=[],c=p.scripts.matchMode,e=Array.from(l.querySelectorAll("script"));for(let i of e){let t=u(i,c),a=A.has(t),f=p.scripts.shouldPreserve(i),m=p.scripts.shouldReAppend(i);a||f?m?(b.push(i),r.push(i)):g.push(i):r.push(i)}for(let i of A){let t=e.some(a=>a.outerHTML===i)}let n=[];for(let i of r){if(p.callbacks.beforeNodeAdded(i)===!1)continue;let t=document.createRange().createContextualFragment(i.outerHTML).firstChild;if(t.src){let a,f=new Promise(function(m){a=m});t.addEventListener("load",function(){a()}),t.addEventListener("error",function(){a()}),n.push(f)}i.replaceWith(t),p.callbacks.afterNodeAdded(t),v.push(t)}return p.scripts.afterScriptsHandled(l,{added:v,kept:g,removed:b}),n}let N=(function(){function l(e,n,i){let{persistentIds:t,idMap:a}=r(e,n),f=h.computeMatches(e,n),m=new Set;for(let O of f.values())m.add(O);let M=A(i),w=M.morphStyle||"outerHTML";if(!["innerHTML","outerHTML"].includes(w))throw`Do not understand how to morph style ${w}`;return{target:e,newContent:n,config:M,morphStyle:w,ignoreActive:M.ignoreActive,ignoreActiveValue:M.ignoreActiveValue,restoreFocus:M.restoreFocus,idMap:a,persistentIds:t,hyperMatches:f,hyperMatchedOldElements:m,pantry:p(),activeElementAndParents:v(e),callbacks:M.callbacks,head:M.head,scripts:M.scripts}}function A(e){let n=Object.assign({},d);return Object.assign(n,e),n.callbacks=Object.assign({},d.callbacks,e.callbacks),n.head=Object.assign({},d.head,e.head),n.scripts=Object.assign({},d.scripts,e.scripts),n}function p(){let e=document.createElement("div");return e.hidden=!0,document.body.insertAdjacentElement("afterend",e),e}function v(e){let n=[],i=document.activeElement;if(i?.tagName!=="BODY"&&e.contains(i))for(;i&&(n.push(i),i!==e);)i=i.parentElement;return n}function b(e){let n=Array.from(e.querySelectorAll("[id]"));return e.getAttribute?.("id")&&n.push(e),n}function g(e,n,i,t){for(let a of t){let f=a.getAttribute("id");if(n.has(f)){let m=a;for(;m;){let M=e.get(m);if(M==null&&(M=new Set,e.set(m,M)),M.add(f),m===i)break;m=m.parentElement}}}}function r(e,n){let i=b(e),t=b(n),a=c(i,t),f=new Map;g(f,a,e,i);let m=n.__hyperMorphRoot||n;return g(f,a,m,t),{persistentIds:a,idMap:f}}function c(e,n){let i=new Set,t=new Map;for(let{id:f,tagName:m}of e)t.has(f)?i.add(f):t.set(f,m);let a=new Set;for(let{id:f,tagName:m}of n)a.has(f)?i.add(f):t.get(f)===m&&a.add(f);for(let f of i)a.delete(f);return a}return l})(),{normalizeElement:R,normalizeParent:B}=(function(){let l=new WeakSet;function A(g){return g instanceof Document?g.documentElement:g}function p(g){if(g==null)return document.createElement("div");if(typeof g=="string")return p(b(g));if(l.has(g))return g;if(g instanceof Node){if(g.parentNode)return new v(g);{let r=document.createElement("div");return r.append(g),r}}else{let r=document.createElement("div");for(let c of[...g])r.append(c);return r}}class v{constructor(r){this.originalNode=r,this.realParentNode=r.parentNode,this.previousSibling=r.previousSibling,this.nextSibling=r.nextSibling}get childNodes(){let r=[],c=this.previousSibling?this.previousSibling.nextSibling:this.realParentNode.firstChild;for(;c&&c!=this.nextSibling;)r.push(c),c=c.nextSibling;return r}querySelectorAll(r){return this.childNodes.reduce((c,e)=>{if(e instanceof Element){e.matches(r)&&c.push(e);let n=e.querySelectorAll(r);for(let i=0;i<n.length;i++)c.push(n[i])}return c},[])}insertBefore(r,c){return this.realParentNode.insertBefore(r,c)}moveBefore(r,c){return this.realParentNode.moveBefore(r,c)}get __hyperMorphRoot(){return this.originalNode}}function b(g){let r=new DOMParser,c=g.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(c.match(/<\/html>/)||c.match(/<\/head>/)||c.match(/<\/body>/)){let e=r.parseFromString(g,"text/html");if(c.match(/<\/html>/))return l.add(e),e;{let n=e.firstChild;return n&&l.add(n),n}}else{let n=r.parseFromString("<body><template>"+g+"</template></body>","text/html").body.querySelector("template").content;return l.add(n),n}}return{normalizeElement:A,normalizeParent:p}})();return{morph:y,defaults:d}})();var de=$.morph,fe=$.defaults,he=$;return X(pe);})();
2
+
3
+ // Convenience morph wrapper with data-id support
4
+ var morph = function(oldEl, newEl, options = {}) {
5
+ return HyperMorph.morph(oldEl, newEl, {
6
+ key: (el) => el.getAttribute('data-id') || el.id,
7
+ ...options
8
+ });
9
+ };
10
+
11
+ // Auto-export to window unless suppressed by loader
12
+ if (!window.__hyperclayNoAutoExport) {
13
+ window.hyperclay = window.hyperclay || {};
14
+ window.hyperclay.HyperMorph = HyperMorph;
15
+ window.hyperclay.morph = morph;
16
+ window.HyperMorph = HyperMorph;
17
+ window.morph = morph;
18
+ window.h = window.hyperclay;
19
+ }
20
+
21
+ export { HyperMorph, morph };
22
+ export default HyperMorph;
@@ -1,20 +0,0 @@
1
- var Idiomorph=function(){"use strict";let o=new Set;let n={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:t,afterNodeAdded:t,beforeNodeMorphed:t,afterNodeMorphed:t,beforeNodeRemoved:t,afterNodeRemoved:t,beforeAttributeUpdated:t},head:{style:"merge",shouldPreserve:function(e){return e.getAttribute("im-preserve")==="true"},shouldReAppend:function(e){return e.getAttribute("im-re-append")==="true"},shouldRemove:t,afterHeadMorphed:t}};function e(e,t,n={}){if(e instanceof Document){e=e.documentElement}if(typeof t==="string"){t=k(t)}let l=y(t);let r=p(e,l,n);return a(e,l,r)}function a(r,i,o){if(o.head.block){let t=r.querySelector("head");let n=i.querySelector("head");if(t&&n){let e=c(n,t,o);Promise.all(e).then(function(){a(r,i,Object.assign(o,{head:{block:false,ignore:true}}))});return}}if(o.morphStyle==="innerHTML"){l(i,r,o);return r.children}else if(o.morphStyle==="outerHTML"||o.morphStyle==null){let e=M(i,r,o);let t=e?.previousSibling;let n=e?.nextSibling;let l=d(r,e,o);if(e){return N(t,l,n)}else{return[]}}else{throw"Do not understand how to morph style "+o.morphStyle}}function u(e,t){return t.ignoreActiveValue&&e===document.activeElement}function d(e,t,n){if(n.ignoreActive&&e===document.activeElement){}else if(t==null){if(n.callbacks.beforeNodeRemoved(e)===false)return e;e.remove();n.callbacks.afterNodeRemoved(e);return null}else if(!g(e,t)){if(n.callbacks.beforeNodeRemoved(e)===false)return e;if(n.callbacks.beforeNodeAdded(t)===false)return e;e.parentElement.replaceChild(t,e);n.callbacks.afterNodeAdded(t);n.callbacks.afterNodeRemoved(e);return t}else{if(n.callbacks.beforeNodeMorphed(e,t)===false)return e;if(e instanceof HTMLHeadElement&&n.head.ignore){}else if(e instanceof HTMLHeadElement&&n.head.style!=="morph"){c(t,e,n)}else{r(t,e,n);if(!u(e,n)){l(t,e,n)}}n.callbacks.afterNodeMorphed(e,t);return e}}function l(n,l,r){let i=n.firstChild;let o=l.firstChild;let a;while(i){a=i;i=a.nextSibling;if(o==null){if(r.callbacks.beforeNodeAdded(a)===false)return;l.appendChild(a);r.callbacks.afterNodeAdded(a);H(r,a);continue}if(b(a,o,r)){d(o,a,r);o=o.nextSibling;H(r,a);continue}let e=A(n,l,a,o,r);if(e){o=v(o,e,r);d(e,a,r);H(r,a);continue}let t=S(n,l,a,o,r);if(t){o=v(o,t,r);d(t,a,r);H(r,a);continue}if(r.callbacks.beforeNodeAdded(a)===false)return;l.insertBefore(a,o);r.callbacks.afterNodeAdded(a);H(r,a)}while(o!==null){let e=o;o=o.nextSibling;T(e,r)}}function f(e,t,n,l){if(e==="value"&&l.ignoreActiveValue&&t===document.activeElement){return true}return l.callbacks.beforeAttributeUpdated(e,t,n)===false}function r(t,n,l){let e=t.nodeType;if(e===1){const r=t.attributes;const i=n.attributes;for(const o of r){if(f(o.name,n,"update",l)){continue}if(n.getAttribute(o.name)!==o.value){n.setAttribute(o.name,o.value)}}for(let e=i.length-1;0<=e;e--){const a=i[e];if(f(a.name,n,"remove",l)){continue}if(!t.hasAttribute(a.name)){n.removeAttribute(a.name)}}}if(e===8||e===3){if(n.nodeValue!==t.nodeValue){n.nodeValue=t.nodeValue}}if(!u(n,l)){s(t,n,l)}}function i(t,n,l,r){if(t[l]!==n[l]){let e=f(l,n,"update",r);if(!e){n[l]=t[l]}if(t[l]){if(!e){n.setAttribute(l,t[l])}}else{if(!f(l,n,"remove",r)){n.removeAttribute(l)}}}}function s(n,l,r){if(n instanceof HTMLInputElement&&l instanceof HTMLInputElement&&n.type!=="file"){let e=n.value;let t=l.value;i(n,l,"checked",r);i(n,l,"disabled",r);if(!n.hasAttribute("value")){if(!f("value",l,"remove",r)){l.value="";l.removeAttribute("value")}}else if(e!==t){if(!f("value",l,"update",r)){l.setAttribute("value",e);l.value=e}}}else if(n instanceof HTMLOptionElement){i(n,l,"selected",r)}else if(n instanceof HTMLTextAreaElement&&l instanceof HTMLTextAreaElement){let e=n.value;let t=l.value;if(f("value",l,"update",r)){return}if(e!==t){l.value=e}if(l.firstChild&&l.firstChild.nodeValue!==e){l.firstChild.nodeValue=e}}}function c(e,t,l){let r=[];let i=[];let o=[];let a=[];let u=l.head.style;let d=new Map;for(const n of e.children){d.set(n.outerHTML,n)}for(const s of t.children){let e=d.has(s.outerHTML);let t=l.head.shouldReAppend(s);let n=l.head.shouldPreserve(s);if(e||n){if(t){i.push(s)}else{d.delete(s.outerHTML);o.push(s)}}else{if(u==="append"){if(t){i.push(s);a.push(s)}}else{if(l.head.shouldRemove(s)!==false){i.push(s)}}}}a.push(...d.values());m("to append: ",a);let f=[];for(const c of a){m("adding: ",c);let n=document.createRange().createContextualFragment(c.outerHTML).firstChild;m(n);if(l.callbacks.beforeNodeAdded(n)!==false){if(n.href||n.src){let t=null;let e=new Promise(function(e){t=e});n.addEventListener("load",function(){t()});f.push(e)}t.appendChild(n);l.callbacks.afterNodeAdded(n);r.push(n)}}for(const h of i){if(l.callbacks.beforeNodeRemoved(h)!==false){t.removeChild(h);l.callbacks.afterNodeRemoved(h)}}l.head.afterHeadMorphed(t,{added:r,kept:o,removed:i});return f}function m(){}function t(){}function h(e){let t={};Object.assign(t,n);Object.assign(t,e);t.callbacks={};Object.assign(t.callbacks,n.callbacks);Object.assign(t.callbacks,e.callbacks);t.head={};Object.assign(t.head,n.head);Object.assign(t.head,e.head);return t}function p(e,t,n){n=h(n);return{target:e,newContent:t,config:n,morphStyle:n.morphStyle,ignoreActive:n.ignoreActive,ignoreActiveValue:n.ignoreActiveValue,idMap:C(e,t),deadIds:new Set,callbacks:n.callbacks,head:n.head}}function b(e,t,n){if(e==null||t==null){return false}if(e.nodeType===t.nodeType&&e.tagName===t.tagName){if(e.id!==""&&e.id===t.id){return true}else{return L(n,e,t)>0}}return false}function g(e,t){if(e==null||t==null){return false}return e.nodeType===t.nodeType&&e.tagName===t.tagName}function v(t,e,n){while(t!==e){let e=t;t=t.nextSibling;T(e,n)}H(n,e);return e.nextSibling}function A(n,e,l,r,i){let o=L(i,l,e);let t=null;if(o>0){let e=r;let t=0;while(e!=null){if(b(l,e,i)){return e}t+=L(i,e,n);if(t>o){return null}e=e.nextSibling}}return t}function S(e,t,n,l,r){let i=l;let o=n.nextSibling;let a=0;while(i!=null){if(L(r,i,e)>0){return null}if(g(n,i)){return i}if(g(o,i)){a++;o=o.nextSibling;if(a>=2){return null}}i=i.nextSibling}return i}function k(n){let l=new DOMParser;let e=n.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(e.match(/<\/html>/)||e.match(/<\/head>/)||e.match(/<\/body>/)){let t=l.parseFromString(n,"text/html");if(e.match(/<\/html>/)){t.generatedByIdiomorph=true;return t}else{let e=t.firstChild;if(e){e.generatedByIdiomorph=true;return e}else{return null}}}else{let e=l.parseFromString("<body><template>"+n+"</template></body>","text/html");let t=e.body.querySelector("template").content;t.generatedByIdiomorph=true;return t}}function y(e){if(e==null){const t=document.createElement("div");return t}else if(e.generatedByIdiomorph){return e}else if(e instanceof Node){const t=document.createElement("div");t.append(e);return t}else{const t=document.createElement("div");for(const n of[...e]){t.append(n)}return t}}function N(e,t,n){let l=[];let r=[];while(e!=null){l.push(e);e=e.previousSibling}while(l.length>0){let e=l.pop();r.push(e);t.parentElement.insertBefore(e,t)}r.push(t);while(n!=null){l.push(n);r.push(n);n=n.nextSibling}while(l.length>0){t.parentElement.insertBefore(l.pop(),t.nextSibling)}return r}function M(e,t,n){let l;l=e.firstChild;let r=l;let i=0;while(l){let e=w(l,t,n);if(e>i){r=l;i=e}l=l.nextSibling}return r}function w(e,t,n){if(g(e,t)){return.5+L(n,e,t)}return 0}function T(e,t){H(t,e);if(t.callbacks.beforeNodeRemoved(e)===false)return;e.remove();t.callbacks.afterNodeRemoved(e)}function E(e,t){return!e.deadIds.has(t)}function x(e,t,n){let l=e.idMap.get(n)||o;return l.has(t)}function H(e,t){let n=e.idMap.get(t)||o;for(const l of n){e.deadIds.add(l)}}function L(e,t,n){let l=e.idMap.get(t)||o;let r=0;for(const i of l){if(E(e,i)&&x(e,i,n)){++r}}return r}function R(e,n){let l=e.parentElement;let t=e.querySelectorAll("[id]");for(const r of t){let t=r;while(t!==l&&t!=null){let e=n.get(t);if(e==null){e=new Set;n.set(t,e)}e.add(r.id);t=t.parentElement}}}function C(e,t){let n=new Map;R(e,n);R(t,n);return n}return{morph:e,defaults:n}}();
2
- // MODIFIED, added `morph`
3
- var morph = function(oldEl, newEl, options = {}) {
4
- return Idiomorph.morph(oldEl, newEl, {
5
- key: (el) => el.getAttribute('data-id') || el.id,
6
- ...options
7
- });
8
- };
9
-
10
- // Auto-export to window unless suppressed by loader
11
- if (!window.__hyperclayNoAutoExport) {
12
- window.hyperclay = window.hyperclay || {};
13
- window.hyperclay.Idiomorph = Idiomorph;
14
- window.hyperclay.morph = morph;
15
- window.morph = morph;
16
- window.h = window.hyperclay;
17
- }
18
-
19
- export { Idiomorph, morph };
20
- export default Idiomorph;