@epa-wg/custom-element-dist 0.0.35 → 0.0.37

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.
Files changed (123) hide show
  1. package/.ai/mcp/mcp.json +0 -0
  2. package/.claude/settings.local.json +4 -1
  3. package/.storybook/preview.ts +7 -1
  4. package/.yarn/install-state.gz +0 -0
  5. package/README.md +5 -5
  6. package/dist/{custom-element-BzDjIYMe.js → custom-element-BqBcmDiN.js} +5 -2
  7. package/dist/custom-element-bundle.cjs +1 -1
  8. package/dist/custom-element-bundle.js +2 -2
  9. package/dist/{custom-element-Bssk9jRy.cjs → custom-element-jpOyXHF6.cjs} +1 -1
  10. package/dist/demo/for-each.html +213 -0
  11. package/package.json +4 -4
  12. package/public/demo/for-each.html +213 -0
  13. package/src/custom-element/custom-element.js +3 -0
  14. package/src/custom-element/demo/for-each.html +213 -0
  15. package/src/custom-element/ide/web-types-dce.json +1 -1
  16. package/src/custom-element/ide/web-types-xsl.json +1 -1
  17. package/src/custom-element/index.html +2 -1
  18. package/src/material/theme/colors-native.html +32 -1
  19. package/src/mocks/versions.mock.ts +1 -1
  20. package/src/stories/__screenshots__/http-request.test.ts/http-request-http-request-headers-and-response-status-and-headers-1.png +0 -0
  21. package/src/stories/__screenshots__/http-request.test.ts/http-request-http-request-with-delayed--5-seconds-response-1.png +0 -0
  22. package/src/stories/__screenshots__/http-request.test.ts/http-request-http-request-with-error-1.png +0 -0
  23. package/src/stories/__screenshots__/http-request.test.ts/http-request-url-and-slice-1.png +0 -0
  24. package/src/stories/__screenshots__/http-request.test.ts/http-request-url-change-1.png +0 -0
  25. package/src/stories/__screenshots__/slots.test.stories.ts/slots-slots-TemplateWithAttributesAndCondition-1.png +0 -0
  26. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-BooleanAndCondition-1.png +0 -0
  27. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-BooleanOrCondition-1.png +0 -0
  28. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-ChooseNoAttribute-1.png +0 -0
  29. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-ChooseOtherwise-1.png +0 -0
  30. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-ChooseSecondWhen-1.png +0 -0
  31. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-ChooseWhenOtherwise-1.png +0 -0
  32. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-IfFalse-1.png +0 -0
  33. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-IfNotExists-1.png +0 -0
  34. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-IfTrue-1.png +0 -0
  35. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleIfOrderingIssue-1.png +0 -0
  36. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleInstances-1.png +0 -0
  37. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-NestedConditions-1.png +0 -0
  38. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-NestedConditionsInactive-1.png +0 -0
  39. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-NumericComparison-1.png +0 -0
  40. package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-NumericComparisonLow-1.png +0 -0
  41. package/src/stories/__screenshots__/xslt-for-each.test.stories.ts/xslt-for-each-xslt-for-each-MultipleIfOrderingIssue-1.png +0 -0
  42. package/src/stories/__screenshots__/xslt-if.test.stories.ts/xslt-if-xslt-if-MultipleIfOrderingIssue-1.png +0 -0
  43. package/src/stories/attributes.test.stories.ts +2 -0
  44. package/src/stories/dom-merge.test.stories.ts +1 -0
  45. package/src/stories/external-template.test.stories.ts +5 -3
  46. package/src/stories/http-request.stories.ts +2 -1
  47. package/src/stories/module-url.test.stories.ts +1 -0
  48. package/src/stories/slice-events.test.stories.ts +3 -0
  49. package/src/stories/xslt-for-each.test.stories.ts +99 -1
  50. package/storybook-static/assets/{Color-F6OSRLHC-DeDlDLjU.js → Color-F6OSRLHC-FZZzFn7T.js} +1 -1
  51. package/storybook-static/assets/{Configure-CH_tIP5N.js → Configure-DyfktOJO.js} +1 -1
  52. package/storybook-static/assets/{DocsRenderer-CFRXHY34-Bc9EPsUI.js → DocsRenderer-CFRXHY34-5isVpCzj.js} +2 -2
  53. package/storybook-static/assets/{attributes.test.stories-BtamFQkF.js → attributes.test.stories-CrDC-RXf.js} +4 -3
  54. package/storybook-static/assets/{css.test.stories-BfNxLgwr.js → css.test.stories-ChWnZJwa.js} +1 -1
  55. package/storybook-static/assets/{custom-element-CnmjNo0g.js → custom-element-wuk8gYiP.js} +1 -1
  56. package/storybook-static/assets/{dom-merge.test.stories-DxnitrLK.js → dom-merge.test.stories-DkarPqD_.js} +2 -2
  57. package/storybook-static/assets/{external-template.test.stories-BTsww7B0.js → external-template.test.stories-DCboR8sG.js} +17 -16
  58. package/storybook-static/assets/{form.test.stories-DNJFtPJb.js → form.test.stories-BjeeUu0b.js} +1 -1
  59. package/storybook-static/assets/handlers-B7UMnC7v.js +291 -0
  60. package/storybook-static/assets/{http-request.stories-DgrBNle8.js → http-request.stories-WIldq1MC.js} +2 -2
  61. package/storybook-static/assets/{iframe-DiVWehoI.js → iframe-CBHPj1E5.js} +2 -2
  62. package/storybook-static/assets/{index-w6iX3YlR.js → index-BL0FQnAE.js} +3 -3
  63. package/storybook-static/assets/{index-CdEbhcV9.js → index-CzwPLrca.js} +1 -1
  64. package/storybook-static/assets/{local-storage.test.stories-Hwq80yUr.js → local-storage.test.stories-DLMK0p2s.js} +1 -1
  65. package/storybook-static/assets/{location-element.test.stories-mEhZzm7x.js → location-element.test.stories-BroqoLMS.js} +1 -1
  66. package/storybook-static/assets/{module-url.test.stories-Bj46iT0V.js → module-url.test.stories-B-0dibET.js} +2 -2
  67. package/storybook-static/assets/{preview-BjbXcJci.js → preview-BG24UPL5.js} +2 -2
  68. package/storybook-static/assets/preview-C1KnQPMW.js +50 -0
  69. package/storybook-static/assets/{set-url.test.stories-hzxLcqmm.js → set-url.test.stories-Dhq4YQyr.js} +1 -1
  70. package/storybook-static/assets/{slice-events.test.stories-DVyXFRU1.js → slice-events.test.stories-BZJGIFku.js} +17 -15
  71. package/storybook-static/assets/{slots.test.stories-CS544nS4.js → slots.test.stories-DKivHwZH.js} +1 -1
  72. package/storybook-static/assets/{version-select.test.stories-D36nfYBq.js → version-select.test.stories-Dntyd7qb.js} +1 -1
  73. package/storybook-static/assets/{xslt-conditionals.test.stories-BS1PTIHe.js → xslt-conditionals.test.stories-Iq5iQNRj.js} +1 -1
  74. package/storybook-static/assets/{xslt-for-each.test.stories-CtPS20RK.js → xslt-for-each.test.stories-BMygBmj8.js} +132 -12
  75. package/storybook-static/assets/{xslt-if.test.stories-DcHrAMSY.js → xslt-if.test.stories-CVrFWdAX.js} +1 -1
  76. package/storybook-static/demo/for-each.html +213 -0
  77. package/storybook-static/iframe.html +1 -1
  78. package/storybook-static/index.json +1 -1
  79. package/storybook-static/project.json +1 -1
  80. package/vite.config.js +2 -1
  81. package/coverage/base.css +0 -224
  82. package/coverage/block-navigation.js +0 -87
  83. package/coverage/coverage-final.json +0 -12
  84. package/coverage/favicon.png +0 -0
  85. package/coverage/index.html +0 -176
  86. package/coverage/prettify.css +0 -1
  87. package/coverage/prettify.js +0 -2
  88. package/coverage/sort-arrow-sprite.png +0 -0
  89. package/coverage/sorter.js +0 -210
  90. package/coverage/src/coverage.svg +0 -10
  91. package/coverage/src/custom-element/coverage.svg +0 -10
  92. package/coverage/src/custom-element/custom-element.js/coverage.svg +0 -10
  93. package/coverage/src/custom-element/custom-element.js.html +0 -3034
  94. package/coverage/src/custom-element/http-request.js/coverage.svg +0 -10
  95. package/coverage/src/custom-element/http-request.js.html +0 -373
  96. package/coverage/src/custom-element/index.html +0 -176
  97. package/coverage/src/custom-element/local-storage.js/coverage.svg +0 -10
  98. package/coverage/src/custom-element/local-storage.js.html +0 -361
  99. package/coverage/src/custom-element/location-element.js/coverage.svg +0 -10
  100. package/coverage/src/custom-element/location-element.js.html +0 -412
  101. package/coverage/src/custom-element/module-url.js/coverage.svg +0 -10
  102. package/coverage/src/custom-element/module-url.js.html +0 -187
  103. package/coverage/src/index.html +0 -116
  104. package/coverage/src/material/theme/colors.js/coverage.svg +0 -10
  105. package/coverage/src/material/theme/colors.js.html +0 -217
  106. package/coverage/src/material/theme/coverage.svg +0 -10
  107. package/coverage/src/material/theme/index.html +0 -116
  108. package/coverage/src/mocks/coverage.svg +0 -10
  109. package/coverage/src/mocks/handlers.ts/coverage.svg +0 -10
  110. package/coverage/src/mocks/handlers.ts.html +0 -196
  111. package/coverage/src/mocks/index.html +0 -116
  112. package/coverage/src/stories/coverage.svg +0 -10
  113. package/coverage/src/stories/frame.canvas.ts/coverage.svg +0 -10
  114. package/coverage/src/stories/frame.canvas.ts.html +0 -175
  115. package/coverage/src/stories/http-request.stories.ts/coverage.svg +0 -10
  116. package/coverage/src/stories/http-request.stories.ts.html +0 -817
  117. package/coverage/src/stories/index.html +0 -146
  118. package/coverage/src/stories/testStoryBook.ts/coverage.svg +0 -10
  119. package/coverage/src/stories/testStoryBook.ts.html +0 -169
  120. package/coverage/src/sum.ts/coverage.svg +0 -10
  121. package/coverage/src/sum.ts.html +0 -94
  122. package/storybook-static/assets/handlers-Dvg8CAeR.js +0 -470
  123. package/storybook-static/assets/preview-CfuT8gak.js +0 -50
