bitwrench 2.0.31 → 2.1.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 (126) hide show
  1. package/README.md +210 -125
  2. package/dist/bitwrench-bccl.cjs.js +349 -188
  3. package/dist/bitwrench-bccl.cjs.min.js +2 -39
  4. package/dist/bitwrench-bccl.cjs.min.js.gz +0 -0
  5. package/dist/bitwrench-bccl.esm.js +349 -188
  6. package/dist/bitwrench-bccl.esm.min.js +2 -39
  7. package/dist/bitwrench-bccl.esm.min.js.gz +0 -0
  8. package/dist/bitwrench-bccl.umd.js +349 -188
  9. package/dist/bitwrench-bccl.umd.min.js +2 -39
  10. package/dist/bitwrench-bccl.umd.min.js.gz +0 -0
  11. package/dist/bitwrench-code-edit.cjs.js +17 -6
  12. package/dist/bitwrench-code-edit.cjs.min.js +2 -20
  13. package/dist/bitwrench-code-edit.es5.js +8 -3
  14. package/dist/bitwrench-code-edit.es5.min.js +2 -19
  15. package/dist/bitwrench-code-edit.esm.js +17 -6
  16. package/dist/bitwrench-code-edit.esm.min.js +2 -19
  17. package/dist/bitwrench-code-edit.umd.js +17 -6
  18. package/dist/bitwrench-code-edit.umd.min.js +2 -19
  19. package/dist/bitwrench-code-edit.umd.min.js.gz +0 -0
  20. package/dist/bitwrench-debug.js +1 -1
  21. package/dist/bitwrench-debug.min.js +1 -1
  22. package/dist/bitwrench-lean.cjs.js +2492 -1628
  23. package/dist/bitwrench-lean.cjs.min.js +2 -80
  24. package/dist/bitwrench-lean.cjs.min.js.gz +0 -0
  25. package/dist/bitwrench-lean.es5.js +2740 -1838
  26. package/dist/bitwrench-lean.es5.min.js +2 -49
  27. package/dist/bitwrench-lean.es5.min.js.gz +0 -0
  28. package/dist/bitwrench-lean.esm.js +2492 -1628
  29. package/dist/bitwrench-lean.esm.min.js +2 -80
  30. package/dist/bitwrench-lean.esm.min.js.gz +0 -0
  31. package/dist/bitwrench-lean.umd.js +2492 -1628
  32. package/dist/bitwrench-lean.umd.min.js +2 -80
  33. package/dist/bitwrench-lean.umd.min.js.gz +0 -0
  34. package/dist/bitwrench-util-color.cjs.js +251 -0
  35. package/dist/bitwrench-util-color.cjs.min.js +3 -0
  36. package/dist/bitwrench-util-color.es5.js +256 -0
  37. package/dist/bitwrench-util-color.es5.min.js +3 -0
  38. package/dist/bitwrench-util-color.esm.js +241 -0
  39. package/dist/bitwrench-util-color.esm.min.js +3 -0
  40. package/dist/bitwrench-util-color.umd.js +257 -0
  41. package/dist/bitwrench-util-color.umd.min.js +3 -0
  42. package/dist/bitwrench-util-css.cjs.js +2 -1
  43. package/dist/bitwrench-util-css.cjs.min.js +2 -21
  44. package/dist/bitwrench-util-css.es5.js +2 -1
  45. package/dist/bitwrench-util-css.es5.min.js +2 -20
  46. package/dist/bitwrench-util-css.esm.js +2 -1
  47. package/dist/bitwrench-util-css.esm.min.js +1 -19
  48. package/dist/bitwrench-util-css.umd.js +2 -1
  49. package/dist/bitwrench-util-css.umd.min.js +2 -20
  50. package/dist/bitwrench-util-css.umd.min.js.gz +0 -0
  51. package/dist/bitwrench.cjs.js +2826 -1801
  52. package/dist/bitwrench.cjs.min.js +2 -99
  53. package/dist/bitwrench.cjs.min.js.gz +0 -0
  54. package/dist/bitwrench.css +403 -479
  55. package/dist/bitwrench.d.ts +70 -73
  56. package/dist/bitwrench.es5.js +3106 -2020
  57. package/dist/bitwrench.es5.min.js +2 -67
  58. package/dist/bitwrench.es5.min.js.gz +0 -0
  59. package/dist/bitwrench.esm.js +2826 -1801
  60. package/dist/bitwrench.esm.min.js +2 -99
  61. package/dist/bitwrench.esm.min.js.gz +0 -0
  62. package/dist/bitwrench.min.css +1 -1
  63. package/dist/bitwrench.umd.js +2826 -1801
  64. package/dist/bitwrench.umd.min.js +2 -99
  65. package/dist/bitwrench.umd.min.js.gz +0 -0
  66. package/dist/builds.json +222 -134
  67. package/dist/bwserve.cjs.js +308 -298
  68. package/dist/bwserve.d.ts +157 -0
  69. package/dist/bwserve.esm.js +309 -299
  70. package/dist/sri.json +54 -46
  71. package/docs/README.md +6 -3
  72. package/docs/app-patterns.md +7 -6
  73. package/docs/bitwrench-for-wasm.md +53 -54
  74. package/docs/bitwrench-mcp.md +2 -2
  75. package/docs/bitwrench-northstar-principles.md +406 -0
  76. package/docs/bitwrench-taco-schema-discussion.md +2 -2
  77. package/docs/bitwrench_api.md +191 -106
  78. package/docs/bitwrench_typescript_usage.md +5 -5
  79. package/docs/bw-attach.md +29 -75
  80. package/docs/bwserve.md +200 -168
  81. package/docs/cli.md +36 -12
  82. package/docs/component-cheatsheet.md +2 -2
  83. package/docs/component-library.md +4 -4
  84. package/docs/component-lifecycle.md +234 -0
  85. package/docs/drift-lint.md +268 -0
  86. package/docs/framework-translation-table.md +4 -4
  87. package/docs/llm-bitwrench-guide.md +60 -50
  88. package/docs/routing.md +11 -13
  89. package/docs/state-management.md +110 -109
  90. package/docs/taco-format.md +13 -14
  91. package/docs/theming.md +13 -3
  92. package/docs/thinking-in-bitwrench.md +858 -983
  93. package/docs/tutorial-bwserve.md +37 -36
  94. package/docs/tutorial-embedded.md +10 -21
  95. package/docs/tutorial-website.md +2 -2
  96. package/package.json +38 -7
  97. package/readme.html +262 -160
  98. package/src/bitwrench-bccl-entry.js +2 -2
  99. package/src/bitwrench-bccl.js +346 -185
  100. package/src/bitwrench-code-edit.js +16 -5
  101. package/src/bitwrench-color-utils.js +117 -181
  102. package/src/bitwrench-file-ops.js +2 -2
  103. package/src/bitwrench-lean.js +4 -3
  104. package/src/bitwrench-router.js +5 -2
  105. package/src/bitwrench-styles.js +420 -504
  106. package/src/bitwrench-util-color.js +240 -0
  107. package/src/bitwrench-util-css.js +1 -0
  108. package/src/bitwrench-utils.js +4 -0
  109. package/src/bitwrench.d.ts +70 -73
  110. package/src/bitwrench.h +5 -0
  111. package/src/bitwrench.js +1939 -933
  112. package/src/bwserve/attach.js +0 -1
  113. package/src/bwserve/bwclient.js +172 -32
  114. package/src/bwserve/bwshell.js +0 -4
  115. package/src/bwserve/client.js +59 -220
  116. package/src/bwserve/index.js +78 -42
  117. package/src/bwserve.d.ts +157 -0
  118. package/src/bwserve.h +5 -0
  119. package/src/cli/attach.js +12 -75
  120. package/src/cli/convert.js +2 -2
  121. package/src/cli/serve.js +37 -35
  122. package/src/generate-css.js +1 -1
  123. package/src/mcp/knowledge.js +4 -4
  124. package/src/mcp/live.js +21 -13
  125. package/src/mcp/tools.js +0 -1
  126. package/src/version.js +3 -7
