@loadbare/app 0.25.0 → 0.27.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 +1 -2
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +31 -37
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/cli.d.ts +4 -10
- package/dist/build/cli.d.ts.map +1 -1
- package/dist/build/cli.js +11 -33
- package/dist/build/cli.js.map +1 -1
- package/dist/build/declared.js +1 -1
- package/dist/build/declared.js.map +1 -1
- package/dist/core/lb-constants.d.ts +15 -13
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +47 -51
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +12 -11
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js +7 -0
- package/dist/core/lb-types.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +10 -34
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +92 -151
- 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 +115 -127
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/hub/lb-lifecycle.d.ts.map +1 -1
- package/dist/hub/lb-lifecycle.js +4 -11
- package/dist/hub/lb-lifecycle.js.map +1 -1
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +3 -3
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +35 -19
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +141 -88
- package/dist/server/lb-server.js.map +1 -1
- package/docs/binding-cases.md +150 -0
- package/docs/comparison.md +34 -38
- package/docs/opinions.md +2 -2
- package/docs/reference/chrome.md +8 -10
- package/docs/reference/css.md +9 -10
- package/docs/reference/custom-elements.md +11 -8
- package/docs/reference/data-binding.md +93 -134
- package/docs/reference/names.md +21 -22
- package/docs/reference/page-files.md +24 -26
- package/docs/reference/server.md +3 -4
- package/docs/roadmap.md +2 -2
- package/docs/testing.md +5 -6
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +55 -48
- package/skills/loadbare-app/references/chrome.md +8 -10
- package/skills/loadbare-app/references/css.md +9 -10
- package/skills/loadbare-app/references/custom-elements.md +11 -8
- package/skills/loadbare-app/references/data-binding.md +93 -134
- package/skills/loadbare-app/references/names.md +21 -22
- package/skills/loadbare-app/references/page-files.md +24 -26
- package/skills/loadbare-app/references/server.md +3 -4
package/docs/reference/names.md
CHANGED
|
@@ -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
|
|
18
|
-
| `--out` | `dist` | Where the builder writes | [Running the builder](./builder.md
|
|
19
|
-
| `--
|
|
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
|
|
68
|
+
The developer writes ten 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
|
|
@@ -77,12 +76,10 @@ assigns one.
|
|
|
77
76
|
| `lb-query` | Developer | [Landing](./data-binding.md#landing) |
|
|
78
77
|
| `lb-column` | Developer | [Landing](./data-binding.md#landing) |
|
|
79
78
|
| `lb-show` | Developer | [Conditional rendering](./data-binding.md#conditional-rendering) |
|
|
80
|
-
| `lb-order` | Developer | [Order](./data-binding.md#order) |
|
|
81
79
|
| `lb-filter` | Developer | [Filters](./data-binding.md#filters) |
|
|
82
80
|
| `lb-manual` | Developer | [Placing by hand](./data-binding.md#placing-by-hand) |
|
|
83
81
|
| `lb-group` | Developer | [Groups](./data-binding.md#groups) |
|
|
84
|
-
| `lb-
|
|
85
|
-
| `lb-select` | Developer | [Selecting rows](./data-binding.md#selecting-rows) |
|
|
82
|
+
| `lb-aggregate` | Developer | [Aggregates](./data-binding.md#aggregates) |
|
|
86
83
|
| `lb-request` | Developer | [Requests](./data-binding.md#requests) |
|
|
87
84
|
| `lb-url-link` | Developer | [Links](./chrome.md#links) |
|
|
88
85
|
| `lb-url-parm` | Developer | [A link from a row](./chrome.md#a-link-from-a-row) |
|
|
@@ -100,7 +97,6 @@ assigns one.
|
|
|
100
97
|
| `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
98
|
| `lb-row-leaving`, `lb-group-leaving` | Hub | [What happened to a row](./data-binding.md#what-happened-to-a-row) |
|
|
102
99
|
| `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
100
|
| `lb-request-pending` | Hub | [Request state](./data-binding.md#request-state) |
|
|
105
101
|
| `lb-request-error` | Hub | [Request state](./data-binding.md#request-state) |
|
|
106
102
|
| `lb-request-refused` | Hub | [Refusals](./data-binding.md#refusals) |
|
|
@@ -116,9 +112,10 @@ them, and a page declares none.
|
|
|
116
112
|
|
|
117
113
|
| Query | Kind | Key | Columns | Defined in |
|
|
118
114
|
| ------------ | ----- | --------- | --------------------------------------------------------------- | ------------------------------------- |
|
|
119
|
-
| `lb-url` | `row` | `lb-path` | `lb-path`, `lb-page-label`,
|
|
120
|
-
| `lb-
|
|
121
|
-
| `lb-
|
|
115
|
+
| `lb-url` | `row` | `lb-path` | `lb-path`, `lb-page-label`, every query parm | [The URL](./chrome.md#the-url) |
|
|
116
|
+
| `lb-sort` | `rows` | `query` | `query`, `order` | [Sort and filters](./data-binding.md#sort-and-filters) |
|
|
117
|
+
| `lb-filters` | `rows` | `query` | `query`, every filter column | [Sort and filters](./data-binding.md#sort-and-filters) |
|
|
118
|
+
| `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
119
|
|
|
123
120
|
No query parm is reserved: a column of `lb-url` whose name begins with
|
|
124
121
|
`lb-` is never a query parm.
|
|
@@ -176,7 +173,7 @@ accessor or field named `lb` and a capital.
|
|
|
176
173
|
|
|
177
174
|
| Entry point | Exports | Defined in |
|
|
178
175
|
| -------------------------- | ---------------------------------------------------------------- | ---------------------------------------------- |
|
|
179
|
-
| `@loadbare/app/server` | `row`, `rows`, `patch`, `url`, `
|
|
176
|
+
| `@loadbare/app/server` | `row`, `rows`, `patch`, `url`, `sort`, `filters`, `refusal`, `createHub`, and the types `Queries`, `Requests`, `HubContext`, `Hub` | [Page Files](./page-files.md), [The data channel](./server.md#the-data-channel) |
|
|
180
177
|
| `@loadbare/app/express` | `hubRoutes` | [The Express Server](./server.md) |
|
|
181
178
|
| `@loadbare/app/dev` | `devServer`, `appServer`, `gate`, `devProxy`, `DOWN_MESSAGE` | [The Dev Server](./dev-server.md) |
|
|
182
179
|
| `@loadbare/app/build` | `buildApp`, `watchApp` | [Assembling your own](./dev-server.md#assembling-your-own) |
|
|
@@ -207,12 +204,16 @@ imports them rather than writing a string.
|
|
|
207
204
|
| `ATTR_GROUP_COLUMN` | `lb-group-column` |
|
|
208
205
|
| `ATTR_GROUP_VALUE` | `lb-group-value` |
|
|
209
206
|
| `LIVE_GROUP` | `[lb-group-live]`, the selector for a group's element |
|
|
210
|
-
| `
|
|
211
|
-
| `
|
|
207
|
+
| `ATTR_AGGREGATE` | `lb-aggregate` |
|
|
208
|
+
| `AGGREGATE_COUNT`, `AGGREGATE_SUM`, `AGGREGATE_AVG`, `AGGREGATE_MIN`, `AGGREGATE_MAX` | `count`, `sum`, `avg`, `min`, `max` |
|
|
209
|
+
| `AGGREGATES` | All five aggregate functions |
|
|
212
210
|
| `ORDER_DESCENDING` | `-`, written before a column in an order |
|
|
213
211
|
| `COLUMN_TYPES` | `number`, `boolean`, `text` |
|
|
214
|
-
| `
|
|
215
|
-
| `
|
|
212
|
+
| `SORT_QUERY` | `lb-sort` |
|
|
213
|
+
| `SORT_COLUMN_QUERY` | `query` |
|
|
214
|
+
| `SORT_COLUMN_ORDER` | `order` |
|
|
215
|
+
| `FILTERS_QUERY` | `lb-filters` |
|
|
216
|
+
| `FILTERS_COLUMN_QUERY` | `query` |
|
|
216
217
|
| `ATTR_FILTER` | `lb-filter` |
|
|
217
218
|
| `ATTR_MANUAL` | `lb-manual` |
|
|
218
219
|
| `MANUAL_ORDER`, `MANUAL_FILTER` | `order`, `filter`: the sides `lb-manual` names |
|
|
@@ -236,13 +237,12 @@ imports them rather than writing a string.
|
|
|
236
237
|
| `LB_COMMANDS` | All four commands |
|
|
237
238
|
| `LB_COMMAND_PREFIX` | `--lb-` |
|
|
238
239
|
| `ATTR_ROW_EDITING` | `lb-row-editing` |
|
|
239
|
-
| `ATTR_SELECT` | `lb-select` |
|
|
240
|
-
| `ATTR_ROW_SELECTED` | `lb-row-selected` |
|
|
241
240
|
| `LB_RESERVED_PREFIX` | `lb-` |
|
|
242
241
|
| `REQUEST_ROW_INSERT` | `lb-row-insert` |
|
|
243
242
|
| `REQUEST_ROW_UPDATE` | `lb-row-update` |
|
|
244
243
|
| `REQUEST_ROW_DELETE` | `lb-row-delete` |
|
|
245
244
|
| `LB_ROW_REQUESTS` | All three request names |
|
|
245
|
+
| `REQUEST_READ` | `lb-read`, the hub's own read of a bound form's lists; markup never writes it |
|
|
246
246
|
| `LB_METHODS` | The four reserved methods |
|
|
247
247
|
| `BROWSER_LIFECYCLE` | The browser callbacks the build refuses |
|
|
248
248
|
| `KIND_ROW` | `row` |
|
|
@@ -250,8 +250,7 @@ imports them rather than writing a string.
|
|
|
250
250
|
| `URL_QUERY` | `lb-url` |
|
|
251
251
|
| `URL_COLUMN_PATH` | `lb-path` |
|
|
252
252
|
| `URL_COLUMN_PAGE_LABEL` | `lb-page-label` |
|
|
253
|
-
| `
|
|
254
|
-
| `HUB_QUERY` | `lb-hub` |
|
|
253
|
+
| `HUB_QUERY` | `lb-hub-status` |
|
|
255
254
|
| `HUB_COLUMN_LOAD_STATE` | `lb-load-state` |
|
|
256
255
|
| `HUB_COLUMN_SERVER_STATE` | `lb-server-state` |
|
|
257
256
|
| `HUB_COLUMN_ERROR` | `lb-error` |
|
|
@@ -268,7 +267,7 @@ imports them rather than writing a string.
|
|
|
268
267
|
| `ATTR_EXP_TEMPLATE` | `lb-exp-template` |
|
|
269
268
|
| `ATTR_PAGE` | `lb-page` |
|
|
270
269
|
| `ATTR_PAGE_TITLE` | `lb-page-title` |
|
|
271
|
-
| `DEVELOPER_ATTRIBUTES` | The
|
|
270
|
+
| `DEVELOPER_ATTRIBUTES` | The ten attributes a developer writes |
|
|
272
271
|
| `HUB_TAG_NAME` | `lb-hub` |
|
|
273
272
|
| `LB_ENDPOINT` | `/lb` |
|
|
274
273
|
| `LB_REQUEST_TIMEOUT_MS` | `10000` |
|
|
@@ -152,8 +152,8 @@ optional:
|
|
|
152
152
|
|
|
153
153
|
| Key | Runs |
|
|
154
154
|
|---------------|--------------------------------------------------------|
|
|
155
|
-
| `onPageEnter` | Before the page's queries, when the page loads; may move the URL or restore
|
|
156
|
-
| `onChoices` | Each time the user
|
|
155
|
+
| `onPageEnter` | Before the page's queries, when the page loads; may move the URL or restore the user's order and filters |
|
|
156
|
+
| `onChoices` | Each time the user changes the order or a filter |
|
|
157
157
|
| `handlers` | The page's declared requests, by request name |
|
|
158
158
|
| `crud` | The requests Loadbare provides, by query name |
|
|
159
159
|
|
|
@@ -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).
|
|
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
|
|
|
@@ -193,34 +190,41 @@ loads there in the same round trip, and that load does not follow
|
|
|
193
190
|
`onPageEnter` again. A `url()` leading to the parms already in hand is
|
|
194
191
|
ignored. See [Moving the URL](#moving-the-url).
|
|
195
192
|
|
|
196
|
-
It may return `
|
|
197
|
-
[
|
|
193
|
+
It may return `sort()` and `filters()`, alone or beside `url()`, to restore
|
|
194
|
+
the user's [order and filters](./data-binding.md#sort-and-filters) for the
|
|
195
|
+
page:
|
|
198
196
|
|
|
199
197
|
```ts
|
|
200
198
|
// src/pages/directory.requests.ts
|
|
201
|
-
import {
|
|
199
|
+
import { sort, filters, url, type Requests } from "@loadbare/app/server";
|
|
202
200
|
|
|
203
201
|
export const requests: Requests = {
|
|
204
202
|
onPageEnter: async (ctx) => {
|
|
205
203
|
const saved = await ctx.db.savedView("directory");
|
|
206
|
-
if (saved)
|
|
204
|
+
if (saved) {
|
|
205
|
+
return {
|
|
206
|
+
...url(saved.parms),
|
|
207
|
+
...sort(saved.order),
|
|
208
|
+
...filters(saved.filters),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
207
211
|
},
|
|
208
|
-
onChoices: (ctx,
|
|
212
|
+
onChoices: (ctx, change) => ctx.db.saveChoices(change),
|
|
209
213
|
};
|
|
210
214
|
```
|
|
211
215
|
|
|
212
|
-
The page load answers `lb-
|
|
213
|
-
When `url()` moves the page, the choices arrive
|
|
214
|
-
URL. `
|
|
215
|
-
least one of them; anything else is
|
|
216
|
-
ignored.
|
|
216
|
+
The page load answers `lb-sort` and `lb-filters` first, so the rows land by
|
|
217
|
+
the order and the filters. When `url()` moves the page, the choices arrive
|
|
218
|
+
with the load at the new URL. `sort()` and `filters()`, like `url()`, take
|
|
219
|
+
columns whose values are strings, at least one of them; anything else is
|
|
220
|
+
reported on the server console and ignored.
|
|
217
221
|
|
|
218
222
|
### onChoices
|
|
219
223
|
|
|
220
|
-
`onChoices` runs each time the user
|
|
221
|
-
|
|
222
|
-
`onPageEnter` to restore, and answers nothing, by
|
|
223
|
-
returns lands. A page without it is not told.
|
|
224
|
+
`onChoices` runs each time the user changes the order or a filter, with the
|
|
225
|
+
query and its new `sort` or `filters`, as strings. It is how an application
|
|
226
|
+
keeps them for `onPageEnter` to restore, and answers nothing, by
|
|
227
|
+
convention. Whatever it returns lands. A page without it is not told.
|
|
224
228
|
|
|
225
229
|
### handlers
|
|
226
230
|
|
|
@@ -264,12 +268,6 @@ are one vocabulary:
|
|
|
264
268
|
| `lb-row-update` | `rowUpdate` | `query`, `key`, `values`, and `rows` from a form |
|
|
265
269
|
| `lb-row-delete` | `rowDelete` | `query`, `key` |
|
|
266
270
|
|
|
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
271
|
`rows` holds the rows of a query nested in the form the request came from,
|
|
274
272
|
by query name, each with its `key` and the `values` of its own controls; see
|
|
275
273
|
[A form over a set of rows](./data-binding.md#a-form-over-a-set-of-rows).
|
package/docs/reference/server.md
CHANGED
|
@@ -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
|
}
|
|
@@ -229,9 +228,9 @@ in `drop` are removed, and every other row is left alone. A `rows` item on
|
|
|
229
228
|
the answer that loads the page also carries the query's declared `order`
|
|
230
229
|
and `types`, which the hub keeps for every answer after it.
|
|
231
230
|
|
|
232
|
-
A
|
|
233
|
-
|
|
234
|
-
[
|
|
231
|
+
A sort or a filter is sent as `lb-row-update` for `lb-sort` or `lb-filters`,
|
|
232
|
+
keyed by the query's name, with the new order or filter as `values`; see
|
|
233
|
+
[Sort and filters](./data-binding.md#sort-and-filters).
|
|
235
234
|
|
|
236
235
|
`createHub(pages)` builds the `Hub`, which has two calls, both answering
|
|
237
236
|
with response items: `dataForPage(page, ctx, options)` for a page load, and
|
package/docs/roadmap.md
CHANGED
|
@@ -148,8 +148,8 @@ breaks nothing.
|
|
|
148
148
|
|
|
149
149
|
The chrome belongs to no page, so the builder refuses an application query
|
|
150
150
|
named there, and a custom element in the chrome cannot show application
|
|
151
|
-
data. `lb-url` and `lb-
|
|
152
|
-
and an application has no equivalent.
|
|
151
|
+
data. `lb-url`, `lb-sort` and `lb-filters` show the pattern from the
|
|
152
|
+
framework side, and an application has no equivalent.
|
|
153
153
|
|
|
154
154
|
A chrome-level query set on `createHub` would close this, and it is additive.
|
|
155
155
|
It takes its place in the [options on `createHub`](#options-on-createhub).
|
package/docs/testing.md
CHANGED
|
@@ -172,8 +172,8 @@ watch, and surviving a failed build.
|
|
|
172
172
|
that refreshes its own `rows` query are refused
|
|
173
173
|
- an update or delete for several rows runs once per key, lays the patches
|
|
174
174
|
together, and refreshes once
|
|
175
|
-
- `onPageEnter` may return `url()` or `
|
|
176
|
-
every
|
|
175
|
+
- `onPageEnter` may return `url()`, `sort()` or `filters()`, and
|
|
176
|
+
`onChoices` hears every order and filter the user makes
|
|
177
177
|
- a refusal carries a message, columns or both, and passes through the
|
|
178
178
|
engine untouched
|
|
179
179
|
|
|
@@ -276,8 +276,9 @@ What the hub is tested for here:
|
|
|
276
276
|
deadline, under mocked timers, and fails the way any round trip fails
|
|
277
277
|
- a successful insert gathered from a form resets the form, unless the
|
|
278
278
|
answer landed the new row on it
|
|
279
|
-
- a path
|
|
280
|
-
`lb-url-unknown` dialog; two pages for one stub
|
|
279
|
+
- a path naming a page that does not exist reports, lands `lb-page-label`
|
|
280
|
+
as null, and opens the `lb-url-unknown` dialog; two pages for one stub
|
|
281
|
+
report and take the first
|
|
281
282
|
- `lb-url` lands with the path, the page's `lb-page-title` or stub as
|
|
282
283
|
`lb-page-label`, and a column per query parm, and sets the document title
|
|
283
284
|
- `lb-url-link` pushes state and swaps the page on a plain primary click,
|
|
@@ -296,8 +297,6 @@ What the hub is tested for here:
|
|
|
296
297
|
queries land
|
|
297
298
|
- a form pointed at a row by `commandfor` fills from the row the hub holds,
|
|
298
299
|
and a row not yet entered sends no update or delete
|
|
299
|
-
- ticked `lb-select` rows travel as `keys`, and the selection clears once
|
|
300
|
-
the request succeeds
|
|
301
300
|
- a refusal lands its message on the element that committed and on each
|
|
302
301
|
control it names
|
|
303
302
|
- `lb-request-done` reaches the element that committed and its ancestors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: loadbare-app
|
|
3
|
-
description: Build server-bound web applications with Loadbare/app. Covers the file conventions the builder finds by name (`chrome.html`, `*.page.html`, `*.queries.ts`, `*.requests.ts`, `imports.ts`, `<tag>.html`, `<tag>.browser.ts`); the `lb-*` attribute vocabulary that lands query rows on HTML and issues requests (`lb-query`, `lb-column`, `lb-show`, `lb-request`); queries declared with `row(key, run)` and `rows(key, run)`; the URL as the hub's own query `lb-url`, with `lb-url-link`, `lb-url-parm`, `lb-url-push` and `lb-url-unknown`; the user's order and filters as the hub's
|
|
3
|
+
description: Build server-bound web applications with Loadbare/app. Covers the file conventions the builder finds by name (`chrome.html`, `*.page.html`, `*.queries.ts`, `*.requests.ts`, `imports.ts`, `<tag>.html`, `<tag>.browser.ts`); the `lb-*` attribute vocabulary that lands query rows on HTML and issues requests (`lb-query`, `lb-column`, `lb-show`, `lb-request`); queries declared with `row(key, run)` and `rows(key, run)`; the URL as the hub's own query `lb-url`, with `lb-url-link`, `lb-url-parm`, `lb-url-push` and `lb-url-unknown`; the user's order and filters as the hub's queries `lb-sort` and `lb-filters`, read by `lb-filter`; whether the page loaded and the server answers as the hub's query `lb-hub-status`; one form pointed at a row by the `--lb-edit`, `--lb-new` and `--lb-release` commands; rows that hold still under `lb-manual` and are placed again with `--lb-place`; build-time expansion with `exp-*` parameters, `lb-exp-slot` and `lb-exp-template`; custom elements as form-associated controls and row hosts; the Express wiring with `hubRoutes`; and the `@loadbare/widgets` library. Use whenever a task involves `@loadbare/app`, `@loadbare/widgets`, `loadbare-app-build`, an `lb-` attribute, or a page, query, request or custom element file in a Loadbare application. The model is not React, htmx or REST, and cannot be inferred from them.
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
metadata:
|
|
6
6
|
package: "@loadbare/app"
|
|
@@ -75,7 +75,7 @@ server.ts
|
|
|
75
75
|
The chrome carries `<lb-hub>` inside `<body>`, an empty `<main>` inside the
|
|
76
76
|
hub, and `<script src="/client.js" defer>`. Everything a user touches sits
|
|
77
77
|
inside `<lb-hub>`. The chrome belongs to no page, so it names only the
|
|
78
|
-
hub's queries, `lb-url`, `lb-
|
|
78
|
+
hub's queries, `lb-url`, `lb-sort`, `lb-filters` and `lb-hub-status`, and sends no declared
|
|
79
79
|
request.
|
|
80
80
|
|
|
81
81
|
A page is an HTML fragment that lands in `<main>`:
|
|
@@ -195,7 +195,10 @@ is added by a button with `commandfor` naming the nested list and
|
|
|
195
195
|
the form's submit carries it as `{ key: "", values }`, the handler inserts
|
|
196
196
|
each row with no key, and it leaves when the submit succeeds. So a master
|
|
197
197
|
and its details are one save, before or after the master is on record; never
|
|
198
|
-
gate the details behind `lb-show` on the master being saved.
|
|
198
|
+
gate the details behind `lb-show` on the master being saved. A form bound
|
|
199
|
+
by Edit or New reads its nested lists again (`lb-read`) with the bound key
|
|
200
|
+
as the parm named for its key column, so the details query reads that parm
|
|
201
|
+
and follows the row the form is bound to; New sends it empty. The form needs
|
|
199
202
|
a submit. A new outer
|
|
200
203
|
row is filled from the nested query's last answer, whatever order they land
|
|
201
204
|
in.
|
|
@@ -220,21 +223,19 @@ JSON number or is declared one: `types: { amount: "number" }` beside
|
|
|
220
223
|
hold a place.
|
|
221
224
|
|
|
222
225
|
**The user's order and filters are choices, not query parms.** The hub
|
|
223
|
-
serves
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
`lb-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
page changes. A filter that decides which rows the server sends is a query
|
|
234
|
-
parm.
|
|
226
|
+
serves them as two queries, `lb-sort` and `lb-filters`, one row per query
|
|
227
|
+
keyed by the query's name. `lb-sort` holds each query's order as the
|
|
228
|
+
server resolved it; `lb-filters` holds each query's filter values.
|
|
229
|
+
`lb-filter="col, col"` on the element carrying `lb-query` hides each row
|
|
230
|
+
that does not pass its query's filter of the same name: `^=Amazon`,
|
|
231
|
+
`>=2026-01-01 <=2026-03-31`, or plain text for contains. The server's
|
|
232
|
+
`onChoices(ctx, { query, sort, filters })` hears each change, to keep it;
|
|
233
|
+
`onPageEnter` returns `sort()` and `filters()` to restore them. Choices
|
|
234
|
+
hold until the page changes. A filter that decides which rows the server
|
|
235
|
+
sends is a query parm.
|
|
235
236
|
|
|
236
237
|
**A page that failed to load says so.** The hub serves a third query,
|
|
237
|
-
`lb-hub`, and stamps its columns on `<lb-hub>` too: `lb-load-state`
|
|
238
|
+
`lb-hub-status`, and stamps its columns on `<lb-hub>` too: `lb-load-state`
|
|
238
239
|
(`loading`, `loaded`, `failed`), `lb-server-state` (`reachable`, `failing`,
|
|
239
240
|
`unreachable`), `lb-error` (`network`, `timeout` or the HTTP status),
|
|
240
241
|
`lb-pending` and `lb-as-of`. Show a server that is down from the chrome's
|
|
@@ -247,9 +248,10 @@ nested `<template>`, the next level or the row template; the nth breaks on
|
|
|
247
248
|
the order's nth term, to any depth. Contents land before the nested
|
|
248
249
|
template, so put it inside the heading's element for a container and beside
|
|
249
250
|
the heading for a heading row. `<tbody>` and `<optgroup>` do not nest. The
|
|
250
|
-
heading is filled from the group's first row. `lb-
|
|
251
|
-
`
|
|
252
|
-
or in the whole list outside any.
|
|
251
|
+
heading is filled from the group's first row. `lb-aggregate` with `count`,
|
|
252
|
+
`sum`, `avg`, `min` or `max`, and `lb-column` naming the column, totals the
|
|
253
|
+
rows showing in the nearest group, or in the whole list outside any.
|
|
254
|
+
`count` with no column counts the rows.
|
|
253
255
|
|
|
254
256
|
**Animate with CSS.** The hub stamps `lb-row-created`, `lb-row-changed`,
|
|
255
257
|
`lb-row-moved` (its values changed and it now stands elsewhere), and
|
|
@@ -327,16 +329,6 @@ update or delete at all, silently. So a control with
|
|
|
327
329
|
`lb-request="lb-row-update"` saves on a row on record and only holds its
|
|
328
330
|
value on a new one. Never write script to stop such an update.
|
|
329
331
|
|
|
330
|
-
**Select rows with `lb-select`, never with a column.** An
|
|
331
|
-
`<input type="checkbox" lb-select>` in a row template selects its row; the
|
|
332
|
-
hub stamps `lb-row-selected`. A request for that query naming no one row,
|
|
333
|
-
such as a form outside the rows, carries the ticked rows as `keys`.
|
|
334
|
-
`rowUpdate` and `rowDelete` then run once per key with no new code; a
|
|
335
|
-
declared request gets `keys` itself. With none ticked an update or delete
|
|
336
|
-
is not sent. Success clears the selection, and so does `lb-show` hiding a
|
|
337
|
-
selector. A selecting mode kept in the URL reaches the rows as a column the
|
|
338
|
-
query computes from the parm.
|
|
339
|
-
|
|
340
332
|
**Refuse with `refusal()`, never with a plain throw.** `throw
|
|
341
333
|
refusal("message")`, `throw refusal({ column: "message" })` or both, from
|
|
342
334
|
`@loadbare/app/server`. The whole-request message lands as the
|
|
@@ -394,8 +386,7 @@ the element sits.
|
|
|
394
386
|
shows, a filter the server applies, a date range: each is a query parm,
|
|
395
387
|
`/accounts?acct=23&from=2026-09-09`, so a reload, a bookmark or a mailed link
|
|
396
388
|
shows the same thing. The hub serves the query `lb-url`, of kind `row`,
|
|
397
|
-
keyed by `lb-path`, with `lb-page-label
|
|
398
|
-
per query parm. A control inside `lb-query="lb-url"` carrying
|
|
389
|
+
keyed by `lb-path`, with `lb-page-label` and one column per query parm. A control inside `lb-query="lb-url"` carrying
|
|
399
390
|
`lb-request="lb-row-update"` writes its parm; the hub replaces the history
|
|
400
391
|
entry, or pushes one when the control carries `lb-url-push`, and reloads the
|
|
401
392
|
page's queries with no request to the server. A parm the URL repeats,
|
|
@@ -439,9 +430,9 @@ whole data channel.
|
|
|
439
430
|
|
|
440
431
|
**The developer writes `lb-*` attributes in markup, and script never
|
|
441
432
|
assigns them.** The builder refuses any `lb-` attribute other than the
|
|
442
|
-
|
|
443
|
-
`lb-column`, `lb-show`, `lb-
|
|
444
|
-
`lb-
|
|
433
|
+
twelve in [Attributes](references/names.md#attributes): `lb-query`,
|
|
434
|
+
`lb-column`, `lb-show`, `lb-filter`, `lb-manual`, `lb-group`,
|
|
435
|
+
`lb-aggregate`, `lb-request`,
|
|
445
436
|
`lb-url-link`, `lb-url-parm`, `lb-url-push` and `lb-url-unknown`. `lb-exp-slot` and
|
|
446
437
|
`lb-exp-template` are expansion's, and never reach the page. Everything
|
|
447
438
|
else with the prefix is a stamp the hub or the builder writes.
|
|
@@ -527,28 +518,44 @@ The application's own definition of a tag overrides a package's.
|
|
|
527
518
|
Read these when the summary above does not settle the question. They ship
|
|
528
519
|
with the package, so no network is needed.
|
|
529
520
|
|
|
530
|
-
|
|
531
|
-
|
|
521
|
+
[`references/overview.md`](references/overview.md) is the map of the
|
|
522
|
+
reference, in the groups below.
|
|
523
|
+
|
|
524
|
+
The application shell:
|
|
525
|
+
|
|
526
|
+
- [`references/chrome.md`](references/chrome.md) — the chrome, the URL as
|
|
527
|
+
the query `lb-url`, and the hub's state.
|
|
528
|
+
- [`references/server.md`](references/server.md) — the Express server, the
|
|
529
|
+
request context, and where the database layer fits.
|
|
530
|
+
|
|
531
|
+
Building the app:
|
|
532
|
+
|
|
533
|
+
- [`references/builder.md`](references/builder.md) — the builder's options,
|
|
534
|
+
what it reads, where it looks, and what it writes.
|
|
535
|
+
- [`references/css.md`](references/css.md) — how stylesheets are ordered, and
|
|
536
|
+
the stamps a stylesheet selects on.
|
|
537
|
+
- [`references/dev-server.md`](references/dev-server.md) — `devServer` from
|
|
538
|
+
`@loadbare/app/dev`, and the parts to assemble another from.
|
|
539
|
+
|
|
540
|
+
Application pages:
|
|
541
|
+
|
|
542
|
+
- [`references/page-files.md`](references/page-files.md) — what page
|
|
543
|
+
files are, queries, `onPageEnter`, `onChoices`, handlers, `crud`, refresh
|
|
544
|
+
and patch, `url()`, `sort()` and `filters()`.
|
|
532
545
|
- [`references/data-binding.md`](references/data-binding.md) — landing,
|
|
533
546
|
gathering, requests, conditions and request state. Start here for
|
|
534
547
|
anything in a page.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
548
|
+
|
|
549
|
+
Custom elements:
|
|
550
|
+
|
|
538
551
|
- [`references/custom-elements.md`](references/custom-elements.md) —
|
|
539
552
|
expansion, parameters, slots, destinations, and custom element code and
|
|
540
553
|
when it runs.
|
|
541
|
-
- [`references/chrome.md`](references/chrome.md) — the chrome, and the URL
|
|
542
|
-
as the query `lb-url`.
|
|
543
|
-
- [`references/server.md`](references/server.md) — the Express server and
|
|
544
|
-
the request context.
|
|
545
|
-
- [`references/builder.md`](references/builder.md) — the builder's options,
|
|
546
|
-
what it reads, and where it looks.
|
|
547
|
-
- [`references/dev-server.md`](references/dev-server.md) — `devServer` from
|
|
548
|
-
`@loadbare/app/dev`, and the parts to assemble another from.
|
|
549
|
-
- [`references/css.md`](references/css.md) — how stylesheets are ordered.
|
|
550
554
|
- [`references/widgets.md`](references/widgets.md) — the basic widget
|
|
551
555
|
library as a package; each widget is in the loadbare-widgets skill.
|
|
556
|
+
|
|
557
|
+
Names:
|
|
558
|
+
|
|
552
559
|
- [`references/names.md`](references/names.md) — every name Loadbare
|
|
553
560
|
owns, the constants, and the section defining each. Check a name here
|
|
554
561
|
before designing around something the other references do not mention.
|
|
@@ -101,7 +101,6 @@ server's row lands, so a chrome shows where the page is with no code:
|
|
|
101
101
|
|-------------------|---------------------------------------------------------|
|
|
102
102
|
| `lb-path` | The path, such as `/members`. The row's key |
|
|
103
103
|
| `lb-page-label` | The page's title, or its stub when it has none |
|
|
104
|
-
| `lb-page-unknown` | `true` when no page's stub matches the path |
|
|
105
104
|
| Any other name | The query parm of that name, or empty when it is absent |
|
|
106
105
|
|
|
107
106
|
The path names a page, never a resource: `/accounts/42` is not a way to
|
|
@@ -116,9 +115,9 @@ page file carries; see [page files](./page-files.md#the-page-title). The hub
|
|
|
116
115
|
sets the document title to `lb-page-label` whenever it is not null, so the
|
|
117
116
|
tab and the browser history show the page.
|
|
118
117
|
|
|
119
|
-
`lb-url` is one of
|
|
120
|
-
declare. The
|
|
121
|
-
names
|
|
118
|
+
`lb-url` is one of the queries a page may use that the server does not
|
|
119
|
+
declare. The others are `lb-sort`, `lb-filters` and `lb-hub-status`. A page
|
|
120
|
+
names any the same way, anywhere inside the hub.
|
|
122
121
|
|
|
123
122
|
### Where focus starts
|
|
124
123
|
|
|
@@ -223,8 +222,8 @@ pushes one instead when the element carrying `lb-request` also carries
|
|
|
223
222
|
The hub answers the request itself, with no round trip, then reloads the
|
|
224
223
|
page's queries at the new URL. The page stays in place, and rows that come
|
|
225
224
|
back keep their place. A request that leaves the URL as it was does
|
|
226
|
-
nothing. `lb-page-label`
|
|
227
|
-
never sets
|
|
225
|
+
nothing. `lb-page-label` is the hub's, and a request
|
|
226
|
+
never sets it.
|
|
228
227
|
|
|
229
228
|
A request that gives `lb-path` a new value enters that page, pushes a
|
|
230
229
|
history entry, and the new URL carries only the query parms the request
|
|
@@ -288,8 +287,8 @@ it; a per-session database role means an id outside the caller's reach
|
|
|
288
287
|
finds nothing.
|
|
289
288
|
|
|
290
289
|
An order or a filter the hub applies to rows the page already holds is not
|
|
291
|
-
a query parm. It is a [
|
|
292
|
-
the page changes.
|
|
290
|
+
a query parm. It is a [sort or a filter](./data-binding.md#sort-and-filters),
|
|
291
|
+
which holds until the page changes.
|
|
293
292
|
|
|
294
293
|
The hub sends the query parms with every round trip, and the server hands
|
|
295
294
|
them to `contextFor`; see [the Express server](./server.md#database-layer).
|
|
@@ -308,8 +307,7 @@ show the path:
|
|
|
308
307
|
</dialog>
|
|
309
308
|
```
|
|
310
309
|
|
|
311
|
-
When
|
|
312
|
-
`lb-page-label` is null, `<main>` keeps the page it had, the hub calls
|
|
310
|
+
When the path names a page that does not exist, `lb-page-label` is null, `<main>` keeps the page it had, the hub calls
|
|
313
311
|
`showModal()` on the dialog, and reports the path to the console. A chrome
|
|
314
312
|
with no dialog shows nothing. `lb-url` lands before the page is looked up,
|
|
315
313
|
so the dialog shows the path by naming it like any other element.
|
|
@@ -69,7 +69,6 @@ in the stamp, so the selector reads the number and not its text. See
|
|
|
69
69
|
| Select | For |
|
|
70
70
|
|----------------------|-------------------------------------------------|
|
|
71
71
|
| `[lb-row-live]` | Every live row of a list |
|
|
72
|
-
| `[lb-row-selected]` | A row its `lb-select` checkbox ticks |
|
|
73
72
|
| `[lb-row-editing]` | The row a pointed form is editing |
|
|
74
73
|
| `[lb-key-value="…"]` | One row, by its key |
|
|
75
74
|
| `[hidden]` | A row a filter hides; the browser hides it |
|
|
@@ -86,11 +85,10 @@ landed inside a list, such as a total in a table's foot, carries a key and
|
|
|
86
85
|
is not one of the list's rows.
|
|
87
86
|
|
|
88
87
|
```css
|
|
89
|
-
[lb-row-selected] { background: var(--selected); }
|
|
90
88
|
[lb-row-editing] { outline: 2px solid var(--accent); }
|
|
91
89
|
```
|
|
92
90
|
|
|
93
|
-
See [Rows](./data-binding.md#rows)
|
|
91
|
+
See [Rows](./data-binding.md#rows)
|
|
94
92
|
and [Editing a row in one form](./data-binding.md#editing-a-row-in-one-form).
|
|
95
93
|
|
|
96
94
|
### A group
|
|
@@ -179,18 +177,19 @@ form:not([lb-key-value=""]) .save-new { display: none; }
|
|
|
179
177
|
|
|
180
178
|
See [Editing a row in one form](./data-binding.md#editing-a-row-in-one-form).
|
|
181
179
|
|
|
182
|
-
### The user's
|
|
180
|
+
### The user's order and filters
|
|
183
181
|
|
|
184
|
-
|
|
185
|
-
element showing
|
|
186
|
-
it with `:has()`:
|
|
182
|
+
The order the user chose is the `order` column of `lb-sort`, and a filter
|
|
183
|
+
is a column of `lb-filters`, so the element showing either carries it as
|
|
184
|
+
`lb-column-value`. Style anything else by it with `:has()`:
|
|
187
185
|
|
|
188
186
|
```css
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
:has([lb-column="name"][lb-column-value="^=Amazon"]) th.name::after {
|
|
188
|
+
content: "🔍";
|
|
189
|
+
}
|
|
191
190
|
```
|
|
192
191
|
|
|
193
|
-
See [
|
|
192
|
+
See [Sort and filters](./data-binding.md#sort-and-filters).
|
|
194
193
|
|
|
195
194
|
### Content shown by condition
|
|
196
195
|
|
|
@@ -572,18 +572,21 @@ missing a field its name needs, and stamps the dispatching element with
|
|
|
572
572
|
|
|
573
573
|
Let the event bubble, so an ancestor can stop it before the hub sends it.
|
|
574
574
|
|
|
575
|
-
A request with `lb-row-update` for `lb-url`
|
|
576
|
-
|
|
577
|
-
|
|
575
|
+
A request with `lb-row-update` for `lb-url` is keyed by the path; one for
|
|
576
|
+
`lb-sort` or `lb-filters` is keyed by the query's name. An element anywhere
|
|
577
|
+
on the page may set a query parm or make a
|
|
578
|
+
[sort or a filter](./data-binding.md#sort-and-filters) without sitting
|
|
579
|
+
inside the query:
|
|
578
580
|
|
|
579
581
|
```ts
|
|
580
|
-
import {
|
|
582
|
+
import { SORT_QUERY, LB_EVENT_NAME, REQUEST_ROW_UPDATE } from "@loadbare/app/constants";
|
|
581
583
|
import type { HubRequest } from "@loadbare/app/types";
|
|
582
584
|
|
|
583
585
|
const detail: HubRequest = {
|
|
584
586
|
name: REQUEST_ROW_UPDATE,
|
|
585
|
-
query:
|
|
586
|
-
|
|
587
|
+
query: SORT_QUERY,
|
|
588
|
+
key: "ledger",
|
|
589
|
+
values: { order: "-amount" },
|
|
587
590
|
};
|
|
588
591
|
this.dispatchEvent(new CustomEvent(LB_EVENT_NAME, { bubbles: true, detail }));
|
|
589
592
|
```
|
|
@@ -616,8 +619,8 @@ listener. Import its name as `LB_DONE_EVENT_NAME`.
|
|
|
616
619
|
`items` is every response item that landed because of the request, in
|
|
617
620
|
order. `refusal` is set beside `error` when the handler refused the
|
|
618
621
|
request, holding its `message` and `columns`. An answer that moved the URL contributes its `lb-url` item, which
|
|
619
|
-
carries a key only the server knew, and the page load. A
|
|
620
|
-
the row of `lb-
|
|
622
|
+
carries a key only the server knew, and the page load. A sort or a filter contributes
|
|
623
|
+
the row of `lb-sort` or `lb-filters` it made. `error` is set when
|
|
621
624
|
the round trip failed, and then nothing landed. A new row's key is in the
|
|
622
625
|
answer only when the handler returned it in a patch: a refresh sends all
|
|
623
626
|
rows, and nothing marks which one is new.
|