@jasonshimmy/custom-elements-runtime 2.8.0 → 2.8.1

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.
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let u=0;function h(){u=0}function a(){return u++}function s(t,e,n){const r=n??`when-block-${u++}`;return o(typeof e=="function"?t?e():[]:t?e:[],r)}function f(t,e){return t.map((n,r)=>{const c=typeof n=="object"?n?.key??n?.id??`idx-${r}`:String(n);return o(e(n,r),`each-${c}`)})}function l(){const t=[];return{when(e,n){return t.push([e,n]),this},otherwise(e){return t.push([!0,e]),this},done(){const e=u++;for(let n=0;n<t.length;n++){const[r,c]=t[n];if(r){const i=typeof c=="function"?c():c;return[o(i,`match-${e}-branch-${n}`)]}}return[o([],`match-${e}-empty`)]}}}function o(t,e){const n=t?Array.isArray(t)?t.filter(r=>r!=null):[t].filter(r=>r!=null):[];return{tag:"#anchor",key:e,children:n}}exports.anchorBlock=o;exports.each=f;exports.match=l;exports.nextDirectiveIndex=a;exports.resetWhenCounter=h;exports.when=s;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let u="",i=0;const h=[];function y(){u="",i=0,h.length=0}function d(){return i++}function a(n){const t=i++;return n!==void 0?n:u?`${u}.${t}`:`when-block-${t}`}function f(n){h.push([u,i]),u=n,i=0}function l(){const n=h[h.length-1];n&&(h.length--,[u,i]=n)}function $(n,t,e){const r=a(e);if(typeof t!="function")return o(n?t:[],r);if(!n)return o([],r);f(r);const c=t();return l(),o(c,r)}function g(n,t){return n.map((e,r)=>{const c=typeof e=="object"?e?.key??e?.id??`idx-${r}`:String(e);return o(t(e,r),`each-${c}`)})}function x(){const n=[];return{when(t,e){return n.push([t,e]),this},otherwise(t){return n.push([!0,t]),this},done(){const t=`match-${a()}`;for(let e=0;e<n.length;e++){const[r,c]=n[e];if(r){const s=`${t}-branch-${e}`;if(typeof c=="function"){f(s);const p=c();return l(),[o(p,s)]}return[o(c,s)]}}return[o([],`${t}-empty`)]}}}function o(n,t){const e=n?Array.isArray(n)?n.filter(r=>r!=null):[n].filter(r=>r!=null):[];return{tag:"#anchor",key:t,children:e}}exports.anchorBlock=o;exports.each=g;exports.match=x;exports.nextDirectiveIndex=d;exports.resetWhenCounter=y;exports.when=$;
2
2
  //# sourceMappingURL=custom-elements-runtime.directives.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"custom-elements-runtime.directives.cjs.js","sources":["../src/lib/directives.ts"],"sourcesContent":["import type { VNode } from './runtime/types';\n\n/* --- Directive call counter (per-render, reset by the component renderer) --- */\nlet _directiveCallIndex = 0;\n\n/**\n * Reset the per-render directive call counter.\n * Must be called once at the start of every component render pass so that\n * all sibling directive calls automatically receive stable, unique positional keys.\n * @internal\n */\nexport function resetWhenCounter(): void {\n _directiveCallIndex = 0;\n}\n\n/**\n * Get the next per-render directive call index and increment the counter.\n * Used by directives in directive-enhancements.ts to generate unique anchor keys.\n * @internal\n */\nexport function nextDirectiveIndex(): number {\n return _directiveCallIndex++;\n}\n\n/* --- When --- */\nexport function when(\n cond: boolean,\n children: VNode | VNode[],\n key?: string,\n): VNode;\nexport function when(\n cond: boolean,\n factory: () => VNode | VNode[],\n key?: string,\n): VNode;\nexport function when(\n cond: boolean,\n childrenOrFactory: VNode | VNode[] | (() => VNode | VNode[]),\n key?: string,\n): VNode {\n const anchorKey = key ?? `when-block-${_directiveCallIndex++}`;\n if (typeof childrenOrFactory === 'function') {\n return anchorBlock(cond ? childrenOrFactory() : [], anchorKey);\n }\n return anchorBlock(cond ? childrenOrFactory : [], anchorKey);\n}\n\n/* --- Each --- */\nexport function each<\n T extends string | number | boolean | { id?: string | number; key?: string },\n>(list: T[], render: (item: T, index: number) => VNode | VNode[]): VNode[] {\n return list.map((item, i) => {\n // For primitives, use value as key; for objects, prefer key/id\n const itemKey =\n typeof item === 'object'\n ? ((item as Record<string, unknown>)?.key ??\n (item as Record<string, unknown>)?.id ??\n `idx-${i}`)\n : String(item);\n return anchorBlock(render(item, i), `each-${itemKey}`);\n });\n}\n\n/* --- match --- */\ntype Branch = [\n condition: unknown,\n content: VNode | VNode[] | (() => VNode | VNode[]),\n];\n\nexport function match() {\n const branches: Branch[] = [];\n return {\n when(cond: unknown, content: VNode | VNode[] | (() => VNode | VNode[])) {\n branches.push([cond, content]);\n return this;\n },\n otherwise(content: VNode | VNode[]) {\n branches.push([true, content]);\n return this;\n },\n done() {\n const mi = _directiveCallIndex++;\n for (let idx = 0; idx < branches.length; idx++) {\n const [cond, content] = branches[idx];\n if (cond) {\n const payload =\n typeof content === 'function'\n ? (content as () => VNode | VNode[])()\n : content;\n return [anchorBlock(payload, `match-${mi}-branch-${idx}`)];\n }\n }\n return [anchorBlock([], `match-${mi}-empty`)];\n },\n };\n}\n\n/**\n * Create a stable anchor block with consistent boundaries.\n * Always has start/end boundaries.\n */\nexport function anchorBlock(\n children: VNode | VNode[] | null | undefined,\n anchorKey: string,\n): VNode {\n // Normalize children to array, filtering out only null/undefined values.\n // Preserve meaningful falsy values such as 0, false, and empty string.\n const childArray = !children\n ? []\n : Array.isArray(children)\n ? children.filter((c) => c !== null && c !== undefined)\n : [children].filter((c) => c !== null && c !== undefined);\n\n return {\n tag: '#anchor',\n key: anchorKey,\n children: childArray,\n };\n}\n"],"names":["_directiveCallIndex","resetWhenCounter","nextDirectiveIndex","when","cond","childrenOrFactory","key","anchorKey","anchorBlock","each","list","render","item","i","itemKey","match","branches","content","mi","idx","payload","children","childArray","c"],"mappings":"gFAGA,IAAIA,EAAsB,EAQnB,SAASC,GAAyB,CACvCD,EAAsB,CACxB,CAOO,SAASE,GAA6B,CAC3C,OAAOF,GACT,CAaO,SAASG,EACdC,EACAC,EACAC,EACO,CACP,MAAMC,EAAYD,GAAO,cAAcN,GAAqB,GAC5D,OACSQ,EADL,OAAOH,GAAsB,WACZD,EAAOC,EAAA,EAAsB,CAAA,EAE/BD,EAAOC,EAAoB,CAAA,EAFQE,CAAS,CAGjE,CAGO,SAASE,EAEdC,EAAWC,EAA8D,CACzE,OAAOD,EAAK,IAAI,CAACE,EAAMC,IAAM,CAE3B,MAAMC,EACJ,OAAOF,GAAS,SACVA,GAAkC,KACnCA,GAAkC,IACnC,OAAOC,CAAC,GACR,OAAOD,CAAI,EACjB,OAAOJ,EAAYG,EAAOC,EAAMC,CAAC,EAAG,QAAQC,CAAO,EAAE,CACvD,CAAC,CACH,CAQO,SAASC,GAAQ,CACtB,MAAMC,EAAqB,CAAA,EAC3B,MAAO,CACL,KAAKZ,EAAea,EAAoD,CACtE,OAAAD,EAAS,KAAK,CAACZ,EAAMa,CAAO,CAAC,EACtB,IACT,EACA,UAAUA,EAA0B,CAClC,OAAAD,EAAS,KAAK,CAAC,GAAMC,CAAO,CAAC,EACtB,IACT,EACA,MAAO,CACL,MAAMC,EAAKlB,IACX,QAASmB,EAAM,EAAGA,EAAMH,EAAS,OAAQG,IAAO,CAC9C,KAAM,CAACf,EAAMa,CAAO,EAAID,EAASG,CAAG,EACpC,GAAIf,EAAM,CACR,MAAMgB,EACJ,OAAOH,GAAY,WACdA,IACDA,EACN,MAAO,CAACT,EAAYY,EAAS,SAASF,CAAE,WAAWC,CAAG,EAAE,CAAC,CAC3D,CACF,CACA,MAAO,CAACX,EAAY,GAAI,SAASU,CAAE,QAAQ,CAAC,CAC9C,CAAA,CAEJ,CAMO,SAASV,EACda,EACAd,EACO,CAGP,MAAMe,EAAcD,EAEhB,MAAM,QAAQA,CAAQ,EACpBA,EAAS,OAAQE,GAAMA,GAAM,IAAuB,EACpD,CAACF,CAAQ,EAAE,OAAQE,GAAMA,GAAM,IAAuB,EAHxD,CAAA,EAKJ,MAAO,CACL,IAAK,UACL,IAAKhB,EACL,SAAUe,CAAA,CAEd"}
