@loadbare/app 0.24.0 → 0.26.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.
Files changed (56) hide show
  1. package/dist/build/assemble.d.ts +1 -2
  2. package/dist/build/assemble.d.ts.map +1 -1
  3. package/dist/build/assemble.js +61 -53
  4. package/dist/build/assemble.js.map +1 -1
  5. package/dist/build/cli.d.ts +4 -10
  6. package/dist/build/cli.d.ts.map +1 -1
  7. package/dist/build/cli.js +11 -33
  8. package/dist/build/cli.js.map +1 -1
  9. package/dist/build/declared.js +1 -1
  10. package/dist/build/declared.js.map +1 -1
  11. package/dist/core/lb-constants.d.ts +8 -18
  12. package/dist/core/lb-constants.d.ts.map +1 -1
  13. package/dist/core/lb-constants.js +32 -72
  14. package/dist/core/lb-constants.js.map +1 -1
  15. package/dist/core/lb-types.d.ts +12 -11
  16. package/dist/core/lb-types.d.ts.map +1 -1
  17. package/dist/core/lb-types.js +7 -0
  18. package/dist/core/lb-types.js.map +1 -1
  19. package/dist/hub/lb-apply.d.ts +23 -37
  20. package/dist/hub/lb-apply.d.ts.map +1 -1
  21. package/dist/hub/lb-apply.js +205 -518
  22. package/dist/hub/lb-apply.js.map +1 -1
  23. package/dist/hub/lb-hub.browser.d.ts.map +1 -1
  24. package/dist/hub/lb-hub.browser.js +159 -132
  25. package/dist/hub/lb-hub.browser.js.map +1 -1
  26. package/dist/hub/lb-lifecycle.d.ts +2 -2
  27. package/dist/hub/lb-lifecycle.d.ts.map +1 -1
  28. package/dist/hub/lb-lifecycle.js +9 -17
  29. package/dist/hub/lb-lifecycle.js.map +1 -1
  30. package/dist/server/lb-express.d.ts.map +1 -1
  31. package/dist/server/lb-express.js +3 -3
  32. package/dist/server/lb-express.js.map +1 -1
  33. package/dist/server/lb-server.d.ts +35 -19
  34. package/dist/server/lb-server.d.ts.map +1 -1
  35. package/dist/server/lb-server.js +141 -88
  36. package/dist/server/lb-server.js.map +1 -1
  37. package/docs/binding-cases.md +150 -0
  38. package/docs/comparison.md +20 -29
  39. package/docs/miswarts.md +2 -2
  40. package/docs/reference/css.md +2 -15
  41. package/docs/reference/custom-elements.md +6 -8
  42. package/docs/reference/data-binding.md +100 -185
  43. package/docs/reference/names.md +11 -27
  44. package/docs/reference/page-files.md +4 -14
  45. package/docs/reference/server.md +0 -1
  46. package/docs/testing.md +2 -5
  47. package/package.json +1 -1
  48. package/skills/loadbare-app/SKILL.md +66 -56
  49. package/skills/loadbare-app/references/css.md +2 -15
  50. package/skills/loadbare-app/references/custom-elements.md +6 -8
  51. package/skills/loadbare-app/references/data-binding.md +100 -185
  52. package/skills/loadbare-app/references/miswarts.md +2 -2
  53. package/skills/loadbare-app/references/names.md +11 -27
  54. package/skills/loadbare-app/references/page-files.md +4 -14
  55. package/skills/loadbare-app/references/server.md +0 -1
  56. package/docs/temp-proposals.md +0 -251
@@ -2,7 +2,7 @@
2
2
 
3
3
  A page shows server data by naming queries and columns in its HTML, and asks
4
4
  the server to change that data by naming requests. The developer writes
5
- eighteen `lb-` attributes. The server declares every query a page may show and
5
+ fourteen `lb-` attributes. The server declares every query a page may show and
6
6
  every request it may send, and refuses anything it has not declared.
7
7
 
8
8
  Everything is a query. A query is a name for rows, of kind `row` or `rows`,
@@ -48,10 +48,6 @@ each with its key, and permits the three requests on `roster`; see
48
48
  | `lb-show` | Any element but `<template>` | The column that decides whether it is present |
49
49
  | `lb-order` | An element with `lb-query` | The choice holding the user's order; see [Order](#order) |
