@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.
Files changed (82) hide show
  1. package/README.md +3 -3
  2. package/dist/build/assemble.d.ts.map +1 -1
  3. package/dist/build/assemble.js +107 -90
  4. package/dist/build/assemble.js.map +1 -1
  5. package/dist/build/expand.d.ts +6 -1
  6. package/dist/build/expand.d.ts.map +1 -1
  7. package/dist/build/expand.js +112 -26
  8. package/dist/build/expand.js.map +1 -1
  9. package/dist/build/locations.d.ts +2 -3
  10. package/dist/build/locations.d.ts.map +1 -1
  11. package/dist/build/locations.js +2 -3
  12. package/dist/build/locations.js.map +1 -1
  13. package/dist/build/pages.d.ts +3 -4
  14. package/dist/build/pages.d.ts.map +1 -1
  15. package/dist/build/pages.js +3 -4
  16. package/dist/build/pages.js.map +1 -1
  17. package/dist/core/lb-constants.d.ts +27 -24
  18. package/dist/core/lb-constants.d.ts.map +1 -1
  19. package/dist/core/lb-constants.js +103 -168
  20. package/dist/core/lb-constants.js.map +1 -1
  21. package/dist/core/lb-types.d.ts +64 -77
  22. package/dist/core/lb-types.d.ts.map +1 -1
  23. package/dist/core/lb-types.js +40 -7
  24. package/dist/core/lb-types.js.map +1 -1
  25. package/dist/hub/lb-apply.d.ts +47 -37
  26. package/dist/hub/lb-apply.d.ts.map +1 -1
  27. package/dist/hub/lb-apply.js +195 -199
  28. package/dist/hub/lb-apply.js.map +1 -1
  29. package/dist/hub/lb-hub.browser.d.ts +1 -1
  30. package/dist/hub/lb-hub.browser.d.ts.map +1 -1
  31. package/dist/hub/lb-hub.browser.js +410 -449
  32. package/dist/hub/lb-hub.browser.js.map +1 -1
  33. package/dist/server/lb-express.d.ts +5 -5
  34. package/dist/server/lb-express.d.ts.map +1 -1
  35. package/dist/server/lb-express.js +35 -66
  36. package/dist/server/lb-express.js.map +1 -1
  37. package/dist/server/lb-server.d.ts +77 -135
  38. package/dist/server/lb-server.d.ts.map +1 -1
  39. package/dist/server/lb-server.js +132 -79
  40. package/dist/server/lb-server.js.map +1 -1
  41. package/docs/TECHREF-1.0.md +908 -585
  42. package/docs/comparison.md +243 -185
  43. package/docs/prior-art.md +15 -14
  44. package/docs/reference/builder.md +9 -3
  45. package/docs/reference/chrome.md +107 -56
  46. package/docs/reference/custom-elements.md +291 -173
  47. package/docs/reference/data-binding.md +381 -374
  48. package/docs/reference/overview.md +12 -10
  49. package/docs/reference/page-files.md +164 -99
  50. package/docs/reference/server.md +2 -2
  51. package/docs/reference/widgets.md +104 -110
  52. package/docs/roadmap.md +32 -39
  53. package/docs/terms-of-art.md +57 -0
  54. package/docs/testing.md +97 -68
  55. package/docs/theory.md +92 -58
  56. package/docs/tutorials/010-pages-and-navigation.md +20 -12
  57. package/docs/tutorials/020-css.md +6 -3
  58. package/docs/tutorials/030-html-decomposition.md +9 -7
  59. package/docs/tutorials/040-displaying-data.md +30 -13
  60. package/docs/tutorials/{050-actions.md → 050-requests.md} +25 -15
  61. package/docs/tutorials/060-custom-element-code.md +17 -16
  62. package/docs/tutorials/065-conditional-rendering.md +34 -23
  63. package/docs/tutorials/070-displaying-a-list.md +29 -21
  64. package/docs/tutorials/072-inserting-into-a-list.md +24 -16
  65. package/docs/tutorials/074-deleting-from-a-list.md +9 -7
  66. package/docs/tutorials/076-updating-a-list-item.md +11 -10
  67. package/docs/tutorials/080-widget-requests.md +71 -43
  68. package/docs/tutorials/090-using-widget-libraries.md +22 -22
  69. package/docs/what-does-loadbare-extend.md +124 -0
  70. package/package.json +1 -1
  71. package/skills/loadbare-app/SKILL.md +201 -123
  72. package/skills/loadbare-app/references/TECHREF-1.0.md +908 -585
  73. package/skills/loadbare-app/references/builder.md +9 -3
  74. package/skills/loadbare-app/references/chrome.md +107 -56
  75. package/skills/loadbare-app/references/custom-elements.md +291 -173
  76. package/skills/loadbare-app/references/data-binding.md +381 -374
  77. package/skills/loadbare-app/references/overview.md +12 -10
  78. package/skills/loadbare-app/references/page-files.md +164 -99
  79. package/skills/loadbare-app/references/server.md +2 -2
  80. package/skills/loadbare-app/references/widgets.md +104 -110
  81. package/docs/analysis-accidental-complexity.md +0 -149
  82. package/docs/analysis-closed-set.md +0 -210