@@ -1,25 +1,25 @@
1
1
  # State Management
2
2
 
3
- Bitwrench has a three-level component model. Each level adds capability on top of the one below it. You choose the level that fits your use case — there is no single "right" way.
3
+ Bitwrench has a progressive component model. Each stage adds capability on top of the one below it. You choose the stage that fits your use case — there is no single "right" way.
4
4
 
5
- | Level | What you get | When to use it |
5
+ | Stage | What you get | When to use it |
6
6
  |-------|-------------|---------------|
7
- | Level 0 -- TACO data | A plain JavaScript object describing UI | Static content, server rendering, serialization |
8
- | Level 1 -- DOM rendering | A live DOM element with optional lifecycle hooks | Render-once UI, manual state management |
9
- | Level 1.5 -- Component handles | `o.handle` and `o.slots` for imperative control of rendered elements | Update parts of a component without re-rendering |
10
- | Level 2 -- Stateful TACO | A TACO with `o.state` + `o.render` and `bw.update()` for re-rendering | Interactive components with changing state |
7
+ | TACO as data | A plain JavaScript object describing UI | Static content, server rendering, serialization |
8
+ | Mounting and rendering | A live DOM element with optional lifecycle hooks | Render-once UI, manual state management |
9
+ | Component handles | `o.handle` and `o.slots` for imperative control of rendered elements | Update parts of a component without re-rendering |
10
+ | Stateful components | A TACO with `o.state` + `o.render` and `bw.refresh()` for re-rendering | Interactive components with changing state |
11
11
 
12
- This guide covers all three levels, from simplest to most capable.
12
+ This guide covers all stages, from simplest to most capable.
13
13
 
14
- > **Coming from React?** Level 0 is like calling `React.createElement()` to get a virtual element. Level 1 is like `ReactDOM.render()` with no state. Level 2 is like a class component with `this.state` and `this.setState()`, where you call `bw.update(el)` instead of `setState`.
14
+ > **Coming from React?** A static TACO is like calling `React.createElement()` to get a virtual element. Mounting is like `ReactDOM.render()` with no state. A stateful TACO is like a class component with `this.state` and `this.setState()`, where you call `bw.refresh(el)` instead of `setState`.
15
15
 
