@loadbare/app 0.13.0 → 0.15.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/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +31 -1
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/elements.d.ts +12 -2
- package/dist/build/elements.d.ts.map +1 -1
- package/dist/build/elements.js +44 -10
- package/dist/build/elements.js.map +1 -1
- package/dist/core/lb-constants.d.ts +13 -2
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +50 -3
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +52 -8
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +22 -3
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +82 -37
- package/dist/hub/lb-apply.js.map +1 -1
- package/dist/hub/lb-hub.browser.d.ts.map +1 -1
- package/dist/hub/lb-hub.browser.js +382 -26
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/hub/lb-lifecycle.d.ts +40 -0
- package/dist/hub/lb-lifecycle.d.ts.map +1 -0
- package/dist/hub/lb-lifecycle.js +140 -0
- package/dist/hub/lb-lifecycle.js.map +1 -0
- package/dist/server/lb-express.d.ts +13 -3
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +30 -12
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +31 -1
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +112 -2
- package/dist/server/lb-server.js.map +1 -1
- package/docs/TECHREF-1.0.md +343 -68
- package/docs/comparison.md +13 -9
- package/docs/possible-ideas.md +152 -26
- package/docs/reference/custom-elements.md +203 -88
- package/docs/reference/data-binding.md +310 -11
- package/docs/reference/page-files.md +76 -3
- package/docs/reference/server.md +20 -0
- package/docs/reference/widgets.md +35 -12
- package/docs/roadmap.md +9 -2
- package/docs/testing.md +2 -2
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +70 -23
- package/skills/loadbare-app/references/TECHREF-1.0.md +343 -68
- package/skills/loadbare-app/references/custom-elements.md +203 -88
- package/skills/loadbare-app/references/data-binding.md +310 -11
- package/skills/loadbare-app/references/page-files.md +76 -3
- package/skills/loadbare-app/references/server.md +20 -0
- package/skills/loadbare-app/references/widgets.md +35 -12
package/docs/comparison.md
CHANGED
|
@@ -319,10 +319,11 @@ without `.browser` is not bundled, and the build error names it.
|
|
|
319
319
|
- A widget may send a request by dispatching a bubbling `lb-request`
|
|
320
320
|
`CustomEvent`. The hub completes it with `query`, `key` and `values` from
|
|
321
321
|
where the element sits. An ancestor may stop the event.
|
|
322
|
-
- A custom element
|
|
323
|
-
`
|
|
324
|
-
|
|
325
|
-
|
|
322
|
+
- A custom element hears the hub's lifecycle rather than the browser's:
|
|
323
|
+
`lbAttached()` and `lbDetached()` once each, when the hub places and
|
|
324
|
+
removes it, `lbRowsLanded()` once rows land on it, and `lbRequestDone()`
|
|
325
|
+
when a request from inside it finishes. The hub does the cloning,
|
|
326
|
+
matching, ordering, grouping, removal and counting.
|
|
326
327
|
- Method names beginning with `lb` on a custom element are reserved.
|
|
327
328
|
|
|
328
329
|
Widget libraries are npm packages listed in `imports.ts`. The builder scans
|
|
@@ -467,11 +468,13 @@ The hub stamps the element that committed:
|
|
|
467
468
|
|----------------------|------------------------------------------------------------|
|
|
468
469
|
| `lb-request-pending` | The round trip is in flight; `aria-busy="true"` is set with it |
|
|
469
470
|
| `lb-request-error` | The last round trip from this element failed |
|
|
471
|
+
| `lb-request-refused` | The handler refused it, carrying its message |
|
|
470
472
|
|
|
471
473
|
A commit on an element carrying `lb-request-pending` is ignored. A round
|
|
472
474
|
trip has a ten-second deadline, after which it is aborted and treated as a
|
|
473
475
|
failure. `lb-request-error` records that a round trip failed, and carries
|
|
474
|
-
no message.
|
|
476
|
+
no message. A handler's `refusal()` carries words for the user, shown on the
|
|
477
|
+
element and on each control it names.
|
|
475
478
|
|
|
476
479
|
After a successful `lb-row-insert` gathered from a form, the hub resets the
|
|
477
480
|
form. A failed insert resets nothing.
|
|
@@ -789,7 +792,7 @@ TECHREF-1.0 lists every name Loadbare/app owns in one cross-reference.
|
|
|
789
792
|
| `lb-*` stamps | 17 | `lb-column-value`, `lb-key-value`, `lb-row-live`, `lb-query-row-count`, `lb-group-live`, `lb-group-column`, `lb-group-value`, `lb-row-created`, `lb-row-changed`, `lb-row-moved`, `lb-row-requested`, `lb-row-leaving`, `lb-group-leaving`, `lb-request-pending`, `lb-request-error`, `lb-page`, `lb-page-title` |
|
|
790
793
|
| `lb-*` build-time attributes | 2 | `lb-exp-slot`, `lb-exp-template` |
|
|
791
794
|
| Requests Loadbare provides | 3 | `lb-row-insert`, `lb-row-update`, `lb-row-delete` |
|
|
792
|
-
| `lb*` methods on custom elements |
|
|
795
|
+
| `lb*` methods on custom elements | 4 | `lbAttached`, `lbRowsLanded`, `lbRequestDone`, `lbDetached` |
|
|
793
796
|
| Query parms Loadbare reads | 1 | `lb-order-<query>` |
|
|
794
797
|
| Attribute namespace for expansion | 1 | `exp-*` |
|
|
795
798
|
| Reserved tags | 1 | `<lb-hub>` |
|
|
@@ -822,7 +825,7 @@ cross-reference, so no count is given for them here.
|
|
|
822
825
|
- A widget's markup is in the document and in view-source.
|
|
823
826
|
- On navigation the hub sets `document.title` from the page's `<title>`. It
|
|
824
827
|
does not move focus or announce the new page.
|
|
825
|
-
-
|
|
828
|
+
- Radio buttons are not implemented for landing or gathering.
|
|
826
829
|
|
|
827
830
|
### Elsewhere
|
|
828
831
|
|
|
@@ -917,9 +920,9 @@ Roadmap.
|
|
|
917
920
|
| Nested data | A row never holds rows. Trees are sent as joined rows. |
|
|
918
921
|
| Record URLs and view parameters | A path names a page. A record or a filter is a query parm, `/accounts?acct=23`. |
|
|
919
922
|
| Query arguments from the browser | None. Query parms reach queries through `contextFor` and `ctx`. |
|
|
920
|
-
|
|
|
923
|
+
| Radio buttons, file inputs | Not landed and not gathered. Radio buttons are an open blocker. Checkboxes land and gather as `true` and `false`. |
|
|
921
924
|
| Data types and formatting | No conversion. Queries format values. Open blocker. |
|
|
922
|
-
| Error messages | `
|
|
925
|
+
| Error messages | A handler's `refusal()` reaches the user; any other failure carries no message. |
|
|
923
926
|
| Field validation | No mechanism. Per-keystroke validation is a roadmap question. |
|
|
924
927
|
| Optimistic updates | None. |
|
|
925
928
|
| Concurrent writers | No version or conflict check. Roadmap question. |
|
|
@@ -1183,6 +1186,7 @@ Each equivalent is approximate.
|
|
|
1183
1186
|
| `exp-` parameter | A prop fixed at build time |
|
|
1184
1187
|
| `lb-exp-slot`, `lb-exp-template` | Default slot and named slots; `ng-content` with `select` |
|
|
1185
1188
|
| `lbRowsLanded` | An effect after a list renders |
|
|
1189
|
+
| `lbAttached`, `lbDetached` | Mount and unmount; `onMounted` and `onUnmounted` (Vue); `onMount` and `onDestroy` (Svelte) |
|
|
1186
1190
|
| `order`, `lb-group` | `ORDER BY` with report-writer control breaks (`BREAK ON`, group bands) |
|
|
1187
1191
|
| `ctx` / `HubContext` | `event.locals` (SvelteKit); loader `context` (React Router 7); request-scoped dependency injection |
|
|
1188
1192
|
| `imports.ts` | Installing and registering a component library |
|
package/docs/possible-ideas.md
CHANGED
|
@@ -4,6 +4,57 @@
|
|
|
4
4
|
> 2026-10-02 against `@loadbare/app` 0.12.0, from a session in ef. Nothing
|
|
5
5
|
> here is decided or planned.
|
|
6
6
|
|
|
7
|
+
> **Status, 2026-10-04.** The lifecycle in the hub's terms was adopted, on
|
|
8
|
+
> custom elements rather than on behaviors: see
|
|
9
|
+
> [When its code runs](./reference/custom-elements.md#when-its-code-runs).
|
|
10
|
+
> Behavior by attribute, and expansion that replaces the tag, were set aside.
|
|
11
|
+
> What follows is kept as the record of how the decision was reached.
|
|
12
|
+
|
|
13
|
+
## Why these are being considered
|
|
14
|
+
|
|
15
|
+
A custom element is the platform's one way to attach code to markup, and
|
|
16
|
+
widget work keeps running into what that costs.
|
|
17
|
+
|
|
18
|
+
- No decomposition. Code that concerns one row has nowhere to live but a
|
|
19
|
+
wrapper around the whole table, so `lb-table` owns everything inside it.
|
|
20
|
+
That is how page-specific behavior ends up in a shared widget: the COA
|
|
21
|
+
page's ghost row per section grew because row-level code could attach
|
|
22
|
+
only to the table. It is the overfit the README's test guards against.
|
|
23
|
+
- The browser's lifecycle is not the hub's. A moved row is disconnected and
|
|
24
|
+
connected, the copy a move leaves behind is constructed, and an `lb-show`
|
|
25
|
+
toggle adopts twice, so `connectedCallback` must be written to run again.
|
|
26
|
+
- Clutter. The page's source is the widget's dialect of named templates
|
|
27
|
+
rather than HTML, and the shipped page keeps a wrapper tag around what it
|
|
28
|
+
expanded.
|
|
29
|
+
- Plumbing through the wrapper. The tag carrying the code is not the
|
|
30
|
+
control: `WrappedControl` forwards `value`, fires `change` again, and needs
|
|
31
|
+
`ElementInternals` to join a form. Focus is searched for inside the
|
|
32
|
+
wrapper, and `autofocus` on a wrapped `<input>` is lost.
|
|
33
|
+
- Content models reach forms too. A `<form>` cannot wrap a `<tr>`, so the
|
|
34
|
+
ghost row joins its controls to a hidden form outside the table by the
|
|
35
|
+
`form` attribute. A form cannot hold a form, so `lb-insert-dialog` is
|
|
36
|
+
written once outside every row instead of beside the control it serves.
|
|
37
|
+
- Ids repeat in a row template. `lb-confirm` finds its dialog by position,
|
|
38
|
+
because `commandfor`, HTML's own way to open one with no script, works
|
|
39
|
+
only by id.
|
|
40
|
+
- Upgrade timing is the hub's problem. An element shipped inside an
|
|
41
|
+
`lb-show` template, or whose definition loads late, has not upgraded, so
|
|
42
|
+
the hub keeps `waiting()`, lands kept answers again once it upgrades, and
|
|
43
|
+
stamps `lb-column-value` for a control to take up on first connect.
|
|
44
|
+
- A few lines cost a wrapper. `lb-options` has a script mostly to copy
|
|
45
|
+
`lb-group-value` into an `<optgroup>`'s `label` and each key into an
|
|
46
|
+
option's `value`, and for that the whole `<select>` sits inside a custom
|
|
47
|
+
element.
|
|
48
|
+
- Parameters cannot carry structure. Expansion parameters are words, so
|
|
49
|
+
when groups became a template, `lb-picker` lost `exp-group` and a grouped
|
|
50
|
+
picker went back to a hand-written `lb-options`.
|
|
51
|
+
- CSS and accessibility see an element HTML does not define. A wrapper tag
|
|
52
|
+
has no role, shifts child and `:nth-child` selectors, and has no place in
|
|
53
|
+
a table. The usual remedy, `display: contents`, has a history of
|
|
54
|
+
accessibility bugs.
|
|
55
|
+
- One element, one class. A ghost row that should also save as it is typed
|
|
56
|
+
in needs a widget combining the two.
|
|
57
|
+
|
|
7
58
|
## Code on elements the parser constrains
|
|
8
59
|
|
|
9
60
|
Loadbare's data vocabulary is attributes, and an attribute goes on any
|
|
@@ -20,7 +71,8 @@ table. Each new need is another named destination, and the page's source
|
|
|
20
71
|
reads as `lb-table`'s shape rather than a table's. The shipped HTML is
|
|
21
72
|
honest; the source is a dialect.
|
|
22
73
|
|
|
23
|
-
Two ways to put code on the element itself follow
|
|
74
|
+
Two ways to put code on the element itself follow, and only the second
|
|
75
|
+
survives.
|
|
24
76
|
|
|
25
77
|
### Customized built-ins
|
|
26
78
|
|
|
@@ -28,25 +80,11 @@ Two ways to put code on the element itself follow.
|
|
|
28
80
|
<tr is="lb-ghost-row">…</tr>
|
|
29
81
|
```
|
|
30
82
|
|
|
31
|
-
The platform's own answer: a class extending `HTMLTableRowElement`,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- Chrome and Firefox ship it. WebKit has declined to, on principle
|
|
37
|
-
(subclassing a built-in breaks when its internals change), so Safari needs
|
|
38
|
-
a polyfill for as long as the feature exists.
|
|
39
|
-
- Every browser on iOS and iPadOS is WebKit, Chrome included. The polyfill
|
|
40
|
-
is therefore not a Safari fallback but the code path on every iPhone and
|
|
41
|
-
iPad, permanently. The usual one, `@ungap/custom-elements`, watches the
|
|
42
|
-
document with a `MutationObserver`, so on those devices the lifecycle runs
|
|
43
|
-
because something noticed.
|
|
44
|
-
- `is` must be present when the element is created; setting it later does
|
|
45
|
-
nothing. Cloning a template preserves it, so a row template carrying
|
|
46
|
-
`is` yields upgraded rows.
|
|
47
|
-
- A customized built-in cannot be form-associated (`ElementInternals` is for
|
|
48
|
-
autonomous custom elements), which matters little: the built-in elements
|
|
49
|
-
that controls are already take part in forms.
|
|
83
|
+
The platform's own answer: a class extending `HTMLTableRowElement`, which
|
|
84
|
+
the parser treats as a `<tr>`. WebKit has declined to ship it, and every
|
|
85
|
+
browser on iOS and iPadOS is WebKit, so a polyfill, usually a
|
|
86
|
+
`MutationObserver`, would be the code path on every iPhone and iPad for
|
|
87
|
+
good. That rules it out.
|
|
50
88
|
|
|
51
89
|
### Behavior by attribute
|
|
52
90
|
|
|
@@ -114,13 +152,12 @@ A rule for choosing: a custom element makes a new kind of element (its own
|
|
|
114
152
|
markup, expansion, or a control built from scratch); a behavior adds code to
|
|
115
153
|
an element HTML already has.
|
|
116
154
|
|
|
117
|
-
### Where
|
|
155
|
+
### Where it would land
|
|
118
156
|
|
|
119
|
-
|
|
120
|
-
that need it, and leaves `lb-table` to supply only what is truly
|
|
121
|
-
table's.
|
|
122
|
-
|
|
123
|
-
matrix out of it, at the cost of a lifecycle the hub would define.
|
|
157
|
+
Behavior by attribute lets a page write a real `<table lb-query>` with code
|
|
158
|
+
on the rows that need it, and leaves `lb-table` to supply only what is truly
|
|
159
|
+
the table's. It keeps the parser and the browser matrix out of it, at the
|
|
160
|
+
cost of a lifecycle the hub would define.
|
|
124
161
|
|
|
125
162
|
## Expansion that replaces the tag
|
|
126
163
|
|
|
@@ -186,3 +223,92 @@ source, the `lb-behavior` attribute and the comment already give.
|
|
|
186
223
|
the page passes them as parameters (`exp-column`, written into the file as
|
|
187
224
|
`lb-column="{{column}}"`), which works today but reads less naturally
|
|
188
225
|
than `lb-column`. This wants worked examples before a rule.
|
|
226
|
+
|
|
227
|
+
## The case for behaviors
|
|
228
|
+
|
|
229
|
+
Today's model is simple to state: a widget is a name, and a name is one or
|
|
230
|
+
both of a `.html` and a `.browser.ts`. One name is one element the
|
|
231
|
+
developer writes, so what a widget does is easy to predict. Most of what
|
|
232
|
+
that costs is paid inside Loadbare, in service of the simple model. The one
|
|
233
|
+
place it leaks to the developer is the lifecycle, where a widget author must
|
|
234
|
+
follow strict rules to get the behavior they expect.
|
|
235
|
+
|
|
236
|
+
Behaviors would simplify the hub, but they seem to spread code that a
|
|
237
|
+
custom element keeps in one file. The containment comes from the element
|
|
238
|
+
file, though, not from the tag.
|
|
239
|
+
|
|
240
|
+
### What one file bundles today
|
|
241
|
+
|
|
242
|
+
`lb-table`'s script does three jobs, joined by where they sit rather than by
|
|
243
|
+
any data they share:
|
|
244
|
+
|
|
245
|
+
| Job | Reads and writes |
|
|
246
|
+
| -------------------------- | -------------------------------------------------- |
|
|
247
|
+
| Table scaffolding | Caption, head and foot destinations; expansion only |
|
|
248
|
+
| The ghost row | The ghost row's controls, its form, and focus |
|
|
249
|
+
| Scrolling to the saved row | The list's rows and their stamps |
|
|
250
|
+
|
|
251
|
+
It is one file, and three concerns in one class, none reusable without the
|
|
252
|
+
others. A `<ul>` cannot have a ghost row without becoming an `lb-table`.
|
|
253
|
+
|
|
254
|
+
### Two units
|
|
255
|
+
|
|
256
|
+
- A widget is markup. Its element file decides what elements exist, at
|
|
257
|
+
build time, as now.
|
|
258
|
+
- A behavior is what one element does. Its code attaches to the element
|
|
259
|
+
that carries it, and runs on the hub's lifecycle.
|
|
260
|
+
|
|
261
|
+
An element file may write `lb-behavior` on its own inner elements:
|
|
262
|
+
|
|
263
|
+
```html
|
|
264
|
+
<!-- lb-table.html -->
|
|
265
|
+
<table lb-behavior="scroll-to-saved">
|
|
266
|
+
<thead lb-exp-template="head"></thead>
|
|
267
|
+
<tbody lb-exp-slot></tbody>
|
|
268
|
+
<tbody lb-exp-template="ghost" lb-behavior="ghost-row"></tbody>
|
|
269
|
+
</table>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
`lb-table` stays the one place to read, and its element file says which code
|
|
273
|
+
runs on which element. The code is split into files by job, and the widget
|
|
274
|
+
assembles them. A page that wants a ghost row in a `<ul>` writes
|
|
275
|
+
`lb-behavior="ghost-row"` on it.
|
|
276
|
+
|
|
277
|
+
### Where code goes
|
|
278
|
+
|
|
279
|
+
Code goes on the element it reads and writes.
|
|
280
|
+
|
|
281
|
+
- The ghost row's code touches the ghost row's controls and form, so it is a
|
|
282
|
+
behavior on the ghost row.
|
|
283
|
+
- Scrolling touches the list's rows, so it is a behavior on the list.
|
|
284
|
+
- Code that seems to need two elements is the sign to stop. Behaviors never
|
|
285
|
+
call each other. They speak only through what widgets use today:
|
|
286
|
+
attributes the hub stamps, and bubbling events such as `lb-request-done`.
|
|
287
|
+
The scrolling behavior knows nothing of the ghost row; it reads
|
|
288
|
+
`lb-row-requested`.
|
|
289
|
+
|
|
290
|
+
The rule also refuses the overfit that started this: a ghost row per
|
|
291
|
+
section would be a behavior on the table reaching into every section.
|
|
292
|
+
|
|
293
|
+
### Where the leak moves
|
|
294
|
+
|
|
295
|
+
Today the leak is the browser's lifecycle: `connectedCallback` written to
|
|
296
|
+
run again, and a value stamp adopted on first connect. With behaviors it
|
|
297
|
+
becomes three rules Loadbare states:
|
|
298
|
+
|
|
299
|
+
1. Only elements the hub places get behaviors.
|
|
300
|
+
2. A behavior is attached and detached exactly once.
|
|
301
|
+
3. Behaviors speak only through stamps and events.
|
|
302
|
+
|
|
303
|
+
They are fewer, and in the hub's terms rather than the browser's. The cost
|
|
304
|
+
moves to Loadbare's design: the ordering the platform gives custom elements
|
|
305
|
+
must be stated, such as whether a host's behavior attaches before or after
|
|
306
|
+
its rows land, and the order among nested behaviors.
|
|
307
|
+
|
|
308
|
+
### Both, not one
|
|
309
|
+
|
|
310
|
+
Custom elements stay. A control built from scratch still needs
|
|
311
|
+
`ElementInternals`, and a tag with no code is expansion alone. Behaviors
|
|
312
|
+
cover what a tag does badly: code on an element HTML already has, inside
|
|
313
|
+
content models that forbid a tag. The developer's question becomes whether
|
|
314
|
+
they are making a new kind of element, or giving an existing element a job.
|