package/docs/prior-art.md CHANGED
@@ -32,14 +32,14 @@ table repetition agent. A DSO might take "an Open Database Connectivity
32
32
  (ODBC) connection string and an Structured Query Language (SQL) statement,"
33
33
  and had to expose its data through OLE DB.
34
34
 
35
- | IE4 | Loadbare |
36
- |-----------------------------------------------------------------------------|-----------------------|
37
- | `DATASRC` on a table repeats "an entire set of records" ("set binding") | `lb-list` |
38
- | A single-valued consumer takes one value "from the current record" | `lb-row` |
39
- | `DATAFLD` names "a column in the data set" | `lb-cell` |
40
- | The repetition agent "uses the table row (tr) in the table body as a template" | `<template lb-key>` |
41
- | The DSO's SQL statement | a page's queries |
42
- | The binding agent "work[s] completely behind the scenes" | the hub |
35
+ | IE4 | Loadbare |
36
+ |--------------------------------------------------------------------------------|-------------------------------------|
37
+ | `DATASRC` on a table repeats "an entire set of records" ("set binding") | `lb-query` naming a `rows` query |
38
+ | A single-valued consumer takes one value "from the current record" | `lb-query` naming a `row` query |
39
+ | `DATAFLD` names "a column in the data set" | `lb-column` |
40
+ | The repetition agent "uses the table row (tr) in the table body as a template" | the row template, a `<template>` |
41
+ | The DSO's SQL statement | a page's queries |
42
+ | The binding agent "work[s] completely behind the scenes" | the hub |
43
43
 
44
44
  It differed from Loadbare in three ways:
45
45
 
@@ -156,13 +156,14 @@ Sources:
156
156
  **Loadbare only:**
157
157
 
158
158
  - The server is the source of truth, and the hub holds no data.
159
- - A response says what changed, as a whole list, a patch or a row, so nothing
160
- is observed.
161
- - Writes are requests (`lb-action` and the CRUD operations) whose answers land
162
- back.
159
+ - A response says what changed, as response items holding all rows, a patch
160
+ or a row, so nothing is observed.
161
+ - Writes are requests (`lb-request`, naming a declared request or one of the
162
+ row requests Loadbare provides) whose answers land back.
163
163
  - A request's position is read from the document.
164
164
  - A build step: expansion, tree shaking, pages shipped as templates.
165
- - Navigation and request state carried by the hub.
165
+ - The URL and request state carried by the hub, the URL as a query of its
166
+ own.
166
167
 
167
168
  Two of Loadbare's central decisions reject what ended MDV. There is no
168
169
  client-side model to observe, which is what made `Object.observe` too slow in
@@ -195,7 +196,7 @@ current (Polymer, React). No source found keeps the branch in a template in
195
196
  the document, standing where the element stood, with no framework cache. The
196
197
  hub has nowhere else to keep one.
197
198
 
198
- Loadbare's recommendation before `lb-show`, a stylesheet rule on `lb-value`,
199
+ Loadbare's recommendation before `lb-show`, a stylesheet rule on `lb-column-value`,
199
200
  is the same family as Polymer's `dom-if` and MDV's `hidden?`: the element stays and
200
201
  CSS hides it.
201
202
 
@@ -122,11 +122,17 @@ A tag with neither a script nor a definition in any origin is an error.
122
122
  | `app.css` | Every stylesheet, concatenated |
