@webqit/oohtml 1.10.2 → 2.0.0

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 (53) hide show
  1. package/.gitignore +3 -3
  2. package/LICENSE +21 -0
  3. package/README.md +399 -396
  4. package/dist/context-api.js +2 -0
  5. package/dist/context-api.js.map +7 -0
  6. package/dist/html-imports.js +1 -2
  7. package/dist/html-imports.js.map +3 -3
  8. package/dist/html-modules.js +1 -2
  9. package/dist/html-modules.js.map +3 -3
  10. package/dist/main.js +26 -14
  11. package/dist/main.js.map +3 -3
  12. package/dist/namespaced-html.js +1 -2
  13. package/dist/namespaced-html.js.map +3 -3
  14. package/dist/scoped-js.js +27 -0
  15. package/dist/scoped-js.js.map +7 -0
  16. package/dist/state-api.js +1 -2
  17. package/dist/state-api.js.map +3 -3
  18. package/package.json +76 -76
  19. package/src/context-api/HTMLContext.js +158 -0
  20. package/src/context-api/HTMLContextManager.js +77 -0
  21. package/src/context-api/_ContextRequestEvent.js +26 -0
  22. package/src/context-api/index.js +53 -0
  23. package/src/{namespaced-html/browser-entry.js → context-api/targets.browser.js} +9 -9
  24. package/src/html-imports/_HTMLImportElement.js +216 -0
  25. package/src/html-imports/index.js +92 -557
  26. package/src/{browser-entry.js → html-imports/targets.browser.js} +10 -10
  27. package/src/html-modules/HTMLExportsManager.js +191 -0
  28. package/src/html-modules/_HTMLImportsContext.js +114 -0
  29. package/src/html-modules/index.js +133 -384
  30. package/src/{html-imports/browser-entry.js → html-modules/targets.browser.js} +9 -9
  31. package/src/index.js +34 -39
  32. package/src/namespaced-html/index.js +130 -144
  33. package/src/namespaced-html/targets.browser.js +10 -0
  34. package/src/scoped-js/index.js +382 -0
  35. package/src/scoped-js/targets.browser.js +10 -0
  36. package/src/state-api/index.js +55 -142
  37. package/src/state-api/targets.browser.js +10 -0
  38. package/src/{html-modules/browser-entry.js → targets.browser.js} +10 -10
  39. package/src/util.js +20 -180
  40. package/test/imports.test.js +194 -0
  41. package/test/index.js +119 -0
  42. package/test/modules.test.js +198 -0
  43. package/test/namespaced-html.test.js +50 -0
  44. package/test/scoped-js.js +57 -0
  45. package/test/state-api.test.js +34 -0
  46. package/test/test.html +69 -0
  47. package/dist/subscript.js +0 -15
  48. package/dist/subscript.js.map +0 -7
  49. package/src/state-api/browser-entry.js +0 -10
  50. package/src/subscript/Element.js +0 -103
  51. package/src/subscript/browser-entry.js +0 -10
  52. package/src/subscript/index.js +0 -70
  53. package/test/all.test.js +0 -0
