@epa-wg/custom-element 0.0.8 → 0.0.9
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 +11 -6
- package/custom-element.js +8 -7
- package/demo/dce-social-preview.png +0 -0
- package/demo/http-request.html +63 -0
- package/demo/local-storage.html +1 -0
- package/demo/wc-square.svg +1 -0
- package/http-request.js +19 -4
- package/index.html +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# custom-element
|
|
2
|
-
`Declarative Custom Element` proof of concept as a part of
|
|
3
|
-
|
|
2
|
+
`Declarative Custom Element` is a part of pure `Declarative Web Application` stack. A proof of concept as a part of
|
|
3
|
+
[WCCG in Declarative custom elements](https://github.com/w3c/webcomponents-cg/issues/32#issuecomment-1321037301)
|
|
4
|
+
discussion. The functionality of DCE and its data access does not require programming using JavaScript.
|
|
4
5
|
|
|
5
|
-
It allows to define custom HTML tag with template filled from slots and attributes
|
|
6
|
+
It allows to define custom HTML tag with template filled from slots and attributes and data `slice` as of now from
|
|
7
|
+
[local-storage][local-storage-demo] and [http-request][http-request-demo].
|
|
8
|
+
UI is re-rendered on each data slice change.
|
|
6
9
|
|
|
7
10
|
[![git][github-image] GitHub][git-url]
|
|
8
11
|
| Live demo: [custom-element][demo-url]
|
|
@@ -182,12 +185,14 @@ within template
|
|
|
182
185
|
[git-url]: https://github.com/EPA-WG/custom-element
|
|
183
186
|
[git-test-url]: https://github.com/EPA-WG/custom-element-test
|
|
184
187
|
[demo-url]: https://unpkg.com/@epa-wg/custom-element@0.0/index.html
|
|
188
|
+
[local-storage-demo]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/local-storage.html
|
|
189
|
+
[http-request-demo]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/http-request.html
|
|
185
190
|
[github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
|
|
186
191
|
[npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element.svg
|
|
187
192
|
[npm-url]: https://npmjs.org/package/@epa-wg/custom-element
|
|
188
|
-
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
189
|
-
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
190
|
-
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
193
|
+
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.9/coverage/coverage.svg
|
|
194
|
+
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.9/coverage/lcov-report/index.html
|
|
195
|
+
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.9/storybook-static/index.html?path=/story/welcome--introduction
|
|
191
196
|
[sandbox-url]: https://stackblitz.com/github/EPA-WG/custom-element?file=index.html
|
|
192
197
|
[webcomponents-url]: https://www.webcomponents.org/element/@epa-wg/custom-element
|
|
193
198
|
[webcomponents-img]: https://img.shields.io/badge/webcomponents.org-published-blue.svg
|
package/custom-element.js
CHANGED
|
@@ -17,7 +17,9 @@ bodyXml( dce )
|
|
|
17
17
|
{
|
|
18
18
|
const t = dce.firstElementChild
|
|
19
19
|
, sanitize = s => s.replaceAll("<html:","<")
|
|
20
|
-
.replaceAll("</html:","</")
|
|
20
|
+
.replaceAll("</html:","</")
|
|
21
|
+
.replaceAll( />\s*<\/xsl:value-of>/g ,"/>")
|
|
22
|
+
.replaceAll( />\s*<\/(br|hr|img|area|base|col|embed|input|link|meta|param|source|track|wbr)>/g ,"/>");
|
|
21
23
|
if( t?.tagName === 'TEMPLATE')
|
|
22
24
|
return sanitize( new XMLSerializer().serializeToString( t.content ) );
|
|
23
25
|
|
|
@@ -71,17 +73,17 @@ Json2Xml( o, tag )
|
|
|
71
73
|
return "<"+tag+">"+o.map(function(el){ return Json2Xml(el,tag); }).join()+"</"+tag+">";
|
|
72
74
|
}
|
|
73
75
|
noTag && (tag = 'r');
|
|
74
|
-
tag=tag.replace( /[^a-z0-9]/gi,'_' );
|
|
76
|
+
tag=tag.replace( /[^a-z0-9\-]/gi,'_' );
|
|
75
77
|
var oo = {}
|
|
76
78
|
, ret = [ "<"+tag+" "];
|
|
77
|
-
for(
|
|
79
|
+
for( let k in o )
|
|
78
80
|
if( typeof o[k] == "object" )
|
|
79
81
|
oo[k] = o[k];
|
|
80
82
|
else
|
|
81
|
-
ret.push( k.replace( /[^a-z0-9]/gi,'_' ) + '="'+o[k].toString().replace(/&/gi,'&')+'"');
|
|
83
|
+
ret.push( k.replace( /[^a-z0-9\-]/gi,'_' ) + '="'+o[k].toString().replace(/&/gi,'&')+'"');
|
|
82
84
|
if( oo )
|
|
83
85
|
{ ret.push(">");
|
|
84
|
-
for(
|
|
86
|
+
for( let k in oo )
|
|
85
87
|
ret.push( Json2Xml( oo[k], k ) );
|
|
86
88
|
ret.push("</"+tag+">");
|
|
87
89
|
}else
|
|
@@ -142,7 +144,7 @@ CustomElement extends HTMLElement
|
|
|
142
144
|
}
|
|
143
145
|
let timeoutID;
|
|
144
146
|
|
|
145
|
-
|
|
147
|
+
this.onSlice = ev=>
|
|
146
148
|
{ ev.stopPropagation?.();
|
|
147
149
|
sliceEvents.push(ev);
|
|
148
150
|
if( !timeoutID )
|
|
@@ -151,7 +153,6 @@ CustomElement extends HTMLElement
|
|
|
151
153
|
timeoutID =0;
|
|
152
154
|
},10);
|
|
153
155
|
};
|
|
154
|
-
this.onSlice = onSlice;
|
|
155
156
|
const transform = ()=>
|
|
156
157
|
{
|
|
157
158
|
const f = p.transformToFragment( x, document );
|
|
Binary file
|
package/demo/http-request.html
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
5
5
|
<title>http-request Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="./wc-square.svg" />
|
|
7
|
+
|
|
6
8
|
<script type="module" src="../http-request.js"></script>
|
|
7
9
|
<script type="module" src="../custom-element.js"></script>
|
|
8
10
|
<style>
|
|
@@ -35,6 +37,8 @@
|
|
|
35
37
|
<http-request
|
|
36
38
|
url="https://pokeapi.co/api/v2/pokemon?limit=6&offset=0"
|
|
37
39
|
slice="page"
|
|
40
|
+
method="GET"
|
|
41
|
+
header-accept="application/json"
|
|
38
42
|
></http-request>
|
|
39
43
|
<xsl:for-each select="//slice/page/data/results/*">
|
|
40
44
|
<xsl:variable name="slides-url"
|
|
@@ -54,6 +58,65 @@
|
|
|
54
58
|
</template>
|
|
55
59
|
</html-demo-element>
|
|
56
60
|
|
|
61
|
+
<html-demo-element legend="1. http-request headers"
|
|
62
|
+
description="request and response headers access demo">
|
|
63
|
+
|
|
64
|
+
<template>
|
|
65
|
+
<custom-element
|
|
66
|
+
tag="headers-demo"
|
|
67
|
+
hidden
|
|
68
|
+
>
|
|
69
|
+
<http-request
|
|
70
|
+
url="https://pokeapi.co/api/v2/pokemon?offset=6&limit=6"
|
|
71
|
+
slice="request_slice"
|
|
72
|
+
type="text"
|
|
73
|
+
mode="cors"
|
|
74
|
+
header-x-test="testing"
|
|
75
|
+
></http-request>
|
|
76
|
+
Content of <code>//slice/request_slice</code> is filled by <b>request</b> and <b>response</b>
|
|
77
|
+
from <code>${url}</code>
|
|
78
|
+
|
|
79
|
+
<h3>Samples</h3>
|
|
80
|
+
<table>
|
|
81
|
+
<tr><th>//slice/request_slice/request/headers/@mode</th>
|
|
82
|
+
<td><xsl:value-of select="//slice/request_slice/request/@mode"/></td></tr>
|
|
83
|
+
<tr><th>//slice/request_slice/response/headers/@content-type</th>
|
|
84
|
+
<td><xsl:value-of select="//slice/request_slice/response/headers/@content-type"/></td></tr>
|
|
85
|
+
<tr><th>//slice/request_slice/response/@status</th>
|
|
86
|
+
<td><xsl:value-of select="//slice/request_slice/response/@status"/></td></tr>
|
|
87
|
+
</table>
|
|
88
|
+
<xsl:for-each select="//slice/request_slice/*">
|
|
89
|
+
<ul data-request-section="{name(.)}">
|
|
90
|
+
<b data-testid="request-section"><xsl:value-of select='name(.)'/></b>
|
|
91
|
+
<xsl:for-each select="@*">
|
|
92
|
+
<div>
|
|
93
|
+
<var data-testid="section-attribute">@<xsl:value-of select='local-name(.)'/></var>
|
|
94
|
+
=
|
|
95
|
+
<code><xsl:value-of select='.'/></code>
|
|
96
|
+
</div>
|
|
97
|
+
</xsl:for-each>
|
|
98
|
+
<xsl:for-each select="*">
|
|
99
|
+
<div>
|
|
100
|
+
<b data-testid="section-deep"><xsl:value-of select='local-name(.)'/></b>
|
|
101
|
+
<ul>
|
|
102
|
+
<xsl:for-each select="@*">
|
|
103
|
+
<li>
|
|
104
|
+
<var data-testid="section-attribute">@<xsl:value-of select='local-name(.)'/></var>
|
|
105
|
+
=
|
|
106
|
+
<code><xsl:value-of select='.'/></code>
|
|
107
|
+
</li>
|
|
108
|
+
</xsl:for-each>
|
|
109
|
+
<code><xsl:value-of select='.'/></code>
|
|
110
|
+
</ul>
|
|
111
|
+
</div>
|
|
112
|
+
</xsl:for-each>
|
|
113
|
+
</ul>
|
|
114
|
+
</xsl:for-each>
|
|
115
|
+
</custom-element>
|
|
116
|
+
<headers-demo></headers-demo>
|
|
117
|
+
</template>
|
|
118
|
+
</html-demo-element>
|
|
119
|
+
|
|
57
120
|
|
|
58
121
|
<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
|
|
59
122
|
|
package/demo/local-storage.html
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
5
5
|
<title>custom-element Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="./wc-square.svg" />
|
|
6
7
|
<script type="module" src="../local-storage.js"></script>
|
|
7
8
|
<script type="module" src="../custom-element.js"></script>
|
|
8
9
|
<style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><svg id="Artwork" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216 209.18"><defs><style>.cls-1{fill:#c2e6f1;}.cls-2{fill:#dcf1f7;}.cls-3{fill:#2d4554;}.cls-4{fill:#60cae5;}</style></defs><polygon class="cls-3" points="0 82.47 0 126.71 34.84 146.83 34.84 187.06 73.16 209.18 108 189.07 142.84 209.18 181.16 187.06 181.16 146.83 216 126.71 216 82.47 181.16 62.35 181.16 22.12 142.84 0 108 20.12 73.16 0 34.84 22.12 34.84 62.35 0 82.47"/><path class="cls-2" d="m114.33,56.69l20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0Z"/><path class="cls-2" d="m98.19,62.71h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97Z"/><path class="cls-1" d="m48.12,66.01l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97Z"/><path class="cls-2" d="m46.18,24.66l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0s20.64-11.92,20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06Z"/><path class="cls-2" d="m115.87,24.66l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0s20.64-11.92,20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06Z"/><path class="cls-2" d="m152.65,42.59c-4.44,2.56-6.33,5.84-6.33,10.97v23.84c0,.54.45.8.92.54l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0v-23.84c0-.54-.45-.8-.92-.53l-20.64,11.92h0Z"/><path class="cls-2" d="m77.55,158.4l20.65-11.92h0c4.44-2.57,6.33-5.84,6.33-10.97v-23.84c0-.54-.45-.8-.92-.53l-20.64,11.92c-4.44,2.57-6.33,5.84-6.33,10.97h0s0,23.84,0,23.84c0,.54.45.8.92.54Z"/><path class="cls-4" d="m146.31,134.03v23.84c0,.54.45.8.92.54l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0s0-23.84,0-23.84c0-.54-.45-.8-.92-.53l-20.64,11.92h0c-4.44,2.57-6.33,5.84-6.33,10.97Z"/><path class="cls-4" d="m63.35,123.06h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97Z"/><path class="cls-4" d="m103.61,151.37l-20.64,11.92c-4.44,2.57-6.33,5.84-6.33,10.97h0s0,23.84,0,23.84c0,.54.45.8.92.54l20.65-11.92h0c4.44-2.57,6.33-5.84,6.33-10.97v-23.84c0-.54-.45-.8-.92-.53Z"/><path class="cls-4" d="m63.35,163.29h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97Z"/><path class="cls-4" d="m28.51,102.94h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97Z"/><path class="cls-4" d="m133.04,163.29l-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84c0,5.13,1.89,8.4,6.33,10.97h0s20.65,11.92,20.65,11.92c.47.27.92,0,.92-.54v-23.84s0,0,0,0c0-5.13-1.89-8.4-6.33-10.97Z"/><path class="cls-4" d="m173.29,151.37l-20.64,11.92h0c-4.44,2.57-6.33,5.84-6.33,10.97v23.84c0,.54.45.8.92.54l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0s0-23.84,0-23.84c0-.54-.45-.8-.92-.53Z"/><path class="cls-4" d="m209.06,91.55c0-.54-.45-.8-.92-.53l-20.64,11.92h0c-4.44,2.57-6.33,5.84-6.33,10.97v23.84c0,.54.45.8.92.54l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0v-23.84Z"/><path class="cls-2" d="m149.18,117.04l20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0Z"/><path class="cls-1" d="m112.39,98.05l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0v-23.84c0-.54-.45-.8-.92-.53l-20.64,11.92h0c-4.44,2.57-6.33,5.84-6.33,10.97v23.84c0,.54.45.8.92.54Z"/><path class="cls-1" d="m100.13,105.12c.47-.27.47-.79,0-1.06l-20.65-11.92c-4.44-2.57-8.22-2.57-12.67,0h0s-20.65,11.92-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92h0c4.44,2.57,8.22,2.57,12.67,0l20.64-11.92Z"/><path class="cls-2" d="m65.29,85.01c.47-.27.47-.79,0-1.06l-20.65-11.92c-4.44-2.57-8.22-2.57-12.67,0h0s-20.65,11.92-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92h0c4.44,2.57,8.22,2.57,12.67,0l20.64-11.92Z"/><path class="cls-1" d="m133.04,123.06l-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84c0,5.13,1.89,8.4,6.33,10.97h0s20.65,11.92,20.65,11.92c.47.27.92,0,.92-.54v-23.84s0,0,0,0c0-5.13-1.89-8.4-6.33-10.97Z"/><path class="cls-1" d="m184.02,96.93l20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0Z"/></svg>
|
package/http-request.js
CHANGED
|
@@ -6,6 +6,16 @@ export class HttpRequestElement extends HTMLElement
|
|
|
6
6
|
constructor() {
|
|
7
7
|
super();
|
|
8
8
|
}
|
|
9
|
+
get requestHeaders()
|
|
10
|
+
{ const ret = {};
|
|
11
|
+
[...this.attributes].filter(a=>a.name.startsWith('header-')).map( a => ret[a.name.substring(7)] = a.value );
|
|
12
|
+
return ret;
|
|
13
|
+
}
|
|
14
|
+
get requestProps()
|
|
15
|
+
{ const ret = {};
|
|
16
|
+
[...this.attributes].filter(a=>!a.name.startsWith('header-')).map( a => ret[a.name] = a.value );
|
|
17
|
+
return ret;
|
|
18
|
+
}
|
|
9
19
|
sliceInit( s )
|
|
10
20
|
{ if( !s )
|
|
11
21
|
s = {};
|
|
@@ -18,7 +28,7 @@ export class HttpRequestElement extends HTMLElement
|
|
|
18
28
|
controller.abort();
|
|
19
29
|
};
|
|
20
30
|
const url = attr(this, 'url') || ''
|
|
21
|
-
, request = {
|
|
31
|
+
, request = { ...this.requestProps, headers: this.requestHeaders }
|
|
22
32
|
, slice = { detail: { request }, target: this }
|
|
23
33
|
, updateSlice = slice =>
|
|
24
34
|
{ for( let parent = s.element.parentElement; parent; parent = parent.parentElement )
|
|
@@ -30,9 +40,14 @@ export class HttpRequestElement extends HTMLElement
|
|
|
30
40
|
|
|
31
41
|
setTimeout( async ()=>
|
|
32
42
|
{ updateSlice( slice );
|
|
33
|
-
|
|
43
|
+
const response = await fetch(url,{ ...this.requestProps, signal: controller.signal, headers: this.requestHeaders })
|
|
44
|
+
, r= {headers: {}};
|
|
45
|
+
[...response.headers].map( ([k,v]) => r.headers[k]=v );
|
|
46
|
+
'ok,status,statusText,type,url,redirected'.split(',').map(k=>r[k]=response[k])
|
|
47
|
+
|
|
48
|
+
slice.detail.response = r;
|
|
34
49
|
updateSlice( slice );
|
|
35
|
-
slice.detail.data = await
|
|
50
|
+
slice.detail.data = await response.json();
|
|
36
51
|
updateSlice( slice );
|
|
37
52
|
},0 );
|
|
38
53
|
|
|
@@ -41,4 +56,4 @@ export class HttpRequestElement extends HTMLElement
|
|
|
41
56
|
}
|
|
42
57
|
|
|
43
58
|
window.customElements.define( 'http-request', HttpRequestElement );
|
|
44
|
-
export default HttpRequestElement;
|
|
59
|
+
export default HttpRequestElement;
|
package/index.html
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
5
5
|
<title>custom-element Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="demo/wc-square.svg" />
|
|
6
7
|
<script type="module" src="custom-element.js"></script>
|
|
7
8
|
<style>
|
|
8
9
|
@import "demo/demo.css";
|
package/package.json
CHANGED