50
50
  | `lb-filter` | An element with `lb-query` | The columns a choice filters; see [Filters](#filters) |
51
- | `lb-group` | A `<template>` | Nothing: it marks a group template; see [Groups](#groups) |
52
- | `lb-count` | Any element | Nothing: it shows a count of rows; see [Aggregates](#aggregates) |
53
- | `lb-sum`, `lb-avg`, `lb-min`, `lb-max` | Any element | The column aggregated; see [Aggregates](#aggregates) |
54
- | `lb-select` | A checkbox in a row template | Nothing: it selects its live row; see [Selecting rows](#selecting-rows) |
55
51
  | `lb-request` | Any element | The request it sends when it commits |
56
52
  | `lb-url-link` | An `<a>` | A link between pages; see [chrome](./chrome.md#links) |
57
53
  | `lb-url-parm` | An `<a lb-url-link>` in a row | Columns of the row its `href` carries as parms; see [chrome](./chrome.md#a-link-from-a-row) |
@@ -69,11 +65,9 @@ builder writes a stamp, and a stylesheet or a custom element reads it.
69
65
  | `lb-query-row-count` | The number of live rows an element shows |
70
66
  | `lb-query-unplaced-count` | The number of them out of place; see [Placing by hand](#placing-by-hand) |
71
67
  | `lb-query-order` | The order placing them; see [Order](#order) |
72
- | `lb-group-live`, `lb-group-column`, `lb-group-value` | A group, the column it breaks on, and its value; see [Groups](#groups) |
73
68
  | `lb-row-created`, `lb-row-changed`, `lb-row-moved`, `lb-row-requested`, `lb-row-unplaced` | What happened to a row; see [What happened to a row](#what-happened-to-a-row) |
74
- | `lb-row-leaving`, `lb-group-leaving` | A row or group on its way out |
69
+ | `lb-row-leaving` | A row on its way out |
75
70
  | `lb-row-editing` | The row a form is pointed at; see [Editing a row in one form](#editing-a-row-in-one-form) |
76
- | `lb-row-selected` | A row whose `lb-select` is ticked |
77
71
  | `lb-request-pending` | The element's request is in flight |
78
72
  | `lb-request-error` | The element's last request failed |
79
73
  | `lb-request-refused` | The handler refused it; see [Refusals](#refusals) |
@@ -92,8 +86,7 @@ elements as the page needs.
92
86
 
93
87
  What lands depends on the query's kind and on whether the element holds a
94
88
  row template, which is the first `<template>` among its descendants outside
95
- any nested `lb-query`, or, when that template is a [group
96
- template](#groups), the innermost template inside it:
89
+ any nested `lb-query`:
97
90
 
98
91
  | Kind | Row template | The hub |
99
92
  |--------|--------------|----------------------------------------|
@@ -332,8 +325,7 @@ form `--lb-edit` pointed at a row, or a form elsewhere on the page.
332
325
  | The answer | Under `lb-manual`, the row | Side |
333
326
  |----------------------------------------|---------------------------------------------------|----------|
334
327
  | Changes a column the order reads | Stays where it stands | `order` |
335
- | Creates a row | Goes after the last row of its group, or last of all | `order` |
336
- | Changes the column its group breaks on | Stays under its group's heading | `order` |
328
+ | Creates a row | Goes last | `order` |
337
329
  | Changes a row so the filter hides it | Stays showing | `filter` |
338
330
  | Drops a row | Leaves, under either side | |
339
331
 
@@ -394,11 +386,9 @@ its rows the user may filter, separated by commas. The column of
394
386
  </ul>
395
387
  ```
396
388
 
397
- A row that does not pass every filter is `hidden`, and a ticked `lb-select`
398
- in it is cleared. Under `lb-manual="filter"`, a row an answer changed stays
389
+ A row that does not pass every filter is `hidden`. Under `lb-manual="filter"`, a row an answer changed stays
399
390
  showing until the rows are placed again; see
400
- [Placing by hand](#placing-by-hand). A group whose rows are all hidden is hidden too
401
- ([miswart](./miswarts.md#rows-hidden-by-a-filter)). An empty
391
+ [Placing by hand](#placing-by-hand). An empty
402
392
  choice filters nothing.
403
393
 
404
394
  A filter is one or more terms, each an operator followed by a value:
@@ -431,96 +421,6 @@ column that is null or missing, pass only `!=`.
431
421
  `parseFilter`, `passes` and `passesTerm` in `@loadbare/app/types` are the
432
422
  rule the hub applies.
433
423
 
434
- ### Groups
435
-
436
- A group is a run of rows sharing the order's leading term. Write a
437
- `<template lb-group>` where the row template goes, holding the group's
438
- heading and one nested `<template>`: the next group template, or the row
439
- template. The nth group template breaks on the order's nth term.
440
-
441
- ```html
442
- <ul lb-query="roster">
443
- <template lb-group>
444
- <li>
445
- <h3 lb-column="team"></h3>
446
- <ul>
447
- <template><li lb-column="name"></li></template>
448
- </ul>
449
- </li>
450
- </template>
451
- </ul>
452
- ```
453
-
454
- The hub clones the group template where the order breaks, and the group's
455
- contents land immediately before the clone of its nested template, so the
456
- markup's nesting decides the shape:
457
-
458
- | The nested template is | The group's contents land | Example |
459
- |------------------------------|------------------------------------|-----------------------------------|
460
- | Inside the heading's element | Inside it | `<tbody>`, `<li>`, `<details>` |
461
- | Beside the heading | After the heading, as its siblings | A heading `<tr>` in one `<tbody>` |
462
-
463
- `<tbody>` and `<optgroup>` do not nest, so a table's levels below the first
464
- are heading rows beside their rows:
465
-
466
- ```html
467
- <table lb-query="accounts">
468
- <thead><tr><th>Account</th></tr></thead>
469
- <template lb-group>
470
- <tbody>
471
- <tr><th scope="rowgroup" lb-column="category"></th></tr>
472
- <template><tr><td lb-column="account_name"></td></tr></template>
473
- </tbody>
474
- </template>
475
- </table>
476
- ```
477
-
478
- Content after the nested template lands after the group's rows, which is
479
- where a group's footer goes.
480
-
481
- A heading is filled from its group's first row as an element in a row is,
482
- `href`s from `lb-url-parm` included, so it may show a column other than the
483
- one the group breaks on. Under `lb-manual="order"`, a row an answer
484
- moved to another group stays under its old heading, and the heading shows
485
- the row as it stood, until the rows are placed again. The hub stamps each top-level
486
- element of a group with `lb-group-live`, `lb-group-column` and
487
- `lb-group-value`. A row creates its group, and a group leaves with its last
488
- row. When the order changes, a group whose run goes on is kept and moved,
489
- and a group whose run ended leaves.
490
-
491
- A group template with no nested template is reported to the console. More
492
- group templates than the order has terms show each extra level as one
493
- group, and are reported once.
494
-
495
- ### Aggregates
496
-
497
- `lb-count`, `lb-sum="col"`, `lb-avg="col"`, `lb-min="col"` and
498
- `lb-max="col"` set an element from the rows of the nearest group around it,
499
- or of the whole list outside any group:
500
-
501
- ```html
502
- <tr><td><span lb-count></span> people</td><td lb-sum="salary"></td></tr>
503
- ```
504
-
505
- | Attribute | Sets the element to |
506
- |----------------|-----------------------------------------------------------|
507
- | `lb-count` | The number of rows |
508
- | `lb-sum="col"` | The sum of `col` |
509
- | `lb-avg="col"` | The average of `col` |
510
- | `lb-min="col"` | The least value of `col`, by the [order](#order)'s comparison |
511
- | `lb-max="col"` | The greatest, likewise |
512
-
513
- An aggregate lands as a column does, with `lb-column-value`. A sum and an
514
- average are exact decimals, read from JSON numbers and from strings holding
515
- a plain decimal, as Postgres sends `numeric`. A sum has as many places as
516
- the most precise value, and an average up to two more. `null` and empty
517
- values are left out, as SQL leaves them out, and any other value is left
518
- out and reported once. The result lands unformatted.
519
-
520
- An aggregate covers the rows showing, so a row a filter hides is left out.
521
- Where the true total matters beyond what the page shows, have the server
522
- answer it as a row.
523
-
524
424
  ### What happened to a row
525
425
 
526
426
  Every change to a list is one a stylesheet can see:
@@ -533,7 +433,6 @@ Every change to a list is one a stylesheet can see:
533
433
  | `lb-row-requested` | `created`, `changed` or `moved` by this page's request |
534
434
  | `lb-row-unplaced` | Stands where the order or the filter would not leave it |
535
435
  | `lb-row-leaving` | A row on its way out |
536
- | `lb-group-leaving` | A group on its way out |
537
436
 
538
437
  The hub touches a row when an answer names it. `lb-row-created`,
539
438
  `lb-row-changed` and `lb-row-moved` are cleared when it next does, and one
@@ -544,8 +443,8 @@ query, and set only by a landing that answers a request from the page.
544
443
  placed again; see
545
444
  [Placing by hand](#placing-by-hand).
546
445
 
547
- A row or a group that leaves loses `lb-row-live` or `lb-group-live`, takes
548
- `lb-row-leaving` or `lb-group-leaving` and `inert`
446
+ A row that leaves loses `lb-row-live`, takes
447
+ `lb-row-leaving` and `inert`
549
448
  ([miswart](./miswarts.md#leaving-rows-are-inert)), and is removed once its
550
449
  animations finish, at once when there are none.
551
450
 
@@ -569,7 +468,7 @@ The hub keeps each query's last answer until the page changes, with any
569
468
  patch since applied to it. An element that names a query and arrives after
570
469
  that query's answer is filled from what was kept, at the end of the landing
571
470
  that follows its arrival. Such an element is a picker in a new live row, or
572
- scaffolding around rows, such as a group's heading or a ghost row. So
471
+ scaffolding around rows, such as a ghost row. So
573
472
  a query nested in another query's rows need not land again, or land after
574
473
  the outer query, for a new outer row to show its choices.
575
474
 
@@ -637,8 +536,8 @@ answered side by side. A column never holds rows.
637
536
  ```
638
537
 
639
538
  Many masters, each with its own detail, is one `rows` query of joined rows:
640
- each detail row carries its master's columns. A [group template](#groups)
641
- shows each master as a group, ordered by the master's key first.
539
+ each detail row carries its master's columns, ordered by the master's key
540
+ first.
642
541
 
643
542
  A query nested in another query's row template receives the same rows in
644
543
  every live row. That serves a picker offering the same choices on every
@@ -753,8 +652,7 @@ Every request has one shape:
753
652
  ```
754
653
 
755
654
  The hub takes `query`, `key` and `values` from where the element sits, and
756
- sends each when it has one. A request acting on several rows carries `keys`
757
- in place of `key`; see [Selecting rows](#selecting-rows). The server runs the handler for the name and
655
+ sends each when it has one. The server runs the handler for the name and
758
656
  answers with response items, which land like any others.
759
657
 
760
658
  ### Committing
@@ -902,18 +800,66 @@ the master and its details together; see [crud](./page-files.md#crud). The
902
800
  server checks that `rows` holds string keys and string values by query, and
903
801
  ignores a request whose `rows` does not.
904
802
 
803
+ #### Rows not yet entered in a list
804
+
805
+ A detail the master does not have yet is entered with it. `--lb-new` aimed
806
+ at the nested list, rather than at a form, puts a row not yet entered into
807
+ it, and sends nothing:
808
+
809
+ ```html
810
+ <form lb-query="flight" lb-request="lb-row-insert">
811
+ <input lb-column="code" />
812
+ <ul id="arrivals" lb-query="arrivals">
813
+ <template>
814
+ <li>
815
+ <input lb-column="gate" />
816
+ <input lb-column="qty" value="1" />
817
+ <button type="button" lb-request="lb-row-delete">Remove</button>
818
+ </li>
819
+ </template>
820
+ </ul>
821
+ <button type="button" commandfor="arrivals" command="--lb-new">Add arrival</button>
822
+ <button type="submit">Save</button>
823
+ </form>
824
+ ```
825
+
826
+ - The row is a live row with the empty key, copied from the row template.
827
+ Its controls start at their HTML defaults, and its `lb-show` branches are
828
+ as for a row whose every column is null.
829
+ - It stands after every row of the list, in the order added, and is not
830
+ ordered or filtered, since it holds no data. It counts in
831
+ `lb-query-row-count`.
832
+ - The form's submit carries it in `rows`, with `key: ""`, beside the rows on
833
+ record: an insert while the master is not on record, an update once it
834
+ is. The handler inserts each row with no key.
835
+ - Once the submit succeeds, the rows not yet entered leave, and the rows its
836
+ answer lands take their place. A refusal leaves them, with a column's
837
+ message on its control.
838
+ - A delete from one takes it out of the list and sends nothing, and an
839
+ update from one is not sent, as for any [row not yet
840
+ entered](#a-row-not-yet-entered).
841
+
842
+ The form needs a submit: a row not yet entered never sends on its own, so
843
+ one in a form that only saves control by control waits for nothing. The
844
+ list is a query nested directly in the form's own, as for any set of rows
845
+ the form gathers; the builder refuses `--lb-new` aimed at any other list.
846
+ Aimed at a `<form>`, `--lb-new` points the form, as below.
847
+
905
848
  A nested query answers once for the page, so its rows are the same wherever
906
849
  they show. The form enters a new master with its details, or edits the
907
850
  master the page shows, whose details the nested query reads from the same
908
851
  query parm. A form [pointed at a row](#editing-a-row-in-one-form) fills its
909
- own controls from that row; its nested rows stay the nested query's answer.
852
+ own controls from that row; its nested rows stay the nested query's answer,
853
+ so the pointed row's own details come as its columns.
910
854
 
911
855
  ### A row not yet entered
912
856
 
913
- A row whose key is empty is a new one, not yet entered. It arises two ways:
914
- a `row` query answers with an empty key, as one showing the master a query
915
- parm names does when the parm is empty, or New points a form (see
916
- [Editing a row in one form](#editing-a-row-in-one-form)). Either way the
857
+ A row whose key is empty is a new one, not yet entered. It arises three
858
+ ways: a `row` query answers with an empty key, as one showing the master a
859
+ query parm names does when the parm is empty; New points a form (see
860
+ [Editing a row in one form](#editing-a-row-in-one-form)); or New aimed at a
861
+ list adds one to it (see
862
+ [Rows not yet entered in a list](#rows-not-yet-entered-in-a-list)). Either way the
917
863
  element carries `lb-key-value=""`.
918
864
 
919
865
  | Request | From a row not yet entered |
@@ -964,7 +910,7 @@ nothing is not sent.
964
910
  For a query the hub serves, `lb-url` or `lb-choices`, the hub answers
965
911
  `lb-row-update` itself, with no round trip; see
966
912
  [Query parms](./chrome.md#query-parms) and [Choices](#choices). The third,
967
- `lb-hub`, takes no request.
913
+ `lb-hub-status`, takes no request.
968
914
 
969
915
  A key comes from a live row, or from an element a `row` landed on, so all
970
916
  three work against either kind:
@@ -999,7 +945,7 @@ row. Buttons point it with HTML's `commandfor` and `command`:
999
945
  | Command | On a button | The hub |
1000
946
  |----------------|-------------------------------------|---------------------------------------------|
1001
947
  | `--lb-edit` | In a live row of the form's query | Fills the form from that row, keyed by it |
1002
- | `--lb-new` | Anywhere | Starts the form empty, for an insert |
948
+ | `--lb-new` | Anywhere | Starts the form empty, for an insert; aimed at a list, see [Rows not yet entered in a list](#rows-not-yet-entered-in-a-list) |
1003
949
  | `--lb-release` | Anywhere | Lets the form go without saving |
1004
950
 
1005
951
  HTML requires a custom command to begin with `--`.
@@ -1032,6 +978,13 @@ round trip, including columns no element in the table shows. The user
1032
978
  edits a row they can see, so the row is on the page. A row that has to be
1033
979
  fetched to be edited is another page, with that row as its master.
1034
980
 
981
+ A pointed form edits what the row it points at holds. Details the form
982
+ shows for that row come as columns of the row, one per detail when the
983
+ details are a fixed set, or from a master the page shows by a query parm,
984
+ whose nested query reads the same parm. A query nested in a pointed form
985
+ shows the page's answer, whichever row the form points at; see
986
+ [A form over a set of rows](#a-form-over-a-set-of-rows).
987
+
1035
988
  Pointing a form first empties it: every column it names lands as null, and
1036
989
  the form resets, so each control returns to its default. Edit then lands
1037
990
  the row on the form, stamps the form with the row's key, so the form's
@@ -1063,6 +1016,27 @@ The rows a form's answer lands are placed by the list's `lb-manual`, as any
1063
1016
  answer's are, whether the form was pointed by Edit or by New; see
1064
1017
  [Placing by hand](#placing-by-hand).
1065
1018
 
1019
+ A list nested in the form follows the row the form is bound to. When Edit
1020
+ or New binds the form, the hub drops the list's rows not yet entered and
1021
+ asks the server for the list's query again, as the request `lb-read`, with
1022
+ the bound row's key added to the query string as the parm named for the
1023
+ form's key column. `contextFor` receives it among the parms, and the query
1024
+ reads it as it reads any parm, so one query serves a master the URL names
1025
+ and a master Edit binds. New sends the parm empty, and the query answers
1026
+ with no rows:
1027
+
1028
+ ```ts
1029
+ function contextFor(req: Request, parms: URLSearchParams): HubContext {
1030
+ return { db: openDb(), paycheck: parms.get("paycheck_id") ?? "" };
1031
+ }
1032
+
1033
+ deductions: rows("id", (ctx) => ctx.db.deductionsFor(ctx.paycheck)),
1034
+ ```
1035
+
1036
+ A form with no list inside it sends nothing when it is bound. An answer
1037
+ that returns after the form is bound to another row, or after the page
1038
+ moved on, lands nothing.
1039
+
1066
1040
  A successful request from the form lets it go, as Cancel does: the form
1067
1041
  empties, its controls return to their defaults, and the stamps go. A failed
1068
1042
  one leaves the form as the user had it, to correct.
@@ -1090,63 +1064,6 @@ outside a live row of the form's query, Edit for a key the hub holds no row
1090
1064
  for, and any of these three commands aimed at an element that is not a form
1091
1065
  carrying `lb-query`.
1092
1066
 
1093
- ### Selecting rows
1094
-
1095
- A checkbox carrying `lb-select` in a row template selects the live row it
1096
- sits in. It is not a column: it carries no `lb-column`, lands nothing and
1097
- is not gathered. The hub stamps the row `lb-row-selected` while it is
1098
- ticked.
1099
-
1100
- A request for the query that names no one row then acts on the rows
1101
- selected, and carries their keys as `keys`:
1102
-
1103
- ```html
1104
- <tbody lb-query="transactions">
1105
- <template>
1106
- <tr>
1107
- <td><input type="checkbox" lb-select lb-show="selecting" /></td>
1108
- <td lb-column="description"></td>
1109
- <td lb-column="amount"></td>
1110
- </tr>
1111
- </template>
1112
- </tbody>
1113
-
1114
- <form lb-query="transactions" lb-request="lb-row-update">
1115
- <lb-picker lb-query="accounts" lb-column="acct" exp-label="Account" exp-column="name"></lb-picker>
1116
- <button type="submit">Apply</button>
1117
- <button type="button" lb-request="lb-row-delete">Delete</button>
1118
- </form>
1119
- ```
1120
-
1121
- ```json
1122
- { "name": "lb-row-update", "query": "transactions", "keys": ["4", "9"], "values": { "acct": "12" } }
1123
- ```
1124
-
1125
- | Request | With rows selected | With none ticked |
1126
- |------------------|----------------------------------------|----------------------|
1127
- | `lb-row-update` | Sent with `keys` | Not sent |
1128
- | `lb-row-delete` | Sent with `keys` | Not sent |
1129
- | A declared one | Sent with `keys` | Sent with `keys: []` |
1130
- | `lb-row-insert` | Sent as ever; the selection is not its | Sent as ever |
1131
-
1132
- An update or delete with nothing ticked has nothing to act on, and nothing
1133
- is reported. A request from inside a row still names that row alone. The
1134
- server runs the page's `rowUpdate` or `rowDelete` once for each key, as for
1135
- each row alone, and refreshes once; see [crud](./page-files.md#crud).
1136
-
1137
- After the request succeeds, the hub clears the selection. A failed one
1138
- leaves it, to try again.
1139
-
1140
- Only a checkbox that is showing counts. Turning a selector off with
1141
- `lb-show` also clears its tick, so leaving a selecting mode abandons the
1142
- selection rather than keeping it out of sight. With every selector off, a
1143
- request for the query is an ordinary one again.
1144
-
1145
- Which rows are selected, and whether the page is in a selecting mode, is
1146
- interaction state. A mode the URL keeps, such as `?selecting=1`, reaches
1147
- the rows as a column the query computes from the parm, which `lb-show`
1148
- reads.
1149
-
1150
1067
  ### Declared requests
1151
1068
 
1152
1069
  A request name the page declares under `handlers` runs the application's
@@ -1276,7 +1193,7 @@ returns its controls to their defaults, and the hub removes
1276
1193
  `lb-column-value` from each of them. A cancelled reset keeps both.
1277
1194
 
1278
1195
  A page load that fails lands nothing and is reported to the console, and
1279
- the query `lb-hub` says so; see [The hub's state](./chrome.md#the-hubs-state).
1196
+ the query `lb-hub-status` says so; see [The hub's state](./chrome.md#the-hubs-state).
1280
1197
  A load
1281
1198
  started by a request for `lb-url` stamps the element that sent it, as any
1282
1199
  request stamps its element.
@@ -1337,7 +1254,7 @@ The developer writes `lb-` attributes in markup, and script never assigns
1337
1254
  them. The builder checks the markup of the chrome and of every page, after
1338
1255
  expansion, and refuses to build:
1339
1256
 
1340
- - an `lb-` attribute that is not one of the eighteen the developer writes;
1257
+ - an `lb-` attribute that is not one of the fourteen the developer writes;
1341
1258
  `lb-exp-slot` and `lb-exp-template` are consumed by expansion and never
1342
1259
  reach the check
1343
1260
  - `lb-request` naming an `lb-` request other than the three Loadbare provides
@@ -1365,13 +1282,11 @@ expansion, and refuses to build:
1365
1282
  no column
1366
1283
  - `lb-manual` on an element not carrying `lb-query`, or naming anything but
1367
1284
  `order`, `filter` or both
1368
- - `lb-select` on anything but `<input type="checkbox">`, outside a row
1369
- template, or beside `lb-column` or `lb-request`
1370
1285
  - a `command` beginning `--lb-` that is not one of the four commands
1371
1286
  - one of the four commands with no `commandfor`
1372
- - `lb-group` on anything but a `<template>`, or on one holding no
1373
- `<template>` for its contents
1374
- - an aggregate on a `<template>`, or any but `lb-count` naming no column
1287
+ - `--lb-new` aimed at an element the markup holds that is neither a
1288
+ `<form>` nor a list carrying `lb-query` nested directly in a form's own
1289
+ query
1375
1290
  - a chrome without exactly one `<lb-hub>` and exactly one `<main>`, a
1376
1291
  `<main>` outside `<lb-hub>`, or a `<main>` holding anything but whitespace
1377
1292
  - a page carrying an `<lb-hub>` or a `<main>`
@@ -68,7 +68,7 @@ gathered.
68
68
  ## Rows hidden by a filter
69
69
 
70
70
  **What.** A row that does not pass the user's filter gets the `hidden`
71
- attribute, and so does a group whose rows are all hidden.
71
+ attribute.
72
72
 
73
73
  **Rule broken.** The hub writes only its own stamps, which always
74
74
  begin with `lb-`.
@@ -78,7 +78,7 @@ over rows already on the page needs no round trip, and `hidden` is HTML's
78
78
  own word for an element that is present but not shown. A stamp of our
79
79
  own would make every stylesheet restate what the browser already does.
80
80
 
81
- **Why it terminates.** It applies only to live rows and groups under a
81
+ **Why it terminates.** It applies only to live rows under a
82
82
  filter.
83
83
 
84
84
  ## Leaving rows are inert
@@ -14,10 +14,9 @@ that declares a query, a handler or a `crud` entry whose name begins with
14
14
 
15
15
  | Flag | Default | Names | Defined in |
16
16
  | ---------- | ------- | ----------------------------------------- | --------------------------------------------------- |
17
- | `--src` | `src` | The application's own tree, scanned whole | [Running the builder](./builder.md#running-the-builder) |
18
- | `--out` | `dist` | Where the builder writes | [Running the builder](./builder.md#running-the-builder) |
19
- | `--watch` | off | Rebuild on change under `--src` | [Running the builder](./builder.md#running-the-builder) |
20
- | `--minify` | off | Minify `client.js` and `app.css` | [Running the builder](./builder.md#running-the-builder) |
17
+ | `--src` | `src` | The application's own tree, scanned whole | [Running the builder](./builder.md) |
18
+ | `--out` | `dist` | Where the builder writes | [Running the builder](./builder.md) |
19
+ | `--minify` | off | Minify `client.js` and `app.css` | [Running the builder](./builder.md) |
21
20
 
22
21
  ## Reserved file names
23
22
 
@@ -66,7 +65,7 @@ A widget package declares these. An application never does.
66
65
 
67
66
  ## Attributes
68
67
 
69
- The developer writes eighteen attributes in pages and the chrome, and the
68
+ The developer writes fourteen attributes in pages and the chrome, and the
70
69
  builder refuses any other `lb-` attribute there. `lb-exp-slot` and
71
70
  `lb-exp-template` are written for expansion, which removes them before the
72
71
  check. The hub and the builder write the rest, as stamps, and script never
@@ -80,9 +79,6 @@ assigns one.
80
79
  | `lb-order` | Developer | [Order](./data-binding.md#order) |
81
80
  | `lb-filter` | Developer | [Filters](./data-binding.md#filters) |
82
81
  | `lb-manual` | Developer | [Placing by hand](./data-binding.md#placing-by-hand) |
83
- | `lb-group` | Developer | [Groups](./data-binding.md#groups) |
84
- | `lb-count`, `lb-sum`, `lb-avg`, `lb-min`, `lb-max` | Developer | [Aggregates](./data-binding.md#aggregates) |
85
- | `lb-select` | Developer | [Selecting rows](./data-binding.md#selecting-rows) |
86
82
  | `lb-request` | Developer | [Requests](./data-binding.md#requests) |
87
83
  | `lb-url-link` | Developer | [Links](./chrome.md#links) |
88
84
  | `lb-url-parm` | Developer | [A link from a row](./chrome.md#a-link-from-a-row) |
@@ -96,11 +92,9 @@ assigns one.
96
92
  | `lb-query-row-count` | Hub | [Counting rows](./data-binding.md#counting-rows) |
97
93
  | `lb-query-unplaced-count`, `lb-row-unplaced` | Hub | [Placing by hand](./data-binding.md#placing-by-hand) |
98
94
  | `lb-query-order` | Hub | [Order](./data-binding.md#order) |
99
- | `lb-group-live`, `lb-group-column`, `lb-group-value` | Hub | [Groups](./data-binding.md#groups) |
100
95
  | `lb-row-created`, `lb-row-changed`, `lb-row-moved`, `lb-row-requested` | Hub | [What happened to a row](./data-binding.md#what-happened-to-a-row) |
101
- | `lb-row-leaving`, `lb-group-leaving` | Hub | [What happened to a row](./data-binding.md#what-happened-to-a-row) |
96
+ | `lb-row-leaving` | Hub | [What happened to a row](./data-binding.md#what-happened-to-a-row) |
102
97
  | `lb-row-editing` | Hub | [Editing a row in one form](./data-binding.md#editing-a-row-in-one-form) |
103
- | `lb-row-selected` | Hub | [Selecting rows](./data-binding.md#selecting-rows) |
104
98
  | `lb-request-pending` | Hub | [Request state](./data-binding.md#request-state) |
105
99
  | `lb-request-error` | Hub | [Request state](./data-binding.md#request-state) |
106
100
  | `lb-request-refused` | Hub | [Refusals](./data-binding.md#refusals) |
@@ -116,9 +110,9 @@ them, and a page declares none.
116
110
 
117
111
  | Query | Kind | Key | Columns | Defined in |
118
112
  | ------------ | ----- | --------- | --------------------------------------------------------------- | ------------------------------------- |
119
- | `lb-url` | `row` | `lb-path` | `lb-path`, `lb-page-label`, `lb-page-unknown`, every query parm | [The URL](./chrome.md#the-url) |
113
+ | `lb-url` | `row` | `lb-path` | `lb-path`, `lb-page-label`, every query parm | [The URL](./chrome.md#the-url) |
120
114
  | `lb-choices` | `row` | `lb-path` | `lb-path`, every choice | [Choices](./data-binding.md#choices) |
121
- | `lb-hub` | `row` | `lb-path` | `lb-path`, `lb-load-state`, `lb-server-state`, `lb-error`, `lb-pending`, `lb-as-of` | [The hub's state](./chrome.md#the-hubs-state) |
115
+ | `lb-hub-status` | `row` | `lb-path` | `lb-path`, `lb-load-state`, `lb-server-state`, `lb-error`, `lb-pending`, `lb-as-of` | [The hub's state](./chrome.md#the-hubs-state) |
122
116
 
123
117
  No query parm is reserved: a column of `lb-url` whose name begins with
124
118
  `lb-` is never a query parm.
@@ -139,7 +133,7 @@ Loadbare/app owns every value of HTML's `command` attribute beginning with
139
133
  | Command | Defined in |
140
134
  | -------------- | ------------------------------------------------------------------------ |
141
135
  | `--lb-edit` | [Editing a row in one form](./data-binding.md#editing-a-row-in-one-form) |
142
- | `--lb-new` | [Editing a row in one form](./data-binding.md#editing-a-row-in-one-form) |
136
+ | `--lb-new` | [Editing a row in one form](./data-binding.md#editing-a-row-in-one-form), [Rows not yet entered in a list](./data-binding.md#rows-not-yet-entered-in-a-list) |
143
137
  | `--lb-release` | [Editing a row in one form](./data-binding.md#editing-a-row-in-one-form) |
144
138
  | `--lb-place` | [Placing by hand](./data-binding.md#placing-by-hand) |
145
139
 
@@ -202,13 +196,6 @@ imports them rather than writing a string.
202
196
  | `ATTR_QUERY_ROW_COUNT` | `lb-query-row-count` |
203
197
  | `ATTR_QUERY_UNPLACED_COUNT` | `lb-query-unplaced-count` |
204
198
  | `ATTR_QUERY_ORDER` | `lb-query-order` |
205
- | `ATTR_GROUP` | `lb-group` |
206
- | `ATTR_GROUP_LIVE` | `lb-group-live` |
207
- | `ATTR_GROUP_COLUMN` | `lb-group-column` |
208
- | `ATTR_GROUP_VALUE` | `lb-group-value` |
209
- | `LIVE_GROUP` | `[lb-group-live]`, the selector for a group's element |
210
- | `ATTR_COUNT`, `ATTR_SUM`, `ATTR_AVG`, `ATTR_MIN`, `ATTR_MAX` | `lb-count`, `lb-sum`, `lb-avg`, `lb-min`, `lb-max` |
211
- | `AGGREGATES` | All five aggregate attributes |
212
199
  | `ORDER_DESCENDING` | `-`, written before a column in an order |
213
200
  | `COLUMN_TYPES` | `number`, `boolean`, `text` |
214
201
  | `CHOICES_QUERY` | `lb-choices` |
@@ -224,7 +211,6 @@ imports them rather than writing a string.
224
211
  | `REQUESTED_CREATED`, `REQUESTED_CHANGED`, `REQUESTED_MOVED` | `created`, `changed`, `moved` |
225
212
  | `ATTR_ROW_UNPLACED` | `lb-row-unplaced` |
226
213
  | `ATTR_ROW_LEAVING` | `lb-row-leaving` |
227
- | `ATTR_GROUP_LEAVING` | `lb-group-leaving` |
228
214
  | `ATTR_REQUEST` | `lb-request` |
229
215
  | `LB_EVENT_NAME` | `lb-request`, the event every request travels as |
230
216
  | `LB_DONE_EVENT_NAME` | `lb-request-done` |
@@ -236,13 +222,12 @@ imports them rather than writing a string.
236
222
  | `LB_COMMANDS` | All four commands |
237
223
  | `LB_COMMAND_PREFIX` | `--lb-` |
238
224
  | `ATTR_ROW_EDITING` | `lb-row-editing` |
239
- | `ATTR_SELECT` | `lb-select` |
240
- | `ATTR_ROW_SELECTED` | `lb-row-selected` |
241
225
  | `LB_RESERVED_PREFIX` | `lb-` |
242
226
  | `REQUEST_ROW_INSERT` | `lb-row-insert` |
243
227
  | `REQUEST_ROW_UPDATE` | `lb-row-update` |
244
228
  | `REQUEST_ROW_DELETE` | `lb-row-delete` |
245
229
  | `LB_ROW_REQUESTS` | All three request names |
230
+ | `REQUEST_READ` | `lb-read`, the hub's own read of a bound form's lists; markup never writes it |
246
231
  | `LB_METHODS` | The four reserved methods |
247
232
  | `BROWSER_LIFECYCLE` | The browser callbacks the build refuses |
248
233
  | `KIND_ROW` | `row` |
@@ -250,8 +235,7 @@ imports them rather than writing a string.
250
235
  | `URL_QUERY` | `lb-url` |
251
236
  | `URL_COLUMN_PATH` | `lb-path` |
252
237
  | `URL_COLUMN_PAGE_LABEL` | `lb-page-label` |
253
- | `URL_COLUMN_PAGE_UNKNOWN` | `lb-page-unknown` |
254
- | `HUB_QUERY` | `lb-hub` |
238
+ | `HUB_QUERY` | `lb-hub-status` |
255
239
  | `HUB_COLUMN_LOAD_STATE` | `lb-load-state` |
256
240
  | `HUB_COLUMN_SERVER_STATE` | `lb-server-state` |
257
241
  | `HUB_COLUMN_ERROR` | `lb-error` |
@@ -268,7 +252,7 @@ imports them rather than writing a string.
268
252
  | `ATTR_EXP_TEMPLATE` | `lb-exp-template` |
269
253
  | `ATTR_PAGE` | `lb-page` |
270
254
  | `ATTR_PAGE_TITLE` | `lb-page-title` |
271
- | `DEVELOPER_ATTRIBUTES` | The eighteen attributes a developer writes |
255
+ | `DEVELOPER_ATTRIBUTES` | The fourteen attributes a developer writes |
272
256
  | `HUB_TAG_NAME` | `lb-hub` |
273
257
  | `LB_ENDPOINT` | `/lb` |
274
258
  | `LB_REQUEST_TIMEOUT_MS` | `10000` |
@@ -165,14 +165,11 @@ name:
165
165
  | `name` | The request name, from `lb-request` |
166
166
  | `query` | The query the request is for |
167
167
  | `key` | The key of the row the request is for |
168
- | `keys` | The keys of the rows selected, in place of `key` |
169
168
  | `rows` | A form's nested rows, by query: each `key` and `values` |
170
169
  | `values` | The gathered control values, by column |
171
170
 
172
171
  The hub sends `query`, `key` and `values` when it finds them; see
173
- [Gathering](./data-binding.md#gathering). It sends `keys` for a request that
174
- acts on the rows the user selected; see
175
- [Selecting rows](./data-binding.md#selecting-rows).
172
+ [Gathering](./data-binding.md#gathering).
176
173
 
177
174
  ### onPageEnter
178
175
 
@@ -264,17 +261,12 @@ are one vocabulary:
264
261
  | `lb-row-update` | `rowUpdate` | `query`, `key`, `values`, and `rows` from a form |
265
262
  | `lb-row-delete` | `rowDelete` | `query`, `key` |
266
263
 
267
- An `lb-row-update` or `lb-row-delete` carrying `keys` runs `rowUpdate` or
268
- `rowDelete` once for each key, with that key, so a handler written for one
269
- row serves several. The patches the runs return are laid together, and the
270
- refresh set runs once. A `url()` returned for one of several rows is
271
- reported and ignored. A declared request receives `keys` as it is.
272
-
273
264
  `rows` holds the rows of a query nested in the form the request came from,
274
265
  by query name, each with its `key` and the `values` of its own controls; see
275
266
  [A form over a set of rows](./data-binding.md#a-form-over-a-set-of-rows).
276
- The handler writes the master and its details together, deciding what each
277
- row's values mean, such as an empty amount being no row at all:
267
+ A row with `key: ""` is one not yet entered, added by `--lb-new`; insert
268
+ it. The handler writes the master and its details together, deciding what
269
+ each row's values mean, such as an empty amount being no row at all:
278
270
 
279
271
  ```ts
280
272
  rowInsert: {
@@ -385,8 +377,6 @@ A change that seems to need a refresh usually has a patch:
385
377
  [order](./data-binding.md#order), or leaves it where it stands under the
386
378
  list's [`lb-manual`](./data-binding.md#placing-by-hand); a refresh would do
387
379
  the same.
388
- - A group that appears or goes: the hub makes a group with its first row
389
- and removes it with its last, so no row stands in for an empty one.
390
380
  - A row whose other columns change with the edit: re-read the row and patch
391
381
  it.
392
382
  - Rows the database removes with a deleted one: select their keys before the
@@ -199,7 +199,6 @@ interface HubRequest {
199
199
  name: string;
200
200
  query?: string;
201
201
  key?: string;
202
- keys?: string[];
203
202
  values?: Record<string, string>;
204
203
  rows?: Record<string, { key: string; values: Record<string, string> }[]>;
205
204
  }