File without changes
@@ -12,7 +12,10 @@
12
12
  "WebFetch(domain:material.angular.dev)",
13
13
  "Bash(cat:*)",
14
14
  "Bash(git checkout:*)",
15
- "Bash(npm test:*)"
15
+ "Bash(npm test:*)",
16
+ "Bash(yarn test:*)",
17
+ "Bash(node:*)",
18
+ "Bash(echo:*)"
16
19
  ]
17
20
  }
18
21
  }
@@ -2,7 +2,13 @@ import {initialize, mswLoader} from 'msw-storybook-addon';
2
2
 
3
3
  import {handlers} from "../src/mocks/handlers";
4
4
 
5
- initialize({onUnhandledRequest: 'bypass'});// SB
5
+ initialize({
6
+ onUnhandledRequest: 'bypass',
7
+ serviceWorker: {
8
+ url: './mockServiceWorker.js',
9
+ },
10
+ quiet: true, // Suppress MSW warnings in console
11
+ });// SB
6
12
 
7
13
  const preview = {
8
14
  parameters: {
Binary file
package/README.md CHANGED
@@ -27,8 +27,8 @@ CDN version of StoryBook.
27
27
  [github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
28
28
  [npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element-dist.svg
29
29
  [npm-url]: https://npmjs.org/package/@epa-wg/custom-element-dist
30
- [coverage-image]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.35/coverage/src/custom-element/coverage.svg
31
- [coverage-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.35/coverage/src/custom-element/index.html
32
- [sb-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.35/storybook-static/index.html
33
- [bundle-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.35/dist/custom-element-bundle.js
34
- [cem-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.35/src/material/components.html
30
+ [coverage-image]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/coverage/src/custom-element/coverage.svg
31
+ [coverage-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/coverage/src/custom-element/index.html
32
+ [sb-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/storybook-static/index.html
33
+ [bundle-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/dist/custom-element-bundle.js
34
+ [cem-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/src/material/components.html
@@ -412,8 +412,11 @@ const $e = (e) => [...e?.matchAll(/([^{}]*)(\{)([^}]+)}([^{}]*)/g)].map((t) => `
412
412
  for (; e.firstChild; )
413
413
  t.append(e.firstChild);
414
414
  const l = "if,choose,for-each".includes(e.localName) ? (() => {
415
- const a = C("span");
416
- return a.append(t), a;
415
+ const a = e.parentElement;
416
+ if (!a || a.childNodes.length === 1)
417
+ return t;
418
+ const n = C("span");
419
+ return n.append(t), n;
417
420
  })() : t;
418
421
  if (e.parentElement)
419
422
  e.parentElement.replaceChild(l, e);
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./custom-element-Bssk9jRy.cjs"),l=require("./http-request-DSaowcG1.cjs"),t=require("./local-storage-78EivJ_B.cjs"),a=require("./location-element-DRB7hCwA.cjs");exports.CustomElement=e.CustomElement;exports.appendByDceId=e.appendByDceId;exports.assureSlices=e.assureSlices;exports.assureUID=e.assureUID;exports.assureUnique=e.assureUnique;exports.cloneAs=e.cloneAs;exports.createXsltFromDom=e.createXsltFromDom;exports.deepEqual=e.deepEqual;exports.default=e.CustomElement;exports.evalCurly=e.evalCurly;exports.event2slice=e.event2slice;exports.merge=e.merge;exports.mergeAttr=e.mergeAttr;exports.mix=e.mix;exports.obj2node=e.obj2node;exports.sanitizeBlankText=e.sanitizeBlankText;exports.tagUid=e.tagUid;exports.toXsl=e.toXsl;exports.xPath=e.xPath;exports.xPathDefaults=e.xPathDefaults;exports.xhrTemplate=e.xhrTemplate;exports.xml2dom=e.xml2dom;exports.xmlString=e.xmlString;exports.xslTags=e.xslTags;exports.HttpRequestElement=l.HttpRequestElement;exports.LocalStorageElement=t.LocalStorageElement;exports.localStorageSetItem=t.localStorageSetItem;exports.localStorage_clear=t.localStorage_clear;exports.localStorage_removeItem=t.localStorage_removeItem;exports.localStorage_setItem=t.localStorage_setItem;exports.LocationElement=a.LocationElement;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./custom-element-jpOyXHF6.cjs"),l=require("./http-request-DSaowcG1.cjs"),t=require("./local-storage-78EivJ_B.cjs"),a=require("./location-element-DRB7hCwA.cjs");exports.CustomElement=e.CustomElement;exports.appendByDceId=e.appendByDceId;exports.assureSlices=e.assureSlices;exports.assureUID=e.assureUID;exports.assureUnique=e.assureUnique;exports.cloneAs=e.cloneAs;exports.createXsltFromDom=e.createXsltFromDom;exports.deepEqual=e.deepEqual;exports.default=e.CustomElement;exports.evalCurly=e.evalCurly;exports.event2slice=e.event2slice;exports.merge=e.merge;exports.mergeAttr=e.mergeAttr;exports.mix=e.mix;exports.obj2node=e.obj2node;exports.sanitizeBlankText=e.sanitizeBlankText;exports.tagUid=e.tagUid;exports.toXsl=e.toXsl;exports.xPath=e.xPath;exports.xPathDefaults=e.xPathDefaults;exports.xhrTemplate=e.xhrTemplate;exports.xml2dom=e.xml2dom;exports.xmlString=e.xmlString;exports.xslTags=e.xslTags;exports.HttpRequestElement=l.HttpRequestElement;exports.LocalStorageElement=t.LocalStorageElement;exports.localStorageSetItem=t.localStorageSetItem;exports.localStorage_clear=t.localStorage_clear;exports.localStorage_removeItem=t.localStorage_removeItem;exports.localStorage_setItem=t.localStorage_setItem;exports.LocationElement=a.LocationElement;
@@ -1,5 +1,5 @@
1
- import { C as e } from "./custom-element-BzDjIYMe.js";
2
- import { j as o, f as l, l as r, i as m, c, b as n, e as x, n as p, g, k as i, h as u, m as d, o as f, s as S, t as E, u as I, q as h, p as q, d as D, x as L, a as b, r as v } from "./custom-element-BzDjIYMe.js";
1
+ import { C as e } from "./custom-element-BqBcmDiN.js";
2
+ import { j as o, f as l, l as r, i as m, c, b as n, e as x, n as p, g, k as i, h as u, m as d, o as f, s as S, t as E, u as I, q as h, p as q, d as D, x as L, a as b, r as v } from "./custom-element-BqBcmDiN.js";
3
3
  import { H as T } from "./http-request-DTCzZ1gc.js";
4
4
  import { L as _, c as j, b as k, a as y, l as A } from "./local-storage-DzmNKzgN.js";
5
5
  import { L as H } from "./location-element-FJlONi2n.js";
@@ -89,7 +89,7 @@
89
89
  <xsl:with-param name="defaultvalue"/>
90
90
  </xsl:call-template>
91
91
  </xsl:variable>
92
- </xsl:stylesheet>`);o.importStylesheet(n);const v=o.transformToFragment(y,document),u=(i,r)=>i.querySelector(r),w=u(x,'template[mode="payload"]');if(!v)return console.error("transformation error",{xml:y.outerHTML,xsl:U(n)});if(v.firstElementChild.localName!=="dce-root"){const i=v.ownerDocument.createElement("dce-root");[...v.childNodes].forEach(r=>i.append(r)),v.append(i)}[...v.querySelectorAll("[test]")].forEach(i=>{const r=d(i,"test"),f=r.replace(/hasBoolAttribute\((.*?)\)/g,(g,h,b,T,P)=>{const L=h.substring(1);return`(not($${L} = 'false') and ($${L} = '' or $${L} = '${L}' or $${L} = 'true' ))`});r!==f&&i.setAttribute("test",f)}),[...v.querySelectorAll("dce-root>attribute")].forEach(i=>{K(i,"namespace,name,select");const r=te(i,"xsl:param"),f=d(i,"name");if(t.push(f),i.childNodes.length&&(l[f]=i.textContent),w.append(r),i.hasAttribute("select")){a[f]=d(i,"select"),K(r,"select,name");let g=d(i,"select").split("??"),h;if(g?.length>1){r.removeAttribute("select");const b=u(x,'template[match="ignore"]>choose').cloneNode(!0);F(b.firstElementChild).append(D(b,"{"+g[0]+"}")),b.firstElementChild.setAttribute("test",g[0]);for(let T=1;T<g.length-1;T++){const P=b.firstElementChild.cloneNode(!0);F(P).append(D(b,"{"+g[T]+"}")),P.setAttribute("test",g[T]),b.insertBefore(P,b.lastElementChild)}F(b.lastElementChild).append(D(b,"{"+g[g.length-1]+"}")),r.append(b),h=b.cloneNode(!0)}else h=te(i,"xsl:value-of");h.removeAttribute("name"),i.append(h),i.removeAttribute("select")}else K(r,"name"),r.setAttribute("select","/datadom/attributes/"+f),l[f]||i.remove()}),[...v.querySelectorAll("[value]")].filter(i=>i.getAttribute("value").match(/\{(.*)\?\?(.*)\}/g)).forEach(i=>{const r=d(i,"value");r&&i.setAttribute("value",Ne(r))});for(const i of v.childNodes)w.append(x.importNode(i,!0));[...w.getElementsByTagName("xsl:template")].forEach(i=>w.ownerDocument.documentElement.append(i));const O=u(x,'call-template[name="slot"]'),H=i=>{const r=O.cloneNode(!0),f=d(i,"name");f&&r.firstElementChild.setAttribute("select",`'${f}'`);for(let g of i.childNodes)r.lastElementChild.append(g);return r};z(w,"slot",i=>i.parentNode.replaceChild(H(i),i));const p=le(x);return ee(p,{declaredAttributes:t,hardcodedAttributes:l,exposedAttributes:a}),p}async function be(e){return await new Promise((t,l)=>{const a=new XMLHttpRequest;a.open("GET",e),a.responseType="document",a.onload=()=>{a.readyState===a.DONE&&a.status===200?t(a.responseXML?.body||a.responseXML||C("div",a.responseText)):l(`${a.statusText} - ${e}`)},a.addEventListener("error",n=>l(n)),a.send()})}function ye(e,s,t=!1){if(e===s)return!0;if(typeof e!="object"||e===null||typeof s!="object"||s===null||Object.keys(e).length!==Object.keys(s).length)return t;for(let l in e)if(!(l in s)||!ye(e[l],s[l]))return t;return!0}const ge=e=>e.split("|").map(s=>s.trim()).filter(s=>s),Ae=(e,s)=>ge(s).map(t=>{let l=e.ownerDocument,a=n=>(e.append(n),n);if(t.includes("/")){const n=[],o=l.evaluate(t,e);for(let y;y=o.iterateNext();)n.push(y);return n}return[...e.childNodes].find(n=>n.localName===t)||a(C(t,"",l))}).flat();function ne(e,s,t,l){if(!t.sliceProcessed)return t.sliceProcessed=1,Ae(e,s??"").map(a=>{const n=e.ownerDocument,o=t.sliceEventSource,y=t.sliceElement,x=()=>[...a.childNodes].filter(u=>u.nodeType===3||u.localName==="value"||u.localName==="form-data").map(u=>u.remove());o.getAttributeNames().map(u=>a.setAttribute(u,d(o,u))),[...a.childNodes].filter(u=>u.localName==="event").map(u=>u.remove()),"validationMessage"in o&&a.setAttribute("validation-message",o.validationMessage),t.type==="init"&&x(),a.append(M(t,"event",n));const v=(o.type==="checkbox"||o.type==="radio")&&!o.checked;if(y.hasAttribute("slice-value")){o.value===void 0?a.removeAttribute("value"):a.setAttribute("value",o.value);const u=v?"":I(d(y,"slice-value"),a);x(),a.append(D(n,u))}else{if("elements"in o)return x(),a.append(M(new FormData(o),"value",a.ownerDocument)),a;const u=v?"":o.value??d(o,"value");if(x(),u==null)[...a.childNodes].filter(w=>w.localName!=="event").map(w=>w.remove()),a.removeAttribute("value");else{const w=De(u)?D(n,u):M(u,"value",a.ownerDocument);a.append(w),a.setAttribute("value",u)}}return a})}function z(e,s,t){e.querySelectorAll&&[...e.querySelectorAll(s)].forEach(t)}const je=async(e,s)=>{if(!e||!e.trim())return[s];if(e.startsWith("#"))return(t=>{const l=t.querySelectorAll(e);return[...l.length?l:t.getRootNode().querySelectorAll(e)]})(s.parentElement);try{const[t,l]=e.split("#");if(e.charAt(0)===".")e=new URL(t,s.closest("[base]")?.getAttribute("base")||location).href;else try{e=(void 0)(t),l&&(e+="#"+l)}catch(n){console.error(n.message)}const a=await be(e);if(s.setAttributeNS("xml","base",e),l){const n=a.querySelectorAll("#"+l);return n.length?[...n]:(console.error("template not found",e+"#"+l),[s])}return[a]}catch{return[s]}};function ae(e,s){for(let n of e.attributes)try{const o=n.name;if(o.startsWith("xmlns"))continue;n.namespaceURI?(!s.hasAttributeNS(n.namespaceURI,o)||s.getAttributeNS(n.namespaceURI,o)!==n.value)&&s.setAttributeNS(n.namespaceURI,o,n.value):(!s.hasAttribute(o)||s.getAttribute(o)!==n.value)&&s.setAttribute(n.name,n.value),n.name==="value"&&(s.value=n.value)}catch(o){console.warn("attribute assignment error",o?.message||o)}const t=s.dceExportedAttributes,l=s.getAttribute("dce-exported-attributes"),a=l?new Set(l.split(" ")):null;for(let n of s.getAttributeNames())!e.hasAttribute(n)&&!t?.has(n)&&!a?.has(n)&&s.removeAttribute(n)}function ie(e,s=0){const t={};for(const l of e.childNodes){const a=d(l,"data-dce-id")||l.dceId||0;if(!t[a])a?t[a]=1:(t[a]=l.dceId=++s,l.setAttribute&&l.setAttribute("data-dce-id",l.dceId));else{const n=l.dceId=a+"-"+t[a]++;l.setAttribute&&l.setAttribute("data-dce-id",n)}l.childNodes.length&&ie(l)}}function ve(e,s,t){t=1*t;for(let l of e.childNodes)if((l.dceId??l.getAttribute("data-dce-id")*1)>t)return e.insertBefore(s,l);e.append(s)}function re(e,s){if(e.firstElementChild?.localName==="dce-root"&&s[0]?.localName!=="dce-root")return;if(!s.length)return e.firstElementChild?.localName!=="dce-root"&&de(e);const t={};for(let l of e.childNodes)t[l.dceId],me(l)?(l.data.trim(),t[l.dceId||0]=l):t[d(l,"data-dce-id")||0]=l;for(let l of[...s]){const a=d(l,"data-dce-id")||l.dceId,n=t[a];n?(me(l)?n.nodeValue!==l.nodeValue&&(n.nodeValue=l.nodeValue):(ae(l,n),(n.childNodes.length||l.childNodes.length)&&re(n,l.childNodes)),delete t[a]):ve(e,l,a)}for(let l of Object.values(t))l.localName!=="dce-root"&&l.remove()}function Ee(e,s){return e.hasAttribute(s)||e.setAttribute(s,crypto.randomUUID()),e.getAttribute(s)}const Ne=e=>[...e?.matchAll(/([^{}]*)(\{)([^}]+)}([^{}]*)/g)].map(t=>`${t[1]}{${W(t[3])}}${t[4]}`).join(""),W=e=>{if(!e.trim())return e;const s=e.split("??"),t=s.shift(),l=W(s.join("??"));return s.length?`concat( ${t} , substring( ${l} , (1+string-length( ${l} )) * string-length( ${t} ) ) )`:e},I=(e,s)=>{const t=e.split("??");if(t.length>1)return I(t[0],s)||I(t[1],s);e=W(e);const l=s.ownerDocument.evaluate(e,s);switch(l.resultType){case XPathResult.NUMBER_TYPE:return l.numberValue;case XPathResult.STRING_TYPE:return l.stringValue;case XPathResult.BOOLEAN_TYPE:return l.booleanValue}let a="";for(let n;n=l.iterateNext();)a+=n.textContent;return a},we="stylesheet,transform,import,include,strip-space,preserve-space,output,key,decimal-format,namespace-alias,value-of,copy-of,number,apply-templates,apply-imports,for-each,sort,if,choose,when,otherwise,attribute-set,call-template,with-param,variable,param,text,processing-instruction,element,attribute,comment,copy,message,fallback".split(","),Te=(e,s)=>{const t=C("xsl:"+e.localName);for(let a of e.attributes)t.setAttribute(a.name,a.value);for(;e.firstChild;)t.append(e.firstChild);const l="if,choose,for-each".includes(e.localName)?(()=>{const a=C("span");return a.append(t),a})():t;if(e.parentElement)e.parentElement.replaceChild(l,e);else{const a=e.parentElement||s,n=[...a.childNodes];n.forEach((o,y)=>{o===e&&(n[y]=l)}),a.replaceChildren(...n)}};class Se extends HTMLElement{static observedAttributes=["src","tag","hidden"];async connectedCallback(){this.firstElementChild&&this.firstElementChild.localName!=="template"&&console.log(`custom-element used without template wrapping content
92
+ </xsl:stylesheet>`);o.importStylesheet(n);const v=o.transformToFragment(y,document),u=(i,r)=>i.querySelector(r),w=u(x,'template[mode="payload"]');if(!v)return console.error("transformation error",{xml:y.outerHTML,xsl:U(n)});if(v.firstElementChild.localName!=="dce-root"){const i=v.ownerDocument.createElement("dce-root");[...v.childNodes].forEach(r=>i.append(r)),v.append(i)}[...v.querySelectorAll("[test]")].forEach(i=>{const r=d(i,"test"),f=r.replace(/hasBoolAttribute\((.*?)\)/g,(g,h,b,T,P)=>{const L=h.substring(1);return`(not($${L} = 'false') and ($${L} = '' or $${L} = '${L}' or $${L} = 'true' ))`});r!==f&&i.setAttribute("test",f)}),[...v.querySelectorAll("dce-root>attribute")].forEach(i=>{K(i,"namespace,name,select");const r=te(i,"xsl:param"),f=d(i,"name");if(t.push(f),i.childNodes.length&&(l[f]=i.textContent),w.append(r),i.hasAttribute("select")){a[f]=d(i,"select"),K(r,"select,name");let g=d(i,"select").split("??"),h;if(g?.length>1){r.removeAttribute("select");const b=u(x,'template[match="ignore"]>choose').cloneNode(!0);F(b.firstElementChild).append(D(b,"{"+g[0]+"}")),b.firstElementChild.setAttribute("test",g[0]);for(let T=1;T<g.length-1;T++){const P=b.firstElementChild.cloneNode(!0);F(P).append(D(b,"{"+g[T]+"}")),P.setAttribute("test",g[T]),b.insertBefore(P,b.lastElementChild)}F(b.lastElementChild).append(D(b,"{"+g[g.length-1]+"}")),r.append(b),h=b.cloneNode(!0)}else h=te(i,"xsl:value-of");h.removeAttribute("name"),i.append(h),i.removeAttribute("select")}else K(r,"name"),r.setAttribute("select","/datadom/attributes/"+f),l[f]||i.remove()}),[...v.querySelectorAll("[value]")].filter(i=>i.getAttribute("value").match(/\{(.*)\?\?(.*)\}/g)).forEach(i=>{const r=d(i,"value");r&&i.setAttribute("value",Ne(r))});for(const i of v.childNodes)w.append(x.importNode(i,!0));[...w.getElementsByTagName("xsl:template")].forEach(i=>w.ownerDocument.documentElement.append(i));const O=u(x,'call-template[name="slot"]'),H=i=>{const r=O.cloneNode(!0),f=d(i,"name");f&&r.firstElementChild.setAttribute("select",`'${f}'`);for(let g of i.childNodes)r.lastElementChild.append(g);return r};z(w,"slot",i=>i.parentNode.replaceChild(H(i),i));const p=le(x);return ee(p,{declaredAttributes:t,hardcodedAttributes:l,exposedAttributes:a}),p}async function be(e){return await new Promise((t,l)=>{const a=new XMLHttpRequest;a.open("GET",e),a.responseType="document",a.onload=()=>{a.readyState===a.DONE&&a.status===200?t(a.responseXML?.body||a.responseXML||C("div",a.responseText)):l(`${a.statusText} - ${e}`)},a.addEventListener("error",n=>l(n)),a.send()})}function ye(e,s,t=!1){if(e===s)return!0;if(typeof e!="object"||e===null||typeof s!="object"||s===null||Object.keys(e).length!==Object.keys(s).length)return t;for(let l in e)if(!(l in s)||!ye(e[l],s[l]))return t;return!0}const ge=e=>e.split("|").map(s=>s.trim()).filter(s=>s),Ae=(e,s)=>ge(s).map(t=>{let l=e.ownerDocument,a=n=>(e.append(n),n);if(t.includes("/")){const n=[],o=l.evaluate(t,e);for(let y;y=o.iterateNext();)n.push(y);return n}return[...e.childNodes].find(n=>n.localName===t)||a(C(t,"",l))}).flat();function ne(e,s,t,l){if(!t.sliceProcessed)return t.sliceProcessed=1,Ae(e,s??"").map(a=>{const n=e.ownerDocument,o=t.sliceEventSource,y=t.sliceElement,x=()=>[...a.childNodes].filter(u=>u.nodeType===3||u.localName==="value"||u.localName==="form-data").map(u=>u.remove());o.getAttributeNames().map(u=>a.setAttribute(u,d(o,u))),[...a.childNodes].filter(u=>u.localName==="event").map(u=>u.remove()),"validationMessage"in o&&a.setAttribute("validation-message",o.validationMessage),t.type==="init"&&x(),a.append(M(t,"event",n));const v=(o.type==="checkbox"||o.type==="radio")&&!o.checked;if(y.hasAttribute("slice-value")){o.value===void 0?a.removeAttribute("value"):a.setAttribute("value",o.value);const u=v?"":I(d(y,"slice-value"),a);x(),a.append(D(n,u))}else{if("elements"in o)return x(),a.append(M(new FormData(o),"value",a.ownerDocument)),a;const u=v?"":o.value??d(o,"value");if(x(),u==null)[...a.childNodes].filter(w=>w.localName!=="event").map(w=>w.remove()),a.removeAttribute("value");else{const w=De(u)?D(n,u):M(u,"value",a.ownerDocument);a.append(w),a.setAttribute("value",u)}}return a})}function z(e,s,t){e.querySelectorAll&&[...e.querySelectorAll(s)].forEach(t)}const je=async(e,s)=>{if(!e||!e.trim())return[s];if(e.startsWith("#"))return(t=>{const l=t.querySelectorAll(e);return[...l.length?l:t.getRootNode().querySelectorAll(e)]})(s.parentElement);try{const[t,l]=e.split("#");if(e.charAt(0)===".")e=new URL(t,s.closest("[base]")?.getAttribute("base")||location).href;else try{e=(void 0)(t),l&&(e+="#"+l)}catch(n){console.error(n.message)}const a=await be(e);if(s.setAttributeNS("xml","base",e),l){const n=a.querySelectorAll("#"+l);return n.length?[...n]:(console.error("template not found",e+"#"+l),[s])}return[a]}catch{return[s]}};function ae(e,s){for(let n of e.attributes)try{const o=n.name;if(o.startsWith("xmlns"))continue;n.namespaceURI?(!s.hasAttributeNS(n.namespaceURI,o)||s.getAttributeNS(n.namespaceURI,o)!==n.value)&&s.setAttributeNS(n.namespaceURI,o,n.value):(!s.hasAttribute(o)||s.getAttribute(o)!==n.value)&&s.setAttribute(n.name,n.value),n.name==="value"&&(s.value=n.value)}catch(o){console.warn("attribute assignment error",o?.message||o)}const t=s.dceExportedAttributes,l=s.getAttribute("dce-exported-attributes"),a=l?new Set(l.split(" ")):null;for(let n of s.getAttributeNames())!e.hasAttribute(n)&&!t?.has(n)&&!a?.has(n)&&s.removeAttribute(n)}function ie(e,s=0){const t={};for(const l of e.childNodes){const a=d(l,"data-dce-id")||l.dceId||0;if(!t[a])a?t[a]=1:(t[a]=l.dceId=++s,l.setAttribute&&l.setAttribute("data-dce-id",l.dceId));else{const n=l.dceId=a+"-"+t[a]++;l.setAttribute&&l.setAttribute("data-dce-id",n)}l.childNodes.length&&ie(l)}}function ve(e,s,t){t=1*t;for(let l of e.childNodes)if((l.dceId??l.getAttribute("data-dce-id")*1)>t)return e.insertBefore(s,l);e.append(s)}function re(e,s){if(e.firstElementChild?.localName==="dce-root"&&s[0]?.localName!=="dce-root")return;if(!s.length)return e.firstElementChild?.localName!=="dce-root"&&de(e);const t={};for(let l of e.childNodes)t[l.dceId],me(l)?(l.data.trim(),t[l.dceId||0]=l):t[d(l,"data-dce-id")||0]=l;for(let l of[...s]){const a=d(l,"data-dce-id")||l.dceId,n=t[a];n?(me(l)?n.nodeValue!==l.nodeValue&&(n.nodeValue=l.nodeValue):(ae(l,n),(n.childNodes.length||l.childNodes.length)&&re(n,l.childNodes)),delete t[a]):ve(e,l,a)}for(let l of Object.values(t))l.localName!=="dce-root"&&l.remove()}function Ee(e,s){return e.hasAttribute(s)||e.setAttribute(s,crypto.randomUUID()),e.getAttribute(s)}const Ne=e=>[...e?.matchAll(/([^{}]*)(\{)([^}]+)}([^{}]*)/g)].map(t=>`${t[1]}{${W(t[3])}}${t[4]}`).join(""),W=e=>{if(!e.trim())return e;const s=e.split("??"),t=s.shift(),l=W(s.join("??"));return s.length?`concat( ${t} , substring( ${l} , (1+string-length( ${l} )) * string-length( ${t} ) ) )`:e},I=(e,s)=>{const t=e.split("??");if(t.length>1)return I(t[0],s)||I(t[1],s);e=W(e);const l=s.ownerDocument.evaluate(e,s);switch(l.resultType){case XPathResult.NUMBER_TYPE:return l.numberValue;case XPathResult.STRING_TYPE:return l.stringValue;case XPathResult.BOOLEAN_TYPE:return l.booleanValue}let a="";for(let n;n=l.iterateNext();)a+=n.textContent;return a},we="stylesheet,transform,import,include,strip-space,preserve-space,output,key,decimal-format,namespace-alias,value-of,copy-of,number,apply-templates,apply-imports,for-each,sort,if,choose,when,otherwise,attribute-set,call-template,with-param,variable,param,text,processing-instruction,element,attribute,comment,copy,message,fallback".split(","),Te=(e,s)=>{const t=C("xsl:"+e.localName);for(let a of e.attributes)t.setAttribute(a.name,a.value);for(;e.firstChild;)t.append(e.firstChild);const l="if,choose,for-each".includes(e.localName)?(()=>{const a=e.parentElement;if(!a||a.childNodes.length===1)return t;const n=C("span");return n.append(t),n})():t;if(e.parentElement)e.parentElement.replaceChild(l,e);else{const a=e.parentElement||s,n=[...a.childNodes];n.forEach((o,y)=>{o===e&&(n[y]=l)}),a.replaceChildren(...n)}};class Se extends HTMLElement{static observedAttributes=["src","tag","hidden"];async connectedCallback(){this.firstElementChild&&this.firstElementChild.localName!=="template"&&console.log(`custom-element used without template wrapping content
93
93
  `,this.outerHTML);const s=await je(d(this,"src"),this),t=d(this,"tag"),l=t||"dce-"+crypto.randomUUID();for(const p of s)z(p.templateNode||p.content||p,"style",i=>{const r=i.closest("slot"),f=r?`slot[name="${r.name}"]`:"";i.innerHTML=`${l} ${f}{${i.innerHTML}}`,this.append(i)});const a=s.map(p=>xe(p)),n=a.map((p,i)=>{i=new XSLTProcessor;try{i.importStylesheet(p)}catch(r){console.error(r,U(p))}return i});Object.defineProperty(this,"xsltString",{get:()=>a.map(p=>U(p)).join(`
94
94
  `)});const o=this,y=[...this.templateNode.querySelectorAll("[slice]")],x=y.map(p=>d(p,"slice")).filter(p=>!p.includes("/")).filter((p,i,r)=>r.indexOf(p)===i).map(ge).flat(),{declaredAttributes:v,hardcodedAttributes:u,exposedAttributes:w}=a[0],oe=new Set([...Object.keys(u),...Object.keys(w)]);class O extends HTMLElement{static get observedAttributes(){return v}#e=0;get dceExportedAttributes(){return oe}connectedCallback(){let i=se(this.childNodes);if(this.firstElementChild?.tagName==="TEMPLATE"){this.firstElementChild!==this.lastElementChild&&console.error("payload should have TEMPLATE as only child",this.outerHTML);const c=this.firstElementChild;c.remove(),i=se(c.content.childNodes);for(const E of i)if(E.localName==="style"){const m=Ee(this,"data-dce-style");E.innerHTML=`${l}[data-dce-style="${m}"]{${E.innerHTML}}`,c.insertAdjacentElement("beforebegin",E)}else E.nodeType===1?c.insertAdjacentElement("beforebegin",E):E.nodeType===3&&c.insertAdjacentText("beforebegin",E.data)}const r=X("<datadom/>").documentElement,f=(c,E="")=>(m=>(E&&m.append(D(r,E)),m))(r.ownerDocument.createElement(c)),g=_(r,"payload",i,Le);pe(g),fe(g),this.innerHTML="";const h=_(r,"attributes",this.attributes,c=>f(c.nodeName,c.value)),b=c=>this.hasAttribute(c)||[...h.children].find(E=>E.localName===c);ae(this,h),Object.keys(u).map(c=>b(c)||h.append(f(c,u[c]))),Object.keys(w).map(c=>b(c)||h.append(f(c))),_(r,"dataset",Object.keys(this.dataset),c=>f(c,this.dataset[c]));const T=_(r,"slice",x,c=>f(c,"")),P=c=>I(c,T);this.xml=r;const L=[],ce=()=>{const c={};for(let E;E=L.pop();){const m=d(E.sliceElement,"slice");c[m]||(ne(T,m,E),c[m]=E)}Object.keys(c).length!==0&&B()};let Y;this.onSlice=c=>{L.push(c),Y||(Y=setTimeout(()=>{ce(),Y=0},1))};const B=this.transform=()=>{if(this.#e)debugger;this.#e=1;const c=()=>{n.map((A,S)=>{const V=A.transformToFragment(r.ownerDocument,document);return V||console.error(`XSLT transformation error. xsl:
95
95
  `,U(a[S]),`
@@ -0,0 +1,213 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
5
+ <title>for-each - Declarative Custom Element implementation demo</title>
6
+ <link rel="icon" href="./wc-square.svg"/>
7
+
8
+ <script type="module" src="../custom-element.js"></script>
9
+ <style>
10
+ @import "./demo.css";
11
+
12
+ table {
13
+ border-collapse: collapse;
14
+ margin: 1rem 0;
15
+ }
16
+ th, td {
17
+ border: 1px solid #ccc;
18
+ padding: 0.5rem;
19
+ }
20
+ th {
21
+ background: #f0f0f0;
22
+ }
23
+ </style>
24
+ </head>
25
+ <body>
26
+
27
+ <nav>
28
+ <a href="../index.html"><h3><code>custom-element</code> demo</h3></a>
29
+ <h3>for-each loop</h3>
30
+ <p>The <code>&lt;for-each&gt;</code> element iterates over a node-set selected by XPath expression
31
+ and renders its content for each node.</p>
32
+ <p><b>XHTML namespace use</b><br/>
33
+ HTML elements like <code>&lt;table&gt;</code>, <code>&lt;tr&gt;</code>, <code>&lt;td&gt;</code>
34
+ have strict content model rules - only specific child elements are permitted.
35
+ For example, <code>&lt;table&gt;</code> only allows <code>&lt;thead&gt;</code>,
36
+ <code>&lt;tbody&gt;</code>, <code>&lt;tr&gt;</code> as children; <code>&lt;tr&gt;</code>
37
+ only allows <code>&lt;th&gt;</code> or <code>&lt;td&gt;</code>.<br/>
38
+ When the browser parses HTML, it moves non-permitted elements (like <code>&lt;for-each&gt;</code>)
39
+ outside the table before JavaScript runs.<br/>
40
+ Using <code>xhtml:</code> namespace prefix (e.g., <code>&lt;xhtml:table&gt;</code>,
41
+ <code>&lt;xhtml:tr&gt;</code>) prevents the browser from recognizing these as standard HTML
42
+ elements during initial parsing, preserving the template structure for DCE to process correctly.
43
+ See examples 4 and 6.
44
+ </p>
45
+ </nav>
46
+
47
+ <html-demo-element legend="1. Simple for-each"
48
+ description="Loop over inline XML data and render each item">
49
+ <template>
50
+ <custom-element>
51
+ <template>
52
+ <xsl:variable name="fruits">
53
+ <item>Apple</item>
54
+ <item>Banana</item>
55
+ <item>Cherry</item>
56
+ </xsl:variable>
57
+ <ul>
58
+ <for-each select="exsl:node-set($fruits)/*">
59
+ <li>{.}</li>
60
+ </for-each>
61
+ </ul>
62
+ </template>
63
+ </custom-element>
64
+ </template>
65
+ </html-demo-element>
66
+
67
+ <html-demo-element legend="2. for-each with position()"
68
+ description="Using position() to number items in the loop">
69
+ <template>
70
+ <custom-element>
71
+ <template>
72
+ <xsl:variable name="colors">
73
+ <color hex="#ff0000">Red</color>
74
+ <color hex="#00ff00">Green</color>
75
+ <color hex="#0000ff">Blue</color>
76
+ </xsl:variable>
77
+ <for-each select="exsl:node-set($colors)/*">
78
+ <div style="padding: 0.5rem; background: {@hex}; color: white;">
79
+ {position()}. {.}
80
+ </div>
81
+ </for-each>
82
+ </template>
83
+ </custom-element>
84
+ </template>
85
+ </html-demo-element>
86
+
87
+ <html-demo-element legend="3. Conditional for-each"
88
+ description="Initially empty, items shown when checkbox is checked">
89
+ <template>
90
+ <custom-element>
91
+ <template>
92
+ <xsl:variable name="items">
93
+ <item>First</item>
94
+ <item>Second</item>
95
+ <item>Third</item>
96
+ </xsl:variable>
97
+ <label>
98
+ <input type="checkbox" slice="show-items" value="yes"/>
99
+ Show items
100
+ </label>
101
+ <variable name="show" select="//show-items = 'yes'"></variable>
102
+ <div>
103
+ BEFORE
104
+ <for-each select="exsl:node-set($items)/*[$show]">
105
+ <span style="margin: 0 0.25rem; padding: 0.25rem; background: #e0e0ff;">
106
+ {position()}:{.}
107
+ </span>
108
+ </for-each>
109
+ AFTER
110
+ </div>
111
+ </template>
112
+ </custom-element>
113
+ </template>
114
+ </html-demo-element>
115
+
116
+ <html-demo-element legend="4. Nested for-each (Table)"
117
+ description="Nested loops to render table rows and cells">
118
+ <template>
119
+ <custom-element>
120
+ <template>
121
+ <xsl:variable name="table-data">
122
+ <row><cell>A1</cell><cell>A2</cell><cell>A3</cell></row>
123
+ <row><cell>B1</cell><cell>B2</cell><cell>B3</cell></row>
124
+ <row><cell>C1</cell><cell>C2</cell><cell>C3</cell></row>
125
+ </xsl:variable>
126
+ <variable name="rows" select="exsl:node-set($table-data)/*"></variable>
127
+ <xhtml:table>
128
+ <xhtml:thead>
129
+ <xhtml:tr>
130
+ <xhtml:th>Col 1</xhtml:th>
131
+ <xhtml:th>Col 2</xhtml:th>
132
+ <xhtml:th>Col 3</xhtml:th>
133
+ </xhtml:tr>
134
+ </xhtml:thead>
135
+ <xhtml:tbody>
136
+ <for-each select="$rows">
137
+ <xhtml:tr>
138
+ <for-each select="*">
139
+ <xhtml:td>{.}</xhtml:td>
140
+ </for-each>
141
+ </xhtml:tr>
142
+ </for-each>
143
+ </xhtml:tbody>
144
+ </xhtml:table>
145
+ </template>
146
+ </custom-element>
147
+ </template>
148
+ </html-demo-element>
149
+
150
+ <html-demo-element legend="5. for-each with attributes"
151
+ description="Access element attributes within the loop">
152
+ <template>
153
+ <custom-element>
154
+ <template>
155
+ <xsl:variable name="users">
156
+ <user id="1" role="admin">Alice</user>
157
+ <user id="2" role="editor">Bob</user>
158
+ <user id="3" role="viewer">Charlie</user>
159
+ </xsl:variable>
160
+ <for-each select="exsl:node-set($users)/*">
161
+ <div style="padding: 0.5rem; margin: 0.25rem 0; border-left: 3px solid #007bff;">
162
+ <strong>#{@id}</strong> {.}
163
+ <em>({@role})</em>
164
+ </div>
165
+ </for-each>
166
+ </template>
167
+ </custom-element>
168
+ </template>
169
+ </html-demo-element>
170
+
171
+ <html-demo-element legend="6. Dynamic table with toggle"
172
+ description="Table rows appear/disappear based on checkbox state">
173
+ <template>
174
+ <custom-element>
175
+ <template>
176
+ <xsl:variable name="products">
177
+ <product price="10">Widget</product>
178
+ <product price="25">Gadget</product>
179
+ <product price="15">Gizmo</product>
180
+ </xsl:variable>
181
+ <variable name="items" select="exsl:node-set($products)/*"></variable>
182
+ <label>
183
+ <input type="checkbox" slice="show-products" value="yes"/>
184
+ Show products
185
+ </label>
186
+ <variable name="visible" select="//show-products = 'yes'"></variable>
187
+ <xhtml:table>
188
+ <xhtml:thead>
189
+ <xhtml:tr>
190
+ <xhtml:th>#</xhtml:th>
191
+ <xhtml:th>Product</xhtml:th>
192
+ <xhtml:th>Price</xhtml:th>
193
+ </xhtml:tr>
194
+ </xhtml:thead>
195
+ <xhtml:tbody>
196
+ <for-each select="$items[$visible]">
197
+ <xhtml:tr>
198
+ <xhtml:td>{position()}</xhtml:td>
199
+ <xhtml:td>{.}</xhtml:td>
200
+ <xhtml:td>${@price}</xhtml:td>
201
+ </xhtml:tr>
202
+ </for-each>
203
+ </xhtml:tbody>
204
+ </xhtml:table>
205
+ </template>
206
+ </custom-element>
207
+ </template>
208
+ </html-demo-element>
209
+
210
+ <script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
211
+
212
+ </body>
213
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epa-wg/custom-element-dist",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite",
@@ -19,7 +19,7 @@
19
19
  "tt": "vitest --coverage.enabled --coverage.all --no-file-parallelism --watch --browser.headless=false src/stories/external-template.test.stories.ts "
20
20
  },
21
21
  "dependencies": {
22
- "@epa-wg/custom-element": "0.0.35"
22
+ "@epa-wg/custom-element": "0.0.37"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@storybook/addon-essentials": "8.5.3",
@@ -35,8 +35,8 @@
35
35
  "@vitest/coverage-istanbul": "3.0.5",
36
36
  "coverage-svg": "0.0.3",
37
37
  "lit": "3.2.1",
38
- "msw": "2.7.0",
39
- "msw-storybook-addon": "2.0.4",
38
+ "msw": "2.12.7",
39
+ "msw-storybook-addon": "2.0.6",
40
40
  "playwright": "1.50.1",
41
41
  "storybook": "8.5.3",
42
42
  "typescript": "5.7.3",
@@ -0,0 +1,213 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
5
+ <title>for-each - Declarative Custom Element implementation demo</title>
6
+ <link rel="icon" href="./wc-square.svg"/>
7
+
8
+ <script type="module" src="../custom-element.js"></script>
9
+ <style>
10
+ @import "./demo.css";
11
+
12
+ table {
13
+ border-collapse: collapse;
14
+ margin: 1rem 0;
15
+ }
16
+ th, td {
17
+ border: 1px solid #ccc;
18
+ padding: 0.5rem;
19
+ }
20
+ th {
21
+ background: #f0f0f0;
22
+ }
23
+ </style>
24
+ </head>
25
+ <body>
26
+
27
+ <nav>
28
+ <a href="../index.html"><h3><code>custom-element</code> demo</h3></a>
29
+ <h3>for-each loop</h3>
30
+ <p>The <code>&lt;for-each&gt;</code> element iterates over a node-set selected by XPath expression
31
+ and renders its content for each node.</p>
32
+ <p><b>XHTML namespace use</b><br/>
33
+ HTML elements like <code>&lt;table&gt;</code>, <code>&lt;tr&gt;</code>, <code>&lt;td&gt;</code>
34
+ have strict content model rules - only specific child elements are permitted.
35
+ For example, <code>&lt;table&gt;</code> only allows <code>&lt;thead&gt;</code>,
36
+ <code>&lt;tbody&gt;</code>, <code>&lt;tr&gt;</code> as children; <code>&lt;tr&gt;</code>
37
+ only allows <code>&lt;th&gt;</code> or <code>&lt;td&gt;</code>.<br/>
38
+ When the browser parses HTML, it moves non-permitted elements (like <code>&lt;for-each&gt;</code>)
39
+ outside the table before JavaScript runs.<br/>
40
+ Using <code>xhtml:</code> namespace prefix (e.g., <code>&lt;xhtml:table&gt;</code>,
41
+ <code>&lt;xhtml:tr&gt;</code>) prevents the browser from recognizing these as standard HTML
42
+ elements during initial parsing, preserving the template structure for DCE to process correctly.
43
+ See examples 4 and 6.
44
+ </p>
45
+ </nav>
46
+
47
+ <html-demo-element legend="1. Simple for-each"
48
+ description="Loop over inline XML data and render each item">
49
+ <template>
50
+ <custom-element>
51
+ <template>
52
+ <xsl:variable name="fruits">
53
+ <item>Apple</item>
54
+ <item>Banana</item>
55
+ <item>Cherry</item>
56
+ </xsl:variable>
57
+ <ul>
58
+ <for-each select="exsl:node-set($fruits)/*">
59
+ <li>{.}</li>
60
+ </for-each>
61
+ </ul>
62
+ </template>
63
+ </custom-element>
64
+ </template>
65
+ </html-demo-element>
66
+
67
+ <html-demo-element legend="2. for-each with position()"
68
+ description="Using position() to number items in the loop">
69
+ <template>
70
+ <custom-element>
71
+ <template>
72
+ <xsl:variable name="colors">
73
+ <color hex="#ff0000">Red</color>
74
+ <color hex="#00ff00">Green</color>
75
+ <color hex="#0000ff">Blue</color>
76
+ </xsl:variable>
77
+ <for-each select="exsl:node-set($colors)/*">
78
+ <div style="padding: 0.5rem; background: {@hex}; color: white;">
79
+ {position()}. {.}
80
+ </div>
81
+ </for-each>
82
+ </template>
83
+ </custom-element>
84
+ </template>
85
+ </html-demo-element>
86
+
87
+ <html-demo-element legend="3. Conditional for-each"
88
+ description="Initially empty, items shown when checkbox is checked">
89
+ <template>
90
+ <custom-element>
91
+ <template>
92
+ <xsl:variable name="items">
93
+ <item>First</item>
94
+ <item>Second</item>
95
+ <item>Third</item>
96
+ </xsl:variable>
97
+ <label>
98
+ <input type="checkbox" slice="show-items" value="yes"/>
99
+ Show items
100
+ </label>
101
+ <variable name="show" select="//show-items = 'yes'"></variable>
102
+ <div>
103
+ BEFORE
104
+ <for-each select="exsl:node-set($items)/*[$show]">
105
+ <span style="margin: 0 0.25rem; padding: 0.25rem; background: #e0e0ff;">
106
+ {position()}:{.}
107
+ </span>
108
+ </for-each>
109
+ AFTER
110
+ </div>
111
+ </template>
112
+ </custom-element>
113
+ </template>
114
+ </html-demo-element>
115
+
116
+ <html-demo-element legend="4. Nested for-each (Table)"
117
+ description="Nested loops to render table rows and cells">
118
+ <template>
119
+ <custom-element>
120
+ <template>
121
+ <xsl:variable name="table-data">
122
+ <row><cell>A1</cell><cell>A2</cell><cell>A3</cell></row>
123
+ <row><cell>B1</cell><cell>B2</cell><cell>B3</cell></row>
124
+ <row><cell>C1</cell><cell>C2</cell><cell>C3</cell></row>
125
+ </xsl:variable>
126
+ <variable name="rows" select="exsl:node-set($table-data)/*"></variable>
127
+ <xhtml:table>
128
+ <xhtml:thead>
129
+ <xhtml:tr>
130
+ <xhtml:th>Col 1</xhtml:th>
131
+ <xhtml:th>Col 2</xhtml:th>
132
+ <xhtml:th>Col 3</xhtml:th>
133
+ </xhtml:tr>
134
+ </xhtml:thead>
135
+ <xhtml:tbody>
136
+ <for-each select="$rows">
137
+ <xhtml:tr>
138
+ <for-each select="*">
139
+ <xhtml:td>{.}</xhtml:td>
140
+ </for-each>
141
+ </xhtml:tr>
142
+ </for-each>
143
+ </xhtml:tbody>
144
+ </xhtml:table>
145
+ </template>
146
+ </custom-element>
147
+ </template>
148
+ </html-demo-element>
149
+
150
+ <html-demo-element legend="5. for-each with attributes"
151
+ description="Access element attributes within the loop">
152
+ <template>
153
+ <custom-element>
154
+ <template>
155
+ <xsl:variable name="users">
156
+ <user id="1" role="admin">Alice</user>
157
+ <user id="2" role="editor">Bob</user>
158
+ <user id="3" role="viewer">Charlie</user>
159
+ </xsl:variable>
160
+ <for-each select="exsl:node-set($users)/*">
161
+ <div style="padding: 0.5rem; margin: 0.25rem 0; border-left: 3px solid #007bff;">
162
+ <strong>#{@id}</strong> {.}
163
+ <em>({@role})</em>
164
+ </div>
165
+ </for-each>
166
+ </template>
167
+ </custom-element>
168
+ </template>
169
+ </html-demo-element>
170
+
171
+ <html-demo-element legend="6. Dynamic table with toggle"
172
+ description="Table rows appear/disappear based on checkbox state">
173
+ <template>
174
+ <custom-element>
175
+ <template>
176
+ <xsl:variable name="products">
177
+ <product price="10">Widget</product>
178
+ <product price="25">Gadget</product>
179
+ <product price="15">Gizmo</product>
180
+ </xsl:variable>
181
+ <variable name="items" select="exsl:node-set($products)/*"></variable>
182
+ <label>
183
+ <input type="checkbox" slice="show-products" value="yes"/>
184
+ Show products
185
+ </label>
186
+ <variable name="visible" select="//show-products = 'yes'"></variable>
187
+ <xhtml:table>
188
+ <xhtml:thead>
189
+ <xhtml:tr>
190
+ <xhtml:th>#</xhtml:th>
191
+ <xhtml:th>Product</xhtml:th>
192
+ <xhtml:th>Price</xhtml:th>
193
+ </xhtml:tr>
194
+ </xhtml:thead>
195
+ <xhtml:tbody>
196
+ <for-each select="$items[$visible]">
197
+ <xhtml:tr>
198
+ <xhtml:td>{position()}</xhtml:td>
199
+ <xhtml:td>{.}</xhtml:td>
200
+ <xhtml:td>${@price}</xhtml:td>
201
+ </xhtml:tr>
202
+ </for-each>
203
+ </xhtml:tbody>
204
+ </xhtml:table>
205
+ </template>
206
+ </custom-element>
207
+ </template>
208
+ </html-demo-element>
209
+
210
+ <script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
211
+
212
+ </body>
213
+ </html>
@@ -682,6 +682,9 @@ export const toXsl = (el, defParent) => {
682
682
  while(el.firstChild)
683
683
  x.append(el.firstChild);
684
684
  const replacement = 'if,choose,for-each'.includes(el.localName) ? (() => {
685
+ const parent = el.parentElement;
686
+ if( !parent || parent.childNodes.length ===1 )
687
+ return x;
685
688
  const span = create('span');
686
689
  span.append(x);
687
690
  return span;