bitwrench 2.0.32 → 2.1.1

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 +211 -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 +289 -282
  68. package/dist/bwserve.d.ts +157 -0
  69. package/dist/bwserve.esm.js +290 -283
  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 -161
  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 +59 -26
  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
@@ -5,15 +5,15 @@ How common UI operations map across frameworks. Each cell shows the idiomatic on
5
5
  | Operation | What it is | React | Vue 3 | Vanilla JS | Svelte 5 | Solid | Bitwrench |
6
6
  |-----------|-----------|-------|-------|------------|----------|-------|-----------|
7
7
  | **Render element** | Create and display a UI element | `<div className="card">Hi</div>` | `<div class="card">Hi</div>` | `el.innerHTML = '<div>Hi</div>'` | `<div class="card">Hi</div>` | `<div class="card">Hi</div>` | `bw.DOM('#x', {t:'div', a:{class:'card'}, c:'Hi'})` |
8
- | **Update text** | Change text content after render | `setText('new')` via `useState` | `msg.value = 'new'` | `el.textContent = 'new'` | `msg = 'new'` | `setMsg('new')` | `el._bw_state.msg = 'new'; bw.update(el)` or `bw.patch(id, 'new')` |
8
+ | **Update text** | Change text content after render | `setText('new')` via `useState` | `msg.value = 'new'` | `el.textContent = 'new'` | `msg = 'new'` | `setMsg('new')` | `el._bw_state.msg = 'new'; bw.refresh(el)` or `bw.patch(id, 'new')` |
9
9
  | **Conditional render** | Show/hide based on state | `{show && <Comp/>}` | `v-if="show"` | `if (show) el.style.display = ''` | `{#if show}<Comp/>{/if}` | `<Show when={show}><Comp/></Show>` | `show ? taco : null` in `c:` array |
10
10
  | **List rendering** | Render array of items | `{items.map(i => <Li key={i.id}/>)}` | `v-for="i in items" :key="i.id"` | `el.innerHTML = items.map(...)` | `{#each items as i (i.id)}` | `<For each={items}>{i => ...}</For>` | `c: items.map(function(i) { return {t:'li', c:i.name} })` |
11
11
  | **Event handler** | Attach click/input handler | `onClick={handler}` | `@click="handler"` | `el.addEventListener('click', fn)` | `onclick={handler}` | `onClick={handler}` | `a: { onclick: fn }` |
12
12
  | **State declaration** | Declare reactive state | `const [x, setX] = useState(0)` | `const x = ref(0)` | `let x = 0` | `let x = $state(0)` | `const [x, setX] = createSignal(0)` | `o: { state: { x: 0 } }` |
13
- | **State update** | Change state and trigger re-render | `setX(42)` | `x.value = 42` | `x = 42; render()` | `x = 42` | `setX(42)` | `el._bw_state.x = 42; bw.update(el)` |
13
+ | **State update** | Change state and trigger re-render | `setX(42)` | `x.value = 42` | `x = 42; render()` | `x = 42` | `setX(42)` | `el._bw_state.x = 42; bw.refresh(el)` |
14
14
  | **Computed / derived** | Derive value from state | `useMemo(() => x * 2, [x])` | `computed(() => x.value * 2)` | `function get() { return x * 2; }` | `let d = $derived(x * 2)` | `const d = () => x() * 2` | `c: '${x}'` with `'${x * 2}'` |
15
15
  | **Side effect** | Run code on mount/change | `useEffect(() => {...}, [])` | `onMounted(() => {...})` | `window.addEventListener('load', fn)` | `$effect(() => {...})` | `onMount(() => {...})` | `o: { mounted: function(el) {...} }` |