package/README.md CHANGED
@@ -1,396 +1,399 @@
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
- OOHTML offers a set of five features that make common UI development paradigms possible as native web platform features. These features may be used individually or together for some great UI-authoring capabilites. Here is an overview:
11
-
12
- + [HTML Modules](#html-modules)
13
- + [HTML Imports](#html-imports)
14
- + [Namespaced HTML](#namespaced-html)
15
- + [The State API](#the-state-api)
16
- + [Subscript](#subscript)
17
-
18
- ## HTML Modules
19
-
20
- *HTML Modules* are a templating feature that lets us write reusable HTML markup using the *module*, *export* and *import* paradigm. This feature establishes the standard `<template>` element as the foundation of a module infrastructure for HTML and introduces new attributes, properties and events that together closes the loop.
21
-
22
- A module is a regular `<template>` element with a `name` attribute - *the module ID* - and its contents are simply the *exports*.
23
-
24
- ```html
25
- <head>
26
-
27
- <template name="module1">
28
-
29
- <label for="age">How old are you?</div>
30
- <input id="age" />
31
-
32
- </template>
33
-
34
- </head>
35
- ```
36
-
37
- Exports may be more properly wrapped within an `<export>` element of a designated name.
38
-
39
- ```html
40
- <head>
41
-
42
- <template name="module1">
43
-
44
- <export name="question">
45
- <label for="age">How old are you?</label>
46
- <input id="age" />
47
- </export>
48
-
49
- <div>This is another export</div>
50
-
51
- </template>
52
-
53
- </head>
54
- ```
55
-
56
- Or they may be individually *tagged* to an export identifier using the `exportgroup` attribute.
57
-
58
- ```html
59
- <head>
60
-
61
- <template name="module1">
62
-
63
- <label exportgroup="question" for="age">How old are you?</label>
64
- <input exportgroup="question" name="age" />
65
-
66
- <div>This is another export</div>
67
-
68
- </template>
69
-
70
- </head>
71
- ```
72
-
73
- Either way, they are accessed the same way using the *Modules API*.
74
-
75
- ```js
76
- // Access module1 from document.templates
77
- let module1 = document.templates.module1;
78
-
79
- // Import module1's exports
80
- let questionExport = module1.exports.question; // Array
81
-
82
- // Clone the elements in the export
83
- let questionExportClone = questionExport.map(el => el.cloneNode(true));
84
- ```
85
-
86
- Taking things further, template elements may reference remote content using the `src` attribute.
87
-
88
- ```html
89
- <head>
90
-
91
- <template name="module-remote" src="/bundle.html"></template>
92
-
93
- </head>
94
- ```
95
-
96
- The contents of the remote file automatically become the template's content on load.
97
-
98
- **Details are in the [HTML Modules](https://webqit.io/tooling/oohtml/docs/spec/html-modules) specification. Learn more about the convention, API, events, and the polyfill support.**
99
-
100
- ## HTML Imports
101
-
102
- *HTML Imports* are a declarative way to use the *exports* of an *HTML Module* from anywhere in the main document.
103
-
104
- > Note that this is different from the HTML Imports that was spec'd with an early version of Web Components.
105
-
106
- Here, an `<import>` element in the `<body>` area is used to *place* a corresponing *export* of an HTML module.
107
-
108
- ```html
109
- <body>
110
-
111
- <!-- Import question here from module1 -->
112
- <import name="question" template="module1"></import>
113
-
114
- </body>
115
- ```
116
-
117
- Resolution takes place and the `<import>` element is replaced by all of the imported contents.
118
-
119
- ```html
120
- <body>
121
-
122
- <!-- import element replaced -->
123
- <label for="age">How old are you?</label>
124
- <input id="age" />
125
-
126
- </body>
127
- ```
128
-
129
- Also, multiple `<import>` elements within a block can be scoped to just one *module ID* declaration.
130
-
131
- ```html
132
- <body>
133
-
134
- <!-- Point to a module; one module ID for all imports within -->
135
- <div template="module1">
136
-
137
- <!-- Import question here from module1 -->
138
- <import name="question"></import>
139
-
140
- <div>
141
- <!-- Import another export here from module1 -->
142
- <import name="export-2"></import>
143
- </div>
144
-
145
- </div>
146
-
147
- </body>
148
- ```
149
-
150
- On resolution, an `<import>` element will stand by somewhere with a view to returning to its slot on any event that gets the slot empty. In fact, `<import>` elements maintain a *live* relationship with the modules they point to and with the contents that go into their slot.
151
-
152
- So, if we dynamically changed the module ID declaration above to point to another module, *imports* will be resolved again, this time, from the new module.
153
-
154
- ```js
155
- // Changing the module ID on the DIV container above will see all associated imports resolved again
156
- document.querySelector('div[template="module1"]').setAttribute('template', 'module2');
157
- ```
158
-
159
- This opens up new simple ways to create very dynamic applications.
160
-
161
- **Details are in the [HTML Imports](https://webqit.io/tooling/oohtml/docs/spec/html-imports) specification. Learn more about the convention, dynamicity, Slot Inheritance, isomorphic rendering, and the polyfill support.**
162
-
163
- ## Namespaced HTML
164
-
165
- Namespacing provides a way to let an element establish its own naming context for descendant elements. This makes it possible to keep IDs scoped to a context other than the document's global scope; thus the ability to write collision-free IDs across a page.
166
-
167
- The following modular markup implements its IDs in namespaces:
168
-
169
- ```html
170
- <article id="continents" namespace>
171
- <section id="europe" namespace>
172
- <div id="about">About Europe</b></div>
173
- <div id="countries">Countries in Europe</div>
174
- </section>
175
- <section id="asia" namespace>
176
- <div id="about">About Asia</b></div>
177
- <div id="countries">Countries in Asia</div>
178
- </section>
179
- </article>
180
- ```
181
-
182
- The above gives us a conceptual model of repeating objects, each encapsulating its IDs:
183
-
184
- ```html
185
- continents
186
- ├⏤europe
187
- │ ├⏤about
188
- │ ├⏤countries
189
- ├⏤asia
190
- ├⏤about
191
- ├⏤countries
192
- ```
193
-
194
- And beyond the point of giving us collision-free IDs, *Namespaced HTML* features an API that translates namespace models into real object trees:
195
-
196
- ```js
197
- // Get the "continents" article
198
- let continents = document.namespace.continents;
199
-
200
- // Access scoped IDs with the new "namespace" DOM property
201
- let europe = continents.namespace.europe;
202
- let asia = continents.namespace.asia;
203
-
204
- // And for deeply-nested IDs...
205
- let aboutAsia = continents.namespace.asia.namespace.about;
206
- ```
207
-
208
- We get a document structure that translates to a bankable API for building great functionalities.
209
-
210
- > Much of our code in the examples below will now use the `namespace` attribute in markup and the `.namespace` property in JavaScript.
211
-
212
- **Details are in the [Namespaced HTML](https://webqit.io/tooling/oohtml/docs/spec/namespaced-html) specification. Learn more about the convention, Namespaced Selectors, API, observability, and the polyfill support.**
213
-
214
- ## The State API
215
-
216
- The State API is a DOM API that lets us maintain application state at the document level and at individual element levels. It brings application state closer to the UI and makes it easy to keep the UI in sync with all the changes taking place.
217
-
218
- This API exposes a document-level *state object* on a `document.state` property, and an element-level *state object* on an `element.state` property. Arbitrary values can be set and retrieved on *state objects* the same way we would with regular objects.
219
-
220
- ```js
221
- // At the document level
222
- document.state.pageTitle = 'Hello World!';
223
- console.log(document.state.pageTitle); // Hello World!
224
-
225
- // At the element level
226
- element.state.collapsed = true;
227
- console.log(element.state.collapsed); // true
228
- ```
229
-
230
- But state objects are unique in that they support *observability*. They are *live objects* that can be observed for changes using the [Observer API](https://webqit.io/tooling/observer/docs/spec/the-observer-api).
231
-
232
- ```js
233
- Observer.observe(document.state, 'pageTitle', e => {
234
- console.log('New Page Title: ' + e.value);
235
- // Or we could reflect this state on the document title element
236
- document.querySelector('title').innerHTML = e.value;
237
- });
238
- ```
239
-
240
- This lets us build very reactive applications natively.
241
-
242
- Using an element's state API, here's how we could make a *collapsible* component.
243
-
244
- ```html
245
- <my-collapsible namespace>
246
- <div id="control">Toggle Me</div>
247
- <div id="content" style="height: 0px">
248
- Some content
249
- </div>
250
- </my-collapsible>
251
- ```
252
-
253
- ```js
254
- customElements.define('my-collapsible', class extends HTMLElement {
255
-
256
- /**
257
- * Creates the Shadow DOM
258
- */
259
- constructor() {
260
- super();
261
- // Observe state and get the UI synced
262
- Observer.observe(this.state, 'collapsed', e => {
263
- this.namespace.content.style.height = e.value ? '0px' : 'auto';
264
- this.setAttribute('data-collapsed', e.value ? 'true' : 'false');
265
- });
266
-
267
- // Implement the logic for toggling collapsion
268
- this.namespace.control.addEventListener('click', function() {
269
- this.state.collapsed = !this.state.collapsed;
270
- });
271
- }
272
-
273
- });
274
- ```
275
-
276
- Other parts of the application are also able to access the state of this element.
277
-
278
- ```js
279
- let collapsible = document.querySelector('my-collapsible');
280
- Observer.observe(collapsible.state, 'collapsed', e => {
281
- console.log(e.value ? 'element collapsed' : 'element expanded');
282
- });
283
- ```
284
-
285
- **Details are in the [State API](https://webqit.io/tooling/oohtml/docs/spec/the-state-api) specification. Learn more about the API, deep observability, and the polyfill support.**
286
-
287
- ## Subscript
288
-
289
- Subscript is a type of JavaScript runtime that lets us create scoped, *reactive* `<script>` elements across an HTML document. That gives us a UI binding language and the ability to write UI logic without involving actual JavaScript classes or files.
290
-
291
- Subscript lets us write `<script>` elements that are scoped to their host elements instead of the global browser scope. Below is such a `<script>` element, being scoped to the `#alert` element - its host element:
292
-
293
- ```html
294
- <div id="alert">
295
- <script type="subscript">
296
- console.log(this.id); // alert
297
- </script>
298
- </div>
299
- ```
300
-
301
- The `this` variable within Subscript is a reference to the script's host element. In addition, variables declared within the script are available only within the script, and global variables are always available across all scripts.
302
-
303
- ```html
304
- <div id="alert" namespace>
305
-
306
- <div id="message"></div>
307
- <div id="exit" title="Close this message.">X</div>
308
-
309
- <script type="subscript">
310
- this.namespace.exit.addEventListener('click', () => {
311
- this.remove();
312
- });
313
- </script>
314
-
315
- </div>
316
- ```
317
-
318
- Below is how we could render something - a message - from the element's state object - `.state.message`.
319
-
320
- ```html
321
- <body>
322
-
323
- <div id="alert" namespace>
324
-
325
- <div id="message"></div>
326
- <div id="exit" title="Close this message.">X</div>
327
-
328
- <script type="subscript">
329
- // Render the "message" property from the element's state object
330
-
331
- this.namespace.message.innerHTML = this.state.message;
332
- this.namespace.exit.addEventListener('click', () => {
333
- this.remove();
334
- });
335
- </script>
336
-
337
- </div>
338
-
339
- <body>
340
- ```
341
-
342
- But the best part yet is Subscript's reactivity! While Subscript works like regular JavaScript, it is also able to observe changes in its scope and respond to them. And it does this at the granular statement level such that a given statement is evaluated again (independently of other statements in the script) whenever any of the observable references used in the statement experiences a change.
343
-
344
- Below, changing the observable reference`.state.message` will trigger that particular statement in the script above to run again.
345
-
346
-
347
-
348
- ```js
349
- let alertElement = document.querySelector('#alert');
350
- alertElement.state.message = 'Task started!';
351
- setTimeout(() => {
352
- alertElement.state.message = 'Task complete!';
353
- }, 1000);
354
- ```
355
-
356
- Leveraging this reactivity, we could reimplement the `<my-collapsible>` component we created in the *State API* section above - this time, without a JavaScript class.
357
-
358
- ```html
359
- <div id="collapsible" namespace>
360
-
361
- <div id="control">Toggle Me</div>
362
- <div id="content" style="height: 0px">
363
- Some content
364
- </div>
365
-
366
- <script type="subscript">
367
- // Observe state and get the UI synced, without requiring Observer.observe() here...
368
-
369
- this.setAttribute('data-collapsed', this.state.collapsed ? 'true' : 'false');
370
- this.namespace.content.style.height = this.state.collapsed ? '0px' : 'auto';
371
- this.namespace.control.addEventListener('click', () => {
372
- // Toggle collapsion state
373
- this.state.collapsed = !this.state.collapsed;
374
- });
375
- </script>
376
-
377
- </div>
378
- ```
379
-
380
- **Details are in the [Subscript](https://webqit.io/tooling/oohtml/docs/spec/subscript) specification. Learn more about the event-based runtime, deep observability, bindings, the API, error handling, and the polyfill support.**
381
-
382
- ## Getting Started
383
-
384
- [Go to project homepage](https://webqit.io/tooling/oohtml).
385
-
386
- You definitely want to visit the documentation for each of OOHTML's features and try everything out by pasting the code examples and running them right in your browser. Simply include the [OOHTML polyfill](https://webqit.io/tooling/oohtml/docs/getting-started/polyfill) on your page and get away with writing modular, reusable, reactive HTML without a tool!
387
-
388
- We're putting together a collection of examples in the [examples](https://webqit.io/tooling/oohtml/docs/learn/examples) section.
389
-
390
- ## Issues
391
-
392
- To report bugs or request features, please submit an [issue](https://github.com/webqit/oohtml/issues).
393
-
394
- ## License
395
-
396
- 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
+
10
+ OOHTML offers a set of five features that make common UI development paradigms possible as native web platform features. These features may be used individually or together for some great UI-authoring capabilites. Here is an overview:
11
+
12
+ > **Note**
13
+ > <br>Major updates coming in this branch!
14
+
15
+ + [HTML Modules](#html-modules)
16
+ + [HTML Imports](#html-imports)
17
+ + [Namespaced HTML](#namespaced-html)
18
+ + [The State API](#the-state-api)
19
+ + [Subscript](#subscript)
20
+
21
+ ## HTML Modules
22
+
23
+ *HTML Modules* are a templating feature that lets us write reusable HTML markup using the *module*, *export* and *import* paradigm. This feature establishes the standard `<template>` element as the foundation of a module infrastructure for HTML and introduces new attributes, properties and events that together closes the loop.
24
+
25
+ A module is a regular `<template>` element with a `name` attribute - *the module ID* - and its contents are simply the *exports*.
26
+
27
+ ```html
28
+ <head>
29
+
30
+ <template name="module1">
31
+
32
+ <label for="age">How old are you?</div>
33
+ <input id="age" />
34
+
35
+ </template>
36
+
37
+ </head>
38
+ ```
39
+
40
+ Exports may be more properly wrapped within an `<export>` element of a designated name.
41
+
42
+ ```html
43
+ <head>
44
+
45
+ <template name="module1">
46
+
47
+ <export name="question">
48
+ <label for="age">How old are you?</label>
49
+ <input id="age" />
50
+ </export>
51
+
52
+ <div>This is another export</div>
53
+
54
+ </template>
55
+
56
+ </head>
57
+ ```
58
+
59
+ Or they may be individually *tagged* to an export identifier using the `exportgroup` attribute.
60
+
61
+ ```html
62
+ <head>
63
+
64
+ <template name="module1">
65
+
66
+ <label exportgroup="question" for="age">How old are you?</label>
67
+ <input exportgroup="question" name="age" />
68
+
69
+ <div>This is another export</div>
70
+
71
+ </template>
72
+
73
+ </head>
74
+ ```
75
+
76
+ Either way, they are accessed the same way using the *Modules API*.
77
+
78
+ ```js
79
+ // Access module1 from document.templates
80
+ let module1 = document.templates.module1;
81
+
82
+ // Import module1's exports
83
+ let questionExport = module1.exports.question; // Array
84
+
85
+ // Clone the elements in the export
86
+ let questionExportClone = questionExport.map(el => el.cloneNode(true));
87
+ ```
88
+
89
+ Taking things further, template elements may reference remote content using the `src` attribute.
90
+
91
+ ```html
92
+ <head>
93
+
94
+ <template name="module-remote" src="/bundle.html"></template>
95
+
96
+ </head>
97
+ ```
98
+
99
+ The contents of the remote file automatically become the template's content on load.
100
+
101
+ **Details are in the [HTML Modules](https://webqit.io/tooling/oohtml/docs/spec/html-modules) specification. Learn more about the convention, API, events, and the polyfill support.**
102
+
103
+ ## HTML Imports
104
+
105
+ *HTML Imports* are a declarative way to use the *exports* of an *HTML Module* from anywhere in the main document.
106
+
107
+ > Note that this is different from the HTML Imports that was spec'd with an early version of Web Components.
108
+
109
+ Here, an `<import>` element in the `<body>` area is used to *place* a corresponing *export* of an HTML module.
110
+
111
+ ```html
112
+ <body>
113
+
114
+ <!-- Import question here from module1 -->
115
+ <import name="question" template="module1"></import>
116
+
117
+ </body>
118
+ ```
119
+
120
+ Resolution takes place and the `<import>` element is replaced by all of the imported contents.
121
+
122
+ ```html
123
+ <body>
124
+
125
+ <!-- import element replaced -->
126
+ <label for="age">How old are you?</label>
127
+ <input id="age" />
128
+
129
+ </body>
130
+ ```
131
+
132
+ Also, multiple `<import>` elements within a block can be scoped to just one *module ID* declaration.
133
+
134
+ ```html
135
+ <body>
136
+
137
+ <!-- Point to a module; one module ID for all imports within -->
138
+ <div template="module1">
139
+
140
+ <!-- Import question here from module1 -->
141
+ <import name="question"></import>
142
+
143
+ <div>
144
+ <!-- Import another export here from module1 -->
145
+ <import name="export-2"></import>
146
+ </div>
147
+
148
+ </div>
149
+
150
+ </body>
151
+ ```
152
+
153
+ On resolution, an `<import>` element will stand by somewhere with a view to returning to its slot on any event that gets the slot empty. In fact, `<import>` elements maintain a *live* relationship with the modules they point to and with the contents that go into their slot.
154
+
155
+ So, if we dynamically changed the module ID declaration above to point to another module, *imports* will be resolved again, this time, from the new module.
156
+
157
+ ```js
158
+ // Changing the module ID on the DIV container above will see all associated imports resolved again
159
+ document.querySelector('div[template="module1"]').setAttribute('template', 'module2');
160
+ ```
161
+
162
+ This opens up new simple ways to create very dynamic applications.
163
+
164
+ **Details are in the [HTML Imports](https://webqit.io/tooling/oohtml/docs/spec/html-imports) specification. Learn more about the convention, dynamicity, Slot Inheritance, isomorphic rendering, and the polyfill support.**
165
+
166
+ ## Namespaced HTML
167
+
168
+ Namespacing provides a way to let an element establish its own naming context for descendant elements. This makes it possible to keep IDs scoped to a context other than the document's global scope; thus the ability to write collision-free IDs across a page.
169
+
170
+ The following modular markup implements its IDs in namespaces:
171
+
172
+ ```html
173
+ <article id="continents" namespace>
174
+ <section id="europe" namespace>
175
+ <div id="about">About Europe</b></div>
176
+ <div id="countries">Countries in Europe</div>
177
+ </section>
178
+ <section id="asia" namespace>
179
+ <div id="about">About Asia</b></div>
180
+ <div id="countries">Countries in Asia</div>
181
+ </section>
182
+ </article>
183
+ ```
184
+
185
+ The above gives us a conceptual model of repeating objects, each encapsulating its IDs:
186
+
187
+ ```html
188
+ continents
189
+ ├⏤europe
190
+ ├⏤about
191
+ ├⏤countries
192
+ ├⏤asia
193
+ ├⏤about
194
+ ├⏤countries
195
+ ```
196
+
197
+ And beyond the point of giving us collision-free IDs, *Namespaced HTML* features an API that translates namespace models into real object trees:
198
+
199
+ ```js
200
+ // Get the "continents" article
201
+ let continents = document.namespace.continents;
202
+
203
+ // Access scoped IDs with the new "namespace" DOM property
204
+ let europe = continents.namespace.europe;
205
+ let asia = continents.namespace.asia;
206
+
207
+ // And for deeply-nested IDs...
208
+ let aboutAsia = continents.namespace.asia.namespace.about;
209
+ ```
210
+
211
+ We get a document structure that translates to a bankable API for building great functionalities.
212
+
213
+ > Much of our code in the examples below will now use the `namespace` attribute in markup and the `.namespace` property in JavaScript.
214
+
215
+ **Details are in the [Namespaced HTML](https://webqit.io/tooling/oohtml/docs/spec/namespaced-html) specification. Learn more about the convention, Namespaced Selectors, API, observability, and the polyfill support.**
216
+
217
+ ## The State API
218
+
219
+ The State API is a DOM API that lets us maintain application state at the document level and at individual element levels. It brings application state closer to the UI and makes it easy to keep the UI in sync with all the changes taking place.
220
+
221
+ This API exposes a document-level *state object* on a `document.state` property, and an element-level *state object* on an `element.state` property. Arbitrary values can be set and retrieved on *state objects* the same way we would with regular objects.
222
+
223
+ ```js
224
+ // At the document level
225
+ document.state.pageTitle = 'Hello World!';
226
+ console.log(document.state.pageTitle); // Hello World!
227
+
228
+ // At the element level
229
+ element.state.collapsed = true;
230
+ console.log(element.state.collapsed); // true
231
+ ```
232
+
233
+ But state objects are unique in that they support *observability*. They are *live objects* that can be observed for changes using the [Observer API](https://webqit.io/tooling/observer/docs/spec/the-observer-api).
234
+
235
+ ```js
236
+ Observer.observe(document.state, 'pageTitle', e => {
237
+ console.log('New Page Title: ' + e.value);
238
+ // Or we could reflect this state on the document title element
239
+ document.querySelector('title').innerHTML = e.value;
240
+ });
241
+ ```
242
+
243
+ This lets us build very reactive applications natively.
244
+
245
+ Using an element's state API, here's how we could make a *collapsible* component.
246
+
247
+ ```html
248
+ <my-collapsible namespace>
249
+ <div id="control">Toggle Me</div>
250
+ <div id="content" style="height: 0px">
251
+ Some content
252
+ </div>
253
+ </my-collapsible>
254
+ ```
255
+
256
+ ```js
257
+ customElements.define('my-collapsible', class extends HTMLElement {
258
+
259
+ /**
260
+ * Creates the Shadow DOM
261
+ */
262
+ constructor() {
263
+ super();
264
+ // Observe state and get the UI synced
265
+ Observer.observe(this.state, 'collapsed', e => {
266
+ this.namespace.content.style.height = e.value ? '0px' : 'auto';
267
+ this.setAttribute('data-collapsed', e.value ? 'true' : 'false');
268
+ });
269
+
270
+ // Implement the logic for toggling collapsion
271
+ this.namespace.control.addEventListener('click', function() {
272
+ this.state.collapsed = !this.state.collapsed;
273
+ });
274
+ }
275
+
276
+ });
277
+ ```
278
+
279
+ Other parts of the application are also able to access the state of this element.
280
+
281
+ ```js
282
+ let collapsible = document.querySelector('my-collapsible');
283
+ Observer.observe(collapsible.state, 'collapsed', e => {
284
+ console.log(e.value ? 'element collapsed' : 'element expanded');
285
+ });
286
+ ```
287
+
288
+ **Details are in the [State API](https://webqit.io/tooling/oohtml/docs/spec/the-state-api) specification. Learn more about the API, deep observability, and the polyfill support.**
289
+
290
+ ## Subscript
291
+
292
+ Subscript is a type of JavaScript runtime that lets us create scoped, *reactive* `<script>` elements across an HTML document. That gives us a UI binding language and the ability to write UI logic without involving actual JavaScript classes or files.
293
+
294
+ Subscript lets us write `<script>` elements that are scoped to their host elements instead of the global browser scope. Below is such a `<script>` element, being scoped to the `#alert` element - its host element:
295
+
296
+ ```html
297
+ <div id="alert">
298
+ <script type="subscript">
299
+ console.log(this.id); // alert
300
+ </script>
301
+ </div>
302
+ ```
303
+
304
+ The `this` variable within Subscript is a reference to the script's host element. In addition, variables declared within the script are available only within the script, and global variables are always available across all scripts.
305
+
306
+ ```html
307
+ <div id="alert" namespace>
308
+
309
+ <div id="message"></div>
310
+ <div id="exit" title="Close this message.">X</div>
311
+
312
+ <script type="subscript">
313
+ this.namespace.exit.addEventListener('click', () => {
314
+ this.remove();
315
+ });
316
+ </script>
317
+
318
+ </div>
319
+ ```
320
+
321
+ Below is how we could render something - a message - from the element's state object - `.state.message`.
322
+
323
+ ```html
324
+ <body>
325
+
326
+ <div id="alert" namespace>
327
+
328
+ <div id="message"></div>
329
+ <div id="exit" title="Close this message.">X</div>
330
+
331
+ <script type="subscript">
332
+ // Render the "message" property from the element's state object
333
+
334
+ this.namespace.message.innerHTML = this.state.message;
335
+ this.namespace.exit.addEventListener('click', () => {
336
+ this.remove();
337
+ });
338
+ </script>
339
+
340
+ </div>
341
+
342
+ <body>
343
+ ```
344
+
345
+ But the best part yet is Subscript's reactivity! While Subscript works like regular JavaScript, it is also able to observe changes in its scope and respond to them. And it does this at the granular statement level such that a given statement is evaluated again (independently of other statements in the script) whenever any of the observable references used in the statement experiences a change.
346
+
347
+ Below, changing the observable reference`.state.message` will trigger that particular statement in the script above to run again.
348
+
349
+
350
+
351
+ ```js
352
+ let alertElement = document.querySelector('#alert');
353
+ alertElement.state.message = 'Task started!';
354
+ setTimeout(() => {
355
+ alertElement.state.message = 'Task complete!';
356
+ }, 1000);
357
+ ```
358
+
359
+ Leveraging this reactivity, we could reimplement the `<my-collapsible>` component we created in the *State API* section above - this time, without a JavaScript class.
360
+
361
+ ```html
362
+ <div id="collapsible" namespace>
363
+
364
+ <div id="control">Toggle Me</div>
365
+ <div id="content" style="height: 0px">
366
+ Some content
367
+ </div>
368
+
369
+ <script type="subscript">
370
+ // Observe state and get the UI synced, without requiring Observer.observe() here...
371
+
372
+ this.setAttribute('data-collapsed', this.state.collapsed ? 'true' : 'false');
373
+ this.namespace.content.style.height = this.state.collapsed ? '0px' : 'auto';
374
+ this.namespace.control.addEventListener('click', () => {
375
+ // Toggle collapsion state
376
+ this.state.collapsed = !this.state.collapsed;
377
+ });
378
+ </script>
379
+
380
+ </div>
381
+ ```
382
+
383
+ **Details are in the [Subscript](https://webqit.io/tooling/oohtml/docs/spec/subscript) specification. Learn more about the event-based runtime, deep observability, bindings, the API, error handling, and the polyfill support.**
384
+
385
+ ## Getting Started
386
+
387
+ [Go to project homepage](https://webqit.io/tooling/oohtml).
388
+
389
+ You definitely want to visit the documentation for each of OOHTML's features and try everything out by pasting the code examples and running them right in your browser. Simply include the [OOHTML polyfill](https://webqit.io/tooling/oohtml/docs/getting-started/polyfill) on your page and get away with writing modular, reusable, reactive HTML without a tool!
390
+
391
+ We're putting together a collection of examples in the [examples](https://webqit.io/tooling/oohtml/docs/learn/examples) section.
392
+
393
+ ## Issues
394
+
395
+ To report bugs or request features, please submit an [issue](https://github.com/webqit/oohtml/issues).
396
+
397
+ ## License
398
+
399
+ MIT.