16
- > **Coming from Vue?** Level 0 is like a render function's return value. Level 1 is mounting with `createApp().mount()`. Level 2 is like a component with a `setup()` function that manages its own reactivity, where the render function re-runs on `bw.update()`.
16
+ > **Coming from Vue?** A static TACO is like a render function's return value. Mounting is like `createApp().mount()`. A stateful TACO is like a component with a `setup()` function that manages its own reactivity, where the render function re-runs on `bw.refresh()`.
17
17
 
18
- > **Coming from Svelte?** Level 0 is like the compiled component descriptor. Level 1 is mounting with `new Component({ target })`. Level 2 is a live component with state variables, where `bw.update(el)` triggers the re-render.
18
+ > **Coming from Svelte?** A static TACO is like the compiled component descriptor. Mounting is like `new Component({ target })`. A stateful TACO is a live component with state variables, where `bw.refresh(el)` triggers the re-render.
19
19
 
20
20
  ---
21
21
 
22
- ## Level 0: TACO as Data
22
+ ## TACO as Data
23
23
 
24
24
  Every UI element in bitwrench starts as a plain object:
25
25
 
@@ -29,7 +29,7 @@ var greeting = { t: 'h1', c: 'Hello World' };
29
29
 
30
30
  This is a TACO object — **T**ag, **A**ttributes, **C**ontent, **O**ptions. It describes what you want, not how to render it. See [TACO Format](taco-format.md) for the full specification.
31
31
 
32
- At Level 0, a TACO object is inert data. You can:
32
+ As data, a TACO object is inert. You can:
33
33
 
34
34
  - Store it in a variable
35
35
  - Put it in an array with other TACOs
@@ -47,7 +47,7 @@ var list = { t: 'ul', c: items };
47
47
 
48
48
  ### The `make*()` factories
49
49
 
50
- The component library provides over 50 factory functions that return Level 0 TACO objects:
50
+ The component library provides over 50 factory functions that return static TACO objects:
51
51
 
52
52
  ```javascript
53
53
  var card = bw.makeCard({ title: 'Users', content: '1,234 active' });
@@ -72,9 +72,9 @@ var page = {
72
72
 
73
73
  See [Component Library](component-library.md) for all available factories.
74
74
 
75
- ### When Level 0 is enough
75
+ ### When static TACOs are enough
76
76
 
77
- Use Level 0 when the content does not change after rendering:
77
+ Use static TACOs when the content does not change after rendering:
78
78
 
79
79
  - Static pages and reports
80
80
  - Server-rendered HTML (`bw.html(taco)` in Node.js)
@@ -84,7 +84,7 @@ Use Level 0 when the content does not change after rendering:
84
84
 
85
85
  ---
86
86
 
87
- ## Level 1: Fire-and-Forget DOM Rendering
87
+ ## Mounting and Rendering
88
88
 
89
89
  To turn a TACO into something visible, pass it to a rendering function:
90
90
 
@@ -94,7 +94,7 @@ var html = bw.html({ t: 'div', c: 'Hello' });
94
94
  // '<div>Hello</div>'
95
95
 
96
96
  // Create a detached DOM element (browser only)
97
- var el = bw.createDOM({ t: 'div', c: 'Hello' });
97
+ var el = bw.create({ t: 'div', c: 'Hello' });
98
98
 
99
99
  // Mount into an existing DOM element (browser only)
100
100
  bw.DOM('#app', { t: 'div', c: 'Hello' });
@@ -102,9 +102,9 @@ bw.DOM('#app', { t: 'div', c: 'Hello' });
102
102
 
103
103
  `bw.DOM()` finds the element matching the selector, cleans up any previous content (running unmount hooks, clearing subscriptions), and mounts the new TACO as live DOM.
104
104
 
105
- ### Adding interactivity at Level 1
105
+ ### Adding interactivity to mounted components
106
106
 
107
- You can make Level 1 components interactive using closures, `o.state`, and `o.render`:
107
+ You can make mounted components interactive using closures, `o.state`, and `o.render`:
108
108
 
109
109
  ```javascript