16
- | **Cleanup on unmount** | Tear down timers/listeners | `useEffect return cleanup` | `onUnmounted(() => {...})` | manual | `return () => {...}` in `$effect` | `onCleanup(() => {...})` | `o: { unmount: fn }` or `bw.cleanup(el)` |
16
+ | **Cleanup on unmount** | Tear down timers/listeners | `useEffect return cleanup` | `onUnmounted(() => {...})` | manual | `return () => {...}` in `$effect` | `onCleanup(() => {...})` | `o: { unmount: fn }` or `bw.unmount(el)` |
17
17
  | **Style inline** | Apply inline styles | `style={{color: 'red'}}` | `:style="{color: 'red'}"` | `el.style.color = 'red'` | `style="color:red"` | `style={{color: 'red'}}` | `a: { style: bw.s({ color: 'red' }) }` |
18
18
  | **Style composition** | Compose/merge styles | `{...base, ...override}` | `[baseStyle, overrideStyle]` | `Object.assign({}, base, over)` | `{...base, ...override}` | `{...base, ...override}` | `bw.s({ display: 'flex' }, { padding: '1rem' }, { color: accent })` |
19
19
  | **CSS class conditional** | Toggle classes | `className={active ? 'on' : ''}` | `:class="{on: active}"` | `el.classList.toggle('on')` | `class:on={active}` | `classList={{on: active()}}` | `a: { class: 'btn ' + (active ? 'on' : '') }` |
@@ -26,7 +26,7 @@ How common UI operations map across frameworks. Each cell shows the idiomatic on
26
26
  | **Theme / design tokens** | Apply consistent theming | ThemeProvider / CSS vars | CSS vars / provide | CSS custom properties | CSS vars | CSS vars / createContext | `bw.loadStyles({ primary: '#hex' })` or `bw.makeStyles(cfg)` => `styles.palette` |
27
27
  | **Build step required** | Required toolchain | Yes (Babel/Vite/webpack) | Yes (Vite or Vue CLI) | No | Yes (Svelte compiler) | Yes (Vite/Babel) | **No** |
28
28
  | **Client-side routing** | Map URLs to views | React Router / TanStack Router | Vue Router | Manual `hashchange` | SvelteKit routes | @solidjs/router | `bw.router({ routes: { '/': fn } })` |
29
- | **Bundle size** | Shipped JS size | ~45KB (React + ReactDOM) | ~33KB (Vue 3) | 0KB | ~2KB (runtime) | ~7KB | **~40KB** (includes components + CSS gen + router) |
29
+ | **Bundle size** | Shipped JS size | ~45KB (React + ReactDOM) | ~33KB (Vue 3) | 0KB | ~2KB (runtime) | ~7KB | **~45KB** (includes components + CSS gen + router) |
30
30
 
31
31
  ---
32
32
 
@@ -25,7 +25,7 @@ Start here. This is a complete bitwrench page:
25
25
  bw.loadStyles({ primary: '#336699', secondary: '#cc6633' }); // themed colors
26
26
 