1
+ {"version":3,"file":"custom-elements-runtime.directives.cjs.js","sources":["../src/lib/directives.ts"],"sourcesContent":["import type { VNode } from './runtime/types';\n\n// ── Per-render directive scope tracking ─────────────────────────────────────\n//\n// A FLAT counter (index++) breaks when a when() factory itself contains more\n// when() calls: those inner calls consume counter slots, causing SUBSEQUENT\n// SIBLING when() calls to get a different index depending on whether the factory\n// ran. For example:\n//\n// when(A, () => { when(B); when(C); }) // ← factory may or may not run\n// when(D) // ← index shifts when factory runs\n//\n// The fix: each when() call claims its own slot (stable regardless of whether\n// the factory runs), then ENTERS a new child scope for the factory. Inner\n// when() calls consume indices in that child scope, never bleeding into the\n// sibling counter of the outer scope.\n//\n// Key format: root sibling 0 \"when-block-0\"\n// child of \"when-block-0\" at pos 1 → \"when-block-0.1\"\n// grandchild → \"when-block-0.1.0\" etc.\n\n/** Current scope's parent prefix (empty string = root scope). */\nlet _scopeParent = '';\n/** Next sibling index inside the current scope. */\nlet _scopeIndex = 0;\n/** Stack of [parentPrefix, siblingIndex] for nested scopes. */\nconst _scopeStack: Array<readonly [string, number]> = [];\n\n/**\n * Reset all scope state at the start of each component render pass.\n * Called automatically by the component renderer — not needed in user code.\n * @internal\n */\nexport function resetWhenCounter(): void {\n _scopeParent = '';\n _scopeIndex = 0;\n _scopeStack.length = 0;\n}\n\n/**\n * Claim the next directive call index within the current scope.\n * Used by directive-enhancements.ts for non-when() directives (switchOnLength,\n * switchOnPromise, etc.) that need a stable unique number per call site.\n * @internal\n */\nexport function nextDirectiveIndex(): number {\n return _scopeIndex++;\n}\n\n/** Claim the next slot in the current scope and return its anchor key. */\nfunction claimKey(explicitKey?: string): string {\n const idx = _scopeIndex++;\n if (explicitKey !== undefined) return explicitKey;\n return _scopeParent ? `${_scopeParent}.${idx}` : `when-block-${idx}`;\n}\n\n/** Push a new child scope keyed under `anchorKey`. */\nfunction enterScope(anchorKey: string): void {\n _scopeStack.push([_scopeParent, _scopeIndex] as const);\n _scopeParent = anchorKey;\n _scopeIndex = 0;\n}\n\n/** Pop back to the parent scope. */\nfunction exitScope(): void {\n const top = _scopeStack[_scopeStack.length - 1];\n if (top) {\n _scopeStack.length--;\n [_scopeParent, _scopeIndex] = top;\n }\n}\n\n/* --- When --- */\nexport function when(\n cond: boolean,\n children: VNode | VNode[],\n key?: string,\n): VNode;\nexport function when(\n cond: boolean,\n factory: () => VNode | VNode[],\n key?: string,\n): VNode;\nexport function when(\n cond: boolean,\n childrenOrFactory: VNode | VNode[] | (() => VNode | VNode[]),\n key?: string,\n): VNode {\n // Claim this call's position BEFORE potentially entering a child scope.\n // This guarantees sibling when() calls always get the same index regardless\n // of whether a factory executes and how many when() calls it contains.\n const anchorKey = claimKey(key);\n\n if (typeof childrenOrFactory !== 'function') {\n return anchorBlock(cond ? childrenOrFactory : [], anchorKey);\n }\n\n if (!cond) {\n return anchorBlock([], anchorKey);\n }\n\n // Run the factory in a child scope so its inner when() calls don't\n // affect the sibling counter of the outer scope.\n enterScope(anchorKey);\n const children = childrenOrFactory();\n exitScope();\n return anchorBlock(children, anchorKey);\n}\n\n/* --- Each --- */\nexport function each<\n T extends string | number | boolean | { id?: string | number; key?: string },\n>(list: T[], render: (item: T, index: number) => VNode | VNode[]): VNode[] {\n return list.map((item, i) => {\n // For primitives, use value as key; for objects, prefer key/id\n const itemKey =\n typeof item === 'object'\n ? ((item as Record<string, unknown>)?.key ??\n (item as Record<string, unknown>)?.id ??\n `idx-${i}`)\n : String(item);\n return anchorBlock(render(item, i), `each-${itemKey}`);\n });\n}\n\n/* --- match --- */\ntype Branch = [\n condition: unknown,\n content: VNode | VNode[] | (() => VNode | VNode[]),\n];\n\nexport function match() {\n const branches: Branch[] = [];\n return {\n when(cond: unknown, content: VNode | VNode[] | (() => VNode | VNode[])) {\n branches.push([cond, content]);\n return this;\n },\n otherwise(content: VNode | VNode[]) {\n branches.push([true, content]);\n return this;\n },\n done() {\n const matchKey = `match-${claimKey()}`;\n for (let idx = 0; idx < branches.length; idx++) {\n const [cond, content] = branches[idx];\n if (cond) {\n const branchKey = `${matchKey}-branch-${idx}`;\n if (typeof content === 'function') {\n enterScope(branchKey);\n const payload = (content as () => VNode | VNode[])();\n exitScope();\n return [anchorBlock(payload, branchKey)];\n }\n return [anchorBlock(content, branchKey)];\n }\n }\n return [anchorBlock([], `${matchKey}-empty`)];\n },\n };\n}\n\n/**\n * Create a stable anchor block with consistent boundaries.\n * Always has start/end boundaries.\n */\nexport function anchorBlock(\n children: VNode | VNode[] | null | undefined,\n anchorKey: string,\n): VNode {\n // Normalize children to array, filtering out only null/undefined values.\n // Preserve meaningful falsy values such as 0, false, and empty string.\n const childArray = !children\n ? []\n : Array.isArray(children)\n ? children.filter((c) => c !== null && c !== undefined)\n : [children].filter((c) => c !== null && c !== undefined);\n\n return {\n tag: '#anchor',\n key: anchorKey,\n children: childArray,\n };\n}\n"],"names":["_scopeParent","_scopeIndex","_scopeStack","resetWhenCounter","nextDirectiveIndex","claimKey","explicitKey","idx","enterScope","anchorKey","exitScope","top","when","cond","childrenOrFactory","key","anchorBlock","children","each","list","render","item","i","itemKey","match","branches","content","matchKey","branchKey","payload","childArray","c"],"mappings":"gFAsBA,IAAIA,EAAe,GAEfC,EAAc,EAElB,MAAMC,EAAgD,CAAA,EAO/C,SAASC,GAAyB,CACvCH,EAAe,GACfC,EAAc,EACdC,EAAY,OAAS,CACvB,CAQO,SAASE,GAA6B,CAC3C,OAAOH,GACT,CAGA,SAASI,EAASC,EAA8B,CAC9C,MAAMC,EAAMN,IACZ,OAAIK,IAAgB,OAAkBA,EAC/BN,EAAe,GAAGA,CAAY,IAAIO,CAAG,GAAK,cAAcA,CAAG,EACpE,CAGA,SAASC,EAAWC,EAAyB,CAC3CP,EAAY,KAAK,CAACF,EAAcC,CAAW,CAAU,EACrDD,EAAeS,EACfR,EAAc,CAChB,CAGA,SAASS,GAAkB,CACzB,MAAMC,EAAMT,EAAYA,EAAY,OAAS,CAAC,EAC1CS,IACFT,EAAY,SACZ,CAACF,EAAcC,CAAW,EAAIU,EAElC,CAaO,SAASC,EACdC,EACAC,EACAC,EACO,CAIP,MAAMN,EAAYJ,EAASU,CAAG,EAE9B,GAAI,OAAOD,GAAsB,WAC/B,OAAOE,EAAYH,EAAOC,EAAoB,CAAA,EAAIL,CAAS,EAG7D,GAAI,CAACI,EACH,OAAOG,EAAY,CAAA,EAAIP,CAAS,EAKlCD,EAAWC,CAAS,EACpB,MAAMQ,EAAWH,EAAA,EACjB,OAAAJ,EAAA,EACOM,EAAYC,EAAUR,CAAS,CACxC,CAGO,SAASS,EAEdC,EAAWC,EAA8D,CACzE,OAAOD,EAAK,IAAI,CAACE,EAAMC,IAAM,CAE3B,MAAMC,EACJ,OAAOF,GAAS,SACVA,GAAkC,KACnCA,GAAkC,IACnC,OAAOC,CAAC,GACR,OAAOD,CAAI,EACjB,OAAOL,EAAYI,EAAOC,EAAMC,CAAC,EAAG,QAAQC,CAAO,EAAE,CACvD,CAAC,CACH,CAQO,SAASC,GAAQ,CACtB,MAAMC,EAAqB,CAAA,EAC3B,MAAO,CACL,KAAKZ,EAAea,EAAoD,CACtE,OAAAD,EAAS,KAAK,CAACZ,EAAMa,CAAO,CAAC,EACtB,IACT,EACA,UAAUA,EAA0B,CAClC,OAAAD,EAAS,KAAK,CAAC,GAAMC,CAAO,CAAC,EACtB,IACT,EACA,MAAO,CACL,MAAMC,EAAW,SAAStB,EAAA,CAAU,GACpC,QAASE,EAAM,EAAGA,EAAMkB,EAAS,OAAQlB,IAAO,CAC9C,KAAM,CAACM,EAAMa,CAAO,EAAID,EAASlB,CAAG,EACpC,GAAIM,EAAM,CACR,MAAMe,EAAY,GAAGD,CAAQ,WAAWpB,CAAG,GAC3C,GAAI,OAAOmB,GAAY,WAAY,CACjClB,EAAWoB,CAAS,EACpB,MAAMC,EAAWH,EAAA,EACjB,OAAAhB,EAAA,EACO,CAACM,EAAYa,EAASD,CAAS,CAAC,CACzC,CACA,MAAO,CAACZ,EAAYU,EAASE,CAAS,CAAC,CACzC,CACF,CACA,MAAO,CAACZ,EAAY,CAAA,EAAI,GAAGW,CAAQ,QAAQ,CAAC,CAC9C,CAAA,CAEJ,CAMO,SAASX,EACdC,EACAR,EACO,CAGP,MAAMqB,EAAcb,EAEhB,MAAM,QAAQA,CAAQ,EACpBA,EAAS,OAAQc,GAAMA,GAAM,IAAuB,EACpD,CAACd,CAAQ,EAAE,OAAQc,GAAMA,GAAM,IAAuB,EAHxD,CAAA,EAKJ,MAAO,CACL,IAAK,UACL,IAAKtB,EACL,SAAUqB,CAAA,CAEd"}
@@ -1,56 +1,79 @@
1
- let c = 0;
2
- function h() {
3
- c = 0;
1
+ let u = "", i = 0;
2
+ const s = [];
3
+ function y() {
4
+ u = "", i = 0, s.length = 0;
4
5
  }
5
- function a() {
6
- return c++;
6
+ function d() {
7
+ return i++;
7
8
  }
8
- function f(t, e, n) {
9
- const r = n ?? `when-block-${c++}`;
10
- return u(typeof e == "function" ? t ? e() : [] : t ? e : [], r);
9
+ function h(n) {
10
+ const t = i++;
11
+ return n !== void 0 ? n : u ? `${u}.${t}` : `when-block-${t}`;
11
12
  }
12
- function s(t, e) {
13
- return t.map((n, r) => {
14
- const o = typeof n == "object" ? n?.key ?? n?.id ?? `idx-${r}` : String(n);
15
- return u(e(n, r), `each-${o}`);
13
+ function a(n) {
14
+ s.push([u, i]), u = n, i = 0;
15
+ }
16
+ function p() {
17
+ const n = s[s.length - 1];
18
+ n && (s.length--, [u, i] = n);
19
+ }
20
+ function $(n, t, e) {
21
+ const r = h(e);
22
+ if (typeof t != "function")
23
+ return c(n ? t : [], r);
24
+ if (!n)
25
+ return c([], r);
26
+ a(r);
27
+ const o = t();
28
+ return p(), c(o, r);
29
+ }
30
+ function x(n, t) {
31
+ return n.map((e, r) => {
32
+ const o = typeof e == "object" ? e?.key ?? e?.id ?? `idx-${r}` : String(e);
33
+ return c(t(e, r), `each-${o}`);
16
34
  });
17
35
  }
18
- function l() {
19
- const t = [];
36
+ function g() {
37
+ const n = [];
20
38
  return {
21
- when(e, n) {
22
- return t.push([e, n]), this;
39
+ when(t, e) {
40
+ return n.push([t, e]), this;
23
41
  },
24
- otherwise(e) {
25
- return t.push([!0, e]), this;
42
+ otherwise(t) {
43
+ return n.push([!0, t]), this;
26
44
  },
27
45
  done() {
28
- const e = c++;
29
- for (let n = 0; n < t.length; n++) {
30
- const [r, o] = t[n];
46
+ const t = `match-${h()}`;
47
+ for (let e = 0; e < n.length; e++) {
48
+ const [r, o] = n[e];
31
49
  if (r) {
32
- const i = typeof o == "function" ? o() : o;
33
- return [u(i, `match-${e}-branch-${n}`)];
50
+ const f = `${t}-branch-${e}`;
51
+ if (typeof o == "function") {
52
+ a(f);
53
+ const l = o();
54
+ return p(), [c(l, f)];
55
+ }
56
+ return [c(o, f)];
34
57
  }
35
58
  }
36
- return [u([], `match-${e}-empty`)];
59
+ return [c([], `${t}-empty`)];
37
60
  }
38
61
  };
39
62
  }
40
- function u(t, e) {
41
- const n = t ? Array.isArray(t) ? t.filter((r) => r != null) : [t].filter((r) => r != null) : [];
63
+ function c(n, t) {
64
+ const e = n ? Array.isArray(n) ? n.filter((r) => r != null) : [n].filter((r) => r != null) : [];
42
65
  return {
43
66
  tag: "#anchor",
44
- key: e,
45
- children: n
67
+ key: t,
68
+ children: e
46
69
  };
47
70
  }
48
71
  export {
49
- u as anchorBlock,
50
- s as each,
51
- l as match,
52
- a as nextDirectiveIndex,
53
- h as resetWhenCounter,
54
- f as when
72
+ c as anchorBlock,
73
+ x as each,
74
+ g as match,
75
+ d as nextDirectiveIndex,
76
+ y as resetWhenCounter,
77
+ $ as when
55
78
  };
56
79
  //# sourceMappingURL=custom-elements-runtime.directives.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"custom-elements-runtime.directives.es.js","sources":["../src/lib/directives.ts"],"sourcesContent":["import type { VNode } from './runtime/types';\n\n/* --- Directive call counter (per-render, reset by the component renderer) --- */\nlet _directiveCallIndex = 0;\n\n/**\n * Reset the per-render directive call counter.\n * Must be called once at the start of every component render pass so that\n * all sibling directive calls automatically receive stable, unique positional keys.\n * @internal\n */\nexport function resetWhenCounter(): void {\n _directiveCallIndex = 0;\n}\n\n/**\n * Get the next per-render directive call index and increment the counter.\n * Used by directives in directive-enhancements.ts to generate unique anchor keys.\n * @internal\n */\nexport function nextDirectiveIndex(): number {\n return _directiveCallIndex++;\n}\n\n/* --- When --- */\nexport function when(\n cond: boolean,\n children: VNode | VNode[],\n key?: string,\n): VNode;\nexport function when(\n cond: boolean,\n factory: () => VNode | VNode[],\n key?: string,\n): VNode;\nexport function when(\n cond: boolean,\n childrenOrFactory: VNode | VNode[] | (() => VNode | VNode[]),\n key?: string,\n): VNode {\n const anchorKey = key ?? `when-block-${_directiveCallIndex++}`;\n if (typeof childrenOrFactory === 'function') {\n return anchorBlock(cond ? childrenOrFactory() : [], anchorKey);\n }\n return anchorBlock(cond ? childrenOrFactory : [], anchorKey);\n}\n\n/* --- Each --- */\nexport function each<\n T extends string | number | boolean | { id?: string | number; key?: string },\n>(list: T[], render: (item: T, index: number) => VNode | VNode[]): VNode[] {\n return list.map((item, i) => {\n // For primitives, use value as key; for objects, prefer key/id\n const itemKey =\n typeof item === 'object'\n ? ((item as Record<string, unknown>)?.key ??\n (item as Record<string, unknown>)?.id ??\n `idx-${i}`)\n : String(item);\n return anchorBlock(render(item, i), `each-${itemKey}`);\n });\n}\n\n/* --- match --- */\ntype Branch = [\n condition: unknown,\n content: VNode | VNode[] | (() => VNode | VNode[]),\n];\n\nexport function match() {\n const branches: Branch[] = [];\n return {\n when(cond: unknown, content: VNode | VNode[] | (() => VNode | VNode[])) {\n branches.push([cond, content]);\n return this;\n },\n otherwise(content: VNode | VNode[]) {\n branches.push([true, content]);\n return this;\n },\n done() {\n const mi = _directiveCallIndex++;\n for (let idx = 0; idx < branches.length; idx++) {\n const [cond, content] = branches[idx];\n if (cond) {\n const payload =\n typeof content === 'function'\n ? (content as () => VNode | VNode[])()\n : content;\n return [anchorBlock(payload, `match-${mi}-branch-${idx}`)];\n }\n }\n return [anchorBlock([], `match-${mi}-empty`)];\n },\n };\n}\n\n/**\n * Create a stable anchor block with consistent boundaries.\n * Always has start/end boundaries.\n */\nexport function anchorBlock(\n children: VNode | VNode[] | null | undefined,\n anchorKey: string,\n): VNode {\n // Normalize children to array, filtering out only null/undefined values.\n // Preserve meaningful falsy values such as 0, false, and empty string.\n const childArray = !children\n ? []\n : Array.isArray(children)\n ? children.filter((c) => c !== null && c !== undefined)\n : [children].filter((c) => c !== null && c !== undefined);\n\n return {\n tag: '#anchor',\n key: anchorKey,\n children: childArray,\n };\n}\n"],"names":["_directiveCallIndex","resetWhenCounter","nextDirectiveIndex","when","cond","childrenOrFactory","key","anchorKey","anchorBlock","each","list","render","item","i","itemKey","match","branches","content","mi","idx","payload","children","childArray","c"],"mappings":"AAGA,IAAIA,IAAsB;AAQnB,SAASC,IAAyB;AACvC,EAAAD,IAAsB;AACxB;AAOO,SAASE,IAA6B;AAC3C,SAAOF;AACT;AAaO,SAASG,EACdC,GACAC,GACAC,GACO;AACP,QAAMC,IAAYD,KAAO,cAAcN,GAAqB;AAC5D,SACSQ,EADL,OAAOH,KAAsB,aACZD,IAAOC,EAAA,IAAsB,CAAA,IAE/BD,IAAOC,IAAoB,CAAA,GAFQE,CAAS;AAGjE;AAGO,SAASE,EAEdC,GAAWC,GAA8D;AACzE,SAAOD,EAAK,IAAI,CAACE,GAAMC,MAAM;AAE3B,UAAMC,IACJ,OAAOF,KAAS,WACVA,GAAkC,OACnCA,GAAkC,MACnC,OAAOC,CAAC,KACR,OAAOD,CAAI;AACjB,WAAOJ,EAAYG,EAAOC,GAAMC,CAAC,GAAG,QAAQC,CAAO,EAAE;AAAA,EACvD,CAAC;AACH;AAQO,SAASC,IAAQ;AACtB,QAAMC,IAAqB,CAAA;AAC3B,SAAO;AAAA,IACL,KAAKZ,GAAea,GAAoD;AACtE,aAAAD,EAAS,KAAK,CAACZ,GAAMa,CAAO,CAAC,GACtB;AAAA,IACT;AAAA,IACA,UAAUA,GAA0B;AAClC,aAAAD,EAAS,KAAK,CAAC,IAAMC,CAAO,CAAC,GACtB;AAAA,IACT;AAAA,IACA,OAAO;AACL,YAAMC,IAAKlB;AACX,eAASmB,IAAM,GAAGA,IAAMH,EAAS,QAAQG,KAAO;AAC9C,cAAM,CAACf,GAAMa,CAAO,IAAID,EAASG,CAAG;AACpC,YAAIf,GAAM;AACR,gBAAMgB,IACJ,OAAOH,KAAY,aACdA,MACDA;AACN,iBAAO,CAACT,EAAYY,GAAS,SAASF,CAAE,WAAWC,CAAG,EAAE,CAAC;AAAA,QAC3D;AAAA,MACF;AACA,aAAO,CAACX,EAAY,IAAI,SAASU,CAAE,QAAQ,CAAC;AAAA,IAC9C;AAAA,EAAA;AAEJ;AAMO,SAASV,EACda,GACAd,GACO;AAGP,QAAMe,IAAcD,IAEhB,MAAM,QAAQA,CAAQ,IACpBA,EAAS,OAAO,CAACE,MAAMA,KAAM,IAAuB,IACpD,CAACF,CAAQ,EAAE,OAAO,CAACE,MAAMA,KAAM,IAAuB,IAHxD,CAAA;AAKJ,SAAO;AAAA,IACL,KAAK;AAAA,IACL,KAAKhB;AAAA,IACL,UAAUe;AAAA,EAAA;AAEd;"}
1
+ {"version":3,"file":"custom-elements-runtime.directives.es.js","sources":["../src/lib/directives.ts"],"sourcesContent":["import type { VNode } from './runtime/types';\n\n// ── Per-render directive scope tracking ─────────────────────────────────────\n//\n// A FLAT counter (index++) breaks when a when() factory itself contains more\n// when() calls: those inner calls consume counter slots, causing SUBSEQUENT\n// SIBLING when() calls to get a different index depending on whether the factory\n// ran. For example:\n//\n// when(A, () => { when(B); when(C); }) // ← factory may or may not run\n// when(D) // ← index shifts when factory runs\n//\n// The fix: each when() call claims its own slot (stable regardless of whether\n// the factory runs), then ENTERS a new child scope for the factory. Inner\n// when() calls consume indices in that child scope, never bleeding into the\n// sibling counter of the outer scope.\n//\n// Key format: root sibling 0 \"when-block-0\"\n// child of \"when-block-0\" at pos 1 → \"when-block-0.1\"\n// grandchild → \"when-block-0.1.0\" etc.\n\n/** Current scope's parent prefix (empty string = root scope). */\nlet _scopeParent = '';\n/** Next sibling index inside the current scope. */\nlet _scopeIndex = 0;\n/** Stack of [parentPrefix, siblingIndex] for nested scopes. */\nconst _scopeStack: Array<readonly [string, number]> = [];\n\n/**\n * Reset all scope state at the start of each component render pass.\n * Called automatically by the component renderer — not needed in user code.\n * @internal\n */\nexport function resetWhenCounter(): void {\n _scopeParent = '';\n _scopeIndex = 0;\n _scopeStack.length = 0;\n}\n\n/**\n * Claim the next directive call index within the current scope.\n * Used by directive-enhancements.ts for non-when() directives (switchOnLength,\n * switchOnPromise, etc.) that need a stable unique number per call site.\n * @internal\n */\nexport function nextDirectiveIndex(): number {\n return _scopeIndex++;\n}\n\n/** Claim the next slot in the current scope and return its anchor key. */\nfunction claimKey(explicitKey?: string): string {\n const idx = _scopeIndex++;\n if (explicitKey !== undefined) return explicitKey;\n return _scopeParent ? `${_scopeParent}.${idx}` : `when-block-${idx}`;\n}\n\n/** Push a new child scope keyed under `anchorKey`. */\nfunction enterScope(anchorKey: string): void {\n _scopeStack.push([_scopeParent, _scopeIndex] as const);\n _scopeParent = anchorKey;\n _scopeIndex = 0;\n}\n\n/** Pop back to the parent scope. */\nfunction exitScope(): void {\n const top = _scopeStack[_scopeStack.length - 1];\n if (top) {\n _scopeStack.length--;\n [_scopeParent, _scopeIndex] = top;\n }\n}\n\n/* --- When --- */\nexport function when(\n cond: boolean,\n children: VNode | VNode[],\n key?: string,\n): VNode;\nexport function when(\n cond: boolean,\n factory: () => VNode | VNode[],\n key?: string,\n): VNode;\nexport function when(\n cond: boolean,\n childrenOrFactory: VNode | VNode[] | (() => VNode | VNode[]),\n key?: string,\n): VNode {\n // Claim this call's position BEFORE potentially entering a child scope.\n // This guarantees sibling when() calls always get the same index regardless\n // of whether a factory executes and how many when() calls it contains.\n const anchorKey = claimKey(key);\n\n if (typeof childrenOrFactory !== 'function') {\n return anchorBlock(cond ? childrenOrFactory : [], anchorKey);\n }\n\n if (!cond) {\n return anchorBlock([], anchorKey);\n }\n\n // Run the factory in a child scope so its inner when() calls don't\n // affect the sibling counter of the outer scope.\n enterScope(anchorKey);\n const children = childrenOrFactory();\n exitScope();\n return anchorBlock(children, anchorKey);\n}\n\n/* --- Each --- */\nexport function each<\n T extends string | number | boolean | { id?: string | number; key?: string },\n>(list: T[], render: (item: T, index: number) => VNode | VNode[]): VNode[] {\n return list.map((item, i) => {\n // For primitives, use value as key; for objects, prefer key/id\n const itemKey =\n typeof item === 'object'\n ? ((item as Record<string, unknown>)?.key ??\n (item as Record<string, unknown>)?.id ??\n `idx-${i}`)\n : String(item);\n return anchorBlock(render(item, i), `each-${itemKey}`);\n });\n}\n\n/* --- match --- */\ntype Branch = [\n condition: unknown,\n content: VNode | VNode[] | (() => VNode | VNode[]),\n];\n\nexport function match() {\n const branches: Branch[] = [];\n return {\n when(cond: unknown, content: VNode | VNode[] | (() => VNode | VNode[])) {\n branches.push([cond, content]);\n return this;\n },\n otherwise(content: VNode | VNode[]) {\n branches.push([true, content]);\n return this;\n },\n done() {\n const matchKey = `match-${claimKey()}`;\n for (let idx = 0; idx < branches.length; idx++) {\n const [cond, content] = branches[idx];\n if (cond) {\n const branchKey = `${matchKey}-branch-${idx}`;\n if (typeof content === 'function') {\n enterScope(branchKey);\n const payload = (content as () => VNode | VNode[])();\n exitScope();\n return [anchorBlock(payload, branchKey)];\n }\n return [anchorBlock(content, branchKey)];\n }\n }\n return [anchorBlock([], `${matchKey}-empty`)];\n },\n };\n}\n\n/**\n * Create a stable anchor block with consistent boundaries.\n * Always has start/end boundaries.\n */\nexport function anchorBlock(\n children: VNode | VNode[] | null | undefined,\n anchorKey: string,\n): VNode {\n // Normalize children to array, filtering out only null/undefined values.\n // Preserve meaningful falsy values such as 0, false, and empty string.\n const childArray = !children\n ? []\n : Array.isArray(children)\n ? children.filter((c) => c !== null && c !== undefined)\n : [children].filter((c) => c !== null && c !== undefined);\n\n return {\n tag: '#anchor',\n key: anchorKey,\n children: childArray,\n };\n}\n"],"names":["_scopeParent","_scopeIndex","_scopeStack","resetWhenCounter","nextDirectiveIndex","claimKey","explicitKey","idx","enterScope","anchorKey","exitScope","top","when","cond","childrenOrFactory","key","anchorBlock","children","each","list","render","item","i","itemKey","match","branches","content","matchKey","branchKey","payload","childArray","c"],"mappings":"AAsBA,IAAIA,IAAe,IAEfC,IAAc;AAElB,MAAMC,IAAgD,CAAA;AAO/C,SAASC,IAAyB;AACvC,EAAAH,IAAe,IACfC,IAAc,GACdC,EAAY,SAAS;AACvB;AAQO,SAASE,IAA6B;AAC3C,SAAOH;AACT;AAGA,SAASI,EAASC,GAA8B;AAC9C,QAAMC,IAAMN;AACZ,SAAIK,MAAgB,SAAkBA,IAC/BN,IAAe,GAAGA,CAAY,IAAIO,CAAG,KAAK,cAAcA,CAAG;AACpE;AAGA,SAASC,EAAWC,GAAyB;AAC3C,EAAAP,EAAY,KAAK,CAACF,GAAcC,CAAW,CAAU,GACrDD,IAAeS,GACfR,IAAc;AAChB;AAGA,SAASS,IAAkB;AACzB,QAAMC,IAAMT,EAAYA,EAAY,SAAS,CAAC;AAC9C,EAAIS,MACFT,EAAY,UACZ,CAACF,GAAcC,CAAW,IAAIU;AAElC;AAaO,SAASC,EACdC,GACAC,GACAC,GACO;AAIP,QAAMN,IAAYJ,EAASU,CAAG;AAE9B,MAAI,OAAOD,KAAsB;AAC/B,WAAOE,EAAYH,IAAOC,IAAoB,CAAA,GAAIL,CAAS;AAG7D,MAAI,CAACI;AACH,WAAOG,EAAY,CAAA,GAAIP,CAAS;AAKlC,EAAAD,EAAWC,CAAS;AACpB,QAAMQ,IAAWH,EAAA;AACjB,SAAAJ,EAAA,GACOM,EAAYC,GAAUR,CAAS;AACxC;AAGO,SAASS,EAEdC,GAAWC,GAA8D;AACzE,SAAOD,EAAK,IAAI,CAACE,GAAMC,MAAM;AAE3B,UAAMC,IACJ,OAAOF,KAAS,WACVA,GAAkC,OACnCA,GAAkC,MACnC,OAAOC,CAAC,KACR,OAAOD,CAAI;AACjB,WAAOL,EAAYI,EAAOC,GAAMC,CAAC,GAAG,QAAQC,CAAO,EAAE;AAAA,EACvD,CAAC;AACH;AAQO,SAASC,IAAQ;AACtB,QAAMC,IAAqB,CAAA;AAC3B,SAAO;AAAA,IACL,KAAKZ,GAAea,GAAoD;AACtE,aAAAD,EAAS,KAAK,CAACZ,GAAMa,CAAO,CAAC,GACtB;AAAA,IACT;AAAA,IACA,UAAUA,GAA0B;AAClC,aAAAD,EAAS,KAAK,CAAC,IAAMC,CAAO,CAAC,GACtB;AAAA,IACT;AAAA,IACA,OAAO;AACL,YAAMC,IAAW,SAAStB,EAAA,CAAU;AACpC,eAASE,IAAM,GAAGA,IAAMkB,EAAS,QAAQlB,KAAO;AAC9C,cAAM,CAACM,GAAMa,CAAO,IAAID,EAASlB,CAAG;AACpC,YAAIM,GAAM;AACR,gBAAMe,IAAY,GAAGD,CAAQ,WAAWpB,CAAG;AAC3C,cAAI,OAAOmB,KAAY,YAAY;AACjC,YAAAlB,EAAWoB,CAAS;AACpB,kBAAMC,IAAWH,EAAA;AACjB,mBAAAhB,EAAA,GACO,CAACM,EAAYa,GAASD,CAAS,CAAC;AAAA,UACzC;AACA,iBAAO,CAACZ,EAAYU,GAASE,CAAS,CAAC;AAAA,QACzC;AAAA,MACF;AACA,aAAO,CAACZ,EAAY,CAAA,GAAI,GAAGW,CAAQ,QAAQ,CAAC;AAAA,IAC9C;AAAA,EAAA;AAEJ;AAMO,SAASX,EACdC,GACAR,GACO;AAGP,QAAMqB,IAAcb,IAEhB,MAAM,QAAQA,CAAQ,IACpBA,EAAS,OAAO,CAACc,MAAMA,KAAM,IAAuB,IACpD,CAACd,CAAQ,EAAE,OAAO,CAACc,MAAMA,KAAM,IAAuB,IAHxD,CAAA;AAKJ,SAAO;AAAA,IACL,KAAK;AAAA,IACL,KAAKtB;AAAA,IACL,UAAUqB;AAAA,EAAA;AAEd;"}
@@ -1,14 +1,14 @@
1
1
  import type { VNode } from './runtime/types';
2
2
  /**
3
- * Reset the per-render directive call counter.
4
- * Must be called once at the start of every component render pass so that
5
- * all sibling directive calls automatically receive stable, unique positional keys.
3
+ * Reset all scope state at the start of each component render pass.
4
+ * Called automatically by the component renderer not needed in user code.
6
5
  * @internal
7
6
  */
8
7
  export declare function resetWhenCounter(): void;
9
8
  /**
10
- * Get the next per-render directive call index and increment the counter.
11
- * Used by directives in directive-enhancements.ts to generate unique anchor keys.
9
+ * Claim the next directive call index within the current scope.
10
+ * Used by directive-enhancements.ts for non-when() directives (switchOnLength,
11
+ * switchOnPromise, etc.) that need a stable unique number per call site.
12
12
  * @internal
13
13
  */
14
14
  export declare function nextDirectiveIndex(): number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jasonshimmy/custom-elements-runtime",
3
3
  "description": "A powerful, modern, and lightweight runtime for creating reactive web components with TypeScript",
4
- "version": "2.8.0",
4
+ "version": "2.8.1",
5
5
  "type": "module",
6
6
  "keywords": [
7
7
  "web-components",