@webqit/oohtml 2.1.34 → 2.1.35

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 (52) hide show
  1. package/.gitignore +3 -3
  2. package/LICENSE +20 -20
  3. package/README.md +733 -67
  4. package/dist/bindings-api.js +1 -1
  5. package/dist/bindings-api.js.map +3 -3
  6. package/dist/context-api.js +1 -1
  7. package/dist/context-api.js.map +3 -3
  8. package/dist/html-imports.js +1 -1
  9. package/dist/html-imports.js.map +3 -3
  10. package/dist/main.js +12 -12
  11. package/dist/main.js.map +3 -3
  12. package/dist/namespace-api.js +1 -1
  13. package/dist/namespace-api.js.map +3 -3
  14. package/dist/scoped-css.js +2 -2
  15. package/dist/scoped-css.js.map +3 -3
  16. package/dist/scoped-js.js +7 -7
  17. package/dist/scoped-js.js.map +3 -3
  18. package/package.json +76 -76
  19. package/src/bindings-api/index.js +83 -83
  20. package/src/bindings-api/targets.browser.js +10 -10
  21. package/src/context-api/HTMLContext.js +76 -157
  22. package/src/context-api/HTMLContextProvider.js +158 -0
  23. package/src/context-api/_ContextRequestEvent.js +25 -25
  24. package/src/context-api/index.js +51 -51
  25. package/src/context-api/targets.browser.js +9 -9
  26. package/src/{html-modules/HTMLExportsManager.js → html-imports/_HTMLExportsManager.js} +185 -199
  27. package/src/html-imports/_HTMLImportElement.js +211 -213
  28. package/src/{html-modules/_HTMLImportsContext.js → html-imports/_HTMLImportsProvider.js} +122 -114
  29. package/src/html-imports/index.js +197 -88
  30. package/src/html-imports/targets.browser.js +9 -9
  31. package/src/index.js +30 -32
  32. package/src/namespace-api/index.js +144 -144
  33. package/src/namespace-api/targets.browser.js +10 -10
  34. package/src/scoped-css/index.js +45 -45
  35. package/src/scoped-css/targets.browser.js +10 -10
  36. package/src/scoped-js/Compiler.js +297 -297
  37. package/src/scoped-js/index.js +112 -112
  38. package/src/scoped-js/targets.browser.js +10 -10
  39. package/src/targets.browser.js +9 -9
  40. package/src/util.js +34 -34
  41. package/test/bindings-api.test.js +42 -42
  42. package/test/imports.test.js +221 -221
  43. package/test/index.js +50 -50
  44. package/test/modules.test.js +200 -200
  45. package/test/namespace-api.test.js +51 -51
  46. package/test/scoped-css.test.js +31 -31
  47. package/test/scoped-js.test.js +29 -29
  48. package/dist/html-modules.js +0 -2
  49. package/dist/html-modules.js.map +0 -7
  50. package/src/context-api/HTMLContextManager.js +0 -77
  51. package/src/html-modules/index.js +0 -131
  52. package/src/html-modules/targets.browser.js +0 -10
