@loadbare/app 0.14.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/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 +2 -1
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +16 -3
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +25 -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 +2 -0
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +18 -29
- 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 +41 -5
- 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/docs/TECHREF-1.0.md +49 -47
- package/docs/comparison.md +7 -5
- package/docs/possible-ideas.md +6 -0
- package/docs/reference/custom-elements.md +106 -87
- package/docs/reference/data-binding.md +7 -7
- package/docs/reference/widgets.md +2 -2
- package/docs/testing.md +2 -2
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +20 -16
- package/skills/loadbare-app/references/TECHREF-1.0.md +49 -47
- package/skills/loadbare-app/references/custom-elements.md +106 -87
- package/skills/loadbare-app/references/data-binding.md +7 -7
- package/skills/loadbare-app/references/widgets.md +2 -2
|
@@ -278,10 +278,10 @@ A custom element reads `lb-` attributes and never assigns one. The developer
|
|
|
278
278
|
writes them in markup, and the hub and the builder write their stamps.
|
|
279
279
|
|
|
280
280
|
Loadbare reserves method names beginning with `lb` on a custom element, for
|
|
281
|
-
the methods it calls; see [
|
|
282
|
-
a script that declares a method, accessor or field whose name
|
|
283
|
-
capital, and anything else Loadbare does not call, so a
|
|
284
|
-
`lbRowLanded` fails the build rather than never being called.
|
|
281
|
+
the methods it calls; see [When its code runs](#when-its-code-runs). The
|
|
282
|
+
build refuses a script that declares a method, accessor or field whose name
|
|
283
|
+
is `lb`, a capital, and anything else Loadbare does not call, so a
|
|
284
|
+
misspelled `lbRowLanded` fails the build rather than never being called.
|
|
285
285
|
|
|
286
286
|
### What the hub and an element say to each other
|
|
287
287
|
|
|
@@ -291,39 +291,80 @@ Each direction has one mechanism for each kind of message:
|
|
|
291
291
|
|----------------|--------------------------------------------|-----------------------------|-------|
|
|
292
292
|
| Hub to element | State that lasts | An attribute the hub stamps | `lb-column-value`, `lb-key-value`, `lb-query-row-count`, `lb-group-*`, `lb-row-*`, `lb-request-pending`, `lb-request-error` |
|
|
293
293
|
| Hub to element | State the platform already names | A property | A control's `value` |
|
|
294
|
-
| Hub to element |
|
|
294
|
+
| Hub to element | What the hub did | An optional `lb` method | `lbAttached`, `lbRowsLanded`, `lbRequestDone`, `lbDetached` |
|
|
295
295
|
| Hub to element | A moment an element started | A bubbling event | `lb-request-done` |
|
|
296
296
|
| Element to hub | A moment | A bubbling event | `lb-request`, and `change`, `click` and `submit` |
|
|
297
297
|
|
|
298
|
-
State is an attribute
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
and an event reaches it knowing neither.
|
|
298
|
+
State is an attribute, because a stylesheet can select on it. A method is
|
|
299
|
+
how the hub tells one element what it just did to that element. A moment is
|
|
300
|
+
an event, because the element that cares is often an ancestor of the one it
|
|
301
|
+
concerns, and an event reaches it knowing neither.
|
|
303
302
|
|
|
304
303
|
### When its code runs
|
|
305
304
|
|
|
306
|
-
The hub
|
|
307
|
-
|
|
308
|
-
|
|
305
|
+
The hub tells a custom element what it did through four optional methods,
|
|
306
|
+
named for the hub's own work. The `HubLifecycle` interface in
|
|
307
|
+
`@loadbare/app/types` declares them. Here is an element that closes its
|
|
308
|
+
popup on Escape, listening on `document` only while the hub has it on the
|
|
309
|
+
page:
|
|
309
310
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
| Turns `lb-show` on | `adoptedCallback`, `connectedCallback` |
|
|
319
|
-
| Turns on an element the builder shipped absent | `constructor`, `connectedCallback` |
|
|
311
|
+
```ts
|
|
312
|
+
// src/note-popup.browser.ts
|
|
313
|
+
import type { HubLifecycle } from "@loadbare/app/types";
|
|
314
|
+
|
|
315
|
+
class NotePopup extends HTMLElement implements HubLifecycle {
|
|
316
|
+
#onKey = (e: KeyboardEvent) => {
|
|
317
|
+
if (e.key === "Escape") this.querySelector("dialog")?.close();
|
|
318
|
+
};
|
|
320
319
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
[Conditional rendering](./data-binding.md#conditional-rendering).
|
|
320
|
+
lbAttached() {
|
|
321
|
+
document.addEventListener("keydown", this.#onKey);
|
|
322
|
+
}
|
|
325
323
|
|
|
326
|
-
|
|
324
|
+
lbDetached() {
|
|
325
|
+
document.removeEventListener("keydown", this.#onKey);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
customElements.define("note-popup", NotePopup);
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
| Method | The hub calls it |
|
|
333
|
+
|---------------------------------|-------------------------------------------------------------------|
|
|
334
|
+
| `lbAttached()` | Once, after it places the element and every column has landed on it |
|
|
335
|
+
| `lbRowsLanded()` | After rows land on the element, with every row placed and stamped |
|
|
336
|
+
| `lbRequestDone(detail, origin)` | After a request committed by the element, or inside it, has finished |
|
|
337
|
+
| `lbDetached()` | Once, after it removes the element |
|
|
338
|
+
|
|
339
|
+
The hub places an element when it starts up the chrome, shows a page,
|
|
340
|
+
creates a live row, or builds a group. It places the chrome and a page as
|
|
341
|
+
the page's first answer lands, or once that round trip fails, so an element
|
|
342
|
+
in either hears `lbAttached` with the page's data in place. It removes an
|
|
343
|
+
element when a live row or a group has finished leaving, and when it shows
|
|
344
|
+
another page in place of the one holding it. Write setup in `lbAttached` and its undoing in
|
|
345
|
+
`lbDetached`; the two pair exactly, so neither guards against running
|
|
346
|
+
twice.
|
|
347
|
+
|
|
348
|
+
Moving a row and turning `lb-show` off and on are neither placing nor
|
|
349
|
+
removing. The element keeps its instance and hears nothing. An element
|
|
350
|
+
under an `lb-show` that is off is placed inside its template, so its
|
|
351
|
+
`lbAttached` runs whether or not it shows. Measure and focus when the user
|
|
352
|
+
acts, never in `lbAttached`, where the element may not be rendered.
|
|
353
|
+
|
|
354
|
+
The hub calls `lbAttached` on an outer custom element before the ones
|
|
355
|
+
inside it, and `lbDetached` on the inner ones first. A table that sets the
|
|
356
|
+
`form` attribute on its controls in `lbAttached` does so before each control
|
|
357
|
+
hears its own.
|
|
358
|
+
|
|
359
|
+
An element a script creates hears none of the four, and neither does the
|
|
360
|
+
copy of a moved row the hub leaves behind while it fades. The hub calls
|
|
361
|
+
them only on what it places.
|
|
362
|
+
|
|
363
|
+
Never write `connectedCallback`, `disconnectedCallback`, `adoptedCallback`
|
|
364
|
+
or `connectedMoveCallback`. The browser calls those on every move, and the
|
|
365
|
+
build refuses a script that declares one.
|
|
366
|
+
|
|
367
|
+
Each kind of work then has one place:
|
|
327
368
|
|
|
328
369
|
1. **A listener on the element itself goes in the constructor.** It is
|
|
329
370
|
attached once and survives every move, and a live row gets its own
|
|
@@ -331,15 +372,11 @@ So each kind of work has one place:
|
|
|
331
372
|
element, so the listener needs no child to exist yet. The constructor
|
|
332
373
|
reads no attribute and no child: an element made with
|
|
333
374
|
`document.createElement` has neither when it runs.
|
|
334
|
-
2. **A child is looked up when it is needed**, in a handler, a getter,
|
|
335
|
-
|
|
336
|
-
3.
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
`disconnectedCallback` removes. Work done once per instance that needs
|
|
340
|
-
the element's attributes, such as a control taking up a value that landed
|
|
341
|
-
before it upgraded, goes behind a flag there; see
|
|
342
|
-
[Being a control](#being-a-control).
|
|
375
|
+
2. **A child is looked up when it is needed**, in a handler, a getter, or
|
|
376
|
+
one of the four methods, and never held from setup.
|
|
377
|
+
3. **Work done once per instance goes in `lbAttached`**, with its undoing
|
|
378
|
+
in `lbDetached`: rearranging the element's own children, or a listener on
|
|
379
|
+
`document` or `window`.
|
|
343
380
|
|
|
344
381
|
### Being a control
|
|
345
382
|
|
|
@@ -350,20 +387,10 @@ and commits its `lb-request` on `change`:
|
|
|
350
387
|
|
|
351
388
|
```ts
|
|
352
389
|
// src/star-rating.browser.ts
|
|
353
|
-
import { ATTR_COLUMN_VALUE } from "@loadbare/app/constants";
|
|
354
|
-
|
|
355
390
|
class StarRating extends HTMLElement {
|
|
356
391
|
static formAssociated = true;
|
|
357
392
|
#internals = this.attachInternals();
|
|
358
393
|
#value = "";
|
|
359
|
-
#connected = false;
|
|
360
|
-
|
|
361
|
-
connectedCallback() {
|
|
362
|
-
if (this.#connected) return;
|
|
363
|
-
this.#connected = true;
|
|
364
|
-
const stamped = this.getAttribute(ATTR_COLUMN_VALUE);
|
|
365
|
-
if (stamped !== null) this.value = stamped;
|
|
366
|
-
}
|
|
367
394
|
|
|
368
395
|
get value(): string {
|
|
369
396
|
return this.#value;
|
|
@@ -399,14 +426,6 @@ customElements.define("star-rating", StarRating);
|
|
|
399
426
|
Dispatch `change` with `bubbles: true`, as a native control's does, when the
|
|
400
427
|
user commits an edit. Setting `value` from the hub fires nothing.
|
|
401
428
|
|
|
402
|
-
A control can receive its value before it is a control. An element the
|
|
403
|
-
builder shipped absent, or one whose definition loads after the hub has
|
|
404
|
-
landed, is not upgraded when its column lands, so the hub cannot set its
|
|
405
|
-
`value` and the value arrives as `lb-column-value` alone. Take the stamp up
|
|
406
|
-
the first time the control connects, as `connectedCallback` does above, and
|
|
407
|
-
never again: after that the hub sets `value` itself, and a later move must
|
|
408
|
-
not undo an edit.
|
|
409
|
-
|
|
410
429
|
A form owns a form-associated custom element the way it owns an `<input>`,
|
|
411
430
|
including through the HTML `form` attribute, so a form gathers it on submit.
|
|
412
431
|
Write `formResetCallback` to restore the default value: the hub resets a form
|
|
@@ -571,23 +590,28 @@ Let the event bubble, so an ancestor can stop it before the hub sends it.
|
|
|
571
590
|
### Hearing how it turned out
|
|
572
591
|
|
|
573
592
|
Once what a request brought back has landed, or its round trip has failed,
|
|
574
|
-
the hub
|
|
575
|
-
|
|
576
|
-
|
|
593
|
+
the hub calls `lbRequestDone(detail, origin)` on the custom element that
|
|
594
|
+
committed and on every custom element around it, innermost first. `origin`
|
|
595
|
+
is the element that committed, so the element that cares need not be the
|
|
596
|
+
one that committed: a dialog hears it from the form inside it.
|
|
577
597
|
|
|
578
598
|
```ts
|
|
579
|
-
import {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
}
|
|
599
|
+
import type { HubLifecycle, HubRequestDone } from "@loadbare/app/types";
|
|
600
|
+
|
|
601
|
+
class NewRowDialog extends HTMLElement implements HubLifecycle {
|
|
602
|
+
lbRequestDone({ request, items, error }: HubRequestDone) {
|
|
603
|
+
if (error) return;
|
|
604
|
+
const item = items.find((i) => i.query === request.query);
|
|
605
|
+
const created = item?.patch?.rows?.[0];
|
|
606
|
+
if (created) this.choose(String(created[item!.key]));
|
|
607
|
+
}
|
|
608
|
+
}
|
|
589
609
|
```
|
|
590
610
|
|
|
611
|
+
The hub then dispatches `lb-request-done` from the element that committed,
|
|
612
|
+
carrying the same `detail` as a bubbling `CustomEvent`, for any other
|
|
613
|
+
listener. Import its name as `LB_DONE_EVENT_NAME`.
|
|
614
|
+
|
|
591
615
|
`items` is every response item that landed because of the request, in
|
|
592
616
|
order. `refusal` is set beside `error` when the handler refused the
|
|
593
617
|
request, holding its `message` and `columns`. An answer that moved the URL contributes its `lb-url` item, which
|
|
@@ -596,11 +620,12 @@ the round trip failed, and then nothing landed. A new row's key is in the
|
|
|
596
620
|
answer only when the handler returned it in a patch: a refresh sends all
|
|
597
621
|
rows, and nothing marks which one is new.
|
|
598
622
|
|
|
599
|
-
By the time
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
623
|
+
By the time either is called, `lb-request-pending` is gone and the page is
|
|
624
|
+
as the answer left it. A request that was never sent, because the hub or an
|
|
625
|
+
ancestor stopped it, gets neither. An element the answer removed, such as
|
|
626
|
+
the row a delete took away, is outside the document by then: no ancestor it
|
|
627
|
+
had there hears the event, and no custom element the hub has removed hears
|
|
628
|
+
`lbRequestDone`.
|
|
604
629
|
|
|
605
630
|
### Holding rows
|
|
606
631
|
|
|
@@ -611,26 +636,22 @@ plain element carrying `lb-query` with a row template inside it needs no
|
|
|
611
636
|
code, so a custom element holds rows only to do something with them once
|
|
612
637
|
they land.
|
|
613
638
|
|
|
614
|
-
A custom element carrying `lb-query` and a row template
|
|
615
|
-
|
|
639
|
+
A custom element carrying `lb-query` and a row template implements
|
|
640
|
+
`lbRowsLanded`, which the hub calls once the rows have landed, with every
|
|
641
|
+
row placed and stamped:
|
|
616
642
|
|
|
617
643
|
```ts
|
|
618
|
-
import type {
|
|
644
|
+
import type { HubLifecycle } from "@loadbare/app/types";
|
|
619
645
|
import { ATTR_ROW_REQUESTED, REQUESTED_CREATED } from "@loadbare/app/constants";
|
|
620
646
|
|
|
621
|
-
class ScrollingList extends HTMLElement implements
|
|
647
|
+
class ScrollingList extends HTMLElement implements HubLifecycle {
|
|
622
648
|
lbRowsLanded() {
|
|
623
|
-
// Once, after the rows have landed, every row placed and stamped.
|
|
624
649
|
this.querySelector(`[${ATTR_ROW_REQUESTED}="${REQUESTED_CREATED}"]`)
|
|
625
650
|
?.scrollIntoView({ block: "nearest" });
|
|
626
651
|
}
|
|
627
652
|
}
|
|
628
653
|
```
|
|
629
654
|
|
|
630
|
-
| Method | The hub calls it |
|
|
631
|
-
|----------------|-------------------------------------------------------|
|
|
632
|
-
| `lbRowsLanded` | After the rows land, with every row placed and stamped |
|
|
633
|
-
|
|
634
655
|
Everything else is the hub's:
|
|
635
656
|
|
|
636
657
|
| Concern | The hub |
|
|
@@ -649,11 +670,9 @@ gives each option and `<optgroup>` what landing does not, a value and a
|
|
|
649
670
|
label, and the other scrolls to the row the page's request created or
|
|
650
671
|
moved.
|
|
651
672
|
|
|
652
|
-
A custom element
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
upgrades, the hub lands the query's last answer on it again, as all rows,
|
|
656
|
-
so `lbRowsLanded` runs.
|
|
673
|
+
A custom element under an `lb-show` that is off still holds its rows. The
|
|
674
|
+
hub places the rows that land on it then as it places any, and calls its
|
|
675
|
+
`lbRowsLanded`, so it returns current.
|
|
657
676
|
|
|
658
677
|
A custom element that walks its own rows finds them with `LIVE_ROW` from
|
|
659
678
|
`@loadbare/app/constants`, never by `lb-key-value`: an element a `row` lands
|
|
@@ -284,10 +284,9 @@ scaffolding around rows, such as a group's heading or a ghost row. So
|
|
|
284
284
|
a query nested in another query's rows need not land again, or land after
|
|
285
285
|
the outer query, for a new outer row to show its choices.
|
|
286
286
|
|
|
287
|
-
A custom element
|
|
288
|
-
`
|
|
289
|
-
|
|
290
|
-
runs. See [Holding rows](./custom-elements.md#holding-rows).
|
|
287
|
+
A custom element under an `lb-show` that is off is filled like any other,
|
|
288
|
+
and its `lbRowsLanded` runs as its rows land. See
|
|
289
|
+
[Holding rows](./custom-elements.md#holding-rows).
|
|
291
290
|
|
|
292
291
|
Nothing is answered from what the hub kept: a request always goes to the
|
|
293
292
|
server, and a query re-runs only when a response names it. A patch that
|
|
@@ -877,9 +876,10 @@ An ancestor may stop the event, and the request is not sent. A custom
|
|
|
877
876
|
element may dispatch the event itself; see
|
|
878
877
|
[Sending a request](./custom-elements.md#sending-a-request).
|
|
879
878
|
|
|
880
|
-
Once the answer has landed, or the round trip has failed, the hub
|
|
881
|
-
|
|
882
|
-
|
|
879
|
+
Once the answer has landed, or the round trip has failed, the hub calls
|
|
880
|
+
`lbRequestDone` on the custom elements from the committing element outward,
|
|
881
|
+
then dispatches a bubbling `lb-request-done` event from the same element.
|
|
882
|
+
Both carry the request and what landed because of it, or the error; see
|
|
883
883
|
[Hearing how it turned out](./custom-elements.md#hearing-how-it-turned-out).
|
|
884
884
|
|
|
885
885
|
## The URL
|
|
@@ -182,8 +182,8 @@ the hub until the user says yes:
|
|
|
182
182
|
| `exp-request` | The confirm button's `lb-request` |
|
|
183
183
|
| `exp-confirm` | The confirm button's text, `Confirm` when absent |
|
|
184
184
|
|
|
185
|
-
The widget closes the dialog once
|
|
186
|
-
|
|
185
|
+
The widget closes the dialog once the request succeeds, and leaves it open
|
|
186
|
+
on a refusal.
|
|
187
187
|
|
|
188
188
|
## `lb-form`
|
|
189
189
|
|