@loadbare/app 0.9.0 → 0.11.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 +3 -3
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +107 -90
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/expand.d.ts +6 -1
- package/dist/build/expand.d.ts.map +1 -1
- package/dist/build/expand.js +112 -26
- package/dist/build/expand.js.map +1 -1
- package/dist/build/locations.d.ts +2 -3
- package/dist/build/locations.d.ts.map +1 -1
- package/dist/build/locations.js +2 -3
- package/dist/build/locations.js.map +1 -1
- package/dist/build/pages.d.ts +3 -4
- package/dist/build/pages.d.ts.map +1 -1
- package/dist/build/pages.js +3 -4
- package/dist/build/pages.js.map +1 -1
- package/dist/core/lb-constants.d.ts +27 -24
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +103 -168
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +64 -77
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js +40 -7
- package/dist/core/lb-types.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +47 -37
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +195 -199
- package/dist/hub/lb-apply.js.map +1 -1
- package/dist/hub/lb-hub.browser.d.ts +1 -1
- package/dist/hub/lb-hub.browser.d.ts.map +1 -1
- package/dist/hub/lb-hub.browser.js +410 -449
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/server/lb-express.d.ts +5 -5
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +35 -66
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +77 -135
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +132 -79
- package/dist/server/lb-server.js.map +1 -1
- package/docs/TECHREF-1.0.md +908 -585
- package/docs/comparison.md +243 -185
- package/docs/prior-art.md +15 -14
- package/docs/reference/builder.md +9 -3
- package/docs/reference/chrome.md +107 -56
- package/docs/reference/custom-elements.md +291 -173
- package/docs/reference/data-binding.md +381 -374
- package/docs/reference/overview.md +12 -10
- package/docs/reference/page-files.md +164 -99
- package/docs/reference/server.md +2 -2
- package/docs/reference/widgets.md +104 -110
- package/docs/roadmap.md +32 -39
- package/docs/terms-of-art.md +57 -0
- package/docs/testing.md +97 -68
- package/docs/theory.md +92 -58
- package/docs/tutorials/010-pages-and-navigation.md +20 -12
- package/docs/tutorials/020-css.md +6 -3
- package/docs/tutorials/030-html-decomposition.md +9 -7
- package/docs/tutorials/040-displaying-data.md +30 -13
- package/docs/tutorials/{050-actions.md → 050-requests.md} +25 -15
- package/docs/tutorials/060-custom-element-code.md +17 -16
- package/docs/tutorials/065-conditional-rendering.md +34 -23
- package/docs/tutorials/070-displaying-a-list.md +29 -21
- package/docs/tutorials/072-inserting-into-a-list.md +24 -16
- package/docs/tutorials/074-deleting-from-a-list.md +9 -7
- package/docs/tutorials/076-updating-a-list-item.md +11 -10
- package/docs/tutorials/080-widget-requests.md +71 -43
- package/docs/tutorials/090-using-widget-libraries.md +22 -22
- package/docs/what-does-loadbare-extend.md +124 -0
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +201 -123
- package/skills/loadbare-app/references/TECHREF-1.0.md +908 -585
- package/skills/loadbare-app/references/builder.md +9 -3
- package/skills/loadbare-app/references/chrome.md +107 -56
- package/skills/loadbare-app/references/custom-elements.md +291 -173
- package/skills/loadbare-app/references/data-binding.md +381 -374
- package/skills/loadbare-app/references/overview.md +12 -10
- package/skills/loadbare-app/references/page-files.md +164 -99
- package/skills/loadbare-app/references/server.md +2 -2
- package/skills/loadbare-app/references/widgets.md +104 -110
- package/docs/analysis-accidental-complexity.md +0 -149
- package/docs/analysis-closed-set.md +0 -210
package/docs/comparison.md
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
# Loadbare/app and current front-end frameworks
|
|
2
2
|
|
|
3
3
|
> LLM-authored, not yet revised by a person. Drafted by Claude on
|
|
4
|
-
> 2026-09-16
|
|
5
|
-
>
|
|
4
|
+
> 2026-09-16 and brought up to date with the working tree that follows
|
|
5
|
+
> `@loadbare/app` 0.9.0. Statements about other frameworks are from general
|
|
6
6
|
> knowledge of those projects as of 2026 and carry no per-claim sources.
|
|
7
7
|
|
|
8
8
|
This document states how `@loadbare/app` differs from the frameworks and
|
|
9
9
|
libraries most used for front-end development today. It repeats material
|
|
10
|
-
from [Theory](./theory.md), [TECHREF-1.0](./TECHREF-1.0.md)
|
|
11
|
-
[Prior art](./prior-art.md) and
|
|
12
|
-
[Assessing the accidental complexity claim](./analysis-accidental-complexity.md)
|
|
13
|
-
so that it can be read on its own. Where this document and
|
|
10
|
+
from [Theory](./theory.md), [TECHREF-1.0](./TECHREF-1.0.md) and
|
|
11
|
+
[Prior art](./prior-art.md) so that it can be read on its own. Where this document and
|
|
14
12
|
[Theory](./theory.md) disagree, Theory is authoritative.
|
|
15
13
|
|
|
16
14
|
Loadbare/app has not reached 1.0. The [Blockers](./TECHREF-1.0.md#blockers)
|
|
@@ -50,10 +48,11 @@ Loadbare/app is a framework for server-bound database applications. The
|
|
|
50
48
|
browser receives one HTML document containing every page as a `<template>`,
|
|
51
49
|
one script and one stylesheet. After that, only JSON rows cross the wire.
|
|
52
50
|
HTML attributes bind elements to named server queries, and one attribute,
|
|
53
|
-
`lb-
|
|
54
|
-
every request with
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
`lb-request`, turns a click, a change or a submit into a request. The
|
|
52
|
+
server answers every request with response items: one row, a set of rows,
|
|
53
|
+
or a patch to a set of rows, each named by its query. The browser-side
|
|
54
|
+
runtime, called the hub, lands those values on the elements that name the
|
|
55
|
+
query.
|
|
57
56
|
|
|
58
57
|
Compared with the client component frameworks (React, Vue, Angular, Svelte,
|
|
59
58
|
Solid), Loadbare/app has no component tree rendered at run time, no
|
|
@@ -62,7 +61,8 @@ template expressions.
|
|
|
62
61
|
|
|
63
62
|
Compared with the server-integrated meta-frameworks (Next.js, Nuxt,
|
|
64
63
|
SvelteKit, React Router 7, Astro), Loadbare/app has no server rendering and
|
|
65
|
-
no hydration, ships no server of its own, and has no route parameters
|
|
64
|
+
no hydration, ships no server of its own, and has no route parameters:
|
|
65
|
+
a path names a page, and the query parms carry everything finer.
|
|
66
66
|
|
|
67
67
|
Compared with the hypermedia libraries (htmx, Hotwire Turbo, Unpoly),
|
|
68
68
|
Loadbare/app sends JSON rather than HTML after the first load, requires a
|
|
@@ -131,22 +131,25 @@ The hub holds no application data. There is no store, no signal, no
|
|
|
131
131
|
observable, and no client cache of query results.
|
|
132
132
|
|
|
133
133
|
- A value that has landed exists in the DOM: as `textContent` or `value`, and
|
|
134
|
-
as the `lb-value`
|
|
135
|
-
-
|
|
136
|
-
`lb-key-value`.
|
|
134
|
+
as the `lb-column-value` stamp.
|
|
135
|
+
- The rows of a `rows` query exist as the live rows the hub cloned, each
|
|
136
|
+
stamped with `lb-row-live` and `lb-key-value`.
|
|
137
|
+
- The URL is a row too: the hub serves the query `lb-url`, whose columns are
|
|
138
|
+
the path, the page label and the query parms.
|
|
137
139
|
- An element hidden by `lb-show` exists inside a `<template>` standing where
|
|
138
140
|
it stood.
|
|
139
141
|
- The hub keeps two pieces of state of its own: the name of the current page,
|
|
140
|
-
and, until an insert completes,
|
|
142
|
+
and, until an insert completes, the form it gathered from.
|
|
141
143
|
|
|
142
|
-
The server is the source of truth for everything else
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
The server is the source of truth for everything else. A query takes no
|
|
145
|
+
argument from the browser; its only input is `ctx`, which the application
|
|
146
|
+
builds with `contextFor` from the Express request and the query parms.
|
|
147
|
+
Which record a page shows, a filter or a date range is a query parm, so a
|
|
148
|
+
reload, a bookmark or a mailed link runs the page's queries again and shows
|
|
149
|
+
the same state.
|
|
147
150
|
|
|
148
|
-
A URL names a page and nothing finer.
|
|
149
|
-
|
|
151
|
+
A URL's path names a page and nothing finer. Everything finer is a query
|
|
152
|
+
parm.
|
|
150
153
|
|
|
151
154
|
### Elsewhere
|
|
152
155
|
|
|
@@ -179,20 +182,22 @@ At run time the hub performs a closed set of operations:
|
|
|
179
182
|
|
|
180
183
|
| Trigger | Operation |
|
|
181
184
|
|----------------------------|----------------------------------------------------------------------------|
|
|
182
|
-
| Navigation | Clone the page's `<template>` into `<main
|
|
183
|
-
| A value for a
|
|
184
|
-
| A value for
|
|
185
|
-
| A value for a custom element |
|
|
186
|
-
| A
|
|
187
|
-
| A
|
|
185
|
+
| Navigation | Clone the page's `<template>` into `<main>`, land `lb-url` |
|
|
186
|
+
| A value for a control | Set `value`, and stamp `lb-column-value` |
|
|
187
|
+
| A value for another native element | Set `textContent`, and stamp `lb-column-value` |
|
|
188
|
+
| A value for a custom element that is not a control | Stamp `lb-column-value` |
|
|
189
|
+
| A `row` with no row template | Land it on the element itself, stamp `lb-key-value` |
|
|
190
|
+
| A new key through a row template | Clone the row template, stamp `lb-row-live` and `lb-key-value`, fill it, insert it |
|
|
191
|
+
| All rows | Place every row in the order given, remove rows whose keys did not arrive |
|
|
188
192
|
| A patch | Upsert the rows named, remove the keys named, leave other rows in place |
|
|
189
|
-
| After
|
|
193
|
+
| After rows land | Stamp `lb-query-row-count` |
|
|
190
194
|
| An `lb-show` column | Move the element into, or out of, a `<template lb-show>` |
|
|
191
|
-
| A request starts or ends | Set or remove `lb-pending` and `aria-busy`; set `lb-error` on failure
|
|
192
|
-
| An insert succeeds
|
|
195
|
+
| A request starts or ends | Set or remove `lb-request-pending` and `aria-busy`; set `lb-request-error` on failure |
|
|
196
|
+
| An insert from a form succeeds | Reset the form |
|
|
193
197
|
|
|
194
198
|
The hub finds targets with `querySelectorAll` on the attributes written in
|
|
195
|
-
the HTML.
|
|
199
|
+
the HTML. Each response item names its query, its kind and its key, so the
|
|
200
|
+
markup names none of the three beyond the query. No tree is compared with a previous tree. A response names what
|
|
196
201
|
changed, so the hub does not determine what changed. Between interactions
|
|
197
202
|
the hub runs no timers, observers or polling loops.
|
|
198
203
|
|
|
@@ -224,7 +229,7 @@ values its queries return, serialized as JSON.
|
|
|
224
229
|
|
|
225
230
|
The HTML written in `.html` files is the HTML that ships, after expansion.
|
|
226
231
|
Attribute values in the `lb-` namespace are names: a query name, a column
|
|
227
|
-
name, or
|
|
232
|
+
name, or a request name. No attribute value is an expression.
|
|
228
233
|
|
|
229
234
|
There are two kinds of placeholder, and they run at different times.
|
|
230
235
|
|
|
@@ -232,7 +237,7 @@ There are two kinds of placeholder, and they run at different times.
|
|
|
232
237
|
a whole attribute value or a whole text node. The tag supplies it with an
|
|
233
238
|
`exp-name` attribute. An unsupplied placeholder with no default drops the
|
|
234
239
|
attribute. The value becomes permanent in the shipped HTML.
|
|
235
|
-
- Run time. Data lands through `lb-
|
|
240
|
+
- Run time. Data lands through `lb-column`, `lb-query` with a row
|
|
236
241
|
`<template>`, and `lb-show`. There is no run-time interpolation into
|
|
237
242
|
attribute values or text.
|
|
238
243
|
|
|
@@ -241,8 +246,8 @@ listed as decided against in the [Roadmap](./roadmap.md#decided-against).
|
|
|
241
246
|
|
|
242
247
|
| Task | Loadbare/app | React (JSX) | Vue | Angular | Svelte | Alpine.js |
|
|
243
248
|
|-------------------|-----------------------------------------------|--------------------------------------|--------------------------------------|---------------------------------------|-------------------------------|--------------------------------------------|
|
|
244
|
-
| Show a value | `<span lb-
|
|
245
|
-
| Keyed list | `<template
|
|
249
|
+
| Show a value | `<span lb-column="name">` | `{row.name}` | `{{ row.name }}` | `{{ row.name }}` | `{row.name}` | `<span x-text="row.name">` |
|
|
250
|
+
| Keyed list | `<template>` inside `lb-query`, key from the server | `rows.map(r => <li key={r.id}>)` | `<li v-for="r in rows" :key="r.id">` | `@for (r of rows; track r.id)` | `{#each rows as r (r.id)}` | `<template x-for="r in rows" :key="r.id">` |
|
|
246
251
|
| Condition | `lb-show="column"` | `{cond && <X />}` | `v-if`, `v-show` | `@if (cond) { }` | `{#if cond}` | `x-if`, `x-show` |
|
|
247
252
|
| Expression in markup | Not supported | Any JavaScript expression | JavaScript expressions | Template expressions | JavaScript expressions | JavaScript expressions |
|
|
248
253
|
| Build-time constant | `exp-label="Name"` into `{{label}}` | A prop | A prop | An input | A prop | Not applicable |
|
|
@@ -296,20 +301,24 @@ without `.browser` is not bundled, and the build error names it.
|
|
|
296
301
|
- Light DOM throughout. Loadbare/app uses no shadow DOM.
|
|
297
302
|
- No base class. A widget extends `HTMLElement`.
|
|
298
303
|
- No props at run time. Build-time parameters arrive as `exp-` attributes.
|
|
299
|
-
Data arrives
|
|
304
|
+
Data arrives one of two ways. A form-associated custom element with a
|
|
305
|
+
`value` property is a control: the hub sets its `value`, gathers it back
|
|
306
|
+
like an `<input>`, and commits it on `change`. Any other custom element
|
|
307
|
+
receives the `lb-column-value` stamp, which it observes through
|
|
300
308
|
`attributeChangedCallback`. The browser calls that callback for an
|
|
301
309
|
attribute already present at upgrade, so first render and refresh are one
|
|
302
310
|
code path.
|
|
303
|
-
- Composition at build time. `lb-slot` marks where authored content
|
|
304
|
-
`lb-template` names additional destinations filled by
|
|
305
|
-
`<template lb-template="name">`. A definition may use other widgets; a
|
|
311
|
+
- Composition at build time. `lb-exp-slot` marks where authored content
|
|
312
|
+
goes; `lb-exp-template` names additional destinations filled by
|
|
313
|
+
`<template lb-exp-template="name">`. A definition may use other widgets; a
|
|
306
314
|
cycle is a build error.
|
|
307
|
-
- A widget
|
|
308
|
-
`CustomEvent`. The hub
|
|
309
|
-
ancestor may stop the event.
|
|
310
|
-
- A
|
|
311
|
-
|
|
312
|
-
headings. The hub does
|
|
315
|
+
- A widget may send a request by dispatching a bubbling `lb-request`
|
|
316
|
+
`CustomEvent`. The hub completes it with `query`, `key` and `values` from
|
|
317
|
+
where the element sits. An ancestor may stop the event.
|
|
318
|
+
- A custom element carrying `lb-query` and a row template may implement
|
|
319
|
+
`lbPlaceRow(el, row, template)` to decide where a row goes, and
|
|
320
|
+
`lbRowsLanded()` to build scaffolding such as group headings. The hub does
|
|
321
|
+
the cloning, matching, removal and counting.
|
|
313
322
|
- Method names beginning with `lb` on a custom element are reserved.
|
|
314
323
|
|
|
315
324
|
Widget libraries are npm packages listed in `imports.ts`. The builder scans
|
|
@@ -330,14 +339,15 @@ The following follow from the builder and hub code.
|
|
|
330
339
|
- A `.browser.ts` file is bundled by esbuild and may import any package
|
|
331
340
|
esbuild resolves. A custom element may mount another framework's component
|
|
332
341
|
tree inside itself.
|
|
333
|
-
-
|
|
334
|
-
|
|
335
|
-
`lb-request`
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
342
|
+
- A third-party form-associated custom element with a `value` property that
|
|
343
|
+
fires `change` is a control, and takes `lb-column` and `lb-request` as an
|
|
344
|
+
`<input>` does. Any other third-party element carrying `lb-request`
|
|
345
|
+
commits on `click`.
|
|
346
|
+
- A value lands on a third-party element that is not a control as the
|
|
347
|
+
`lb-column-value` stamp. The element displays it only if it observes that
|
|
348
|
+
attribute.
|
|
349
|
+
- Gathering reads controls found in the light DOM and through a form's
|
|
350
|
+
owner, which does not enter a shadow root.
|
|
341
351
|
|
|
342
352
|
### Elsewhere
|
|
343
353
|
|
|
@@ -366,27 +376,29 @@ the query string the browser is showing.
|
|
|
366
376
|
|
|
367
377
|
- An empty body asks for the page's whole query set. The server runs the
|
|
368
378
|
page's `onPageEnter`, then every query the page declares.
|
|
369
|
-
- A body
|
|
370
|
-
|
|
379
|
+
- A body carrying a request, `{ name, query, key, values }`, runs the handler
|
|
380
|
+
its name picks and then its refresh set.
|
|
381
|
+
- A request without a name answers 400. A `run` that throws answers 500.
|
|
371
382
|
|
|
372
|
-
Every response has one shape: an
|
|
383
|
+
Every response has one shape: an array of response items. Each names its
|
|
384
|
+
query, the kind and key the server declared, and one of these:
|
|
373
385
|
|
|
374
|
-
|
|
|
375
|
-
|
|
376
|
-
|
|
|
377
|
-
|
|
|
378
|
-
| `{ rows, drop }`
|
|
386
|
+
| Member | Means |
|
|
387
|
+
|------------------|-------------------------------------------------------|
|
|
388
|
+
| `row` | One row, for a query declared with `row()` |
|
|
389
|
+
| `rows` | All rows, and their order, for a query declared with `rows()` |
|
|
390
|
+
| `patch` | `{ rows, drop }` for a `rows` query: upsert these, remove these keys |
|
|
379
391
|
|
|
380
|
-
A
|
|
381
|
-
contains rows. Master-detail is a row and
|
|
382
|
-
Many masters with their details is one
|
|
383
|
-
display by a
|
|
392
|
+
A column holds one value. A set of values is a query of its own. A row
|
|
393
|
+
never contains rows. Master-detail is a row and rows answered under two
|
|
394
|
+
names. Many masters with their details is one `rows` query of joined rows,
|
|
395
|
+
grouped for display by a custom element's `lbPlaceRow`.
|
|
384
396
|
|
|
385
397
|
The application designs no endpoints, routes or serialization format. The
|
|
386
398
|
names in the markup are the keys in the page's `.queries.ts` and
|
|
387
|
-
`.requests.ts` files. The browser can reach only the queries,
|
|
388
|
-
|
|
389
|
-
server warning.
|
|
399
|
+
`.requests.ts` files. The browser can reach only the queries, declared
|
|
400
|
+
requests and `crud` entries a page declares; any other name answers `[]` and
|
|
401
|
+
logs a server warning.
|
|
390
402
|
|
|
391
403
|
Values are not converted. The hub hands each value to the browser as the
|
|
392
404
|
query produced it. Formatting a date or an amount is done in the query.
|
|
@@ -411,48 +423,54 @@ Data types are an open blocker in TECHREF-1.0.
|
|
|
411
423
|
|
|
412
424
|
### Loadbare/app
|
|
413
425
|
|
|
414
|
-
`lb-
|
|
415
|
-
is one of three
|
|
416
|
-
declares.
|
|
417
|
-
|
|
418
|
-
| `lb-
|
|
419
|
-
|
|
420
|
-
| `lb-row-insert` |
|
|
421
|
-
| `lb-row-update` |
|
|
422
|
-
| `lb-row-delete` |
|
|
423
|
-
| Any other name |
|
|
424
|
-
|
|
425
|
-
-
|
|
426
|
-
|
|
427
|
-
own `lb-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
`lb-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
-
|
|
434
|
-
-
|
|
435
|
-
|
|
426
|
+
`lb-request` names what an interaction asks for. A name beginning with
|
|
427
|
+
`lb-` is one of three requests Loadbare provides; any other name is a
|
|
428
|
+
request the page declares.
|
|
429
|
+
|
|
430
|
+
| `lb-request` | Needs | Server key |
|
|
431
|
+
|------------------|--------------------------|--------------------------------|
|
|
432
|
+
| `lb-row-insert` | `query`, `values` | `crud.<query>.rowInsert` |
|
|
433
|
+
| `lb-row-update` | `query`, `key`, `values` | `crud.<query>.rowUpdate` |
|
|
434
|
+
| `lb-row-delete` | `query`, `key` | `crud.<query>.rowDelete` |
|
|
435
|
+
| Any other name | Whatever is present | `handlers.<name>` |
|
|
436
|
+
|
|
437
|
+
- An element commits the way HTML says it does: a form on `submit`, a
|
|
438
|
+
control on `change`, anything else on `click`. A submit button commits
|
|
439
|
+
with its form, and its own `lb-request` wins over the form's, the way
|
|
440
|
+
`formaction` wins over `action`.
|
|
441
|
+
- Position comes from the document. `query` is the nearest ancestor
|
|
442
|
+
`lb-query` of what was gathered, and `key` comes from the nearest ancestor
|
|
443
|
+
row of that query. The author writes the request name and not the
|
|
444
|
+
position.
|
|
445
|
+
- Values are gathered from controls: the element alone when it carries
|
|
446
|
+
`lb-column`, a form's controls, a live row's, or the controls whose form
|
|
447
|
+
owner is the element's form owner, the HTML `form` attribute included. A
|
|
448
|
+
control carrying `lb-column` and `lb-request` sends its own column alone,
|
|
449
|
+
so one `rowUpdate` answers a form and a per-field edit.
|
|
450
|
+
- Every request has one shape, `{ name, query, key, values }`, and a
|
|
451
|
+
declared request receives the same fields.
|
|
452
|
+
- The hub does not send a request Loadbare provides that lacks what the
|
|
453
|
+
table lists, and says why in the console.
|
|
436
454
|
|
|
437
455
|
On the server, each entry has `run` and `refresh`. `run` does the work and
|
|
438
|
-
may return results, such as a `patch()
|
|
439
|
-
again. What `run` returns is laid
|
|
456
|
+
may return results, such as a `patch()`, or a new row for the URL with
|
|
457
|
+
`url()`. `refresh` names queries to run again. What `run` returns is laid
|
|
458
|
+
over the refreshed results.
|
|
440
459
|
|
|
441
|
-
The hub stamps the
|
|
460
|
+
The hub stamps the element that committed:
|
|
442
461
|
|
|
443
|
-
|
|
|
444
|
-
|
|
445
|
-
| `lb-pending`
|
|
446
|
-
| `lb-error`
|
|
462
|
+
| Stamp | Means |
|
|
463
|
+
|----------------------|------------------------------------------------------------|
|
|
464
|
+
| `lb-request-pending` | The round trip is in flight; `aria-busy="true"` is set with it |
|
|
465
|
+
| `lb-request-error` | The last round trip from this element failed |
|
|
447
466
|
|
|
448
|
-
A
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
467
|
+
A commit on an element carrying `lb-request-pending` is ignored. A round
|
|
468
|
+
trip has a ten-second deadline, after which it is aborted and treated as a
|
|
469
|
+
failure. `lb-request-error` records that a round trip failed, and carries
|
|
470
|
+
no message.
|
|
452
471
|
|
|
453
|
-
After a successful `lb-row-insert
|
|
454
|
-
|
|
455
|
-
the round trip. A failed insert resets nothing.
|
|
472
|
+
After a successful `lb-row-insert` gathered from a form, the hub resets the
|
|
473
|
+
form. A failed insert resets nothing.
|
|
456
474
|
|
|
457
475
|
The browser displays only values the server returned. There is no
|
|
458
476
|
optimistic update. Per-keystroke validation is an open question in the
|
|
@@ -482,24 +500,30 @@ roadmap.
|
|
|
482
500
|
- The path `/members` names the page `members`. The path `/` names `index`.
|
|
483
501
|
- There are no route parameters, nested routes or per-page layouts. The
|
|
484
502
|
chrome, `chrome.html`, is the one document surrounding every page.
|
|
485
|
-
- An anchor carrying `lb-
|
|
486
|
-
calls `history.pushState`, clones the page
|
|
487
|
-
fetches the page's data. An anchor without
|
|
488
|
-
link. `popstate` navigates back and forward.
|
|
503
|
+
- An anchor carrying `lb-url-link` navigates inside the application on a
|
|
504
|
+
plain primary click: the hub calls `history.pushState`, clones the page
|
|
505
|
+
template into `<main>`, then fetches the page's data. An anchor without
|
|
506
|
+
the attribute is an ordinary link. `popstate` navigates back and forward.
|
|
489
507
|
- Navigation fetches no HTML and no code. Every page's markup is already in
|
|
490
508
|
the document.
|
|
491
509
|
- The server answers every GET with the same `app.html` and status 200. A
|
|
492
510
|
path that names no page is detected in the browser, which opens a
|
|
493
|
-
`<dialog lb-unknown
|
|
494
|
-
- The hub
|
|
495
|
-
`
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
511
|
+
`<dialog lb-url-unknown>` if the chrome has one.
|
|
512
|
+
- The hub serves its own query, `lb-url`, of kind `row` and keyed by
|
|
513
|
+
`lb-path`. Its columns are `lb-path`, `lb-page-label` (the page file's
|
|
514
|
+
`<title>`, or its stub), `lb-page-unknown`, and one column per query parm,
|
|
515
|
+
bound like any server row.
|
|
516
|
+
- A control inside `lb-query="lb-url"` carrying `lb-request="lb-row-update"`
|
|
517
|
+
writes a query parm. The hub answers that request itself: it replaces the
|
|
518
|
+
history entry, or pushes one when the element carries `lb-url-push`, and
|
|
519
|
+
reloads the page's queries. A handler moves the URL by returning
|
|
520
|
+
`url({ ... })`, and the page loads there in the same round trip.
|
|
521
|
+
- The query string rides on every round trip, and the server hands its parms
|
|
522
|
+
to `contextFor`.
|
|
499
523
|
- The application must be served from the origin root. The hub reaches
|
|
500
524
|
`/lb`, `/client.js` and `/app.css` by absolute path.
|
|
501
|
-
- The hub
|
|
502
|
-
position on navigation.
|
|
525
|
+
- The hub sets `document.title` from `lb-page-label`. It does not move focus
|
|
526
|
+
or restore scroll position on navigation.
|
|
503
527
|
|
|
504
528
|
### Elsewhere
|
|
505
529
|
|
|
@@ -551,20 +575,25 @@ Checked at build time, as errors:
|
|
|
551
575
|
containing a capital
|
|
552
576
|
- slot and template errors: two slots, two templates of one name, a template
|
|
553
577
|
naming a missing destination, content in a definition with no slot
|
|
554
|
-
- `lb
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
578
|
+
- an `lb-` attribute in markup that is not one a developer writes (`lb-query`,
|
|
579
|
+
`lb-column`, `lb-show`, `lb-request`, `lb-url-link`, `lb-url-push`,
|
|
580
|
+
`lb-url-unknown`); the rest are stamps, and script never assigns them
|
|
581
|
+
- an `lb-request` value beginning with `lb-` that is not one of the three
|
|
582
|
+
requests Loadbare provides
|
|
583
|
+
- `lb-url-link` on anything but an `<a>`, `lb-url-push` without
|
|
584
|
+
`lb-request`, `lb-url-unknown` on anything but a `<dialog>` inside
|
|
585
|
+
`<lb-hub>`
|
|
586
|
+
- `lb-show` on a `<template>`, on a row template's root, or with no
|
|
587
|
+
`lb-query` around it
|
|
559
588
|
- a `.queries.ts` or `.requests.ts` with no matching page
|
|
560
589
|
|
|
561
|
-
Checked when the server starts: a query or
|
|
590
|
+
Checked when the server starts: a query or declared request name beginning
|
|
591
|
+
with `lb-`.
|
|
562
592
|
|
|
563
|
-
Not checked at build time: that an `lb-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
last two are listed under the builder blockers. A language server is a
|
|
593
|
+
Not checked at build time: that an `lb-query` name matches a declared query,
|
|
594
|
+
that an `lb-request` matches a declared request or `crud` entry, that the
|
|
595
|
+
chrome contains one `<lb-hub>` and one empty `<main>`. The first two are a
|
|
596
|
+
roadmap item; the last is listed under the builder blockers. A language server is a
|
|
568
597
|
roadmap item.
|
|
569
598
|
|
|
570
599
|
### Elsewhere
|
|
@@ -598,9 +627,10 @@ Nothing is scoped, renamed, added or removed.
|
|
|
598
627
|
with a tag is a roadmap item.
|
|
599
628
|
- Light DOM means every selector reaches every element, in the chrome and in
|
|
600
629
|
widgets.
|
|
601
|
-
- The hub stamps attributes a stylesheet can select on: `lb-value`,
|
|
602
|
-
`lb-
|
|
603
|
-
`
|
|
630
|
+
- The hub stamps attributes a stylesheet can select on: `lb-column-value`,
|
|
631
|
+
`lb-key-value`, `lb-row-live`, `lb-request-pending`, `lb-request-error`,
|
|
632
|
+
`lb-query-row-count`. An empty `rows` query is styled with
|
|
633
|
+
`[lb-query-row-count="0"]`.
|
|
604
634
|
|
|
605
635
|
### Elsewhere
|
|
606
636
|
|
|
@@ -638,8 +668,9 @@ app.get(/.*/, (_req, res) => res.sendFile(path.join(DIST, "app.html")));
|
|
|
638
668
|
|
|
639
669
|
These lines do not change as pages are added.
|
|
640
670
|
|
|
641
|
-
`contextFor(req)` returns `ctx`, which Loadbare passes to every query
|
|
642
|
-
|
|
671
|
+
`contextFor(req, parms)` returns `ctx`, which Loadbare passes to every query
|
|
672
|
+
and handler and never reads. `parms` are the query parms of the URL the
|
|
673
|
+
browser is showing. Its type is declared by the application through
|
|
643
674
|
TypeScript declaration merging on `HubContext`. Authentication, sessions,
|
|
644
675
|
logging, database access, and any ORM or business-logic layer are the
|
|
645
676
|
application's, placed in Express middleware and in `ctx`.
|
|
@@ -648,12 +679,33 @@ A page's server half:
|
|
|
648
679
|
|
|
649
680
|
| File | Exports | Contents |
|
|
650
681
|
|----------------------|------------|--------------------------------------------------------------|
|
|
651
|
-
| `<name>.queries.ts` | `queries` | Named queries, each built with `row()` or `
|
|
652
|
-
| `<name>.requests.ts` | `requests` | `onPageEnter`, `
|
|
682
|
+
| `<name>.queries.ts` | `queries` | Named queries, each built with `row(key, run)` or `rows(key, run)` |
|
|
683
|
+
| `<name>.requests.ts` | `requests` | `onPageEnter`, `handlers` by request name, `crud` by query name |
|
|
653
684
|
|
|
654
|
-
A query's
|
|
685
|
+
A query's `run` is `(ctx) => Row` or `(ctx) => Row[]`. An answer whose
|
|
655
686
|
shape disagrees with its declaration is dropped with a warning.
|
|
656
687
|
|
|
688
|
+
A page's queries are that page's view model, computed on the server: a
|
|
689
|
+
backend-for-frontend scoped to one page, whose answers are the values the
|
|
690
|
+
page shows.
|
|
691
|
+
|
|
692
|
+
| | Data layer (repository, ORM, API) | Backend-for-frontend | Loadbare/app page files |
|
|
693
|
+
|------------------|-----------------------------------|----------------------|-------------------------|
|
|
694
|
+
| Serves | Any consumer | One client application | One page |
|
|
695
|
+
| Shaped by | Entities | A client's screens | One page's elements |
|
|
696
|
+
| Answers with | Domain objects, independent of any UI | Data the client still turns into a view | Values as the page shows them, formatted and worded |
|
|
697
|
+
| Client-side work | Mapping, state, view models, components | View models, components | None: the hub lands each column on the element that names it |
|
|
698
|
+
| Keeps the rules | Yes, in code | Usually not | No: the application keeps them beneath, in its database or in code its handlers share |
|
|
699
|
+
| Reused by | Many screens | One application's screens | No other page |
|
|
700
|
+
|
|
701
|
+
A typical stack runs database, ORM or repository, service, API contract,
|
|
702
|
+
client store, view model, component and template. A Loadbare/app page keeps
|
|
703
|
+
three places: the database with the application's rules, the page files that
|
|
704
|
+
say what one page asks and answers, and the markup that says where each
|
|
705
|
+
answer goes. Reuse does not happen through a layer. Two pages showing the
|
|
706
|
+
same data repeat a query's shape or share a database view, and shared
|
|
707
|
+
wording goes in a helper module.
|
|
708
|
+
|
|
657
709
|
The data channel carries no CSRF token. Where an options argument for
|
|
658
710
|
hooks, transaction wrapping, error handling and CSRF would go is an open
|
|
659
711
|
blocker. Serving the static files from a separate origin is a roadmap item.
|
|
@@ -729,22 +781,24 @@ TECHREF-1.0 lists every name Loadbare/app owns in one cross-reference.
|
|
|
729
781
|
|
|
730
782
|
| Owned | Count | Names |
|
|
731
783
|
|-------------------------------------|-------|---------------------------------------------------------------|
|
|
732
|
-
| `lb-*`
|
|
733
|
-
|
|
|
784
|
+
| `lb-*` attributes a developer writes | 7 | `lb-query`, `lb-column`, `lb-show`, `lb-request`, `lb-url-link`, `lb-url-push`, `lb-url-unknown` |
|
|
785
|
+
| `lb-*` stamps | 8 | `lb-column-value`, `lb-key-value`, `lb-row-live`, `lb-query-row-count`, `lb-request-pending`, `lb-request-error`, `lb-page`, `lb-page-title` |
|
|
786
|
+
| `lb-*` build-time attributes | 2 | `lb-exp-slot`, `lb-exp-template` |
|
|
787
|
+
| Requests Loadbare provides | 3 | `lb-row-insert`, `lb-row-update`, `lb-row-delete` |
|
|
734
788
|
| `lb*` methods on custom elements | 2 | `lbPlaceRow`, `lbRowsLanded` |
|
|
735
789
|
| Attribute namespace for expansion | 1 | `exp-*` |
|
|
736
790
|
| Reserved tags | 1 | `<lb-hub>` |
|
|
737
791
|
| Reserved events | 1 | `lb-request` |
|
|
738
|
-
|
|
|
792
|
+
| Queries the hub serves | 1 | `lb-url`, with columns `lb-path`, `lb-page-label`, `lb-page-unknown` |
|
|
739
793
|
| Builder flags | 4 | `--src`, `--out`, `--watch`, `--minify` |
|
|
740
794
|
| Reserved file names and patterns | 8 | `chrome.html`, `imports.ts`, `*.page.html`, `*.queries.ts`, `*.requests.ts`, `<tag>.html`, `<tag>.browser.ts`, `*.css` |
|
|
741
795
|
| Reserved `package.json` keys | 1 | `loadbare.widgets` |
|
|
742
|
-
| Server functions |
|
|
743
|
-
| Browser exports | 2 | `applyRow`, `
|
|
796
|
+
| Server functions | 6 | `row`, `rows`, `patch`, `url`, `createHub`, `hubRoutes` |
|
|
797
|
+
| Browser exports | 2 | `applyRow`, `applyResponse` |
|
|
744
798
|
|
|
745
799
|
The technical reference, TECHREF-1.0.md, is 1,181 lines. Theory states that
|
|
746
800
|
the vocabulary fits in an LLM's context window, and discloses that Anthropic
|
|
747
|
-
models writing `.requests.ts` files consistently refresh a
|
|
801
|
+
models writing `.requests.ts` files consistently refresh a `rows` query after
|
|
748
802
|
returning a patch for it.
|
|
749
803
|
|
|
750
804
|
The other projects in the comparison set do not publish a comparable
|
|
@@ -757,12 +811,12 @@ cross-reference, so no count is given for them here.
|
|
|
757
811
|
- Pages and widgets are native HTML in light DOM. Loadbare/app adds no ARIA
|
|
758
812
|
roles and no elements of its own except `<lb-hub>`, `<template>` for
|
|
759
813
|
absent branches, and the custom elements an application writes.
|
|
760
|
-
- `aria-busy="true"` is set and removed with `lb-pending`.
|
|
814
|
+
- `aria-busy="true"` is set and removed with `lb-request-pending`.
|
|
761
815
|
- An element hidden by `lb-show` is inside template content, so it is not in
|
|
762
816
|
the accessibility tree.
|
|
763
817
|
- A widget's markup is in the document and in view-source.
|
|
764
|
-
- On navigation the hub
|
|
765
|
-
|
|
818
|
+
- On navigation the hub sets `document.title` from the page's `<title>`. It
|
|
819
|
+
does not move focus or announce the new page.
|
|
766
820
|
- Checkboxes and radio buttons are not implemented for landing or gathering.
|
|
767
821
|
|
|
768
822
|
### Elsewhere
|
|
@@ -808,7 +862,7 @@ The documentation describes no testing approach for applications.
|
|
|
808
862
|
|
|
809
863
|
### Loadbare/app
|
|
810
864
|
|
|
811
|
-
Loadbare/app is at 0.
|
|
865
|
+
Loadbare/app is at 0.9.0 and has not reached 1.0. TECHREF-1.0 lists items
|
|
812
866
|
to decide before 1.0 because they would be breaking changes afterward.
|
|
813
867
|
Theory states that 1.0 is scoped so that foreseeable features can be added
|
|
814
868
|
without breaking existing code.
|
|
@@ -853,14 +907,14 @@ Loadbare's history begins with Andromeda in 2003, whose data layer is now
|
|
|
853
907
|
Each item is current behavior or an open item named in TECHREF-1.0 or the
|
|
854
908
|
Roadmap.
|
|
855
909
|
|
|
856
|
-
| Area | Status in 0.
|
|
910
|
+
| Area | Status in the working tree after 0.9.0 |
|
|
857
911
|
|-------------------------------|------------------------------------------------------------------------|
|
|
858
912
|
| Nested data | A row never holds rows. Trees are sent as joined rows. |
|
|
859
|
-
| Record URLs and view parameters | A
|
|
860
|
-
| Query arguments from the browser | None.
|
|
913
|
+
| Record URLs and view parameters | A path names a page. A record or a filter is a query parm, `/accounts?acct=23`. |
|
|
914
|
+
| Query arguments from the browser | None. Query parms reach queries through `contextFor` and `ctx`. |
|
|
861
915
|
| Checkboxes, radio buttons, file inputs | Not landed and not gathered. Open blocker. |
|
|
862
916
|
| Data types and formatting | No conversion. Queries format values. Open blocker. |
|
|
863
|
-
| Error messages | `lb-error` carries no message.
|
|
917
|
+
| Error messages | `lb-request-error` carries no message. |
|
|
864
918
|
| Field validation | No mechanism. Per-keystroke validation is a roadmap question. |
|
|
865
919
|
| Optimistic updates | None. |
|
|
866
920
|
| Concurrent writers | No version or conflict check. Roadmap question. |
|
|
@@ -870,7 +924,7 @@ Roadmap.
|
|
|
870
924
|
| Subpath hosting | Not possible. The hub uses absolute paths. |
|
|
871
925
|
| Chrome-level queries | A widget in the chrome bound to a query requires every page to declare it. Open blocker. |
|
|
872
926
|
| A widget receiving a whole row | Not available. Open blocker. |
|
|
873
|
-
| A nested
|
|
927
|
+
| A nested `rows` query per outer row | A nested query receives the same rows in every outer row. A new outer row's nested query stays empty until its name lands again. Open blocker. |
|
|
874
928
|
| Configurable request deadline | Fixed at ten seconds. |
|
|
875
929
|
| Internationalization | Roadmap item. |
|
|
876
930
|
| Lazy page loading | Roadmap item. |
|
|
@@ -893,14 +947,14 @@ one set of accidental complexity for another, and that the system is
|
|
|
893
947
|
The table lists requirements an application may have, and whether each
|
|
894
948
|
approach provides them without additional libraries.
|
|
895
949
|
|
|
896
|
-
| Requirement | Loadbare/app 0.
|
|
950
|
+
| Requirement | Loadbare/app 0.9 | Client component + API | Meta-frameworks | Hypermedia | Server-driven stateful |
|
|
897
951
|
|-----------------------------------------------|--------------------|------------------------|-----------------|------------|------------------------|
|
|
898
952
|
| Pages bound to relational query results | yes | application code | application code | server templates | server templates |
|
|
899
953
|
| No endpoint or route design | yes | no | partly (actions, loaders) | no | partly (routes, events) |
|
|
900
954
|
| No client-side state management | yes | no | no | yes | yes |
|
|
901
955
|
| No build step | no | no | no | yes | depends on stack |
|
|
902
956
|
| Server-rendered HTML for crawlers | no | no | yes | yes | yes |
|
|
903
|
-
| Route parameters and record URLs |
|
|
957
|
+
| Route parameters and record URLs | query parms only | yes | yes | yes | yes |
|
|
904
958
|
| Optimistic updates | no | yes | yes | no | partly |
|
|
905
959
|
| Offline or local-first operation | no | with libraries | with libraries | no | no |
|
|
906
960
|
| Real-time server push | no | with libraries | with libraries | extensions, Turbo Streams over WebSocket | yes |
|
|
@@ -921,7 +975,7 @@ approach provides them without additional libraries.
|
|
|
921
975
|
| Components | Light-DOM custom elements | Framework components | Framework components | Server partials; Stimulus controllers | Server components |
|
|
922
976
|
| Wire | One POST endpoint, JSON rows | Application-designed | Framework-defined | HTML over HTTP | WebSocket or snapshot POSTs |
|
|
923
977
|
| Mutation refresh | Declared `refresh` names; patches | Application code or query invalidation | Revalidation | Response HTML | Re-render |
|
|
924
|
-
| Routing | Flat page names;
|
|
978
|
+
| Routing | Flat page names; query parms | Router library | File-based, with parameters and layouts | Server routes | Server routes |
|
|
925
979
|
| Build | `loadbare-app-build`, esbuild | Vite and others | Vite, Turbopack, others | None required | Stack-specific |
|
|
926
980
|
| CSS | Concatenated, unscoped | Varies | Varies, scoped options | None | None built in |
|
|
927
981
|
| Server | Application's Express app | Application's API | Framework server or adapters | Any | Phoenix, Laravel, ASP.NET Core |
|
|
@@ -936,18 +990,19 @@ row, so the invoice is refreshed.
|
|
|
936
990
|
|
|
937
991
|
```html
|
|
938
992
|
<!-- invoice.page.html -->
|
|
939
|
-
<
|
|
940
|
-
|
|
941
|
-
<
|
|
993
|
+
<title>Invoice</title>
|
|
994
|
+
<section lb-query="invoice">
|
|
995
|
+
<h2 lb-column="number"></h2>
|
|
996
|
+
<span lb-column="customer"></span>
|
|
942
997
|
</section>
|
|
943
998
|
|
|
944
999
|
<table>
|
|
945
|
-
<tbody lb-
|
|
946
|
-
<template
|
|
1000
|
+
<tbody lb-query="invoiceLines">
|
|
1001
|
+
<template>
|
|
947
1002
|
<tr>
|
|
948
|
-
<td lb-
|
|
949
|
-
<td lb-
|
|
950
|
-
<td><button lb-
|
|
1003
|
+
<td lb-column="item"></td>
|
|
1004
|
+
<td lb-column="amount"></td>
|
|
1005
|
+
<td><button lb-request="lb-row-delete">Remove</button></td>
|
|
951
1006
|
</tr>
|
|
952
1007
|
</template>
|
|
953
1008
|
</tbody>
|
|
@@ -956,11 +1011,11 @@ row, so the invoice is refreshed.
|
|
|
956
1011
|
|
|
957
1012
|
```ts
|
|
958
1013
|
// invoice.queries.ts
|
|
959
|
-
import {
|
|
1014
|
+
import { row, rows, type Queries } from "@loadbare/app/server";
|
|
960
1015
|
|
|
961
1016
|
export const queries: Queries = {
|
|
962
|
-
invoice: row((ctx) => ctx.db.
|
|
963
|
-
invoiceLines:
|
|
1017
|
+
invoice: row("id", (ctx) => ctx.db.invoice(ctx.invoiceId)),
|
|
1018
|
+
invoiceLines: rows("id", (ctx) => ctx.db.invoiceLines(ctx.invoiceId)),
|
|
964
1019
|
};
|
|
965
1020
|
```
|
|
966
1021
|
|
|
@@ -972,9 +1027,9 @@ export const requests: Requests = {
|
|
|
972
1027
|
crud: {
|
|
973
1028
|
invoiceLines: {
|
|
974
1029
|
rowDelete: {
|
|
975
|
-
run: async (ctx,
|
|
976
|
-
await ctx.db.deleteLine(
|
|
977
|
-
return { invoiceLines: patch({ drop: [
|
|
1030
|
+
run: async (ctx, { key }) => {
|
|
1031
|
+
await ctx.db.deleteLine(key);
|
|
1032
|
+
return { invoiceLines: patch({ drop: [key] }) };
|
|
978
1033
|
},
|
|
979
1034
|
refresh: ["invoice"],
|
|
980
1035
|
},
|
|
@@ -983,11 +1038,13 @@ export const requests: Requests = {
|
|
|
983
1038
|
};
|
|
984
1039
|
```
|
|
985
1040
|
|
|
986
|
-
Which invoice is current is
|
|
987
|
-
|
|
988
|
-
flight. The
|
|
989
|
-
|
|
990
|
-
|
|
1041
|
+
Which invoice is current is a query parm, `/invoice?id=7`, which
|
|
1042
|
+
`contextFor` puts on `ctx` as `invoiceId`. The button carries
|
|
1043
|
+
`lb-request-pending` and `aria-busy` while the request is in flight. The
|
|
1044
|
+
request sent is
|
|
1045
|
+
`{ "name": "lb-row-delete", "query": "invoiceLines", "key": "42" }`. The
|
|
1046
|
+
response carries two response items: the refreshed `invoice` row and a
|
|
1047
|
+
patch dropping key `42`.
|
|
991
1048
|
|
|
992
1049
|
### Next.js (App Router)
|
|
993
1050
|
|
|
@@ -1097,28 +1154,29 @@ Each equivalent is approximate.
|
|
|
1097
1154
|
| Hub | Client runtime; router plus data layer |
|
|
1098
1155
|
| Chrome (`chrome.html`) | Root layout (`app/layout.tsx`, `+layout.svelte`); application shell |
|
|
1099
1156
|
| Page (`<name>.page.html`) | Route component; page template |
|
|
1100
|
-
| Query (`row()`, `
|
|
1157
|
+
| Query (`row()`, `rows()`) | Loader (React Router 7); load function (SvelteKit); data read in a Server Component |
|
|
1101
1158
|
| `onPageEnter` | LiveView `mount`; code at the top of a loader |
|
|
1102
|
-
| Declared
|
|
1159
|
+
| Declared request (`handlers`) | Route action (React Router 7); form action (SvelteKit); Server Function; LiveView `handle_event` |
|
|
1103
1160
|
| `crud` operation | Resource controller action (Rails); REST verb on a row |
|
|
1104
1161
|
| `refresh` | Revalidation; `invalidateQueries`; `revalidatePath` |
|
|
1105
1162
|
| `patch({ rows, drop })` | Keyed partial update; Turbo Stream `append`/`replace`/`remove`; LiveView `stream_insert`/`stream_delete` |
|
|
1106
1163
|
| Landing | Render and commit; swap; patch |
|
|
1107
|
-
| `lb-
|
|
1108
|
-
| `
|
|
1164
|
+
| `lb-query`, `lb-column` | IE4 `DATASRC` and `DATAFLD`; `v-for` and `{{ }}`; `x-for` and `x-text` |
|
|
1165
|
+
| Key declared by `row()`/`rows()` | `key` (React, Vue); `track` (Angular); keyed `each` (Svelte) |
|
|
1109
1166
|
| `lb-show` | `v-if`, `@if`, `{#if}`, `x-if` |
|
|
1110
|
-
| `lb-value`
|
|
1111
|
-
| `lb-
|
|
1167
|
+
| `lb-column-value` | A prop; an observed attribute |
|
|
1168
|
+
| `lb-request` | `hx-post`; `phx-click`; `wire:click`; `<form action>` |
|
|
1112
1169
|
| `lb-request` event | `htmx:beforeRequest`; a component `emit` |
|
|
1113
|
-
| `lb-pending`
|
|
1114
|
-
| `lb-error`
|
|
1115
|
-
| `lb-row-count`
|
|
1116
|
-
| `lb-
|
|
1117
|
-
| `lb-
|
|
1170
|
+
| `lb-request-pending` | `htmx-request` class; `phx-click-loading`; `useFormStatus().pending`; `wire:loading` |
|
|
1171
|
+
| `lb-request-error` | `htmx:responseError`; an error boundary |
|
|
1172
|
+
| `lb-query-row-count` | An empty-state conditional in a template |
|
|
1173
|
+
| `lb-url-link` | `<Link>`; `hx-boost`; Turbo Drive |
|
|
1174
|
+
| `lb-url` | `useLocation` and `useSearchParams`; `page.url` (SvelteKit); `$route` (Vue Router) |
|
|
1175
|
+
| `url()` from a handler | A redirect after POST; `redirect()` in a Server Function |
|
|
1118
1176
|
| Widget | Component; custom element |
|
|
1119
1177
|
| Expansion | Server-side include; partial; build-time component render (Astro) |
|
|
1120
1178
|
| `exp-` parameter | A prop fixed at build time |
|
|
1121
|
-
| `lb-slot`, `lb-template`
|
|
1179
|
+
| `lb-exp-slot`, `lb-exp-template` | Default slot and named slots; `ng-content` with `select` |
|
|
1122
1180
|
| `lbPlaceRow`, `lbRowsLanded` | Custom list rendering; a render prop |
|
|
1123
1181
|
| `ctx` / `HubContext` | `event.locals` (SvelteKit); loader `context` (React Router 7); request-scoped dependency injection |
|
|
1124
1182
|
| `imports.ts` | Installing and registering a component library |
|