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.
- package/README.md +210 -125
- package/dist/bitwrench-bccl.cjs.js +349 -188
- package/dist/bitwrench-bccl.cjs.min.js +2 -39
- package/dist/bitwrench-bccl.cjs.min.js.gz +0 -0
- package/dist/bitwrench-bccl.esm.js +349 -188
- package/dist/bitwrench-bccl.esm.min.js +2 -39
- package/dist/bitwrench-bccl.esm.min.js.gz +0 -0
- package/dist/bitwrench-bccl.umd.js +349 -188
- package/dist/bitwrench-bccl.umd.min.js +2 -39
- package/dist/bitwrench-bccl.umd.min.js.gz +0 -0
- package/dist/bitwrench-code-edit.cjs.js +17 -6
- package/dist/bitwrench-code-edit.cjs.min.js +2 -20
- package/dist/bitwrench-code-edit.es5.js +8 -3
- package/dist/bitwrench-code-edit.es5.min.js +2 -19
- package/dist/bitwrench-code-edit.esm.js +17 -6
- package/dist/bitwrench-code-edit.esm.min.js +2 -19
- package/dist/bitwrench-code-edit.umd.js +17 -6
- package/dist/bitwrench-code-edit.umd.min.js +2 -19
- package/dist/bitwrench-code-edit.umd.min.js.gz +0 -0
- package/dist/bitwrench-debug.js +1 -1
- package/dist/bitwrench-debug.min.js +1 -1
- package/dist/bitwrench-lean.cjs.js +2492 -1628
- package/dist/bitwrench-lean.cjs.min.js +2 -80
- package/dist/bitwrench-lean.cjs.min.js.gz +0 -0
- package/dist/bitwrench-lean.es5.js +2740 -1838
- package/dist/bitwrench-lean.es5.min.js +2 -49
- package/dist/bitwrench-lean.es5.min.js.gz +0 -0
- package/dist/bitwrench-lean.esm.js +2492 -1628
- package/dist/bitwrench-lean.esm.min.js +2 -80
- package/dist/bitwrench-lean.esm.min.js.gz +0 -0
- package/dist/bitwrench-lean.umd.js +2492 -1628
- package/dist/bitwrench-lean.umd.min.js +2 -80
- package/dist/bitwrench-lean.umd.min.js.gz +0 -0
- package/dist/bitwrench-util-color.cjs.js +251 -0
- package/dist/bitwrench-util-color.cjs.min.js +3 -0
- package/dist/bitwrench-util-color.es5.js +256 -0
- package/dist/bitwrench-util-color.es5.min.js +3 -0
- package/dist/bitwrench-util-color.esm.js +241 -0
- package/dist/bitwrench-util-color.esm.min.js +3 -0
- package/dist/bitwrench-util-color.umd.js +257 -0
- package/dist/bitwrench-util-color.umd.min.js +3 -0
- package/dist/bitwrench-util-css.cjs.js +2 -1
- package/dist/bitwrench-util-css.cjs.min.js +2 -21
- package/dist/bitwrench-util-css.es5.js +2 -1
- package/dist/bitwrench-util-css.es5.min.js +2 -20
- package/dist/bitwrench-util-css.esm.js +2 -1
- package/dist/bitwrench-util-css.esm.min.js +1 -19
- package/dist/bitwrench-util-css.umd.js +2 -1
- package/dist/bitwrench-util-css.umd.min.js +2 -20
- package/dist/bitwrench-util-css.umd.min.js.gz +0 -0
- package/dist/bitwrench.cjs.js +2826 -1801
- package/dist/bitwrench.cjs.min.js +2 -99
- package/dist/bitwrench.cjs.min.js.gz +0 -0
- package/dist/bitwrench.css +403 -479
- package/dist/bitwrench.d.ts +70 -73
- package/dist/bitwrench.es5.js +3106 -2020
- package/dist/bitwrench.es5.min.js +2 -67
- package/dist/bitwrench.es5.min.js.gz +0 -0
- package/dist/bitwrench.esm.js +2826 -1801
- package/dist/bitwrench.esm.min.js +2 -99
- package/dist/bitwrench.esm.min.js.gz +0 -0
- package/dist/bitwrench.min.css +1 -1
- package/dist/bitwrench.umd.js +2826 -1801
- package/dist/bitwrench.umd.min.js +2 -99
- package/dist/bitwrench.umd.min.js.gz +0 -0
- package/dist/builds.json +222 -134
- package/dist/bwserve.cjs.js +308 -298
- package/dist/bwserve.d.ts +157 -0
- package/dist/bwserve.esm.js +309 -299
- package/dist/sri.json +54 -46
- package/docs/README.md +6 -3
- package/docs/app-patterns.md +7 -6
- package/docs/bitwrench-for-wasm.md +53 -54
- package/docs/bitwrench-mcp.md +2 -2
- package/docs/bitwrench-northstar-principles.md +406 -0
- package/docs/bitwrench-taco-schema-discussion.md +2 -2
- package/docs/bitwrench_api.md +191 -106
- package/docs/bitwrench_typescript_usage.md +5 -5
- package/docs/bw-attach.md +29 -75
- package/docs/bwserve.md +200 -168
- package/docs/cli.md +36 -12
- package/docs/component-cheatsheet.md +2 -2
- package/docs/component-library.md +4 -4
- package/docs/component-lifecycle.md +234 -0
- package/docs/drift-lint.md +268 -0
- package/docs/framework-translation-table.md +4 -4
- package/docs/llm-bitwrench-guide.md +60 -50
- package/docs/routing.md +11 -13
- package/docs/state-management.md +110 -109
- package/docs/taco-format.md +13 -14
- package/docs/theming.md +13 -3
- package/docs/thinking-in-bitwrench.md +858 -983
- package/docs/tutorial-bwserve.md +37 -36
- package/docs/tutorial-embedded.md +10 -21
- package/docs/tutorial-website.md +2 -2
- package/package.json +38 -7
- package/readme.html +262 -160
- package/src/bitwrench-bccl-entry.js +2 -2
- package/src/bitwrench-bccl.js +346 -185
- package/src/bitwrench-code-edit.js +16 -5
- package/src/bitwrench-color-utils.js +117 -181
- package/src/bitwrench-file-ops.js +2 -2
- package/src/bitwrench-lean.js +4 -3
- package/src/bitwrench-router.js +5 -2
- package/src/bitwrench-styles.js +420 -504
- package/src/bitwrench-util-color.js +240 -0
- package/src/bitwrench-util-css.js +1 -0
- package/src/bitwrench-utils.js +4 -0
- package/src/bitwrench.d.ts +70 -73
- package/src/bitwrench.h +5 -0
- package/src/bitwrench.js +1939 -933
- package/src/bwserve/attach.js +0 -1
- package/src/bwserve/bwclient.js +172 -32
- package/src/bwserve/bwshell.js +0 -4
- package/src/bwserve/client.js +59 -220
- package/src/bwserve/index.js +78 -42
- package/src/bwserve.d.ts +157 -0
- package/src/bwserve.h +5 -0
- package/src/cli/attach.js +12 -75
- package/src/cli/convert.js +2 -2
- package/src/cli/serve.js +37 -35
- package/src/generate-css.js +1 -1
- package/src/mcp/knowledge.js +4 -4
- package/src/mcp/live.js +21 -13
- package/src/mcp/tools.js +0 -1
- 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.
|
|
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.
|
|
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.
|
|
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 | **~
|
|
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: '
|
|
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: '
|
|
58
|
+
{ t: 'div', a: { class: 'bw_bccl_card', id: 'x' }, c: 'Hello world' }
|
|
59
59
|
// tag attributes content
|
|
60
|
-
// => <div class="
|
|
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:
|
|
115
|
+
## Step 3: From Data to DOM
|
|
116
116
|
|
|
117
|
-
|
|
|
118
|
-
|
|
119
|
-
| **
|
|
120
|
-
| **
|
|
121
|
-
| **
|
|
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
|
|
123
|
+
**Most UI should be static TACOs.** Escalate only when needed.
|
|
124
124
|
|
|
125
|
-
###
|
|
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
|
-
###
|
|
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: ' +
|
|
147
|
+
{ t: 'h3', c: 'Count: ' + state.count },
|
|
149
148
|
bw.makeButton({ text: '+1', onclick: function() {
|
|
150
|
-
|
|
151
|
-
bw.
|
|
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:** `
|
|
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.
|
|
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.
|
|
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
|
-
'.
|
|
252
|
-
'.
|
|
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)': { '.
|
|
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
|
-
|
|
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
|
|
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.
|
|
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-
|
|
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
|
-
//
|
|
470
|
-
client.
|
|
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: {
|
|
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 (
|
|
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
|
-
//
|
|
487
|
-
client.
|
|
488
|
-
client.call('
|
|
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**: `
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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. **
|
|
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 `
|
|
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.
|
|
702
|
+
## Removed APIs (v2.1)
|
|
694
703
|
|
|
695
|
-
`bw.component()`, `bw.
|
|
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:
|
|
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.
|
|
238
|
+
.then(function(d) { el._bw_state.data = d; bw.refresh(el); });
|
|
239
239
|
},
|
|
240
|
-
render: function(el) {
|
|
241
|
-
|
|
242
|
-
|
|
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 (
|
|
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.
|
|
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 ===
|
|
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.
|
|
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.
|
|
493
|
+
client.mount('#app', dashboardShell());
|
|
496
494
|
});
|
|
497
495
|
|
|
498
496
|
// Client handles tab navigation within the dashboard
|