package/README.md CHANGED
@@ -1,67 +1,733 @@
1
- # OOHTML
2
-
3
- <!-- BADGES/ -->
4
-
5
- <span class="badge-npmversion"><a href="https://npmjs.org/package/@webqit/oohtml" title="View this project on NPM"><img src="https://img.shields.io/npm/v/@webqit/oohtml.svg" alt="NPM version" /></a></span> <span class="badge-npmdownloads"><a href="https://npmjs.org/package/@webqit/oohtml" title="View this project on NPM"><img src="https://img.shields.io/npm/dm/@webqit/oohtml.svg" alt="NPM downloads" /></a></span>
6
-
7
- <!-- /BADGES -->
8
-
9
-
10
- Object-Oriented HTML (OOHTML) is a set of language features for authoring modular, reusable markup, and translating that to functional DOM-level objects! Everything comes together as a delightful holistic component architecture for the modern UI!
11
-
12
- OOHTML is an upcoming proposal!
13
-
14
- > **Note**
15
- > <br>This is documentation for `OOHTML@2.x`. (Looking for [`OOHTML@1.x`](https://github.com/webqit/oohtml/tree/v1.10.4)?)
16
-
17
- <details>
18
- <summary>Changes in v2:</summary>
19
-
20
- > + HTML Modules
21
- > + HTML Imports
22
- > + Namespace API
23
- > + Context API <sup>(new)</sup>
24
- > + <ins>Bindings API</ins><del>The State API</del>
25
- > + <ins>Scoped JS</ins><del>Subscript</del>
26
- > + Scoped CSS <sup>new</sup>
27
-
28
- </details>
29
-
30
- ## Overview
31
-
32
- Take a brief overview of OOHTML in [the introductory blog post](https://dev.to/oxharris/the-web-native-equations-1m1p-temp-slug-6661657?preview=ba70ad2c17f05b5761bc74516dbde8c9eff8b581a0420d87334fd9ef6bab9d6e6d3ab6aaf3fe02542bb9e7250d0a88a6df91dae40919aabcc9a07320#an-overview) (draft).
33
-
34
-
35
- ## Download Options
36
-
37
- **_Use as an npm package:_**
38
-
39
- ```bash
40
- npm i @webqit/oohtml
41
- ```
42
-
43
- ```js
44
- // Import
45
- import init from '@webqit/oohtml';
46
-
47
- // Initialize the lib
48
- init.call( window[, options = {} ]);
49
- ```
50
-
51
- **_Use as a script:_**
52
-
53
- ```html
54
- <script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
55
- ```
56
-
57
- ## Documentaion
58
-
59
- > *Full documentaion underway*
60
-
61
- ## Issues
62
-
63
- To report bugs or request features, please submit an [issue](https://github.com/webqit/oohtml/issues).
64
-
65
- ## License
66
-
67
- MIT.
1
+ # OOHTML
2
+
3
+ <!-- BADGES/ -->
4
+
5
+ <span class="badge-npmversion"><a href="https://npmjs.org/package/@webqit/oohtml" title="View this project on NPM"><img src="https://img.shields.io/npm/v/@webqit/oohtml.svg" alt="NPM version" /></a></span> <span class="badge-npmdownloads"><a href="https://npmjs.org/package/@webqit/oohtml" title="View this project on NPM"><img src="https://img.shields.io/npm/dm/@webqit/oohtml.svg" alt="NPM downloads" /></a></span>
6
+
7
+ <!-- /BADGES -->
8
+
9
+ **[Motivation](#motivation) • [Overview](#an-overview) • [Polyfill](#the-polyfill) • [Documentation](#documentation) • [Getting Involved](#getting-involved) • [License](#license)**
10
+
11
+ Object-Oriented HTML (OOHTML) is a set of language features for authoring modular, reusable markup, and translating that to functional DOM-level objects! Everything comes together as a delightful holistic component architecture for the modern UI!
12
+
13
+ OOHTML is an upcoming proposal!
14
+
15
+ > **Warning**
16
+ > <br>The syntax on this page isn't finalized. You may need to keep tabs with us.
17
+
18
+ ## Motivation
19
+
20
+ The web has generally outgrown HTML's idea of a monolith architecture which has held to the document as the unit of abstraction for scripts, style sheets, and element identifiers (the `id` attribute, and in some scenarios, the `name` attribute). You realize that while you're trying to *model things* in markup and are thinking in objects, components, logical building blocks, reusable units of abstraction - as we have of things like [Vue's SFC](https://vuejs.org/api/sfc-spec.html), [Svelte component format](https://svelte.dev/docs#component-format-script), [11ty's WebC](https://www.11ty.dev/docs/languages/webc/#css-and-js-(bundler-mode)) - the language for the job is posing a "per document" constraint!
21
+
22
+ As a consequence, much of this oldish monolith-oriented language by design don't come any useful beyond the global scope in the modern application architecture; **scripts, style sheets and standard identifiers just don't participate in UI modular architectures**! But they're also not harmless! In fact, **it is the sheer global forces that these things constitute that makes it extremely difficult to write even basic modular, reusable markup**! Until we move away from the global scope, **the amount of precision and coordination that must happen at the global level in the typical web page is just too unrealistic without tooling**! UI development may forever invite undue tooling!
23
+
24
+ We need a new standards work that will coexist with seemingly related efforts like Web Components to address the language-level problems that cause all the community-based wizardry around *naming things*, *containing styles*, *containing scripts*, and *reusing things* to proliferate! HTML's vocabulary will need to be extended, and much of its "per document" constraints will need to be relaxed! New APIs that provide an upgrade path from markup to JavaScript will need to be factored in!
25
+
26
+ [See more in the introductory blog post](https://dev.to/oxharris/the-web-native-equations-1fragment1p-temp-slug-6661657?preview=ba70ad2c17f05b5761bc74516dbde8c9eff8b581a0420d87334fd9ef6bab9d6e6d3ab6aaf3fe02542bb9e7250d0a88a6df91dae40919aabcc9a07320)<sup>draft</sup>
27
+
28
+ ## An Overview
29
+
30
+ OOHTML comes in three sets of features. (You may jump to sections.)
31
+
32
+ + [Modular HTML](#modular-html)
33
+ + [HTML Imports](#html-imports)
34
+ + [Reactive HTML](#reactive-html)
35
+ + [Put Together](#put-together)
36
+
37
+ ### Modular HTML
38
+
39
+ The first set of features covers authoring objects with self-contained structure, styling and *scripting*! This simply gets identifiers, style sheets and scripts to serve *at the object level* exactly as they do *at the document (object) level*.
40
+
41
+ └ *Namespaced IDs for modelling structure*:
42
+
43
+ ```html
44
+ <div id="user" namespace>
45
+ <a id="url" href="https://example.org">
46
+ <span id="name">Joe Bloggs</span>
47
+ </a>
48
+ <a id="email" href="mailto:joebloggs@example.com" >joebloggs@example.com</a>
49
+ </div>
50
+ ```
51
+
52
+ ```html
53
+ user
54
+ ├── url
55
+ ├── name
56
+ └── email
57
+ ```
58
+
59
+ ```js
60
+ // The namespace API
61
+ let { user } = document.namespace;
62
+ let { url, name, email } = user.namespace;
63
+ ```
64
+
65
+ *Scoped styles and scripts for styling and functionality*:
66
+
67
+ ```html
68
+ <div id="user">
69
+
70
+ <style scoped>
71
+ :scope { color: red }
72
+ </style>
73
+
74
+ <script scoped>
75
+ console.log(this) // div
76
+ </script>
77
+
78
+ </div>
79
+ ```
80
+
81
+ ```js
82
+ let { styleSheets, scripts } = user; // Analogous to the document.styleSheets, document.scripts properties
83
+ ```
84
+
85
+ └ [Modular HTML concepts](#)
86
+
87
+ ### HTML Imports
88
+
89
+ The next set of features covers *templating and reusing objects* - in both *declarative* and *programmatic* terms! It extends the language with the *module identifier* attribute `as`, and introduces a complementary new `<import>` element; and everything fits together as a real-time module system.
90
+
91
+ └ *The `as` attribute for exposing reusable modules*:
92
+
93
+ ```html
94
+ <head>
95
+
96
+ <template as="foo">
97
+ <div as="fragment1"></div>
98
+ <div as="fragment2"></div>
99
+ </template>
100
+
101
+ </head>
102
+ ```
103
+
104
+ └ *Module nesting for code organization*:
105
+
106
+ ```html
107
+ <head>
108
+
109
+ <template as="foo">
110
+ <div as="fragment1"></div>
111
+
112
+ <template as="nested">
113
+ <div as="fragment2"></div>
114
+ </template>
115
+ </template>
116
+
117
+ </head>
118
+ ```
119
+
120
+ └ *The `<template src>` element for remote modules*:
121
+
122
+ ```html
123
+ <template as="foo" src="/foo.html"></template>
124
+ ```
125
+
126
+ ```html
127
+ -- file: /foo.html --
128
+ <div as="fragment1"></div>
129
+ <template as="nested" src="/nested.html"></template>
130
+ ```
131
+
132
+ ```html
133
+ -- file: /nested.html --
134
+ <div as="fragment2"></div>
135
+ --
136
+ ```
137
+
138
+ ```js
139
+ foo.addEventListener('load', loadedCallback);
140
+ ```
141
+
142
+ └ *The `<import>` element for declarative module import*:
143
+
144
+ ```html
145
+ <body>
146
+ <import ref="/foo#fragment1"></import> <!-- Pending resolution -->
147
+ <import ref="/foo/nested#fragment2"></import> <!-- Pending resolution -->
148
+ </body>
149
+ ```
150
+
151
+ ```html
152
+ <body>
153
+ <div as="fragment1"></div> <!-- After resolution -->
154
+ <div as="fragment2"></div> <!-- After resolution -->
155
+ </body>
156
+ ```
157
+
158
+ ```js
159
+ // Using the HTMLImport API for event-based module import
160
+ document.import('foo#fragment2', docFragment => {
161
+ console.log(docFragment); // DucmentFragment:/foo#fragment2, received synchronously
162
+ });
163
+ ```
164
+
165
+ ```js
166
+ // Using the HTMLImports API
167
+ document.import('/foo/nested#fragment2', docFragment => {
168
+ console.log(docFragment); // DucmentFragment:/foo/nested#fragment2;
169
+ });
170
+ ```
171
+
172
+ └ *Scoped templates for object-scoped module system*:
173
+
174
+ ```html
175
+ <section> <!-- object with own modules -->
176
+
177
+ <template as="foo" scoped> <!-- Scoped to host object and not available globally -->
178
+ <div as="fragment1"></div>
179
+ </template>
180
+
181
+ <div>
182
+ <import ref="foo#fragment1"></import> <!-- Relative path (beginning without a slash), resolves to the local module: foo#fragment1 -->
183
+ <import ref="/foo#fragment1"></import> <!-- Absolute path, resolves to the global module: /foo#fragment1 -->
184
+ </div>
185
+
186
+ </section>
187
+ ```
188
+
189
+ ```js
190
+ // Using the HTMLImports API
191
+ document.querySelector('div').import('foo#fragment1', docFragment => {
192
+ console.log(docFragment); // the local module: foo#fragment1
193
+ });
194
+ ```
195
+
196
+ ```js
197
+ // Using the HTMLImports API
198
+ document.querySelector('div').import('/foo#fragment1', docFragment => {
199
+ console.log(docFragment); // the global module: foo#fragment1
200
+ });
201
+ ```
202
+
203
+ <details><summary>
204
+ Extended Imports concepts
205
+ </summary>
206
+
207
+ └ *Module nesting with inheritance*:
208
+
209
+ ```html
210
+ <template as="foo">
211
+
212
+ <header as="header"></header>
213
+ <footer as="footer"></footer>
214
+
215
+ <template as="nested1" inherits="header footer"> <!-- Using the "inherits" attribute -->
216
+ <main as="main"></main>
217
+ </template>
218
+
219
+ <template as="nested2" inherits="header footer"> <!-- Using the "inherits" attribute -->
220
+ <main as="main"></main>
221
+ </template>
222
+
223
+ </template>
224
+ ```
225
+
226
+ ```html
227
+ <template as="foo">
228
+
229
+ <template as="common">
230
+ <header as="header"></header>
231
+ <footer as="footer"></footer>
232
+ </template>
233
+
234
+ <template as="nested1" extends="common"> <!-- Using the "extends" attribute -->
235
+ <main as="main"></main>
236
+ </template>
237
+
238
+ <template as="nested2" extends="common"> <!-- Using the "extends" attribute -->
239
+ <main as="main"></main>
240
+ </template>
241
+
242
+ </template>
243
+ ```
244
+
245
+ ```html
246
+ <body>
247
+ <import ref="/foo/nested1#header"></import>
248
+ </body>
249
+ ```
250
+
251
+ └ *Remote modules with lazy-loading*:
252
+
253
+ ```html
254
+ <template as="foo" src="/foo.html" loading="lazy"></template>
255
+ ```
256
+
257
+ ```js
258
+ // On first access
259
+ console.log(foo.modules.m1); // Module loading triggered, returns Promise<module:m1>
260
+ ```
261
+
262
+ ```js
263
+ // On subsequent access, after load
264
+ console.log(foo.modules.m1); // module:m1
265
+ ```
266
+
267
+ ```js
268
+ // Using the context API with "live:true"
269
+ let request = { type: 'HTMLModules', detail: 'foo#m2', live: true };
270
+ document.context.ask(request, response => {
271
+ console.log(response); // module:/foo#m2; module loading triggered on first request and received asynchronously, then synchronously on subsequent requests after loaded
272
+ });
273
+ ```
274
+
275
+ └ *"Imports Contexts" for context-based imports resolution*:
276
+
277
+ ```html
278
+ <body importscontext="/foo">
279
+ <section>
280
+ <import ref="#fragment1"></import> <!-- Relative path (beginning without a slash), resolves to: /foo#fragment1 -->
281
+ </section>
282
+ </body>
283
+ ```
284
+
285
+ ```html
286
+ <body importscontext="/foo/nested">
287
+ <section>
288
+ <import ref="#fragment2"></import> <!-- Relative path (beginning without a slash), resolves to: /foo/nested#fragment2 -->
289
+ </section>
290
+ </body>
291
+ ```
292
+
293
+ ```js
294
+ // Using the HTMLImports API
295
+ document.querySelector('section').import('#fragment2', docFragment => {
296
+ console.log(docFragment); // module:/foo/nested#fragment2
297
+ });
298
+ ```
299
+
300
+ └ *"Imports Contexts" with named contexts*:
301
+
302
+ ```html
303
+ <body contextname="context1" importscontext="/foo/nested">
304
+
305
+ <import ref="#fragment2"></import> <!-- Relative path (beginning without a slash), resolves to: /foo/nested#fragment2 -->
306
+
307
+ <section importscontext="/foo">
308
+ <import ref="#fragment1"></import> <!-- Relative path (beginning without a slash), resolves to: /foo#fragment1 -->
309
+ <div>
310
+ <import ref="@context1#fragment2"></import> <!-- Context-relative path (beginning with a context name), resolves to: /foo/nested#fragment2 -->
311
+ </div>
312
+ </section>
313
+
314
+ </body>
315
+ ```
316
+
317
+ ```js
318
+ // Using the HTMLImports API
319
+ document.querySelector('div').import('@context1#fragment2', docFragment => {
320
+ console.log(docFragment); // module:/foo/nested#fragment2
321
+ });
322
+ ```
323
+
324
+ └ *"Imports Contexts" with context inheritance*:
325
+
326
+ ```html
327
+ <body importscontext="/foo">
328
+
329
+ <import ref="#fragment1"></import> <!-- Relative path (beginning without a slash), resolves to: /foo#fragment1 -->
330
+
331
+ <section importscontext="nested"> <!-- Relative path (beginning without a slash), resolves to: /foo/nested -->
332
+ <import ref="#fragment2"></import> <!-- Relative path (beginning without a slash), resolves to: /foo/nested#fragment2 -->
333
+ </section>
334
+
335
+ </body>
336
+ ```
337
+
338
+ └ *Object-scoped module system with context inheritance*:
339
+
340
+ ```html
341
+ <body contextname="context1" importscontext="/bar">
342
+ <section importscontext="nested"> <!-- object with own modules, plus inherited context: /bar/nested -->
343
+
344
+ <template as="foo" scoped> <!-- Scoped to host object and not available globally -->
345
+ <div as="fragment1"></div>
346
+ <div as="fragment2"></div>
347
+ </template>
348
+
349
+ <div>
350
+ <import ref="foo#fragment2"></import> <!-- Relative path (beginning without a slash), resolves to the local module: foo#fragment2, and if not found, resolves from context to the module: /bar/nested/foo#2 -->
351
+ <import ref="/foo#fragment1"></import> <!-- Absolute path, resolves to the global module: /foo#fragment1 -->
352
+ <import ref="@context1#fragment1"></import> <!-- Resolves to the global module: /bar#fragment1 -->
353
+ </div>
354
+
355
+ </section>
356
+ </body>
357
+ ```
358
+
359
+ ```js
360
+ // Using the HTMLImports API
361
+ document.querySelector('div').import('#fragment2', docFragment => {
362
+ console.log(docFragment); // the local module: foo#fragment2, and if not found, resolves from context to the module: /bar/nested#fragment2
363
+ });
364
+ ```
365
+
366
+ </details>
367
+
368
+ └ [HTML Imports concepts](#)
369
+
370
+ ### Reactive HTML
371
+
372
+ The last set of features covers the concept of "state", "bindings", and "reactivity" for those objects at the DOM level - in the most exciting form of the terms and as an upgrade path! This comes factored into the design as something intrinsic to the problem.
373
+
374
+ └ *The Observer API for general-purpose object observability*:
375
+
376
+ ```js
377
+ function changeCallback(changes) {
378
+ console.log(changes[0].type, changes[0].key, changes[0].value, changes[0].oldValue);
379
+ }
380
+ ```
381
+
382
+ ```js
383
+ const obj = {};
384
+ Observer.observe(obj, changeCallback);
385
+ ```
386
+
387
+ ```js
388
+ Observer.set(obj, 'prop1', 'value1'); // Reported synchronously
389
+ ```
390
+
391
+ ```js
392
+ Observer.deleteProperty(obj, 'prop1'); // Reported synchronously
393
+ ```
394
+
395
+ └ *A Namespace API that reflects the real-DOM&trade; in real-time*:
396
+
397
+ ```js
398
+ // Observing the addition or removal of elements with an ID
399
+ Observer.observe(document.namespace, changeCallback);
400
+
401
+ const paragraph = document.createElement('p');
402
+ paragraph.setAttribute('id', 'bar');
403
+ document.body.appendChild(paragraph); // Reported synchronously
404
+ ```
405
+
406
+ ```js
407
+ // Observing the addition or removal of elements with an ID
408
+ paragraph.toggleAttribute('namespace', true);
409
+ Observer.observe(paragraph.namespace, changeCallback);
410
+
411
+ const span = document.createElement('span');
412
+ span.setAttribute('id', 'baz');
413
+ paragraph.appendChild(span); // Reported synchronously
414
+ ```
415
+
416
+ └ *A Bindings API for binding application-level state to an object*:
417
+
418
+ ```js
419
+ // Observing document-level bindings
420
+ Observer.observe(document.bindings, changeCallback);
421
+
422
+ // Set state
423
+ document.bindings.userSignedIn = true;
424
+
425
+ // Set data object
426
+ document.bindings.data = { prop1: 'value1' };
427
+ Observer.set(document.bindings.data, 'prop2', 'value2');
428
+ ```
429
+
430
+ ```js
431
+ // Observing element-level bindings
432
+ Observer.observe(element.bindings, changeCallback);
433
+
434
+ // Set state
435
+ element.bindings.isCollapsed = true;
436
+
437
+ // Set data object
438
+ element.bindings.data = { prop1: 'value1' };
439
+ Observer.set(element.bindings.data, 'prop2', 'value2');
440
+ ```
441
+
442
+ └ *"Contract Scripts" for reactive scripting*:
443
+
444
+ ```html
445
+ <script contract>
446
+ console.log(this) // window
447
+
448
+ console.log(window.liveProperty) // live expression
449
+ console.log(liveProperty) // live expression; technically same as above
450
+
451
+ if (document.bindings.userSignedIn) {
452
+ // Live block
453
+ console.log('User signed in!');
454
+ }
455
+ </script>
456
+ ```
457
+
458
+ ```js
459
+ Observer.set(window, 'liveProperty'); // Live expressions rerun
460
+ ```
461
+
462
+ ```html
463
+ <div>
464
+ <script contract scoped>
465
+ console.log(this) // div
466
+
467
+ console.log(this.liveProperty) // live expression
468
+
469
+ if (this.bindings.isCollapsed) {
470
+ // Live block
471
+ console.log('Section collapsed!');
472
+ }
473
+ </script>
474
+ </div>
475
+ ```
476
+
477
+ ```js
478
+ Observer.set(element, 'liveProperty'); // Live expressions rerun
479
+ ```
480
+
481
+ └ [Reactive HTML concepts](#)
482
+
483
+ ### Put Together
484
+
485
+ All of OOHTML brings to the platform much of the modern UI development paradigms that community-based tools have encoded for years, and that just opens up new ways to leverage the web platform and bank less on abstractions! For example, the following is how something you could call a Single Page Application ([SPA](https://en.wikipedia.org/wiki/Single-page_application)) could be made - with zero tooling:
486
+
487
+ └ *First, two components that are themselves analogous to a Single File Component ([SFC](https://vuejs.org/guide/scaling-up/sfc.html))*:
488
+
489
+ ```html
490
+ <template as="pages">
491
+
492
+ <template as="layout">
493
+ <header as="header"></header>
494
+ <footer as="footer"></footer>
495
+ </template>
496
+
497
+ <!-- Home Page -->
498
+ <template as="home" extends="layout">
499
+ <main as="main" namespace>
500
+ <h1 id="banner">Home Page</h1>
501
+ <a id="cta" href="#/products">Go to Products</a>
502
+ <template scoped></template>
503
+ <style scoped></style>
504
+ <script scoped></script>
505
+ </main>
506
+ </template>
507
+
508
+ <!-- Products Page -->
509
+ <template as="products" extends="layout">
510
+ <main as="main" namespace>
511
+ <h1 id="banner">Products Page</h1>
512
+ <a id="cta" href="#/home">Go to Home</a>
513
+ <template scoped></template>
514
+ <style scoped></style>
515
+ <script scoped></script>
516
+ </main>
517
+ </template>
518
+
519
+ </template>
520
+ ```
521
+
522
+ └ *Then a 2-line router that alternates the view based on the URL hash*:
523
+
524
+ ```html
525
+ <body importscontext="/pages/home">
526
+
527
+ <import module="#header"></import>
528
+ <import module="#main"></import>
529
+ <import module="#footer"></import>
530
+
531
+ <script>
532
+ const route = () => { document.body.setAttribute('importscontext', '/pages' + location.hash.substring(1)); };
533
+ window.addEventListener('hashchange', route);
534
+ </script>
535
+
536
+ </body>
537
+ ```
538
+
539
+ As another example - being that a wide range of use cases exists beyond the above, the following is a Listbox component lifted directively from [ARIA Authoring Practices Guide (APG)](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/examples/listbox-grouped/#sc_label) but with IDs effectively "contained" at different levels within the component using the `namespace` attribute.
540
+
541
+ └ *A Listbox with namespaced IDs*:
542
+
543
+ ```html
544
+ <div namespace class="listbox-area">
545
+ <div>
546
+ <span id="ss_elem" class="listbox-label">
547
+ Choose your animal sidekick
548
+ </span>
549
+ <div id="ss_elem_list"
550
+ tabindex="0"
551
+ role="listbox"
552
+ aria-labelledby="ss_elem">
553
+ <ul role="group" aria-labelledby="cat" namespace>
554
+ <li role="presentation" id="cat">
555
+ Land
556
+ </li>
557
+ <li id="ss_elem_1" role="option">
558
+ Cat
559
+ </li>
560
+ <li id="ss_elem_2" role="option">
561
+ Dog
562
+ </li>
563
+ <li id="ss_elem_3" role="option">
564
+ Tiger
565
+ </li>
566
+ <li id="ss_elem_4" role="option">
567
+ Reindeer
568
+ </li>
569
+ <li id="ss_elem_5" role="option">
570
+ Raccoon
571
+ </li>
572
+ </ul>
573
+ <ul role="group" aria-labelledby="cat" namespace>
574
+ <li role="presentation" id="cat">
575
+ Water
576
+ </li>
577
+ <li id="ss_elem_6" role="option">
578
+ Dolphin
579
+ </li>
580
+ <li id="ss_elem_7" role="option">
581
+ Flounder
582
+ </li>
583
+ <li id="ss_elem_8" role="option">
584
+ Eel
585
+ </li>
586
+ </ul>
587
+ <ul role="group" aria-labelledby="cat" namespace>
588
+ <li role="presentation" id="cat">
589
+ Air
590
+ </li>
591
+ <li id="ss_elem_9" role="option">
592
+ Falcon
593
+ </li>
594
+ <li id="ss_elem_10" role="option">
595
+ Winged Horse
596
+ </li>
597
+ <li id="ss_elem_11" role="option">
598
+ Owl
599
+ </li>
600
+ </ul>
601
+ </div>
602
+ </div>
603
+ </div>
604
+ ```
605
+
606
+ ## The Polyfill
607
+
608
+ OOHTML is being developed as something to be used today - via a polyfill. This has been helping to facilitate the "release - iterations" loop and its overall evolution.
609
+
610
+ The polyfill can be loaded from the `unpkg.com` CDN, and should be placed early on in the document - before any OOHTML-specific features are used - and should be a classic script without any `defer` or `async` directives:
611
+
612
+ ```html
613
+ <head>
614
+ <script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
615
+ </head>
616
+ ```
617
+
618
+ > 22.75KB min+gzipped | 76.53KB min
619
+
620
+ <details><summary>
621
+ Extended usage concepts
622
+ </summary>
623
+
624
+ If you must load the script "async", one little trade-off has to be made for `<script scoped>` and `<script contract>` elements to have them ignored by the browser until the polyfill comes picking them up: *employing a custom MIME type in place of the standard `text/javascript` and `module` types*, in which case, a `<meta name="scoped-js">` element is used to configure the polyfill to honor the custom MIME type:
625
+
626
+ ```html
627
+ <head>
628
+ <meta name="scoped-js" content="script.mimeType=some-mime">
629
+ <script async src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
630
+ </head>
631
+ <body>
632
+ <script type="some-mime" scoped>
633
+ console.log(this); // body
634
+ </script>
635
+ </body>
636
+ ```
637
+
638
+ The custom MIME type strategy also comes in as a "fix" for older browsers (in macOS, typical) where the polyfill is not able to intercept `<script scoped>` and `<script contract>` elements ahead of the browser - e.g. where...
639
+
640
+ ```html
641
+ <body>
642
+ <script scoped>
643
+ console.log(this); // body
644
+ </script>
645
+ </body>
646
+ ```
647
+
648
+ ...still gives the `window` object in the console.
649
+
650
+ To use the polyfill on server-side DOM instances as made possible by libraries like [jsdom](https://github.com/jsdom/jsdom), simply install and initialize the library `@webqit/oohtml` with the DOM instance:
651
+
652
+ ```bash
653
+ npm i @webqit/oohtml
654
+ ```
655
+
656
+ ```js
657
+ // Import
658
+ import init from '@webqit/oohtml';
659
+
660
+ // Initialize the lib
661
+ init.call( window[, options = {} ]);
662
+ ```
663
+
664
+ But all things "SSR" for OOHTML is best left to the [`@webqit/oohtml-ssr`](https://github.com/webqit/oohtml-ssr) package!
665
+
666
+ Also, if you'll be going ahead to build a real world app to see OOHTML in action, you may want to consider also using:
667
+
668
+ + the [`@webqit/oohtml-cli`](https://github.com/webqit/oohtml-cli) package for operating a file-based templating system.
669
+
670
+ + the modest, OOHTML-based [Webflo](https://github.com/webqit/webflo) framework to greatly streamline your application development process!
671
+
672
+ </details>
673
+
674
+ <details><summary>
675
+ Notes
676
+ </summary>
677
+
678
+ Here are the performance-specific notes for this polyfill:
679
+
680
+ + By default, the Contract Functions compiler (43.15KB min+gzipped | 157KB min) is excluded from the polyfill build and fetched separately on demand - on the first encounter with a Contract Script. This is loaded into a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) and all compilations are able to happen off the main thread! This ensures near-zero cost to your application loading and runtime performance!
681
+
682
+ Note that this lazy-loading approach means that all Contract Scripts will behave "async" just like module scripts; i.e. scripts are defered until the compiler has been loaded. In other words, the following two scripts will have the same timing semantics:
683
+
684
+ ```html
685
+ <script contract></script>
686
+ <script type="module" contract></script>
687
+ ```
688
+
689
+ This isn't necessarily bad unless there is a requirment to have classic scripts follow their [native synchronous timing](https://html.spec.whatwg.org/multipage/parsing.html#scripts-that-modify-the-page-as-it-is-being-parsed), in which case the Contract Functions compiler will need to be explicitly and synchronously loaded ahead of any encounter with classic Contract Scripts:
690
+
691
+ ```html
692
+ <head>
693
+ <script src="https://unpkg.com/@webqit/subscript@next/dist/compiler.js"></script> <!-- Must come before the polyfil -->
694
+ <script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
695
+ </head>
696
+ ```
697
+
698
+ + Whether loaded lazily or eaderly, the compiler also factors in additional optimizations. For example, identical scripts are handled only first time, and only ever have once Contract Function instance!
699
+
700
+ </details>
701
+
702
+ ## Documentation
703
+
704
+ A more detailed documentation for OOHTML is underway in the [project wiki](https://github.com/webqit/oohtml/wiki).
705
+
706
+ > **Note**
707
+ > <br>This is documentation for `OOHTML@2.x`. (Looking for [`OOHTML@1.x`](https://github.com/webqit/oohtml/tree/v1.10.4)?)
708
+
709
+ <details>
710
+ <summary>Changes in v2:</summary>
711
+
712
+ > + HTML Modules <sup>(overhauled)</sup>
713
+ > + HTML Imports <sup>(overhauled)</sup>
714
+ > + Namespace API <sup>(overhauled)</sup>
715
+ > + Context API <sup>(new)</sup>
716
+ > + <ins>Bindings API</ins> <del>The State API</del>
717
+ > + <ins>Scoped JS</ins> <del>Subscript</del>
718
+ > + Scoped CSS <sup>new</sup>
719
+
720
+ </details>
721
+
722
+ ## Getting Involved
723
+
724
+ All forms of contributions are welcome at this time. For example, syntax and other implementation details are all up for discussion. Also, help is needed with more formal documentation. And here are specific links:
725
+
726
+ + [Project](https://github.com/webqit/oohtml)
727
+ + [Documentation](https://github.com/webqit/oohtml/wiki)
728
+ + [Discusions](https://github.com/webqit/oohtml/discussions)
729
+ + [Issues](https://github.com/webqit/oohtml/issues)
730
+
731
+ ## License
732
+
733
+ MIT.