123
123
  | `pages.ts` | The `hub` the server passes to `hubRoutes` |
124
124
 
125
- The builder expands the chrome and every page against the available widget
125
+ The builder expands the chrome and every page against the available
126
126
  definitions — see [Custom Elements](./custom-elements.md#html) for the
127
127
  substitution rules — wraps each expanded page in
128
- `<template lb-page="<name>">`, and splices them into the chrome's `<body>`. It formats the result with
129
- Prettier when the application has it installed.
128
+ `<template lb-page="<stub>">`, and splices them into the chrome's `<body>`.
129
+ It removes a page file's `<title>` and stamps its text on the page's
130
+ template as `lb-page-title`; see [The page title](./page-files.md#the-page-title).
131
+ It formats the result with Prettier when the application has it installed.
132
+
133
+ The builder checks the `lb-` attributes of the chrome and every page after
134
+ expansion, and stops on the first file with a problem; see
135
+ [The markup checks](./data-binding.md#the-markup-checks).
130
136
 
131
137
  The builder writes `app.css` only when it finds a stylesheet, and `pages.ts`
132
138
  only when some page has a `.requests.ts` or a `.queries.ts` file. Import `hub`
@@ -9,7 +9,7 @@ anywhere in the `src/` tree. Any directory will do.
9
9
 
10
10
  ## A complete chrome
11
11
 
12
- Here is a minimal but fully complaint chrome for a typical app:
12
+ Here is a minimal but complete chrome for a typical app:
13
13
 
14
14
  ```html
15
15
  <!-- src/chrome.html -->
@@ -24,18 +24,18 @@ Here is a minimal but fully complaint chrome for a typical app:
24
24
  </head>
25
25
  <body hidden>
26
26
  <lb-hub>
27
- <header lb-row="lb-navigation">
27
+ <header lb-query="lb-url">
28
28
  <h1>Membership Roster</h1>
29
- <h2 lb-cell="page-label"></h2>
29
+ <h2 lb-column="lb-page-label"></h2>
30
30
  </header>
31
31
  <nav>
32
- <a href="/" lb-nav-link>Home</a>
33
- <a href="/members" lb-nav-link>Members</a>
32
+ <a href="/" lb-url-link>Home</a>
33
+ <a href="/members" lb-url-link>Members</a>
34
34
  <a href="https://example.org/">Our website</a>
35
35
  </nav>
36
36
  <main></main>
37
- <dialog lb-unknown-page lb-row="lb-navigation">
38
- The URL <span lb-cell="page-uri"></span> is not in this app.
37
+ <dialog lb-url-unknown lb-query="lb-url">
38
+ The URL <span lb-column="lb-path"></span> is not in this app.
39
39
  </dialog>
40
40
  </lb-hub>
41
41
  </body>
@@ -52,81 +52,133 @@ The chrome is plain HTML; nothing in it is generated or templated.
52
52
  | A complete HTML document | Doctype, `<html>`, `<head>`, `<body>` |
53
53
  | `<lb-hub>` inside `<body>` | The application's live element |
54
54
  | An empty `<main>` inside `<lb-hub>` | Holds the current page |
55
- | `<script src="/client.js" defer>` | Defines `<lb-hub>` and every other widget |
55
+ | `<script src="/client.js" defer>` | Defines `<lb-hub>` and every other custom element |
56
56
 
57
57
  Everything else is optional:
58
58
 
59
59
  | Optional | Description |
60
60
  |-------------------------------------------|---------------------------------------------|
61
61
  | `<link rel="stylesheet" href="/app.css">` | The bundled stylesheet |
62
- | `<a lb-nav-link>` | Navigation between pages |
63
- | `lb-row="lb-navigation"` | Where the page is — see below |
64
- | `<dialog lb-unknown-page>` | A message when a URL matches no page |
65
- | Custom elements | The chrome, decomposed into widget files |
62
+ | `<a lb-url-link>` | A link between pages |
63
+ | `lb-query="lb-url"` | Where the page is — see below |
64
+ | `<dialog lb-url-unknown>` | A message when a URL matches no page |
65
+ | Custom elements | The chrome, decomposed into element files |
66
66
  | `<body hidden>` + a `<noscript>` fallback | Avoids a first-load blink — see below |
67
67
  | Any other HTML | Header, footer, skip links, meta tags, etc. |
68
68
 
69
- ## Rules for writing chrome
69
+ ## Rules for writing chrome
70
70
 
71
- Anything the user interacts with must be inside `<lb-hub>`. The hub normally
71
+ Put everything the user interacts with inside `<lb-hub>`. The hub normally
72
72
  sits directly inside `<body>`, with banner, nav, footer and `<main>` inside
73
73
  it, so Loadbare can act on all of them.
74
74
 
75
- A navigation anchor's `href` is a path, and the path names a page:
76
- `/members` shows `members.page.html`. A query string on it is kept, so
77
- `/members?team=Engines` opens the page narrowed; see
78
- [Query parms](./data-binding.md#query-parms). A bare `/` resolves to `index`, so the
79
- landing page is the one named `index.page.html`. An anchor without
80
- `lb-nav-link` is left alone and behaves like any other link.
75
+ The chrome's `<title>` is the document title until the first page shows.
76
+ From then on the hub sets the document title to the page's label; see
77
+ [The URL](#the-url).
81
78
 
82
- The `lb-unknown-page` attribute, if used, must appear on a `<dialog>` inside
83
- `<lb-hub>`; the builder rejects it anywhere else. The hub opens it when a
84
- path names no page. What it says is up to the chrome:
85
- the dialog is a subtree like any other, and it displays where the page is by
86
- naming the hub's own query, described next.
79
+ Put `lb-url-unknown` on a `<dialog>` inside `<lb-hub>`; the builder rejects
80
+ it anywhere else.
87
81
 
88
- ## Where the page is
82
+ ## The URL
89
83
 
90
- On every navigation the hub lands a query of its own, `lb-navigation`, on
91
- any subtree inside the hub that names it. It arrives the way a server's
92
- row arrives — `lb-row` on the subtree, `lb-cell` on each element that
93
- shows a value — so a chrome displays the current page with no code at all:
84
+ The hub serves one query of its own, `lb-url`, of kind `row`, keyed by
85
+ `lb-path`. It lands on every element inside the hub that names it, the way a
86
+ server's row lands, so a chrome shows where the page is with no code:
94
87
 
95
88
  ```html
96
- <header lb-row="lb-navigation">
89
+ <header lb-query="lb-url">
97
90
  <h1>Membership Roster</h1>
98
- <h2 lb-cell="page-label"></h2>
91
+ <h2 lb-column="lb-page-label"></h2>
99
92
  </header>
100
93
  ```
101
94
 
102
- | Cell | Holds |
103
- |--------------|-----------------------------------------------------------|
104
- | `page-label` | The text of the `lb-nav-link` anchor for the path, or empty if none |
105
- | `page-uri` | The path and query string as the browser has them, such as `/members?team=Engines` |
95
+ | Column | Holds |
96
+ |-------------------|---------------------------------------------------------|
97
+ | `lb-path` | The path, such as `/members`. The row's key |
98
+ | `lb-page-label` | The page's title, or its stub when it has none |
99
+ | `lb-page-unknown` | `true` when no page's stub matches the path |
100
+ | Any other name | The query parm of that name, or empty when it is absent |
106
101
 
107
- The label is the nav's. The hub takes it from the first `lb-nav-link`
108
- anchor whose path names the current page, whatever its query string, so a click, a reload and the
109
- back button all land the same text, and a path no anchor names lands an
110
- empty label. A chrome that shows the label somewhere fixed should expect
111
- that case for a page reachable only by URL.
102
+ A path names a page by its stub: `/members` shows `members.page.html`, and
103
+ `/` shows `index.page.html`. A page's title is the text of the `<title>` its
104
+ page file carries; see [page files](./page-files.md#the-page-title). The hub
105
+ sets the document title to `lb-page-label` whenever it is not null, so the
106
+ tab and the browser history show the page.
112
107
 
113
- The `lb-` prefix on the query name is what keeps it out of the server's
114
- namespace: no server answers a query so named. It is landed only where a
115
- subtree names it, so a chrome that displays no navigation is not warned
116
- about a query with no scope.
108
+ `lb-url` is the one query a page may use that the server does not declare. A
109
+ page names it the same way, anywhere inside the hub.
117
110
 
118
- The same row is what an unknown-page dialog has to work with. It lands
119
- before the page host is looked up, so a miss has it too. Name the query on
120
- the dialog and show whichever cell fits:
111
+ ### Links
112
+
113
+ Write `lb-url-link` on an `<a>` to move between pages:
114
+
115
+ ```html
116
+ <nav>
117
+ <a href="/" lb-url-link>Home</a>
118
+ <a href="/members?team=Engines" lb-url-link>Engines</a>
119
+ </nav>
120
+ ```
121
+
122
+ On a plain primary click, the hub pushes a history entry for the `href`,
123
+ path and query string both, and shows the page it names. A click with a
124
+ modifier key or another button, and a link without `lb-url-link`, behave as
125
+ the browser has them behave. Back and Forward show the page at the URL they
126
+ arrive at.
127
+
128
+ ### Query parms
129
+
130
+ A query parm is a column of `lb-url`. A control inside `lb-query="lb-url"`
131
+ that sends `lb-row-update` writes its value into the query string:
132
+
133
+ ```html
134
+ <div lb-query="lb-url">
135
+ <select lb-column="team" lb-request="lb-row-update">
136
+ <option value="">Every team</option>
137
+ <option value="Engines">Engines</option>
138
+ </select>
139
+ </div>
140
+ ```
141
+
142
+ On `change`, the hub sets that parm and keeps every other, and takes the
143
+ parm out when the value is empty. It replaces the current history entry, and
144
+ pushes one instead when the element carrying `lb-request` also carries
145
+ `lb-url-push`:
146
+
147
+ ```html
148
+ <input lb-column="q" lb-request="lb-row-update" lb-url-push />
149
+ ```
150
+
151
+ The hub answers the request itself, with no round trip, then reloads the
152
+ page's queries at the new URL. The page stays in place, and rows that come
153
+ back keep their place.
154
+
155
+ A control whose column the URL does not carry lands empty, so every control
156
+ inside `lb-query="lb-url"` shows what the address bar says, after a reload
157
+ and after Back alike.
158
+
159
+ The hub sends the query parms with every round trip, and the server hands
160
+ them to `contextFor`; see [the Express server](./server.md#database-layer).
161
+ A handler moves the URL by returning `url()`, when only the server knows the
162
+ new value; see [page files](./page-files.md#moving-the-url).
163
+
164
+ ### An unknown page
165
+
166
+ A path that names no page shows the unknown-page dialog. Write it in the
167
+ chrome as a `<dialog>` carrying `lb-url-unknown`, and name `lb-url` on it to
168
+ show the path:
121
169
 
122
170
  ```html
123
- <dialog lb-unknown-page lb-row="lb-navigation">
124
- The URL <span lb-cell="page-uri"></span> is not in this app.
171
+ <dialog lb-url-unknown lb-query="lb-url">
172
+ The URL <span lb-column="lb-path"></span> is not in this app.
125
173
  </dialog>
126
174
  ```
127
175
 
128
- `@loadbare/widgets` ships this dialog as a widget, `<lb-unknown-page>`, for a
129
- chrome that would rather write one tag — see
176
+ When no page's stub matches the path, `lb-page-unknown` is `true`,
177
+ `lb-page-label` is null, `<main>` keeps the page it had, and the hub calls
178
+ `showModal()` on the dialog.
179
+
180
+ `@loadbare/widgets` ships this dialog as `<lb-unknown-page>`, for a chrome
181
+ that would rather write one tag; see
130
182
  [The Basic Widget Library](./widgets.md#lb-unknown-page).
131
183
 
132
184
  ## Preventing the first-load blink
@@ -137,10 +189,9 @@ visible flash: the chrome appears first, then `<main>`'s real content pops in
137
189
  a moment later and shifts everything around it.
138
190
 
139
191
  `<body hidden>` avoids this by hiding the whole document, not just `<main>`,
140
- until the hub has something to show. `<lb-hub>` un-hides `<body>` itself the
141
- first time `navigate()` finishes, so the chrome and the first page's content
142
- always appear together, already in their final layout — there is no
143
- intermediate state to flash.
192
+ until the hub has something to show. `<lb-hub>` un-hides `<body>` itself
193
+ once it has put the first page in `<main>`, so the chrome and the first
194
+ page's markup appear together, already in their final layout.
144
195
 
145
196
  Hiding `<main>` alone doesn't work: an empty `<main>` already renders at zero
146
197
  height, so hiding it changes nothing visible. The pop-in comes from the