110
110
  function makeCounter() {
@@ -112,14 +112,14 @@ function makeCounter() {
112
112
  t: 'div',
113
113
  o: {
114
114
  state: { count: 0 },
115
- render: function(el) {
115
+ render: function(el, state) {
116
116
  bw.DOM(el, {
117
117
  t: 'div', c: [
118
- { t: 'span', c: 'Count: ' + el._bw_state.count },
118
+ { t: 'span', c: 'Count: ' + state.count },
119
119
  { t: 'button', c: '+1', a: {
120
120
  onclick: function() {
121
- el._bw_state.count++;
122
- bw.update(el);
121
+ state.count++;
122
+ bw.refresh(el);
123
123
  }
124
124
  }}
125
125
  ]
@@ -136,13 +136,13 @@ This is the **manual render pump** pattern:
136
136
 
137
137
  1. Define state in `o.state`
138
138
  2. Define a render function in `o.render`
139
- 3. When state changes, call `bw.update(el)` to re-invoke the render function
139
+ 3. When state changes, call `bw.refresh(el)` to re-invoke the render function
140
140
 
141
141
  This pattern works and is fully supported. It gives you direct control over when and how re-rendering happens.
142
142
 
143
143
  ### Lifecycle hooks
144
144
 
145
- Level 1 components can respond to mount and unmount events:
145
+ Mounted components can respond to mount and unmount events:
146
146
 
147
147
  ```javascript
148
148
  {
@@ -161,7 +161,7 @@ Level 1 components can respond to mount and unmount events:
161
161
  }
162
162
  ```
163
163
 
164
- > **Warning: Never use `o.mounted` to attach event handlers.** When a stateful component re-renders (after `bw.update()`), the old DOM content is replaced and any listeners attached via `addEventListener` in `mounted` are silently lost. Always put event handlers in `a: { onclick: fn }` -- bitwrench re-attaches them on every render. Use `o.mounted` only for non-event setup: timers, observers, third-party library init, measuring dimensions.
164
+ > **Warning: Never use `o.mounted` to attach event handlers.** When a stateful component re-renders (after `bw.refresh()`), the old DOM content is replaced and any listeners attached via `addEventListener` in `mounted` are silently lost. Always put event handlers in `a: { onclick: fn }` -- bitwrench re-attaches them on every render. Use `o.mounted` only for non-event setup: timers, observers, third-party library init, measuring dimensions.
165
165
 
166
166
  ### Targeted updates with `bw.patch()`
167
167
 
@@ -185,21 +185,21 @@ bw.patchAll({
185
185
  });
186
186
  ```
187
187
 
188
- ### When Level 1 is enough
188
+ ### When mounting is enough
189
189
 
190
- Use Level 1 when:
190
+ Use this approach when:
191
191
 
192
192
  - You need interactivity but want full control over the render cycle
193
193
  - You are building a one-off interactive widget
194
194
  - You are integrating with external libraries that manage their own state
195
- - You prefer explicit `bw.update()` calls over automatic re-rendering
195
+ - You prefer explicit `bw.refresh()` calls over automatic re-rendering
196
196
  - You are building the transport layer for server-driven UI (bwserve)
197
197
 
198
- > **Coming from jQuery?** Level 1 with `o.render` + `bw.update()` is conceptually similar to jQuery's manual DOM updates, but structured. Instead of scattered `$('.count').text(val)` calls, you have a single render function that produces the complete UI from state. When state changes, you call `bw.update()` and the render function runs again.
198
+ > **Coming from jQuery?** Mounting with `o.render` + `bw.refresh()` is conceptually similar to jQuery's manual DOM updates, but structured. Instead of scattered `$('.count').text(val)` calls, you have a single render function that produces the complete UI from state. When state changes, you call `bw.refresh()` and the render function runs again.
199
199
 
200
200
  ---
201
201
 
202
- ## Level 1.5: Component Handles
202
+ ## Component Handles
203
203
 
204
204
  When you need imperative control of a rendered element -- updating a title, advancing a carousel, or reading a form value -- without re-rendering the entire component, use `o.handle` and `o.slots`.
205
205
 
@@ -231,7 +231,7 @@ Declare named content areas with CSS selectors. Bitwrench auto-generates `el.bw.
231
231
 
232
232
  ```javascript
233
233
  var card = bw.makeCard({ title: 'Stats', content: '0' });
234
- // makeCard declares o.slots: { title: '.bw_card_title', content: '.bw_card_body', footer: '.bw_card_footer' }
234
+ // makeCard declares o.slots: { title: '.bw_bccl_card_title', content: '.bw_bccl_card_body', footer: '.bw_bccl_card_footer' }
235
235
  var el = bw.mount('#app', card);
236
236
  el.bw.setTitle('Updated Title');
237
237
  el.bw.setContent({ t: 'strong', c: '42' }); // accepts TACO objects
@@ -240,9 +240,9 @@ var text = el.bw.getTitle(); // returns text content
240
240
 
241
241
  Slot setters accept strings or TACO objects. They update just the targeted element -- no full re-render, so input focus, scroll position, and animation state are preserved.
242
242
 
243
- ### bw.mount() -- get the element back
243
+ ### bw.mount() / bw.DOM() -- get the element back
244
244
 
245
- `bw.mount()` works like `bw.DOM()` but returns the created root element instead of the container. This is how you get access to `el.bw`:
245
+ `bw.mount()` and `bw.DOM()` are identical (aliases). Both return the created root element, which gives you access to `el.bw`:
246
246
 
247
247
  ```javascript
248
248
  var el = bw.mount('#app', bw.makeCarousel({ items: slides }));
@@ -273,35 +273,34 @@ All BCCL factories include `o.handle` and/or `o.slots`. Examples:
273
273
  | makeCard | setTitle/getTitle, setContent/getContent, setFooter/getFooter (slots) |
274
274
  | makeStatCard | setValue/getValue, setLabel/getLabel (slots) |
275
275
 
276
- ### When to use handles vs Level 2
276
+ ### When to use handles vs stateful components
277
277
 
278
278
  | Situation | Use |
279
279
  |-----------|-----|
280
280
  | Update a label, badge, or slot text | **Handles** -- `el.bw.setTitle('new')` |
281
281
  | Advance a carousel or toggle an accordion | **Handles** -- `el.bw.next()`, `el.bw.toggle(0)` |
282
- | Component has complex state that triggers full UI rebuild | **Level 2** -- `o.state` + `o.render` + `bw.update()` |
282
+ | Component has complex state that triggers full UI rebuild | **Stateful** -- `o.state` + `o.render` + `bw.refresh()` |
283
283
  | Need to preserve input focus during updates | **Handles** -- slot setters don't re-render siblings |
284
284
  | External code needs to control an embedded widget | **Handles** -- `bw.mount()` + `el.bw.method()` |
285
285
 
286
286
  ---
287
287
 
288
- ## Level 2: Stateful TACO
288
+ ## Stateful Components
289
289
 
290
- Level 2 adds `o.state` and `o.render` to a TACO, giving it managed state and a render pump. When state changes, you call `bw.update(el)` to re-invoke the render function. This is the recommended pattern for interactive components.
290
+ Adding `o.state` and `o.render` to a TACO gives it managed state and a render pump. When state changes, you call `bw.refresh(el)` to re-invoke the render function. This is the recommended pattern for interactive components.
291
291
 
292
292
  ```javascript
293
293
  var counter = {
294
294
  t: 'div',
295
295
  o: {
296
296
  state: { count: 0 },
297
- render: function(el) {
298
- var s = el._bw_state;
297
+ render: function(el, state) {
299
298
  bw.DOM(el, {
300
299
  t: 'div', c: [
301
- { t: 'h3', c: 'Count: ' + s.count },
300
+ { t: 'h3', c: 'Count: ' + state.count },
302
301
  bw.makeButton({ text: '+1', onclick: function() {
303
- s.count++;
304
- bw.update(el);
302
+ state.count++;
303
+ bw.refresh(el);
305
304
  }})
306
305
  ]
307
306
  });
@@ -314,9 +313,9 @@ bw.DOM('#app', counter);
314
313
 
315
314
  ### How it works
316
315
 
317
- 1. `bw.createDOM()` (called internally by `bw.DOM()`) sees `o.state` and copies it to `el._bw_state`
316
+ 1. `bw.create()` (called internally by `bw.DOM()`) sees `o.state` and copies it to `el._bw_state`
318
317
  2. If `o.render` is defined, it is stored as `el._bw_render` and called immediately: `o.render(el, el._bw_state)`
319
- 3. When state changes, you call `bw.update(el)` which re-invokes `el._bw_render(el, el._bw_state)` and emits a `bw:statechange` event
318
+ 3. When state changes, you call `bw.refresh(el)` which re-invokes `el._bw_render(el, el._bw_state)` and emits a `bw:refresh` event
320
319
  4. The render function produces new content via `bw.DOM(el, ...)`, replacing the old children
321
320
 
322
321
  ### Accessing state
@@ -328,10 +327,9 @@ State lives directly on the DOM element as `el._bw_state`:
328
327
  t: 'div',
329
328
  o: {
330
329
  state: { count: 0, label: 'Clicks' },
331
- render: function(el) {
332
- var s = el._bw_state;
330
+ render: function(el, state) {
333
331
  bw.DOM(el, {
334
- t: 'div', c: s.label + ': ' + s.count
332
+ t: 'div', c: state.label + ': ' + state.count
335
333
  });
336
334
  }
337
335
  }
@@ -343,12 +341,12 @@ To read or modify state from outside, get a reference to the element:
343
341
  ```javascript
344
342
  var el = bw.$('#my-component')[0];
345
343
  el._bw_state.count = 42;
346
- bw.update(el);
344
+ bw.refresh(el);
347
345
  ```
348
346
 
349
347
  ### Lifecycle hooks
350
348
 
351
- Stateful TACOs support two primary lifecycle hooks:
349
+ Stateful components support two primary lifecycle hooks:
352
350
 
353
351
  | Hook | When it fires | Typical use |
354
352
  |------|--------------|-------------|
@@ -363,20 +361,20 @@ var timer = {
363
361
  mounted: function(el) {
364
362
  el._interval = setInterval(function() {
365
363
  el._bw_state.seconds++;
366
- bw.update(el);
364
+ bw.refresh(el);
367
365
  }, 1000);
368
366
  },
369
367
  unmount: function(el) {
370
368
  clearInterval(el._interval);
371
369
  },
372
- render: function(el) {
373
- bw.DOM(el, { t: 'span', c: 'Elapsed: ' + el._bw_state.seconds + 's' });
370
+ render: function(el, state) {
371
+ bw.DOM(el, { t: 'span', c: 'Elapsed: ' + state.seconds + 's' });
374
372
  }
375
373
  }
376
374
  };
377
375
  ```
378
376
 
379
- > **Warning: Never attach event handlers in `o.mounted`.** When `bw.update()` re-renders a component, the old DOM children are replaced. Any listeners attached via `addEventListener` in `mounted` are silently lost. Always put event handlers in `a: { onclick: fn }` -- bitwrench re-attaches them on every render.
377
+ > **Warning: Never attach event handlers in `o.mounted`.** When `bw.refresh()` re-renders a component, the old DOM children are replaced. Any listeners attached via `addEventListener` in `mounted` are silently lost. Always put event handlers in `a: { onclick: fn }` -- bitwrench re-attaches them on every render.
380
378
 
381
379
  ### Targeted updates with `bw.patch()`
382
380
 
@@ -387,11 +385,10 @@ var dashboard = {
387
385
  t: 'div',
388
386
  o: {
389
387
  state: { temp: 0 },
390
- render: function(el) {
391
- var s = el._bw_state;
388
+ render: function(el, state) {
392
389
  bw.DOM(el, {
393
390
  t: 'div', c: [
394
- { t: 'span', a: { class: bw.uuid('temp') }, c: s.temp + ' C' },
391
+ { t: 'span', a: { class: bw.uuid('temp') }, c: state.temp + ' C' },
395
392
  { t: 'span', a: { class: bw.uuid('status') }, c: 'OK' }
396
393
  ]
397
394
  });
@@ -406,40 +403,40 @@ bw.patch('temp', '23.5 C');
406
403
  bw.patch('status', 'Warning');
407
404
  ```
408
405
 
409
- ### When to use Level 2
406
+ ### When to use stateful components
410
407
 
411
- Use Level 2 when:
408
+ Use stateful components when:
412
409
 
413
410
  - The component has state that changes after initial render
414
411
  - You need a render function that re-runs on state changes
415
412
  - You need lifecycle management (mount, unmount)
416
413
  - You want explicit control over what triggers a re-render
417
414
 
418
- > **Coming from React?** Level 2 is like a class component with `this.state` and a manual `forceUpdate()`. The render function rebuilds the component from state each time `bw.update()` is called.
415
+ > **Coming from React?** A stateful TACO is like a class component with `this.state` and a manual `forceUpdate()`. The render function rebuilds the component from state each time `bw.refresh()` is called.
419
416
 
420
- > **Coming from jQuery?** Level 2 with `o.render` + `bw.update()` is conceptually similar to jQuery's manual DOM updates, but structured. Instead of scattered `$('.count').text(val)` calls, you have a single render function that produces the complete UI from state.
417
+ > **Coming from jQuery?** A stateful TACO with `o.render` + `bw.refresh()` is conceptually similar to jQuery's manual DOM updates, but structured. Instead of scattered `$('.count').text(val)` calls, you have a single render function that produces the complete UI from state.
421
418
 
422
419
  ---
423
420
 
424
- ## Escalating Between Levels
421
+ ## Progressing Between Stages
425
422
 
426
- You can start at any level and escalate when you need more capability.
423
+ You can start at any stage and progress when you need more capability.
427
424
 
428
- ### Level 0 Level 1
425
+ ### From Data to DOM
429
426
 
430
427
  Pass a TACO to a rendering function:
431
428
 
432
429
  ```javascript
433
- var taco = bw.makeCard({ title: 'Hello' }); // Level 0
434
- bw.DOM('#app', taco); // Level 1 — now it's in the DOM
430
+ var taco = bw.makeCard({ title: 'Hello' }); // static TACO
431
+ bw.DOM('#app', taco); // mounted — now it's in the DOM
435
432
  ```
436
433
 
437
- ### Level 0 => Level 2
434
+ ### From Data to Stateful
438
435
 
439
436
  Add `o.state` and `o.render` to make a static TACO stateful:
440
437
 
441
438
  ```javascript
442
- // Start with Level 0
439
+ // Start with a static TACO
443
440
  var card = bw.makeCard({ title: 'Hello' });
444
441
 
445
442
  // Wrap in a stateful container
@@ -447,19 +444,19 @@ var statefulCard = {
447
444
  t: 'div',
448
445
  o: {
449
446
  state: { title: 'Hello' },
450
- render: function(el) {
451
- bw.DOM(el, bw.makeCard({ title: el._bw_state.title }));
447
+ render: function(el, state) {
448
+ bw.DOM(el, bw.makeCard({ title: state.title }));
452
449
  }
453
450
  }
454
451
  };
455
452
  bw.DOM('#app', statefulCard);
456
453
  ```
457
454
 
458
- ### Level 1 => Level 2
455
+ ### From Mounted to Stateful
459
456
 
460
- If you have a Level 1 component using manual `bw.DOM()` calls, add `o.state` and `o.render`:
457
+ If you have a mounted component using manual `bw.DOM()` calls, add `o.state` and `o.render`:
461
458
 
462
- **Before (Level 1 -- manual re-render):**
459
+ **Before (manual re-render):**
463
460
  ```javascript
464
461
  var count = 0;
465
462
  function renderCounter() {
@@ -475,19 +472,18 @@ function renderCounter() {
475
472
  renderCounter();
476
473
  ```
477
474
 
478
- **After (Level 2 -- stateful TACO):**
475
+ **After (stateful TACO):**
479
476
  ```javascript
480
477
  bw.DOM('#app', {
481
478
  t: 'div',
482
479
  o: {
483
480
  state: { count: 0 },
484
- render: function(el) {
485
- var s = el._bw_state;
481
+ render: function(el, state) {
486
482
  bw.DOM(el, {
487
483
  t: 'div', c: [
488
- { t: 'span', c: 'Count: ' + s.count },
484
+ { t: 'span', c: 'Count: ' + state.count },
489
485
  { t: 'button', c: '+1', a: {
490
- onclick: function() { s.count++; bw.update(el); }
486
+ onclick: function() { state.count++; bw.refresh(el); }
491
487
  }}
492
488
  ]
493
489
  });
@@ -496,7 +492,7 @@ bw.DOM('#app', {
496
492
  });
497
493
  ```
498
494
 
499
- The Level 2 version encapsulates state inside the component. No external variable, no standalone render function. The render function is called automatically on mount and on each `bw.update(el)` call.
495
+ The stateful version encapsulates state inside the component. No external variable, no standalone render function. The render function is called automatically on mount and on each `bw.refresh(el)` call.
500
496
 
501
497
  ---
502
498
 
@@ -506,7 +502,7 @@ Bitwrench provides three mechanisms for components to communicate, each suited t
506
502
 
507
503
  ### Shared state (parent-child)
508
504
 
509
- Multiple components can share the same state object. When either calls `bw.update()`, it re-renders with the current shared state:
505
+ Multiple components can share the same state object. When either calls `bw.refresh()`, it re-renders with the current shared state:
510
506
 
511
507
  ```javascript
512
508
  var appState = { user: { name: 'Alice' }, items: [] };
@@ -515,8 +511,8 @@ var header = {
515
511
  t: 'header',
516
512
  o: {
517
513
  state: appState,
518
- render: function(el) {
519
- bw.DOM(el, { t: 'span', c: 'Hello, ' + el._bw_state.user.name });
514
+ render: function(el, state) {
515
+ bw.DOM(el, { t: 'span', c: 'Hello, ' + state.user.name });
520
516
  }
521
517
  }
522
518
  };
@@ -525,10 +521,9 @@ var main = {
525
521
  t: 'main',
526
522
  o: {
527
523
  state: appState,
528
- render: function(el) {
529
- var s = el._bw_state;
524
+ render: function(el, state) {
530
525
  bw.DOM(el, {
531
- t: 'div', c: s.items.map(function(item) {
526
+ t: 'div', c: state.items.map(function(item) {
532
527
  return { t: 'div', c: item.text };
533
528
  })
534
529
  });
@@ -555,17 +550,17 @@ var results = {
555
550
  mounted: function(el) {
556
551
  bw.sub('search:changed', function(detail) {
557
552
  el._bw_state.query = detail.query;
558
- bw.update(el);
553
+ bw.refresh(el);
559
554
  }, el);
560
555
  },
561
- render: function(el) {
562
- bw.DOM(el, { t: 'span', c: 'Results for: ' + el._bw_state.query });
556
+ render: function(el, state) {
557
+ bw.DOM(el, { t: 'span', c: 'Results for: ' + state.query });
563
558
  }
564
559
  }
565
560
  };
566
561
  ```
567
562
 
568
- Pub/sub is app-scoped -- publishers and subscribers do not need to know about each other. Pass the element as the third argument to `bw.sub()` to tie the subscription's lifetime to the element (auto-cleaned on `bw.cleanup()`).
563
+ Pub/sub is app-scoped -- publishers and subscribers do not need to know about each other. Pass the element as the third argument to `bw.sub()` to tie the subscription's lifetime to the element (auto-cleaned on `bw.unmount()`).
569
564
 
570
565
  Wildcard subscriptions let you listen to a group of related topics at once:
571
566
 
@@ -596,15 +591,14 @@ bw.DOM('#app', {
596
591
  mounted: function(el) {
597
592
  bw.sub('upload:progress', function(d) {
598
593
  el._bw_state.pct = d.pct;
599
- bw.update(el);
594
+ bw.refresh(el);
600
595
  }, el);
601
596
  },
602
- render: function(el) {
603
- var s = el._bw_state;
597
+ render: function(el, state) {
604
598
  bw.DOM(el, {
605
599
  t: 'div', c: [
606
600
  { t: 'h2', c: 'Upload Progress' },
607
- bw.makeProgress({ value: s.pct, label: s.pct + '%' }),
601
+ bw.makeProgress({ value: state.pct, label: state.pct + '%' }),
608
602
  bw.makeButton({ text: 'Start', onclick: function() {
609
603
  var pct = 0;
610
604
  var interval = setInterval(function() {
@@ -630,7 +624,8 @@ These primitives are the building blocks of the stateful TACO model. They are al
630
624
 
631
625
  | Function | Purpose |
632
626
  |----------|---------|
633
- | `bw.update(el)` | Re-invoke `el._bw_render(el)` to re-render |
627
+ | `bw.refresh(ref)` | Re-invoke `el._bw_render(el, state)` to re-render |
628
+ | `bw.update(ref, data)` | Dispatch to `el.bw.update(data)` |
634
629
  | `bw.patch(uuid, content, attr)` | Update a single UUID-addressed element |
635
630
  | `bw.patchAll(patches)` | Batch-update multiple UUID-addressed elements |
636
631
  | `bw.uuid(prefix)` | Generate a UUID class for addressing |
@@ -640,7 +635,14 @@ These primitives are the building blocks of the stateful TACO model. They are al
640
635
  | `bw.sub(topic, handler, el?)` | Subscribe to topic (supports wildcard `'ns:*'` patterns) |
641
636
  | `bw.once(topic, handler, el?)` | One-shot subscribe (auto-unsub after first fire) |
642
637
  | `bw.unsub(topic, handler)` | Unsubscribe from topic |
643
- | `bw.cleanup(el)` | Run unmount hooks and clear subscriptions |
638
+ | `bw.unmount(el)` | Tear down subtree lifecycle |
639
+ | `bw.mountTree(el)` | Register an inserted subtree |
640
+ | `bw.unmountChildren(el)` | Unmount descendants only |
641
+ | `bw.detach(el)` | Keep-alive disconnect |
642
+ | `bw.hydrate(el, taco)` | Wire lifecycle onto existing DOM |
643
+ | `bw.append(target, taco)` | Add child without removing existing |
644
+ | `bw.replace(ref, taco)` | Swap element at DOM position |
645
+ | `bw.remove(ref)` | Unmount + remove from DOM |
644
646
 
645
647
  ### `bw.emit()` / `bw.on()` vs `bw.pub()` / `bw.sub()`
646
648
 
@@ -651,7 +653,7 @@ Bitwrench has two event systems that serve different purposes:
651
653
  | Scope | DOM element and its ancestors (bubbles) | App-wide (all subscribers) |
652
654
  | Addressing | By DOM element reference | By topic string |
653
655
  | Use case | Parent-child DOM communication | Decoupled cross-component messaging |
654
- | Cleanup | Manual or via bw.cleanup() | Auto-cleanup via `handle.sub()` or element lifecycle |
656
+ | Cleanup | Manual or via bw.unmount() | Auto-cleanup via `handle.sub()` or element lifecycle |
655
657
 
656
658
  ---
657
659
 
@@ -690,12 +692,11 @@ function renderTodoView(target) {
690
692
  mounted: function(el) {
691
693
  bw.sub('store:todos', function(todos) {
692
694
  el._bw_state.items = todos;
693
- bw.update(el);
695
+ bw.refresh(el);
694
696
  }, el); // auto-unsubscribes when view is removed
695
697
  },
696
- render: function(el) {
697
- var s = el._bw_state;
698
- bw.DOM(el, { t: 'ul', c: s.items.map(function(item) {
698
+ render: function(el, state) {
699
+ bw.DOM(el, { t: 'ul', c: state.items.map(function(item) {
699
700
  return { t: 'li', c: item.text };
700
701
  })});
701
702
  }
@@ -712,10 +713,10 @@ function renderProjectView(target) {
712
713
  mounted: function(el) {
713
714
  bw.sub('store:projects', function(projects) {
714
715
  el._bw_state.projects = projects;
715
- bw.update(el);
716
+ bw.refresh(el);
716
717
  }, el);
717
718
  },
718
- render: function(el) {
719
+ render: function(el, state) {
719
720
  // ... render projects
720
721
  }
721
722
  }
@@ -755,7 +756,7 @@ bw.sub('store:*', function(data, topic) {
755
756
  - Dashboard panels that react to shared metrics
756
757
  - Any app with >1 view reading from the same data source
757
758
 
758
- For surgical updates within a view (changing a title, updating a counter), use [Level 1.5 handles](state-management.md#level-15-component-handles) instead of a full re-render.
759
+ For surgical updates within a view (changing a title, updating a counter), use [component handles](state-management.md#component-handles) instead of a full re-render.
759
760
 
760
761
  For URL-driven view switching, combine with [bw.router()](routing.md):
761
762
 
@@ -775,11 +776,11 @@ bw.router({
775
776
 
776
777
  | Situation | Recommended approach |
777
778
  |-----------|---------------------|
778
- | Static content, server rendering | Level 0 -- TACO data, `bw.html()` |
779
- | Interactive widget, full control | Level 1 -- manual `bw.DOM()` re-renders |
780
- | Update a slot, label, or control a widget | Level 1.5 -- `o.handle` / `o.slots` via `bw.mount()` + `el.bw` |
781
- | Stateful component with changing data | Level 2 -- `o.state` + `o.render` + `bw.update()` |
782
- | Server pushes UI updates | Level 1 -- `bw.patch()` / `bw.DOM()` |
779
+ | Static content, server rendering | Static TACO data, `bw.html()` |
780
+ | Interactive widget, full control | Mounted -- manual `bw.DOM()` re-renders |
781
+ | Update a slot, label, or control a widget | Component handles -- `o.handle` / `o.slots` via `bw.mount()` + `el.bw` |
782
+ | Stateful component with changing data | Stateful -- `o.state` + `o.render` + `bw.refresh()` |
783
+ | Server pushes UI updates | Mounted -- `bw.patch()` / `bw.DOM()` |
783
784
  | Components need to talk to each other | `bw.pub()`/`bw.sub()` |
784
785
  | URL-driven views (SPA) | `bw.router()` -- see [Routing](routing.md) |
785
786
  | Debugging component state | `el._bw_state` in the console, or `bw.inspect(selector, 0)` |
@@ -788,4 +789,4 @@ bw.router({
788
789
 
789
790
  ## Removed: bw.component() (v2.0.19)
790
791
 
791
- `bw.component()`, `bw.compile()`, `bw.when()`, and `bw.each()` were removed in v2.0.19. Calling these functions now throws an Error. Their functionality is replaced by `o.handle`, `o.slots`, and `bw.mount()` -- see [Level 1.5: Component Handles](#level-15-component-handles) above.
792
+ `bw.component()`, `bw.compile()`, `bw.when()`, and `bw.each()` were removed in v2.0.19. These functions are now `undefined`. Their functionality is replaced by `o.handle`, `o.slots`, and `bw.mount()` -- see [Component Handles](#component-handles) above.