27
27
  bw.DOM('#app', {
28
- t: 'div', a: { class: 'bw-container' },
28
+ t: 'div', a: { class: 'bw_container' },
29
29
  c: [
30
30
  bw.makeNavbar({ brand: 'My App', items: [{ text: 'Home', href: '#' }] }),
31
31
  bw.makeCard({ title: 'Hello', content: 'Built with bitwrench.' }),
@@ -55,9 +55,9 @@ That's it. No build step. No npm install. Open the file in a browser.
55
55
  Every UI element is a plain JS object `{t, a, c, o}`:
56
56
 
57
57
  ```javascript
58
- { t: 'div', a: { class: 'card', id: 'x' }, c: 'Hello world' }
58
+ { t: 'div', a: { class: 'bw_bccl_card', id: 'x' }, c: 'Hello world' }
59
59
  // tag attributes content
60
- // => <div class="card" id="x">Hello world</div>
60
+ // => <div class="bw_bccl_card" id="x">Hello world</div>
61
61
  ```
62
62
 
63
63
  - `t` -- tag name (defaults to `'div'` if omitted)
@@ -112,17 +112,17 @@ bw.DOM('#app', { t: 'div', c: [
112
112
 
113
113
  ---
114
114
 
115
- ## Step 3: Three Levels
115
+ ## Step 3: From Data to DOM
116
116
 
117
- | Level | What | How | When |
118
- |-------|------|-----|------|
119
- | **0 -- Data** | Plain JS object | `bw.makeCard({...})` or `{t,a,c}` | Static content, SSR |
120
- | **1 -- DOM** | Rendered tree | `bw.DOM('#x', taco)` | Re-render on demand |
121
- | **2 -- Stateful** | Reactive component | `o.state` + `o.render` + `bw.update()` | Interactive UI |
117
+ | Form | What | How | When |
118
+ |------|------|-----|------|
119
+ | **Static TACO** | Plain JS object | `bw.makeCard({...})` or `{t,a,c}` | Static content, SSR |
120
+ | **Mounted TACO** | Rendered tree | `bw.DOM('#x', taco)` | Re-render on demand |
121
+ | **Stateful TACO** | Stateful component | `o.state` + `o.render` + `bw.refresh()` | Interactive UI |
122
122
 
123
- **Most UI should be Level 0.** Escalate only when needed.
123
+ **Most UI should be static TACOs.** Escalate only when needed.
124
124
 
125
- ### Level 1 -- re-render when data changes
125
+ ### Mounted -- re-render when data changes
126
126
 
127
127
  ```javascript
128
128
  var filter = 'all';
@@ -135,20 +135,19 @@ function render() {
135
135
  render();
136
136
  ```
137
137
 
138
- ### Level 2 -- stateful TACO
138
+ ### Stateful TACO
139
139
 
140
140
  ```javascript
141
141
  bw.DOM('#app', {
142
142
  t: 'div',
143
143
  o: {
144
144
  state: { count: 0 },
145
- render: function(el) {
146
- var s = el._bw_state;
145
+ render: function(el, state) {
147
146
  bw.DOM(el, { t: 'div', c: [
148
- { t: 'h3', c: 'Count: ' + s.count },
147
+ { t: 'h3', c: 'Count: ' + state.count },
149
148
  bw.makeButton({ text: '+1', onclick: function() {
150
- s.count++;
151
- bw.update(el);
149
+ state.count++;
150
+ bw.refresh(el);
152
151
  }})
153
152
  ]});
154
153
  }
@@ -156,7 +155,7 @@ bw.DOM('#app', {
156
155
  });
157
156
  ```
158
157
 
159
- **How it works:** `createDOM()` copies `o.state` to `el._bw_state`, stores `o.render` as `el._bw_render`, calls it immediately. On state change, call `bw.update(el)` to re-invoke render.
158
+ **How it works:** `bw.create()` copies `o.state` to `el._bw_state`, stores `o.render` as `el._bw_render`, calls it immediately. On state change, call `bw.refresh(el)` to re-invoke render.
160
159
 
161
160
  ---
162
161
 
@@ -164,7 +163,7 @@ bw.DOM('#app', {
164
163
 
165
164
  **Always put event handlers in `a: { onclick: fn }`, never in `o.mounted`.**
166
165
 
167
- When a stateful component re-renders (after `bw.update()`), old DOM children are replaced. Listeners attached via `addEventListener` in `o.mounted` are silently lost.
166
+ When a stateful component re-renders (after `bw.refresh()`), old DOM children are replaced. Listeners attached via `addEventListener` in `o.mounted` are silently lost.
168
167
 
169
168
  ```javascript
170
169
  // CORRECT -- re-attached on every render
@@ -187,7 +186,7 @@ bw.pub('cart:updated', { count: cart.length });
187
186
  // Subscriber (auto-cleans when element is removed)
188
187
  bw.sub('cart:updated', function(d) {
189
188
  el._bw_state.n = d.count;
190
- bw.update(el);
189
+ bw.refresh(el);
191
190
  }, el);
192
191
  ```
193
192
 
@@ -248,10 +247,10 @@ var brand = '#336699', radius = '12px';
248
247
 
249
248
  ```javascript
250
249
  bw.injectCSS(bw.css({
251
- '.card': { borderRadius: '12px', padding: '1.5rem', border: '1px solid #ddd' },
252
- '.card:hover': { boxShadow: '0 4px 12px rgba(0,0,0,.1)' },
250
+ '.bw_bccl_card': { borderRadius: '12px', padding: '1.5rem', border: '1px solid #ddd' },
251
+ '.bw_bccl_card:hover': { boxShadow: '0 4px 12px rgba(0,0,0,.1)' },
253
252
  '@keyframes fadeIn': { '0%': { opacity: '0' }, '100%': { opacity: '1' } },
254
- '@media (max-width: 768px)': { '.card': { padding: '0.75rem' } }
253
+ '@media (max-width: 768px)': { '.bw_bccl_card': { padding: '0.75rem' } }
255
254
  }));
256
255
  ```
257
256
 
@@ -280,7 +279,11 @@ bw.loadStyles({
280
279
  harmonize: 0.20 // hue shift semantics toward primary (0-1)
281
280
  });
282
281
 
283
- bw.toggleStyles(); // switch primary <=> alternate palette
282
+ // Theme switching: generate both themes and manually re-apply
283
+ var primary = bw.makeStyles({ primary: '#336699', secondary: '#cc6633' });
284
+ var dark = bw.makeStyles({ primary: '#1a1a2e', secondary: '#e94560' });
285
+ bw.applyStyles(primary); // apply primary theme
286
+ // To switch: bw.applyStyles(dark);
284
287
 
285
288
  // Or generate separately:
286
289
  var theme = bw.makeStyles({ primary: '#336699', secondary: '#cc6633' });
@@ -329,7 +332,7 @@ bw.u.css('p4 shadow') // includes your custom token
329
332
 
330
333
  ## Step 6: BCCL Components
331
334
 
332
- **Bitwrench ships ready-made components. Check the table below BEFORE writing custom TACO for common UI patterns.** All `bw.make*()` return Level 0 TACO objects. Factory dispatcher: `bw.make('card', props)`.
335
+ **Bitwrench ships ready-made components. Check the table below BEFORE writing custom TACO for common UI patterns.** All `bw.make*()` return static TACO objects. Factory dispatcher: `bw.make('card', props)`.
333
336
 
334
337
  ### Most-Used Components
335
338
 
@@ -446,12 +449,12 @@ import bwserve from 'bitwrench/bwserve';
446
449
  var app = bwserve.create({ port: 7902, allowScreenshot: true });
447
450
 
448
451
  app.page('/', function(client) {
449
- client.render('#app', myTaco);
452
+ client.mount('#app', myTaco);
450
453
 
451
454
  // Capture what the user sees
452
455
  var img = await client.screenshot('#app', { maxWidth: 800 });
453
456
  // img.data is a Buffer (PNG) -- send to vision model for evaluation
454
- // Vision model says "button is too small" => adjust TACO => re-render => screenshot again
457
+ // Vision model says "button is too small" => adjust TACO => re-mount => screenshot again
455
458
  });
456
459
  ```
457
460
 
@@ -466,31 +469,31 @@ import bwserve from 'bitwrench/bwserve';
466
469
  var app = bwserve.create({ port: 7902 });
467
470
 
468
471
  app.page('/', function(client) {
469
- // Render initial UI
470
- client.render('#app', {
472
+ // Mount initial UI
473
+ client.mount('#app', {
471
474
  t: 'div', c: [
472
475
  { t: 'h1', c: 'Hello from server' },
473
476
  { t: 'p', a: { id: 'status' }, c: 'Connected.' },
474
- { t: 'button', a: { 'data-bw-action': 'greet' }, c: 'Say hello' }
477
+ { t: 'button', a: { class: 'bw_act_greet' }, c: 'Say hello' }
475
478
  ]
476
479
  });
477
480
 
478
481
  // Incremental updates
479
- client.patch('#status', 'Processing...');
482
+ client.patch('#status', { text: 'Processing...' });
480
483
  client.append('#log', { t: 'p', c: 'New entry' });
481
484
  client.remove('.old-item');
482
485
 
483
- // Handle user actions (data-bw-action elements)
484
- client.on('greet', function() { client.patch('#status', 'Hello!'); });
486
+ // Handle user actions (bw_act_* class elements)
487
+ client.on('greet', function() { client.patch('#status', { text: 'Hello!' }); });
485
488
 
486
- // Register + call client-side functions
487
- client.register('showAlert', 'function(msg) { alert(msg); }');
488
- client.call('showAlert', 'Server says hi!');
489
+ // Call built-in client-side functions
490
+ client.call('scrollTo', '#bottom');
491
+ client.call('focus', '#search-input');
489
492
  });
490
493
  app.listen();
491
494
  ```
492
495
 
493
- **Protocol**: `replace`, `patch`, `append`, `remove`, `batch`, `message`, `register`, `call`, `exec`.
496
+ **Protocol (v2.1)**: `mount`, `patch`, `append`, `remove`, `batch`, `call`, `message`, `listen`, `unlisten`. All messages stamped `v: 1`. Wire fields: `ref` (not `target`), `taco` (not `node`).
494
497
  **Language-agnostic**: any server that writes SSE works (Python, Go, Rust, C, shell scripts).
495
498
 
496
499
  ---
@@ -580,7 +583,7 @@ bwcli serve # dev server (port 7902)
580
583
  | Function | Description |
581
584
  |----------|-------------|
582
585
  | `bw.html(taco)` | TACO to HTML string |
583
- | `bw.createDOM(taco)` | TACO to detached DOM element |
586
+ | `bw.create(taco)` | TACO to detached DOM element |
584
587
  | `bw.DOM(sel, taco)` | Mount TACO into existing element |
585
588
  | `bw.mount(sel, taco)` | Like DOM() but returns root element (for el.bw access) |
586
589
  | `bw.h(tag, a?, c?, o?)` | TACO constructor from positional args |
@@ -597,20 +600,27 @@ bwcli serve # dev server (port 7902)
597
600
  | `bw.loadStyles()` | Load structural CSS (no args) or generate+apply theme (with config) |
598
601
  | `bw.makeStyles(cfg)` | Generate styles from seed colors (returns styles object) |
599
602
  | `bw.applyStyles(styles)` | Inject generated styles into document |
600
- | `bw.toggleStyles()` | Switch primary/alternate palettes |
601
603
 
602
604
  ### State and Lifecycle
603
605
  | Function | Description |
604
606
  |----------|-------------|
605
607
  | `o.state` | Initial state (copied to `el._bw_state`) |
606
- | `o.render(el, state)` | Render function, called on mount and `bw.update()` |
608
+ | `o.render(el, state)` | Render function, called on mount and `bw.refresh()` |
607
609
  | `o.handle` | Methods attached to `el.bw` namespace |
608
610
  | `o.slots` | `{name: '.selector'}` => auto `el.bw.setName()`/`el.bw.getName()` |
609
611
  | `o.mounted(el)` | After DOM insertion (NOT for event handlers) |
610
612
  | `o.unmount(el)` | Before DOM removal |
611
- | `bw.update(el)` | Re-invoke render function |
613
+ | `bw.refresh(ref)` | Re-invoke render function |
614
+ | `bw.update(ref, data)` | Dispatch to `el.bw.update(data)` |
612
615
  | `bw.mount(sel, taco)` | Mount + return root element |
613
- | `bw.cleanup(el)` | Run unmount hooks, clear subscriptions |
616
+ | `bw.unmount(el)` | Tear down subtree lifecycle |
617
+ | `bw.mountTree(el)` | Register an inserted subtree |
618
+ | `bw.unmountChildren(el)` | Unmount descendants only |
619
+ | `bw.detach(el)` | Keep-alive disconnect |
620
+ | `bw.hydrate(el, taco)` | Wire lifecycle onto existing DOM |
621
+ | `bw.append(target, taco)` | Add child without removing existing |
622
+ | `bw.replace(ref, taco)` | Swap element at DOM position |
623
+ | `bw.remove(ref)` | Unmount + remove from DOM |
614
624
  | `bw.patch(id, content)` | Update element by id or UUID |
615
625
  | `bw.inspect(el, depth)` | Introspect DOM subtree with bitwrench metadata |
616
626
 
@@ -639,9 +649,8 @@ bwcli serve # dev server (port 7902)
639
649
  | `bw.escapeHTML(str)` | Escape HTML special chars |
640
650
  | `bw.deriveShades(hex)` | 8 shade variants from one color |
641
651
  | `bw.textOnColor(hex)` | Contrast-safe text color ('#fff' or '#000') |
642
- | `bw.random(min, max)` | Random integer (or array variant) |
643
652
  | `bw.loremIpsum(n)` | Placeholder text |
644
- | `bw.parseRJSON(str)` | Relaxed JSON (unquoted keys, trailing commas) |
653
+ | `bw.parseJSONFlex(str)` | Relaxed JSON (single-quoted keys, trailing commas, r-prefix) |
645
654
  | `bw.saveClientFile(name, data)` | Browser file download |
646
655
 
647
656
  ---
@@ -651,12 +660,12 @@ bwcli serve # dev server (port 7902)
651
660
  1. **Events in `a: { onclick: fn }`** -- never in `o.mounted`. This is the #1 mistake.
652
661
  2. **Call `bw.loadStyles()`** before rendering. Use `bw.loadStyles(config)` for themed colors.
653
662
  3. **Content is escaped by default.** Use `bw.raw(str)` for trusted HTML only.
654
- 4. **All `make*()` return Level 0 TACOs** -- pass to `bw.DOM()` or `bw.html()`.
663
+ 4. **All `make*()` return static TACOs** -- pass to `bw.DOM()` or `bw.html()`.
655
664
  5. **TACO is computation** -- every field is a JS expression. Use variables, `.map()`, ternaries.
656
665
  6. **CSS is just strings** -- store in variables, compose with `bw.s()`, generate with `bw.css()`.
657
- 7. **Three levels are explicit** -- you always know if you have data (L0), DOM (L1), or stateful (L2).
666
+ 7. **TACO forms are explicit** -- you always know if you have a static TACO, a mounted TACO, or a stateful TACO.
658
667
  8. **No raw DOM** -- use `bw.DOM()`, not `innerHTML` or `document.querySelector`.
659
- 9. **CSS classes use `bw-` prefix**: `bw-card`, `bw-btn`, `bw-container`.
668
+ 9. **CSS classes use `bw_` prefix**: `bw_bccl_card`, `bw_bccl_btn`, `bw_container`.
660
669
  10. **Routing is built in** -- `bw.router()` for SPAs. Hash mode by default, history mode optional.
661
670
  11. **Use `bw.mount()` + `el.bw`** for targeted updates. `o.handle` for methods, `o.slots` for content areas. Avoids re-render side effects (lost focus, scroll reset).
662
671
  12. **Debug**: `bw.inspect(el, 0)`, `el._bw_state`, `bwcli attach` for remote REPL.
@@ -690,11 +699,12 @@ See [TypeScript Usage Guide](bitwrench_typescript_usage.md) for full details.
690
699
 
691
700
  ---
692
701
 
693
- ## Removed APIs (v2.0.19)
702
+ ## Removed APIs (v2.1)
694
703
 
695
- `bw.component()`, `bw.compile()`, `bw.when()`, `bw.each()` -- all throw Error.
704
+ `bw.component()`, `bw.when()`, `bw.each()` -- removed (undefined).
705
+ `bw.compile()` -- throws Error with migration message.
696
706
  Replaced by `o.handle` + `o.slots` + `bw.mount()`. See Step 4.
697
707
 
698
708
  ---
699
709
 
700
- *Bitwrench: 40KB gzipped, zero dependencies, no build step. [github.com/deftio/bitwrench](https://github.com/deftio/bitwrench)*
710
+ *Bitwrench: ~45KB gzipped, zero dependencies, no build step. [github.com/deftio/bitwrench](https://github.com/deftio/bitwrench)*
package/docs/routing.md CHANGED
@@ -235,12 +235,11 @@ function dashboard() {
235
235
  state: { data: null },
236
236
  mounted: function(el) {
237
237
  fetch('/api/stats').then(function(r) { return r.json(); })
238
- .then(function(d) { el._bw_state.data = d; bw.update(el); });
238
+ .then(function(d) { el._bw_state.data = d; bw.refresh(el); });
239
239
  },
240
- render: function(el) {
241
- var s = el._bw_state;
242
- bw.DOM(el, s.data
243
- ? bw.makeTable({ data: s.data, sortable: true })
240
+ render: function(el, state) {
241
+ bw.DOM(el, state.data
242
+ ? bw.makeTable({ data: state.data, sortable: true })
244
243
  : { t: 'p', c: 'Loading...' }
245
244
  );
246
245
  }
@@ -249,7 +248,7 @@ function dashboard() {
249
248
  }
250
249
  ```
251
250
 
252
- When the router mounts this TACO, `mounted` fires, fetches data, updates state, and triggers a re-render. The route handler is just a function that returns any valid TACO -- the full component model (Level 0 through Level 2) is available.
251
+ When the router mounts this TACO, `mounted` fires, fetches data, updates state, and triggers a re-render. The route handler is just a function that returns any valid TACO -- the full component model (static TACOs, mounted components, and stateful components) is available.
253
252
 
254
253
  ---
255
254
 
@@ -405,15 +404,14 @@ function makeNav() {
405
404
  mounted: function(el) {
406
405
  bw.sub('bw:route', function(d) {
407
406
  el._bw_state.active = d.path;
408
- bw.update(el);
407
+ bw.refresh(el);
409
408
  }, el);
410
409
  },
411
- render: function(el) {
412
- var s = el._bw_state;
410
+ render: function(el, state) {
413
411
  bw.DOM(el, {
414
412
  t: 'ul', c: links.map(function(link) {
415
413
  return { t: 'li', a: {
416
- style: link.path === s.active ? 'font-weight:bold' : ''
414
+ style: link.path === state.active ? 'font-weight:bold' : ''
417
415
  }, c: bw.link(link.path, link.label) };
418
416
  })
419
417
  });
@@ -460,9 +458,9 @@ function usersPage() {
460
458
  o: {
461
459
  state: {},
462
460
  mounted: function(el) {
463
- bw.sub('store:users', function() { bw.update(el); }, el);
461
+ bw.sub('store:users', function() { bw.refresh(el); }, el);
464
462
  },
465
- render: function(el) {
463
+ render: function(el, state) {
466
464
  bw.DOM(el, bw.makeTable({
467
465
  data: store.users,
468
466
  columns: ['name', 'role', 'status'],
@@ -492,7 +490,7 @@ The client router complements bwserve's server-side `app.page()`. Use bwserve fo
492
490
  ```javascript
493
491
  // Server handles top-level pages
494
492
  app.page('/dashboard', function(client) {
495
- client.render('#app', dashboardShell());
493
+ client.mount('#app', dashboardShell());
496
494
  });
497
495
 
498
496
  // Client handles tab navigation within the dashboard