@webqit/oohtml 2.1.60 → 2.1.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,40 +7,36 @@
7
7
 
8
8
  **[Overview](#overview) • [Modular HTML](#modular-html) • [HTML Imports](#html-imports) • [Reactive HTML](#reactive-html) • [Polyfill](#polyfill) • [Examples](#examples) • [License](#license)**
9
9
 
10
- Object-Oriented HTML (OOHTML) is a set of language features for authoring modular, reusable markup, and for 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!
10
+ Object-Oriented HTML (OOHTML) is a set of features that extend standard HTML and the DOM to enable authoring modular, reusable and reactive markup - with a "buildless", web-native workflow as design goal! This project presents what "modern" HTML could look like!
13
11
 
14
12
  ## Motivation
15
13
 
16
- <details><summary>Show</summary>
17
-
18
- The web has generally outgrown the idea of a monolith architecture on the UI! But enter HTML; the current authoring experience is one where an author is trying to think out one thing but forced to work out everything, in how the language for the job poses one global scope as the unit of abstraction for styles, scripts and element identifiers — enforcing many global dependencies; inflicting much global thinking!
14
+ Vanilla HTML is increasingly becoming the compelling option for web developers! But the current authoring experience still leaves much to be desired in how the language lacks modularity, reusability, and data binding! Authors still have to rely on tools - or, to say the least, do half of the work in HTML and half in JS - to get even basic things working!
19
15
 
20
- Think too of how authors often have to do half of the work in HTML and half in JS just to have reusable markup!
21
-
22
- This project is a proposal for a new standards work that revisits much of the oldish monolith-oriented constraints in HTML that inhibit the idea of a *component* architecture in HTML!
16
+ This project pursues an object-oriented approach to HTML and implicitly revisits much of what inhibits the idea of a *component* architecture for HTML!
23
17
 
24
18
  └ [See more in the introductory blog post](https://dev.to/oxharris/the-web-native-equations-1m1p-temp-slug-6661657?preview=ba70ad2c17f05b5761bc74516dbde8c9eff8b581a0420d87334fd9ef6bab9d6e6d3ab6aaf3fe02542bb9e7250d0a88a6df91dae40919aabcc9a07320)<sup>draft</sup>
25
19
 
26
- </details>
27
-
28
20
  ## Overview
29
21
 
30
- OOHTML comes in three sets of features, and the following is an overview. A more detailed documentation for OOHTML is underway in the [project wiki](https://github.com/webqit/oohtml/wiki).
22
+ On the agenda is a set of features that normalises how the modern UI lends itself to be built! And all of it comes as a special love letter to Single Page Applications!
31
23
 
32
24
  + [Modular HTML](#modular-html)
33
25
  + [HTML Imports](#html-imports)
34
- + [Reactive HTML](#reactive-html)
35
- + [Put Together](#put-together)
26
+ + [Data Binding](#data-binding)
27
+ + [Data Plumbing](#data-plumbing)
36
28
 
37
29
  > **Note** This is documentation for `OOHTML@2.x`. (Looking for [`OOHTML@1.x`](https://github.com/webqit/oohtml/tree/v1.10.4)?)
38
30
 
39
31
  ## Modular HTML
40
32
 
41
- 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*.
33
+ Modular HTML is a markup pattern that lets us write markup as self-contained objects - with each *encapsulating* its own structure, styling and logic - as against the regular idea of having everything converge and conflict on one global scope!
34
+
35
+ OOHTML makes this possible in just simple conventions - via two new attributes: `namespace` and `scoped`!
42
36
 
43
- *Namespaced IDs for modelling structure*:
37
+ ### Namespacing
38
+
39
+ The `namespace` attribute for designating an element as own naming context for identifiers - i.e. the `id` and `name` attributes:
44
40
 
45
41
  ```html
46
42
  <div id="user" namespace>
@@ -51,6 +47,8 @@ The first set of features covers authoring objects with self-contained structure
51
47
  </div>
52
48
  ```
53
49
 
50
+ *which translates really well to an object model*:
51
+
54
52
  ```html
55
53
  user
56
54
  ├── url
@@ -58,16 +56,64 @@ user
58
56
  └── email
59
57
  ```
60
58
 
59
+ *with a corresponding API that exposes said structure to JavaScript applications*:
60
+
61
61
  ```js
62
- // The namespace API
62
+ // The document.namespace API
63
63
  let { user } = document.namespace;
64
+ // The Element.prototype.namespace API
64
65
  let { url, name, email } = user.namespace;
65
66
  ```
66
67
 
67
- *Scoped styles and scripts for styling and functionality*:
68
+ <details><summary>Learn more</summary>
69
+
70
+ You want to see how IDs are otherwise exposed as global variables:
71
+
72
+ ```html
73
+ <div id="foo"><div>
74
+ ```
75
+
76
+ ```js
77
+ console.log(window.foo); // div
78
+ ```
79
+
80
+ [Read more](https://stackoverflow.com/questions/6381425/is-there-a-spec-that-the-id-of-elements-should-be-made-global-variable)
81
+
82
+ </details>
83
+
84
+ └ A Namespace API that reflects the real-DOM&trade; in real-time, in conjunction with the general-purpose object observability API - [Observer API](https://github.com/webqit/observer):
85
+
86
+ ```js
87
+ // Observing the addition or removal of elements with an ID
88
+ Observer.observe(document.namespace, changeCallback);
89
+
90
+ const paragraph = document.createElement('p');
91
+ paragraph.setAttribute('id', 'bar');
92
+ document.body.appendChild(paragraph); // Reported synchronously
93
+ ```
94
+
95
+ ```js
96
+ // Observing the addition or removal of elements with an ID
97
+ paragraph.toggleAttribute('namespace', true);
98
+ Observer.observe(paragraph.namespace, changeCallback);
99
+
100
+ const span = document.createElement('span');
101
+ span.setAttribute('id', 'baz');
102
+ paragraph.appendChild(span); // Reported synchronously
103
+ ```
104
+
105
+ ```js
106
+ function changeCallback(changes) {
107
+ console.log(changes[0].type, changes[0].key, changes[0].value, changes[0].oldValue);
108
+ }
109
+ ```
110
+
111
+ ### Style and Script Scoping
112
+
113
+ The `scoped` attribute for *scoping* element-specific stylesheets and scripts:
68
114
 
69
115
  ```html
70
- <div id="user">
116
+ <div>
71
117
 
72
118
  <style scoped>
73
119
  :scope { color: red }
@@ -80,17 +126,23 @@ let { url, name, email } = user.namespace;
80
126
  </div>
81
127
  ```
82
128
 
129
+ *with a corresponding API that exposes said assets to JavaScript applications*:
130
+
83
131
  ```js
84
132
  let { styleSheets, scripts } = user; // APIs that are analogous to the document.styleSheets, document.scripts properties
85
133
  ```
86
134
 
87
- └ [Modular HTML concepts](#)
135
+ └ [Modular HTML examples](#modular-html-examples)
88
136
 
89
137
  ## HTML Imports
90
138
 
91
- 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 `def`, and introduces a complementary new `<import>` element, and has everything working together as a real-time module system.
139
+ HTML Imports is a realtime module system for *templating and reusing* HTML in HTML, and optionally in JavaScript! Something like it is the [`<defs>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs) and [`<use>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use) system in SVG.
140
+
141
+ OOHTML makes this possible in just simple conventions - via a new `def` attribute and a complementary new `<import>` element!
142
+
143
+ ### Module Definition
92
144
 
93
- └ *The `def` attribute for reusable "module" and "fragment" definitions*:
145
+ The `def` attribute for defining reusable markup - either as whole *module* or as *fragment*:
94
146
 
95
147
  ```html
96
148
  <head>
@@ -104,7 +156,7 @@ The next set of features covers *templating and reusing objects* - in both *decl
104
156
  </head>
105
157
  ```
106
158
 
107
- *Module nesting for code organization*:
159
+ └ Module nesting for code organization:
108
160
 
109
161
  ```html
110
162
  <head>
@@ -120,16 +172,20 @@ The next set of features covers *templating and reusing objects* - in both *decl
120
172
  </head>
121
173
  ```
122
174
 
123
- *The `<template src>` element for remote modules*:
175
+ ### Remote Modules
176
+
177
+ The `<template src>` element for remote modules:
124
178
 
125
179
  ```html
126
180
  <template def="foo" src="/foo.html"></template>
181
+ <!-- which links to the file below -->
127
182
  ```
128
183
 
129
184
  ```html
130
185
  -- file: /foo.html --
131
186
  <div def="fragment1"></div>
132
187
  <template def="nested" src="/nested.html"></template>
188
+ <!-- which itself links to the file below -->
133
189
  ```
134
190
 
135
191
  ```html
@@ -138,11 +194,16 @@ The next set of features covers *templating and reusing objects* - in both *decl
138
194
  --
139
195
  ```
140
196
 
197
+ *which extends how elements like images already work; terminating with either a `load` or an `error` event*:
198
+
141
199
  ```js
142
- foo.addEventListener('load', loadedCallback);
200
+ foo.addEventListener('load', loadCallback);
201
+ foo.addEventListener('error', errorCallback);
143
202
  ```
144
203
 
145
- *The `<import>` element for declarative module import*:
204
+ ### Declarative Module Imports
205
+
206
+ The `<import>` element for declarative module import:
146
207
 
147
208
  ```html
148
209
  <body>
@@ -158,20 +219,140 @@ foo.addEventListener('load', loadedCallback);
158
219
  </body>
159
220
  ```
160
221
 
161
- *The HTMLImports API for programmatic module import*:
222
+ <details><summary>All in Realtime</summary>
223
+
224
+ As a realtime module system, `<import> `elements maintain a live relationship with given module definition `<template def>` elements and are resolved again in the event that:
225
+ + the `<import>` element points to another module — either by `ref` change or by a change in `importscontext` (below).
226
+ + the module definition `<template def>` element has had its contents updated, either programmatically or automatically from having loaded.
227
+
228
+ Conversely, an `<import>` element that has been resolved will self-restore in the event that:
229
+ + the `<import>` element no longer points to a module; or the module has been emptied or removed.
230
+ + the previously slotted contents have been programmatically removed and slot is empty.
231
+
232
+ </details>
233
+
234
+ <details><summary>With SSR Support</summary>
235
+
236
+ On the server, these `<import>` elements would retain their place in the DOM, but this time, serialized into comment nodes, while having their output rendered just above them as siblings.
237
+
238
+ The above resolved imports would thus give us something like:
239
+
240
+ ```html
241
+ <body>
242
+ <div def="fragment1"></div>
243
+ <!--&lt;import ref="/foo#fragment1"&gt;&lt;/import&gt;-->
244
+ <div def="fragment2"></div>
245
+ <!--&lt;import ref="/foo/nested#fragment2"&gt;&lt;/import&gt;-->
246
+ </body>
247
+ ```
248
+
249
+ But they also have to remember the exact imported nodes that they manage so as to be able to re-establish that relationship on getting to the client. This information is automatically encoded as part of the serialised element itself, in something like:
250
+
251
+ ```html
252
+ <!--&lt;import ref="/foo/nested#fragment2" nodecount="1"&gt;&lt;/import&gt;-->
253
+ ```
254
+
255
+ Now that extra bit of information gets decoded and original relationships are formed again on getting to the client and "hydrating" the `<import>` element. But, the `<import>` element itself stays invisible in the DOM while still continuing to kick as above!
256
+
257
+ > Note: We know we're on the server when `window.webqit.env === 'server'`. This flag is automatically set by OOHTML's current SSR engine: [OOHTML-SSR](https://github.com/webqit/oohtml-ssr)
258
+
259
+ </details>
260
+
261
+ ### Programmatic Module Imports
262
+
263
+ The *HTMLImports* API for programmatic module import:
162
264
 
163
265
  ```js
164
- const import1 = document.import('/foo#fragment1');
165
- console.log(import1); // { value: div }
266
+ const moduleObject1 = document.import('/foo#fragment1');
267
+ console.log(moduleObject1.value); // divElement
166
268
  ```
167
269
 
168
270
  ```js
169
- const import2 = document.import('/foo/nested#fragment2');
170
- console.log(import2); // { value: div }
271
+ const moduleObject2 = document.import('/foo/nested#fragment2');
272
+ console.log(moduleObject2.value); // divElement
171
273
  ```
172
274
 
173
- *Scoped templates for object-scoped module system*:
174
- > With an equivalent `Element.prototype.import()` API for accessing scoped modules
275
+ *with an observable `moduleObject.value` property for working asynchronously; e.g. awaiting and handling remote modules*:
276
+
277
+ ```js
278
+ Observer.observe(moduleObject2, 'value', e => {
279
+ console.log(e.value); // divElement
280
+ });
281
+ ```
282
+
283
+ *with an equivalent `callback` option on the `import()` method itself*:
284
+
285
+ ```js
286
+ document.import('/foo#fragment1', divElement => {
287
+ console.log(divElement);
288
+ });
289
+ ```
290
+
291
+ └ An optional `live` parameter for staying subscribed to any mutations made to source module elements:
292
+
293
+ ```js
294
+ const moduleObject2 = document.import('/foo/nested#fragment2', true/*live*/);
295
+ console.log(moduleObject2.value);
296
+ Observer.observe(moduleObject2, 'value', e => {
297
+ console.log(e.value);
298
+ });
299
+ ```
300
+
301
+ ```js
302
+ document.import('/foo#fragment1', true/*live*/, divElement => {
303
+ console.log(divElement); // To be received after remote module has been loaded
304
+ });
305
+ ```
306
+
307
+ *both of which would get notified on doing the below*:
308
+
309
+ ```js
310
+ document.querySelector('template[def="foo"]').content.firstElementChild.remove();
311
+ ```
312
+
313
+ └ An optional `AbortSignal` parameter for aborting module mutation events:
314
+
315
+ ```js
316
+ const abortController = new AbortController;
317
+ ```
318
+
319
+ ```js
320
+ const moduleObject2 = document.import('/foo/nested#fragment2', { live: true, signal: abortController.signal });
321
+ ```
322
+
323
+ ```js
324
+ document.import('/foo#fragment1', { live: true, signal: abortController.signal }, divElement => {
325
+ console.log(divElement); // To be received after remote module has been loaded
326
+ });
327
+ ```
328
+
329
+ ```js
330
+ setTimeout(() => abortController.abort(), 1000);
331
+ ```
332
+
333
+ <details><summary>Extended Imports concepts</summary>
334
+
335
+ ### Lazy-Loading Modules
336
+
337
+ Remote modules with lazy-loading - which has modules loading on first time access:
338
+
339
+ ```html
340
+ <!-- Loading doesn't happen until the first time this is being accessed -->
341
+ <template def="foo" src="/foo.html" loading="lazy"></template>
342
+ ```
343
+
344
+ ```html
345
+ <body>
346
+ <import ref="/foo#fragment1"></import> <!-- Triggers module loading and resolves on load success -->
347
+ </body>
348
+ ```
349
+ ```js
350
+ const moduleObject2 = document.import('/foo#fragment1'); // Triggers module loading and resolves at moduleObject2.value on load success
351
+ ```
352
+
353
+ ### Scoped Modules
354
+
355
+ The `scoped` attribute for an *object-scoped* module system:
175
356
 
176
357
  ```html
177
358
  <section> <!-- object with own modules -->
@@ -188,6 +369,8 @@ console.log(import2); // { value: div }
188
369
  </section>
189
370
  ```
190
371
 
372
+ *with an equivalent `Element.prototype.import()` API for accessing said scoped modules*:
373
+
191
374
  ```js
192
375
  // Using the HTMLImports API
193
376
  const moduleHost = document.querySelector('div');
@@ -202,11 +385,9 @@ const globalImport1 = moduleHost.import('/foo#fragment1'); // the global module:
202
385
  console.log(globalImport1); // { value: div }
203
386
  ```
204
387
 
205
- <details><summary>
206
- Extended Imports concepts
207
- </summary>
388
+ ### Module Inheritance
208
389
 
209
- └ *Module nesting with inheritance*:
390
+ Module nesting with inheritance:
210
391
 
211
392
  ```html
212
393
  <template def="foo">
@@ -250,34 +431,9 @@ Extended Imports concepts
250
431
  </body>
251
432
  ```
252
433
 
253
- *Remote modules with lazy-loading*:
254
-
255
- ```html
256
- <!-- Loading doesn't happen until the first time this is being accessed -->
257
- <template def="foo" src="/foo.html" loading="lazy"></template>
258
- ```
259
-
260
- ```html
261
- <body>
262
- <import ref="/foo#fragment1"></import> <!-- To be resolved after remote module has been loaded -->
263
- </body>
264
- ```
265
-
266
- ```js
267
- document.import('/foo#fragment1', divElement => {
268
- console.log(divElement); // To be received after remote module has been loaded
269
- });
270
- ```
271
-
272
- ```js
273
- const import1 = document.import('/foo#fragment1', true);
274
- console.log(import1); // { value: undefined }
275
- Observer.observe(import1, 'value', divElement => {
276
- console.log(divElement); // To be received after remote module has been loaded
277
- });
278
- ```
434
+ ### Imports Contexts
279
435
 
280
- └ *"Imports Contexts" for context-based imports resolution*:
436
+ "Imports Contexts" for context-based *import resolution*:
281
437
 
282
438
  ```html
283
439
  <body importscontext="/foo">
@@ -302,7 +458,7 @@ const globalImport2 = moduleHost.import('#fragment2'); // module:/foo/nested#fra
302
458
  console.log(globalImport2); // { value: div }
303
459
  ```
304
460
 
305
- *"Imports Contexts" with named contexts*:
461
+ └ "Imports Contexts" with named contexts:
306
462
 
307
463
  ```html
308
464
  <body contextname="context1" importscontext="/foo/nested">
@@ -326,7 +482,7 @@ const globalImport2 = moduleHost.import('@context1#fragment2'); // module:/foo/n
326
482
  console.log(globalImport2); // { value: div }
327
483
  ```
328
484
 
329
- *"Imports Contexts" with context inheritance*:
485
+ └ "Imports Contexts" with context inheritance:
330
486
 
331
487
  ```html
332
488
  <body importscontext="/foo">
@@ -340,7 +496,9 @@ console.log(globalImport2); // { value: div }
340
496
  </body>
341
497
  ```
342
498
 
343
- *Object-scoped module system with context inheritance*:
499
+ ### Scoped Modules and Imports Contexts
500
+
501
+ Object-scoped module system with context inheritance:
344
502
 
345
503
  ```html
346
504
  <body contextname="context1" importscontext="/bar">
@@ -370,10 +528,148 @@ console.log(localOrGlobalImport2); // { value: div }
370
528
 
371
529
  </details>
372
530
 
373
- └ [HTML Imports concepts](#)
531
+ └ [HTML Imports examples](#html-imports-examples)
532
+
533
+ ## Data Binding
534
+
535
+ Data binding is the concept of declaratively driving the UI with application-level data. It comes as mechanism that sits between the UI and the application itself, ensuring that the relevant parts of the UI are *automatically* updated as application state changes.
536
+
537
+ OOHTML makes this possible in just simple conventions - via a new comment-based data-binding syntax `<?{ }?>` and a complementary new `binding` attribute!
538
+
539
+ ### Comment-Based Data-Binding
540
+
541
+ A web-native, comment-based data-binding syntax `<?{ }?>` which works like regular comment but stay "data-charged":
542
+
543
+ ```js
544
+ <html>
545
+ <head>
546
+ <title><?{ app.title }?></title>
547
+ </head>
548
+ <body>
549
+ Hi, I'm <?{ app.name ?? 'Default name' }?>!
550
+ and here's another way to write the same comment: <!--?{ app.cool }?-->
551
+ </body>
552
+ </html>
553
+ ```
554
+
555
+ <details><summary>With SSR Support</summary>
556
+
557
+ On the server, these data-binding tags would retain their place in the DOM while having their output rendered to their right in a text node.
558
+
559
+ The following: `<?{ 'Hello World' }?>` would thus give us: `<?{ 'Hello World' }?>Hello World`.
560
+
561
+ But they also have to remember the exact text node that they manage, so as to be able to re-establish that relationship on getting to the client. That information is automatically encoded as part of the declaration itself, and that brings us to having a typical server-rendered binding look like this:
562
+
563
+ ```html
564
+ <?{ 'Hello World'; [=11] }?>Hello World
565
+ ```
566
+
567
+ Now that extra bit of information gets decoded and original relationships are forned again on getting to the client. But the binding tag itself graciously disappears from the DOM, while the now "hydrated" text node continues to kick!
568
+
569
+ > Note: We know we're on the server when `window.webqit.env === 'server'`. This flag is automatically set by OOHTML's current SSR engine: [OOHTML-SSR](https://github.com/webqit/oohtml-ssr)
570
+
571
+ </details>
572
+
573
+ ### Directives-Based Data-Binding
574
+
575
+ The `binding` attribute for a declarative and neat, key/value data-binding syntax:
576
+
577
+ ```html
578
+ <div binding="<type><parameter>: <argument>;"></div>
579
+ ```
580
+
581
+ *where*:
582
+
583
+ + *`<type>` is the binding type, which is always a symbol*
584
+ + *`<directive>` is the binding directive, which could be any of CSS property, class name, attribute name, Structural Directive*
585
+ + *`<argument>` is the bound value or expression*
586
+
587
+ *which would give us the following for a CSS property*:
588
+
589
+ ```html
590
+ <div binding="&color: someColor; &backgroundColor: 'red'"></div>
591
+ ```
592
+
593
+ *with enough liberty to separate the binding type from the directive itself*:
594
+
595
+ ```html
596
+ <div binding="& color: someColor; & backgroundColor: 'red'"></div>
597
+ ```
598
+
599
+ *all of which can be seen here*:
600
+
601
+ | Symbol | Meaning | Usage |
602
+ | :---- | :---- | :---- |
603
+ | `&` | CSS Property | `<div binding="&color: someColor;"></div>` |
604
+ | `%` | Class Name | `<div binding="%active: app.isActive;"></div>` |
605
+ | `~` | Attribute Name | `<a binding="~href: person.profileUrl + '#bio';"></a>` |
606
+ | `@` | Structural Directive: | *See next table* |
607
+
608
+ <details><summary>Structural Directives</summary>
609
+
610
+ | Directive | Meaning | Usage |
611
+ | :---- | :---- | :---- |
612
+ | `@text` | For rendering plain text content | `<span binding="@text: firstName + ' ' + lastName;"></span>` |
613
+ | `@html` | For rendering markup content | `<span binding="@html: '<i>' + firstName + '</i>';"></span>` |
614
+ | `@items` | For rendering a list, with argument in the following format:<br>`<declaration> <of\|in> <iterable> / <importRef>` | *See next two tables* |
615
+
616
+ <details><summary>"For ... Of" Loops</summary>
617
+
618
+ | Idea | Usage |
619
+ | :---- | :---- |
620
+ | Loop over an array/iterable | `<ul binding="@items: value of [1,2,3] / 'foo#fragment';"></ul>` |
621
+ | Same as above but with a `key` declaration | `<ul binding="@items: (value, key) of [1,2,3] / 'foo#fragment';"></ul>` |
622
+ | Same as above but with different variable names | `<ul binding="@items: (product, id) of store.products / 'foo#fragment';"></ul>` |
623
+ | Same as above but with a dynamic `importRef` | `<ul binding="@items: (product, id) of store.products / store.importRef;"></ul>` |
624
+
625
+ </details>
626
+
627
+ <details><summary>"For ... In" Loops</summary>
628
+
629
+ | Idea | Usage |
630
+ | :---- | :---- |
631
+ | Loop over an object | `<ul binding="@items: key in { a: 1, b: 2 } / 'foo#fragment';"></ul>` |
632
+ | Same as above but with a `value` and `index` declaration | `<ul binding="@items: (key, value, index) in { a: 1, b: 2 } / 'foo#fragment';"></ul>` |
633
+
634
+ </details>
635
+
636
+ </details>
637
+
638
+ <details><summary>Example</summary>
639
+
640
+ ```html
641
+ <section>
642
+
643
+ <!-- The "items" template -->
644
+ <template def="item" scoped>
645
+ <li binding="@text: key + ': ' + name;"></li>
646
+ </template>
647
+
648
+ <!-- The loop -->
649
+ <ul binding="@items: (name, key) of ['dog','cat','ram'] / 'item';"></ul>
650
+
651
+ </section>
652
+ ```
653
+
654
+ </details>
374
655
 
375
- ## Reactive HTML
656
+ <details><summary>All in Realtime</summary>
376
657
 
658
+ Lists are rendered in realtime, which means that in-place mutations - additions and removals - on the *iteratee* will be automatically reflected on the UI!
659
+
660
+ </details>
661
+
662
+ <details><summary>With SSR Support</summary>
663
+
664
+ Generated item elements are automatically assigned a corresponding index with a `data-index` attribute! This helps in remapping generated item nodes to their respective entry in *iteratee* - universally.
665
+
666
+ </details>
667
+
668
+ ## Data Plumbing
669
+
670
+ *[TODO]: The Context API and Bindings API*
671
+
672
+ <!--
377
673
  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.
378
674
 
379
675
  └ *The [Observer API](https://github.com/webqit/observer) for general-purpose object observability*:
@@ -397,27 +693,6 @@ Observer.set(obj, 'prop1', 'value1'); // Reported synchronously
397
693
  Observer.deleteProperty(obj, 'prop1'); // Reported synchronously
398
694
  ```
399
695
 
400
- └ *A Namespace API that reflects the real-DOM&trade; in real-time*:
401
-
402
- ```js
403
- // Observing the addition or removal of elements with an ID
404
- Observer.observe(document.namespace, changeCallback);
405
-
406
- const paragraph = document.createElement('p');
407
- paragraph.setAttribute('id', 'bar');
408
- document.body.appendChild(paragraph); // Reported synchronously
409
- ```
410
-
411
- ```js
412
- // Observing the addition or removal of elements with an ID
413
- paragraph.toggleAttribute('namespace', true);
414
- Observer.observe(paragraph.namespace, changeCallback);
415
-
416
- const span = document.createElement('span');
417
- span.setAttribute('id', 'baz');
418
- paragraph.appendChild(span); // Reported synchronously
419
- ```
420
-
421
696
  └ *A Bindings API for binding application-level state to an object*:
422
697
 
423
698
  ```js
@@ -485,6 +760,8 @@ Observer.set(element, 'liveProperty'); // Live expressions rerun
485
760
 
486
761
  └ [Reactive HTML concepts](#)
487
762
 
763
+ -->
764
+
488
765
  ## Polyfill
489
766
 
490
767
  OOHTML is being developed as something to be used today - via a polyfill.