@epa-wg/custom-element 0.0.14 → 0.0.16

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.
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # custom-element
2
- `Declarative Custom Element` is a part of pure `Declarative Web Application` stack. A proof of concept as a part of
2
+ `Declarative Custom Element` (DCE) is a part of pure `Declarative Web Application` stack. A proof of concept as a part of
3
3
  [WCCG in Declarative custom elements](https://github.com/w3c/webcomponents-cg/issues/32#issuecomment-1321037301) and [Declarative Web Application](https://github.com/EPA-WG/dwa#readme)
4
4
  discussion. The functionality of DCE and its data access does not require programming using JavaScript.
5
5
 
6
6
  It allows to define custom HTML tag with template filled from slots, attributes and data `slice` as of now from
7
7
  [local-storage][local-storage-demo], [http-request][http-request-demo], [location][location-demo].
8
- UI is re-rendered on each data slice change.
8
+ UI is re-rendered on each data slice change triggered by initialization or DOM event.
9
9
 
10
10
  [![git][github-image] GitHub][git-url]
11
11
  | Live demo: [custom-element][demo-url]
@@ -17,6 +17,33 @@ UI is re-rendered on each data slice change.
17
17
  [![coverage][coverage-image]][coverage-url]
18
18
  [![Published on webcomponents.org][webcomponents-img]][webcomponents-url]
19
19
 
20
+
21
+
22
+ <details>
23
+ <summary> What is DCE? </summary>
24
+ DCE provides the next level of abstraction in HTML - native composition. With native implementation which is
25
+ streaming parser, streaming transformation, multithreading. native assumes the C/Rust compiled code. There is no place for JavaScript except of polyfill and ability to extend DCE, which otherwise has to be native.
26
+
27
+ The composition assumes the fully functional template and ability to call the template with parameters( custom tag + attributes) .
28
+
29
+ As the next to HTML abstraction layer - composition, it needs and provide:
30
+ * ability to use dependencies as from withing the page as from external file/lib via src attribute and # in URL
31
+ * ability to treat external content via content-type like html, SVG, images, video with own template rendering
32
+ * provide styles and embedded DCE declarations in own and named(lib) scope, sharing the scoped registry.
33
+
34
+ As the next to composition layer of **functional component** it provides
35
+ * data layer with access to attributes/payload(+slots), dataset, data bound slice
36
+ * means in template to use the data selector for condition/enumeration/text injection into attributes and DOM
37
+ * Set of native primitives to support browser APIs declaratively: location,storage, http request which bonded to slice and as result to reactive UI.
38
+ * support the data change trigger over events
39
+
40
+ While DCE is no-JS concept, DCE provides the basic declarative constructs to build most of simple apps. Assuming the extending via custom elements and JS. The evolution goal is to adopt most demanded APIs/construct natively into DCE stack over time.
41
+
42
+ DCE is compatible with closed/open/named root. Enabling as site-scoped styling and registry as encapsulated anonymous scopes in shadow root.
43
+
44
+ This project is a POC( Proof of Concept ) targeting to become a base for native DCE implementation polyfill.
45
+ </details>
46
+
20
47
  # use
21
48
  ## install
22
49
  use via CDN
@@ -138,7 +165,7 @@ In order to prevent the style leaking, it has to be defined withing `template` t
138
165
  <custom-element>
139
166
  <template>
140
167
  <style>
141
- color:green;
168
+ color: green;
142
169
  button{ color: blue; }
143
170
  </style>
144
171
  <label> green <button>blue</button> </label>
@@ -169,7 +196,18 @@ In same way as in DCE itself:
169
196
  </dce-2>
170
197
  ```
171
198
  ## Attributes
172
- curly braces `{}` in attributes implemented as [attribute value template](https://www.w3.org/TR/xslt20/#attribute-value-templates)
199
+ To be served by IDE and to track the attributes changes, they have to be declared via `xsl:param` syntax:
200
+ ```html
201
+ <custom-element tag="dce-with-attrs" hidden>
202
+ <xsl:param name="p1" >default_P1</xsl:param>
203
+ <xsl:param name="p2" select="'always_p2'" ></xsl:param>
204
+ <xsl:param name="p3" select="//p3 ?? 'def_P3' " ></xsl:param>
205
+ p1: {$p1} <br/> p2: {$p2} <br/> p3: {$p3}
206
+ </custom-element>
207
+ <dce-with-attrs p1="123" p3="qwe"></dce-with-attrs>
208
+ ```
209
+
210
+ The curly braces `{}` in attributes implemented as [attribute value template](https://www.w3.org/TR/xslt20/#attribute-value-templates)
173
211
 
174
212
  The names in curly braces are matching the instance attributes. I.e. in XML node `/my-component/attributes/`.
175
213
 
@@ -270,9 +308,9 @@ within template
270
308
  [github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
271
309
  [npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element.svg
272
310
  [npm-url]: https://npmjs.org/package/@epa-wg/custom-element
273
- [coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.14/coverage/coverage.svg
274
- [coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.14/coverage/lcov-report/index.html
275
- [storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.14/storybook-static/index.html?path=/story/welcome--introduction
311
+ [coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.16/coverage/coverage.svg
312
+ [coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.16/coverage/lcov-report/index.html
313
+ [storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.16/storybook-static/index.html?path=/story/welcome--introduction
276
314
  [sandbox-url]: https://stackblitz.com/github/EPA-WG/custom-element?file=index.html
277
315
  [webcomponents-url]: https://www.webcomponents.org/element/@epa-wg/custom-element
278
316
  [webcomponents-img]: https://img.shields.io/badge/webcomponents.org-published-blue.svg
package/custom-element.js CHANGED
@@ -7,8 +7,9 @@ const XSL_NS_URL = 'http://www.w3.org/1999/XSL/Transform'
7
7
 
8
8
  const attr = (el, attr)=> el.getAttribute?.(attr)
9
9
  , isText = e => e.nodeType === 3
10
- , create = ( tag, t = '' ) => ( e => ((e.innerText = t||''),e) )(document.createElement( tag ))
10
+ , create = ( tag, t = '', d=document ) => ( e => ((e.innerText = t||''),e) )((d.ownerDocument || d ).createElement( tag ))
11
11
  , createText = ( d, t) => (d.ownerDocument || d ).createTextNode( t )
12
+ , emptyNode = n=> { while(n.firstChild) n.firstChild.remove(); return n; }
12
13
  , createNS = ( ns, tag, t = '' ) => ( e => ((e.innerText = t||''),e) )(document.createElementNS( ns, tag ))
13
14
  , xslNs = x => ( x?.setAttribute('xmlns:xsl', XSL_NS_URL ), x )
14
15
  , xslHtmlNs = x => ( x?.setAttribute('xmlns:xhtml', HTML_NS_URL ), xslNs(x) );
@@ -162,7 +163,12 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
162
163
  xmlns:exsl="http://exslt.org/common"
163
164
  exclude-result-prefixes="exsl"
164
165
  >
165
- <xsl:template match="ignore"><xsl:value-of select="."/></xsl:template>
166
+ <xsl:template match="ignore">
167
+ <xsl:choose>
168
+ <xsl:when test="//attr">{//attr}</xsl:when>
169
+ <xsl:otherwise>{def}</xsl:otherwise>
170
+ </xsl:choose>
171
+ <xsl:value-of select="."/></xsl:template>
166
172
  <xsl:template mode="payload" match="attributes"></xsl:template>
167
173
  <xsl:template match="/">
168
174
  <xsl:apply-templates mode="payload" select="/datadom/attributes"/>
@@ -195,6 +201,24 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
195
201
  , payload = $( xslDom, 'template[mode="payload"]');
196
202
  if( !fr )
197
203
  return console.error("transformation error",{ xml:tc.outerHTML, xsl: xmlString( sanitizeXsl ) });
204
+ const params = [];
205
+ [...fr.querySelectorAll('dce-root>param')].forEach(p=>
206
+ { payload.append(p);
207
+ let select = attr(p,'select')?.split('??')
208
+ if( !select)
209
+ { select = ['//'+attr(p, 'name'), `'${p.textContent}'`];
210
+ emptyNode(p);
211
+ }
212
+ if( select?.length>1){
213
+ p.removeAttribute('select');
214
+ const c = $( xslDom, 'template[match="ignore"]>choose').cloneNode(true);
215
+ c.firstElementChild.setAttribute('test',select[0]);
216
+ emptyNode(c.firstElementChild).append( createText(c,'{'+select[0]+'}'));
217
+ emptyNode(c.lastElementChild ).append( createText(c,'{'+select[1]+'}'));
218
+ p.append(c)
219
+ }
220
+ params.push(p)
221
+ });
198
222
 
199
223
  for( const c of fr.childNodes )
200
224
  payload.append(xslDom.importNode(c,true))
@@ -214,7 +238,9 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
214
238
 
215
239
  forEach$( payload,'slot', s => s.parentNode.replaceChild( slot2xsl(s), s ) )
216
240
 
217
- return tagUid(xslDom)
241
+ const ret = tagUid(xslDom)
242
+ ret.params = params;
243
+ return ret;
218
244
  }
219
245
  export async function
220
246
  xhrTemplate(src)
@@ -382,6 +408,12 @@ CustomElement extends HTMLElement
382
408
  const sliceNames = [...this.templateNode.querySelectorAll('[slice]')].map(e=>attr(e,'slice'));
383
409
  class DceElement extends HTMLElement
384
410
  {
411
+ static get observedAttributes()
412
+ { return templateDocs.reduce( (ret,t) =>
413
+ { if( t.params ) ret.push( ...t.params.map(e=>attr(e,'name')) );
414
+ return ret;
415
+ }, [] );
416
+ }
385
417
  connectedCallback()
386
418
  { if( this.firstElementChild?.tagName === 'TEMPLATE' )
387
419
  { const t = this.firstElementChild;
@@ -416,7 +448,7 @@ CustomElement extends HTMLElement
416
448
  const applySlices = ()=>
417
449
  { const processed = {}
418
450
 
419
- for(let ev; ev = sliceEvents.pop(); )
451
+ for(let ev; ev = sliceEvents.pop(); )
420
452
  { const s = attr( ev.target, 'slice');
421
453
  if( processed[s] )
422
454
  continue;
@@ -440,7 +472,7 @@ CustomElement extends HTMLElement
440
472
  timeoutID =0;
441
473
  },10);
442
474
  };
443
- const transform = ()=>
475
+ const transform = this.transform = ()=>
444
476
  {
445
477
  const ff = xp.map( (p,i) =>
446
478
  { const f = p.transformToFragment(x.ownerDocument, document)
@@ -469,6 +501,20 @@ CustomElement extends HTMLElement
469
501
  transform();
470
502
  applySlices();
471
503
  }
504
+ attributeChangedCallback(name, oldValue, newValue)
505
+ { if( !this.xml )
506
+ return;
507
+ let a = this.xml.querySelector(`attributes>${name}`);
508
+ if( a )
509
+ emptyNode(a).append( createText(a,newValue));
510
+ else
511
+ { a = create( name, newValue, this.xml );
512
+ a.append( createText(a,newValue) );
513
+ this.xml.querySelector('attributes').append( a );
514
+ }
515
+
516
+ this.transform(); // needs throttling
517
+ }
472
518
  get dce(){ return dce }
473
519
  }
474
520
  if(tag)
@@ -0,0 +1,52 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3
+ xmlns:xhtml="http://www.w3.org/1999/xhtml">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
6
+ <title>parameters - custom-element Declarative Custom Element implementation demo</title>
7
+ <link rel="icon" href="./wc-square.svg" />
8
+ <script type="module" src="../location-element.js"></script>
9
+ <script type="module" src="../custom-element.js"></script>
10
+ <style>
11
+ @import "./demo.css";
12
+
13
+ button{ background: forestgreen; }
14
+ table{ min-width: 16rem; }
15
+ td{ border-bottom: 1px solid silver; }
16
+ tfoot td{ border-bottom: none; }
17
+ td,th{text-align: right; }
18
+ caption{ padding: 1rem; font-weight: bolder; font-family: sans-serif; }
19
+ </style>
20
+ </head>
21
+ <body>
22
+ <nav>
23
+ <a href="../index.html"><h3><code>custom-element</code> demo</h3></a>
24
+ </nav>
25
+ <html-demo-element legend="param as attributes definition" description="
26
+ params needed to declare DCE attributes and track the attributes changes. It also be used by IDE and validation.
27
+ ">
28
+ <template>
29
+ <custom-element tag="dce-link" hidden>
30
+ <xsl:param name="p1" >default_P1</xsl:param>
31
+ <xsl:param name="p2" select="'always_p2'" ></xsl:param>
32
+ <xsl:param name="p3" select="//p3 ?? 'def_P3' " ></xsl:param>
33
+ p1:{$p1} <br/> p2: {$p2} <br/> p3: {$p3}
34
+ </custom-element>
35
+ <dce-link id="dce1"></dce-link>
36
+ <section>
37
+ <dce-link id="dce2" p1="123" p2="override ignored as select is defined"></dce-link> <br/>
38
+ <div><input id="i1" value="p1" /> <button onclick="dce2.setAttribute('p1',i1.value)"> set p1</button> </div>
39
+ <div><input id="i2" value="p2" /> <button onclick="dce2.setAttribute('p2',i2.value)"> set p2</button> </div>
40
+ <div><input id="i3" value="p3" /> <button onclick="dce2.setAttribute('p3',i3.value)"> set p3</button> </div>
41
+ </section>
42
+ <dce-link id="dce3" p1="123" p3="qwe"></dce-link> |
43
+
44
+ </template>
45
+ </html-demo-element>
46
+
47
+
48
+
49
+ <script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
50
+
51
+ </body>
52
+ </html>
package/demo/s.xslt CHANGED
@@ -1,29 +1,20 @@
1
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dce="urn:schemas-epa-wg:dce"
2
- xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl">
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:dce="urn:schemas-epa-wg:dce" xmlns:exsl="http://exslt.org/common" version="1.0" exclude-result-prefixes="exsl">
3
3
  <xsl:template match="ignore">
4
- <xsl:value-of select="."/>
5
- </xsl:template>
6
- <xsl:template mode="payload" match="attributes">
7
- <nav data-dce-id="1">
8
- <xsl:for-each select="/datadom/payload/xhtml:*">
9
- <xsl:if test="local-name(.) = 'style'">
10
- <xsl:copy-of select=".">
11
- </xsl:copy-of>
12
- </xsl:if>
13
- <xsl:if test="local-name(.) != 'style' and (local-name(.) != 'span' or normalize-space(.) != '')">
14
- <section data-dce-id="2">
15
- <button class="action" data-dce-id="3">
16
- <dce-text data-dce-id="4">
17
- <xsl:value-of select="@alt"/>
18
- </dce-text>
19
- <xsl:copy-of select=".">
20
- </xsl:copy-of>
21
- </button>
22
- </section>
23
- </xsl:if>
24
- </xsl:for-each>
25
- </nav>
26
- </xsl:template>
4
+ <xsl:choose>
5
+ <xsl:when test="//attr"><xsl:value-of select="//attr"/></xsl:when>
6
+ <xsl:otherwise><xsl:value-of select="def"/></xsl:otherwise>
7
+ </xsl:choose>
8
+ <xsl:value-of select="."/></xsl:template>
9
+ <xsl:template mode="payload" match="attributes"><xsl:param xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="p1"><xsl:choose>
10
+ <xsl:when test="//p1 "><xsl:value-of select="//p1 "/></xsl:when>
11
+ <xsl:otherwise><xsl:value-of select=" 'def_p1' "/></xsl:otherwise>
12
+ </xsl:choose></xsl:param><xsl:param xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="p2" select="'always_p2'"/><xsl:param xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="p3"><xsl:choose>
13
+ <xsl:when test="p3"><xsl:value-of select="p3"/></xsl:when>
14
+ <xsl:otherwise><xsl:value-of select="default_P3"/></xsl:otherwise>
15
+ </xsl:choose></xsl:param><dce-root xmlns="http://www.w3.org/1999/xhtml" xmlns:xhtml="http://www.w3.org/1999/xhtml" data-dce-id="1"><dce-text xmlns="" data-dce-id="2">
16
+ p1:<xsl:value-of select="$p1"/> </dce-text><br xmlns="" data-dce-id="3"/><dce-text xmlns="" data-dce-id="4"> p2: <xsl:value-of select="$p2"/> </dce-text><br xmlns="" data-dce-id="5"/><dce-text xmlns="" data-dce-id="6"> p3: <xsl:value-of select="$p3"/>
17
+ </dce-text></dce-root></xsl:template>
27
18
  <xsl:template match="/">
28
19
  <xsl:apply-templates mode="payload" select="/datadom/attributes"/>
29
20
  </xsl:template>
package/demo/z.html CHANGED
@@ -38,23 +38,13 @@
38
38
  </style>
39
39
  </head>
40
40
  <body>
41
- <custom-element src="hex-grid-dce.html#hex-grid-template">
42
- <template>
43
- <style>nav{--hex-grid-size: 5rem; margin-left:2rem; }</style>
44
- <img src="wc-square.svg" alt="DCE" href="https://github.com/EPA-WG/custom-element"/>
45
- <img src="https://upload.wikimedia.org/wikipedia/commons/a/a7/React-icon.svg" alt="React" href="https://react.dev/"/>
46
- <img src="https://angularjs.org/favicon.ico" alt="Angular" href="https://angularjs.org/"/>
47
- <img src="https://www.svgrepo.com/show/508923/jquery.svg" alt="jQuery"/>
48
- <img src="https://open-wc.org/35ded306.svg" alt="Open WC" href="https://open-wc.org/"/>
49
- <img src="https://storage.googleapis.com/cms-storage-bucket/4fd0db61df0567c0f352.png" alt="Flutter" href="https://flutter.dev/"/>
50
- <img src="https://lit.dev/images/logo.svg#flame" alt="Lit"/>
51
- <img src="https://redux.js.org/img/redux.svg" alt="Redux"/>
52
- </template>
53
- </custom-element>
54
-
55
-
56
-
57
41
 
42
+ <custom-element src="html-template.xhtml#embedded-xsl">
43
+ <template>whole XSLT is embedded into HTML body</template>
44
+ </custom-element>
45
+ <!--<custom-element src="html-template.html#none">-->
46
+ <!-- <template><i>element with id=none is missing in template</i></template>-->
47
+ <!--</custom-element>-->
58
48
 
59
49
  </body>
60
50
  </html>
package/index.html CHANGED
@@ -14,6 +14,7 @@
14
14
  <h3><code>custom-element</code> demo</h3>
15
15
  <div><a href="https://github.com/EPA-WG/custom-element"
16
16
  ><img src="https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg" alt="icon">GIT</a>
17
+ | <a href="https://github.com/EPA-WG/custom-element/blob/main/README.md">README</a>
17
18
  | <a href="https://stackblitz.com/github/EPA-WG/custom-element?file=index.html">Sandbox</a>
18
19
  | <a href="https://chrome.google.com/webstore/detail/epa-wgcustom-element/hiofgpmmkdembdogjpagmbbbmefefhbl"
19
20
  >Chrome devtools plugin</a>
@@ -25,13 +26,14 @@
25
26
  The data query is powered by XPath. </p>
26
27
  <p>Try in <a href="https://stackblitz.com/github/EPA-WG/custom-element?file=index.html" >Sandbox</a> </p>
27
28
  <section>
28
- <h4>Data layer demo</h4>
29
+ <h4>Features demo</h4>
29
30
  <a href="./demo/local-storage.html" >local-storage </a> |
30
31
  <a href="./demo/http-request.html" >http-request </a> |
31
32
  <a href="./demo/location-element.html" >location-element </a> |
32
33
  <a href="./demo/external-template.html" >external template </a> <br/>
33
34
  <a href="./demo/hex-grid.html" >hex grid lib </a> |
34
35
  <a href="./demo/scoped-css.html" >scoped CSS </a> |
36
+ <a href="./demo/parameters.html" >attributes </a> |
35
37
  <a href="./demo/dom-merge.html" >DOM merge on dynamic update </a>
36
38
  </section>
37
39
  </nav>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epa-wg/custom-element",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "Declarative Custom Element as W3C proposal PoC with native(XSLT) based templating",
5
5
  "browser": "custom-element.js",
6
6
  "module": "custom-element.js",