@epa-wg/custom-element 0.0.17 → 0.0.19
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/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.vscode/settings.json +25 -0
- package/README.md +49 -18
- package/bin/xslDtd2Ide.mjs +160 -0
- package/custom-element.d.ts +1 -1
- package/custom-element.js +220 -59
- package/demo/a.html +44 -10
- package/demo/data-slices.html +185 -0
- package/demo/demo.css +1 -0
- package/demo/dom-merge.html +1 -1
- package/demo/external-template.html +1 -0
- package/demo/hex-grid-dce.html +13 -13
- package/demo/http-request.html +19 -17
- package/demo/local-storage.html +3 -3
- package/demo/location-element.html +16 -11
- package/demo/parameters.html +21 -3
- package/demo/s.xml +6 -1
- package/demo/s.xslt +8 -10
- package/demo/z.html +61 -49
- package/http-request.js +2 -1
- package/ide/IDE.md +31 -0
- package/ide/customData-dce.json +112 -0
- package/ide/customData-xsl.json +1018 -0
- package/{web-types.json → ide/web-types-dce.json} +42 -1
- package/ide/web-types-xsl.json +867 -0
- package/index.html +7 -5
- package/package.json +4 -2
- package/request.html +2 -2
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"html.customData": [
|
|
3
|
+
"./ide/customData-dce.json",
|
|
4
|
+
"./ide/customData-xsl.json"
|
|
5
|
+
],
|
|
6
|
+
"terminal.integrated.profiles.windows": {
|
|
7
|
+
|
|
8
|
+
"PowerShell": {
|
|
9
|
+
"source": "PowerShell",
|
|
10
|
+
"icon": "terminal-powershell"
|
|
11
|
+
},
|
|
12
|
+
"Command Prompt": {
|
|
13
|
+
"path": [
|
|
14
|
+
"${env:windir}\\Sysnative\\cmd.exe",
|
|
15
|
+
"${env:windir}\\System32\\cmd.exe"
|
|
16
|
+
],
|
|
17
|
+
"args": [],
|
|
18
|
+
"icon": "terminal-cmd"
|
|
19
|
+
},
|
|
20
|
+
"Git Bash": {
|
|
21
|
+
"source": "Git Bash"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"terminal.integrated.defaultProfile.windows": "Git Bash"
|
|
25
|
+
}
|
package/README.md
CHANGED
|
@@ -22,16 +22,17 @@ UI is re-rendered on each data slice change triggered by initialization or DOM e
|
|
|
22
22
|
<details>
|
|
23
23
|
<summary> What is DCE? </summary>
|
|
24
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.
|
|
25
|
+
streaming parser, streaming transformation, multithreading. native assumes the C/Rust compiled code.
|
|
26
|
+
There is no place for JavaScript except of polyfill and ability to extend DCE, which otherwise has to be native.
|
|
26
27
|
|
|
27
28
|
The composition assumes the fully functional template and ability to call the template with parameters( custom tag + attributes) .
|
|
28
29
|
|
|
29
|
-
As the next to HTML abstraction layer - composition
|
|
30
|
+
As the next to HTML abstraction layer - **composition**, it provides:
|
|
30
31
|
* ability to use dependencies as from withing the page as from external file/lib via src attribute and # in URL
|
|
31
32
|
* ability to treat external content via content-type like html, SVG, images, video with own template rendering
|
|
32
33
|
* provide styles and embedded DCE declarations in own and named(lib) scope, sharing the scoped registry.
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
After composition the layer of **functional component** provides
|
|
35
36
|
* data layer with access to attributes/payload(+slots), dataset, data bound slice
|
|
36
37
|
* means in template to use the data selector for condition/enumeration/text injection into attributes and DOM
|
|
37
38
|
* Set of native primitives to support browser APIs declaratively: location,storage, http request which bonded to slice and as result to reactive UI.
|
|
@@ -45,6 +46,8 @@ This project is a POC( Proof of Concept ) targeting to become a base for native
|
|
|
45
46
|
</details>
|
|
46
47
|
|
|
47
48
|
# use
|
|
49
|
+
|
|
50
|
+
Use the [bootstrap project](https://github.com/EPA-WG/custom-element-bootstrap) with all pre-configured or
|
|
48
51
|
## install
|
|
49
52
|
use via CDN
|
|
50
53
|
```html
|
|
@@ -56,17 +59,44 @@ npm i -P @epa-wg/custom-element
|
|
|
56
59
|
yarn add @epa-wg/custom-element
|
|
57
60
|
```
|
|
58
61
|
|
|
62
|
+
## Enable IDE support
|
|
63
|
+
[IDE.md](ide/IDE.md)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
59
67
|
## [Live demo 🔗][demo-url]
|
|
68
|
+
|
|
69
|
+
### Interactivity via data `slice` triggered by events
|
|
70
|
+
```html
|
|
71
|
+
<custom-element>
|
|
72
|
+
<input slice="typed"> //slice/typed : {//slice/typed}
|
|
73
|
+
</custom-element>
|
|
74
|
+
|
|
75
|
+
<custom-element>
|
|
76
|
+
<template>
|
|
77
|
+
<button slice="clickcount"
|
|
78
|
+
slice-event="click"
|
|
79
|
+
slice-value="//clickcount + 1" > + </button>
|
|
80
|
+
<input slice="clickcount" type="number" value="{//clickcount ?? 0}">
|
|
81
|
+
Click count: { //clickcount }
|
|
82
|
+
</template>
|
|
83
|
+
</custom-element>
|
|
84
|
+
```
|
|
85
|
+
More on `slice` concept in [slice and events demo page][slice-demo-url]
|
|
86
|
+
|
|
87
|
+
### Templating power
|
|
88
|
+
comes from XSLT and XPath. Which is natively implemented in all current browsers, globally tested and well documented.
|
|
60
89
|
```html
|
|
90
|
+
|
|
61
91
|
<custom-element tag="pokemon-tile" hidden>
|
|
62
92
|
<h3>{title}</h3> <!-- title is an attribute in instance
|
|
63
93
|
mapped into /*/attributes/title -->
|
|
64
|
-
<
|
|
94
|
+
<if test="//smile"> <!-- data-smile DCE instance attribute,
|
|
65
95
|
mapped into /*/dataset/smile
|
|
66
96
|
used in condition -->
|
|
67
97
|
<!-- data-smile DCE instance attribute, used as HTML -->
|
|
68
98
|
<div>Smile as: {//smile} </div>
|
|
69
|
-
</
|
|
99
|
+
</if>
|
|
70
100
|
<!-- image would not be visible in sandbox, see live demo -->
|
|
71
101
|
<img src="https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world/{pokemon-id}.svg"
|
|
72
102
|
alt="{title} image"/>
|
|
@@ -205,12 +235,12 @@ In same way as in DCE itself:
|
|
|
205
235
|
</dce-2>
|
|
206
236
|
```
|
|
207
237
|
## Attributes
|
|
208
|
-
To be served by IDE and to track the attributes changes, they have to be declared via `
|
|
238
|
+
To be served by IDE and to track the attributes changes, they have to be declared via `attribute`:
|
|
209
239
|
```html
|
|
210
240
|
<custom-element tag="dce-with-attrs" hidden>
|
|
211
|
-
<
|
|
212
|
-
<
|
|
213
|
-
<
|
|
241
|
+
<attribute name="p1" >default_P1 </attribute>
|
|
242
|
+
<attribute name="p2" select="'always_p2'" ></attribute>
|
|
243
|
+
<attribute name="p3" select="//p3 ?? 'def_P3' " ></attribute>
|
|
214
244
|
p1: {$p1} <br/> p2: {$p2} <br/> p3: {$p3}
|
|
215
245
|
</custom-element>
|
|
216
246
|
<dce-with-attrs p1="123" p3="qwe"></dce-with-attrs>
|
|
@@ -229,7 +259,7 @@ i.e. slot `xxx` is matching `<i slot="xxx">...</i>` in payload.
|
|
|
229
259
|
<custom-element tag="with-description" >
|
|
230
260
|
<slot name="description">description is not available</slot>
|
|
231
261
|
<!-- same as
|
|
232
|
-
<
|
|
262
|
+
<value-of select='/*/payload/*[@slot="description"]'/>
|
|
233
263
|
-->
|
|
234
264
|
</custom-element>
|
|
235
265
|
<with-description>
|
|
@@ -238,12 +268,12 @@ i.e. slot `xxx` is matching `<i slot="xxx">...</i>` in payload.
|
|
|
238
268
|
```
|
|
239
269
|
|
|
240
270
|
## loops, variables
|
|
241
|
-
Loop implemented via [
|
|
271
|
+
Loop implemented via [for-each](https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/for-each)
|
|
242
272
|
|
|
243
273
|
[Variables in XSLT](https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/variable)
|
|
244
274
|
|
|
245
275
|
## [XPath](https://developer.mozilla.org/en-US/docs/Web/XSLT/Transforming_XML_with_XSLT/The_Netscape_XSLT_XPath_Reference)
|
|
246
|
-
is available in `{}` in attributes, in `
|
|
276
|
+
is available in `{}` in attributes, in `for-each`, `if`, `value-of`, and other XSL tags.
|
|
247
277
|
|
|
248
278
|
XPath is a selector language to navigate over custom element instance data, attributes, and payload.
|
|
249
279
|
|
|
@@ -262,12 +292,12 @@ in template. In such cases the `xhtml:` prefix in front of troubled tag would so
|
|
|
262
292
|
<local-storage key="basket" slice="basket" live type="json"></local-storage>
|
|
263
293
|
<xhtml:table xmlns:xhtml="http://www.w3.org/1999/xhtml" >
|
|
264
294
|
<xhtml:tbody>
|
|
265
|
-
<
|
|
295
|
+
<for-each select="//basket/@*">
|
|
266
296
|
<xhtml:tr>
|
|
267
297
|
<xhtml:th> {name()} </xhtml:th>
|
|
268
298
|
<xhtml:td> {.} </xhtml:td>
|
|
269
299
|
</xhtml:tr>
|
|
270
|
-
</
|
|
300
|
+
</for-each>
|
|
271
301
|
</xhtml:tbody>
|
|
272
302
|
<xhtml:tfoot>
|
|
273
303
|
<xhtml:tr>
|
|
@@ -302,13 +332,14 @@ run transformation under debugger.
|
|
|
302
332
|
* try to add as attribute you could observe and put the value of node name or text to identify the current location in data
|
|
303
333
|
within template
|
|
304
334
|
```xml
|
|
305
|
-
<b title="{name(*)} : {text()}">xml tag name: <
|
|
335
|
+
<b title="{name(*)} : {text()}">xml tag name: <value-of select='name()'/></b>
|
|
306
336
|
```
|
|
307
337
|
|
|
308
338
|
[git-url]: https://github.com/EPA-WG/custom-element
|
|
309
339
|
[git-test-url]: https://github.com/EPA-WG/custom-element-test
|
|
310
340
|
[demo-url]: https://unpkg.com/@epa-wg/custom-element@0.0/index.html
|
|
311
341
|
[css-demo-url]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/scoped-css.html
|
|
342
|
+
[slice-demo-url]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/data-slices.html
|
|
312
343
|
[hex-grid-url]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/hex-grid.html
|
|
313
344
|
[hex-grid-image]: demo/hex-grid-transform.png
|
|
314
345
|
[local-storage-demo]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/local-storage.html
|
|
@@ -317,9 +348,9 @@ within template
|
|
|
317
348
|
[github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
|
|
318
349
|
[npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element.svg
|
|
319
350
|
[npm-url]: https://npmjs.org/package/@epa-wg/custom-element
|
|
320
|
-
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
321
|
-
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
322
|
-
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
351
|
+
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.19/coverage/coverage.svg
|
|
352
|
+
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.19/coverage/lcov-report/index.html
|
|
353
|
+
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.19/storybook-static/index.html?path=/story/welcome--introduction
|
|
323
354
|
[sandbox-url]: https://stackblitz.com/github/EPA-WG/custom-element?file=index.html
|
|
324
355
|
[webcomponents-url]: https://www.webcomponents.org/element/@epa-wg/custom-element
|
|
325
356
|
[webcomponents-img]: https://img.shields.io/badge/webcomponents.org-published-blue.svg
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* node xslDtd2Ide.cjs
|
|
3
|
+
* would get xsl 1.0 schema and populate IntelliJ and VS Code IDE custom elements definitions
|
|
4
|
+
*
|
|
5
|
+
* This is one time use script as XSLT 1.0 schema is not changing.
|
|
6
|
+
* DTD parsing here is not generic and cobers only particula XSLT 1.0 schema.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const dtdText = await fetch( 'https://www.w3.org/1999/11/xslt10.dtd' )
|
|
12
|
+
.then( ( response ) => response.text() )
|
|
13
|
+
.then( ( body ) =>
|
|
14
|
+
{
|
|
15
|
+
return body;
|
|
16
|
+
} );
|
|
17
|
+
const matches = dtdText.match( /<([^>]*)>/g );
|
|
18
|
+
|
|
19
|
+
const chopOff = ( s, begin = 1, end = 1 ) => s.substring( begin, s.length - end );
|
|
20
|
+
const trim = s => s?.trim ? s.trim() : s;
|
|
21
|
+
|
|
22
|
+
let lastComment = ''
|
|
23
|
+
const dtdObj = { ENTITY: {}, ELEMENT: {} }
|
|
24
|
+
for( const match of matches ){
|
|
25
|
+
if( match.startsWith( '<!--' ) ) {
|
|
26
|
+
lastComment = match;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const body = chopOff( match, 2 );
|
|
30
|
+
const arr = body.split( /\s/ );
|
|
31
|
+
const name = arr[ 1 ].trim();
|
|
32
|
+
const resolveRef = s => s ? ( s.startsWith ? ( s.startsWith( '%' ) ? dtdObj.ENTITY[ chopOff( s, 1, 0 ).replace( ';',
|
|
33
|
+
'' ) ] : s ) : s ) : s;
|
|
34
|
+
const attrObj = a =>
|
|
35
|
+
{
|
|
36
|
+
if( !a || Array.isArray( a ) || !a.trim )
|
|
37
|
+
return a;
|
|
38
|
+
const as = a.trim();
|
|
39
|
+
if( 'CDATA,#PCDATA,NMTOKEN,NMTOKENS,'.includes( as + ',' ) )
|
|
40
|
+
return as;
|
|
41
|
+
const ar = as.split( ';' )
|
|
42
|
+
const aa = ar[ 0 ].split( ' ' );
|
|
43
|
+
// if( aa[0].includes('select')){debugger;}
|
|
44
|
+
return { name: aa[ 0 ], type: resolveRef( aa[ 1 ] ), defValue: aa[ 1 ], required: (ar[1] || aa[ 2 ])?.trim() }
|
|
45
|
+
};
|
|
46
|
+
switch( arr[ 0 ] ){
|
|
47
|
+
case 'ENTITY':{
|
|
48
|
+
let key = arr[ 2 ];
|
|
49
|
+
let val = body.substring( body.indexOf( key ) + key.length ).trim();
|
|
50
|
+
let ss;
|
|
51
|
+
if( val.startsWith( '"' ) || val.startsWith( "'" ) ) {
|
|
52
|
+
val = chopOff( val );
|
|
53
|
+
if( val.includes( '(#PCDATA' ) ) {
|
|
54
|
+
val = val.replace( '(#PCDATA', '' ).replace( ')*', '' ).trim();
|
|
55
|
+
ss = [ '#PCDATA', ...val.split( '\n' ).map( s => s.trim() ).map( resolveRef ).flat() ];
|
|
56
|
+
} else
|
|
57
|
+
ss = val.split( /[\n]/ ).map( s => s.replace( '|', '' ).trim() ).filter( s => s );
|
|
58
|
+
} else
|
|
59
|
+
ss = val.split( /[|\n]/ );
|
|
60
|
+
|
|
61
|
+
const v = ss.map( trim ).filter( s => s ).map( resolveRef ).map( attrObj ).flat().filter( s => s );
|
|
62
|
+
dtdObj.ENTITY[ key ] = !v.length ? '' : v.length === 1 ? v[ 0 ] : v;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case 'ELEMENT':
|
|
66
|
+
dtdObj.ELEMENT[ name ] = { values: arr[ 2 ], attributes: [] };
|
|
67
|
+
break;
|
|
68
|
+
case 'ATTLIST':{
|
|
69
|
+
const attrStr = body.split( name )[ 1 ].trim();
|
|
70
|
+
const attrs = attrStr.split( '\n' ).map( s => s.trim() );
|
|
71
|
+
const elementAttrs = dtdObj.ELEMENT[ name ].attributes;
|
|
72
|
+
for( let a of attrs ){
|
|
73
|
+
if( a.startsWith( '%' ) ) {
|
|
74
|
+
const v = dtdObj.ENTITY[ chopOff( a.split( ';' )[ 0 ], 1, 0 ) ];
|
|
75
|
+
if( !v ) {
|
|
76
|
+
debugger;
|
|
77
|
+
}
|
|
78
|
+
Array.isArray( v )
|
|
79
|
+
? elementAttrs.push( ...v )
|
|
80
|
+
: elementAttrs.push( v );
|
|
81
|
+
} else
|
|
82
|
+
elementAttrs.push( attrObj( a ) );
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// replace the tags list in custom-element.js
|
|
91
|
+
|
|
92
|
+
const tagsCsv = Object.keys( dtdObj.ELEMENT ).map( s => s.replace( 'xsl:', '' ) ).join( ',' );
|
|
93
|
+
const jsText = readFileSync( '../custom-element.js', 'utf8' )
|
|
94
|
+
const updatedJs = jsText.replace( /^.*export const xslTags = .*$/mg,
|
|
95
|
+
`export const xslTags = '${ tagsCsv }'.split(',');` );
|
|
96
|
+
writeFileSync( '../custom-element.js', updatedJs );
|
|
97
|
+
|
|
98
|
+
const vsCode = {
|
|
99
|
+
"version": 1.1, tags: Object.keys( dtdObj.ELEMENT ).map( s => (
|
|
100
|
+
{ name : s.replace( 'xsl:', '' )
|
|
101
|
+
, description : `${ s }`
|
|
102
|
+
, attributes : dtdObj.ELEMENT[ s ].attributes.map( a => (
|
|
103
|
+
{ name : a.name
|
|
104
|
+
, description: `${ JSON.stringify( a ) }`
|
|
105
|
+
, type : "string"
|
|
106
|
+
, required : a.required === '#REQUIRED'
|
|
107
|
+
} ) )
|
|
108
|
+
, references : [ { name: "MDN docs"
|
|
109
|
+
, url : `https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/${s.replace( 'xsl:', '' )}`
|
|
110
|
+
}]
|
|
111
|
+
} ) )
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
writeFileSync( '.././ide/customData-xsl.json', JSON.stringify( vsCode, undefined, 4 ) );
|
|
115
|
+
|
|
116
|
+
const intelliJ = {
|
|
117
|
+
"$schema": "http://json.schemastore.org/web-types",
|
|
118
|
+
"name": "@epa-wg/custom-element",
|
|
119
|
+
"version": "0.0.19",
|
|
120
|
+
"js-types-syntax": "typescript",
|
|
121
|
+
"description-markup": "markdown",
|
|
122
|
+
"contributions": {
|
|
123
|
+
"html": {
|
|
124
|
+
"elements": [
|
|
125
|
+
...Object.keys( dtdObj.ELEMENT ).map( s => (
|
|
126
|
+
{ name : s.replace( 'xsl:', '' )
|
|
127
|
+
, description : `${ s }`
|
|
128
|
+
, attributes : dtdObj.ELEMENT[ s ].attributes.map( a => (
|
|
129
|
+
{ name : a.name
|
|
130
|
+
, description : `${ JSON.stringify( a ) }`
|
|
131
|
+
, type : "string"
|
|
132
|
+
, required : a.required === '#REQUIRED'
|
|
133
|
+
} ) )
|
|
134
|
+
, 'doc-url' : `https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/${s.replace( 'xsl:', '' )}`
|
|
135
|
+
} ) ),
|
|
136
|
+
{
|
|
137
|
+
"name": "for-each",
|
|
138
|
+
"description": "The <xsl:for-each> element selects a set of nodes and processes each of them in the same way. It is often used to iterate through a set of nodes or to change the current node. If one or more <xsl:sort> elements appear as the children of this element, sorting occurs before processing. Otherwise, nodes are processed in document order.",
|
|
139
|
+
"doc-url": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/for-each",
|
|
140
|
+
"attributes": [
|
|
141
|
+
{
|
|
142
|
+
"name": "select",
|
|
143
|
+
"description": "Uses an XPath expression to select nodes to be processed.",
|
|
144
|
+
"required": true,
|
|
145
|
+
"doc-url": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/for-each#select",
|
|
146
|
+
"value": {
|
|
147
|
+
"type": "string"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
writeFileSync( '.././ide/web-types-xsl.json', JSON.stringify( intelliJ, undefined, 4 ) );
|
|
159
|
+
|
|
160
|
+
|
package/custom-element.d.ts
CHANGED