@loadbare/app 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +87 -1
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/cli.js +2 -1
- package/dist/build/cli.js.map +1 -1
- package/dist/build/elements.d.ts +9 -1
- package/dist/build/elements.d.ts.map +1 -1
- package/dist/build/elements.js +50 -0
- package/dist/build/elements.js.map +1 -1
- package/dist/build/origins.d.ts +2 -0
- package/dist/build/origins.d.ts.map +1 -1
- package/dist/build/origins.js +1 -1
- package/dist/build/origins.js.map +1 -1
- package/dist/core/lb-constants.d.ts +34 -1
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +105 -0
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +74 -18
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js +74 -11
- package/dist/core/lb-types.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +57 -18
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +661 -63
- 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 +400 -33
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/server/lb-express.d.ts +19 -7
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +62 -26
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +80 -11
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +185 -33
- package/dist/server/lb-server.js.map +1 -1
- package/docs/TECHREF-1.0.md +584 -111
- package/docs/comparison.md +17 -13
- package/docs/possible-ideas.md +308 -0
- package/docs/reference/chrome.md +7 -1
- package/docs/reference/custom-elements.md +134 -39
- package/docs/reference/data-binding.md +405 -17
- package/docs/reference/page-files.md +101 -19
- package/docs/reference/server.md +24 -0
- package/docs/reference/widgets.md +118 -25
- package/docs/roadmap.md +17 -6
- package/docs/testing.md +21 -10
- package/package.json +2 -3
- package/skills/loadbare-app/SKILL.md +92 -30
- package/skills/loadbare-app/references/TECHREF-1.0.md +584 -111
- package/skills/loadbare-app/references/chrome.md +7 -1
- package/skills/loadbare-app/references/custom-elements.md +134 -39
- package/skills/loadbare-app/references/data-binding.md +405 -17
- package/skills/loadbare-app/references/page-files.md +101 -19
- package/skills/loadbare-app/references/server.md +24 -0
- package/skills/loadbare-app/references/widgets.md +118 -25
|
@@ -48,7 +48,8 @@ page touches that page's files.
|
|
|
48
48
|
## HTML
|
|
49
49
|
|
|
50
50
|
Write the page as a fragment. The fragment lands in `<main>`, which
|
|
51
|
-
[chrome.html](./chrome.md) supplies.
|
|
51
|
+
[chrome.html](./chrome.md) supplies. A page carries no `<main>` and no
|
|
52
|
+
`<lb-hub>` of its own; the builder rejects one that does.
|
|
52
53
|
|
|
53
54
|
```html
|
|
54
55
|
<!-- src/pages/about.page.html -->
|
|
@@ -89,14 +90,18 @@ export const queries: Queries = {
|
|
|
89
90
|
page: "directory",
|
|
90
91
|
count: String(await ctx.db.visitCount()),
|
|
91
92
|
})),
|
|
92
|
-
directory: rows("id", (ctx) => ctx.db.directory()),
|
|
93
|
+
directory: rows("id", (ctx) => ctx.db.directory(), { order: "name" }),
|
|
93
94
|
};
|
|
94
95
|
```
|
|
95
96
|
|
|
96
|
-
| Declared with
|
|
97
|
-
|
|
98
|
-
| `row(key, run)`
|
|
99
|
-
| `rows(key, run)` | All its rows, an array of objects
|
|
97
|
+
| Declared with | Answers with |
|
|
98
|
+
|----------------------------|-------------------------------------------|
|
|
99
|
+
| `row(key, run)` | One row, an object |
|
|
100
|
+
| `rows(key, run, options)` | All its rows, an array of objects |
|
|
101
|
+
|
|
102
|
+
`options` are a `rows` query's order: `order`, the columns the hub places
|
|
103
|
+
its rows by, and `serverSortedByUrl`, set when the query reads the user's
|
|
104
|
+
order parm itself. See [Order](./data-binding.md#order).
|
|
100
105
|
|
|
101
106
|
`key` names the column that identifies a row. Give every row that column,
|
|
102
107
|
including a `row` query's: an aggregate row answers with a constant key. The
|
|
@@ -109,8 +114,8 @@ page that needs the same data as one row and as a set declares two queries.
|
|
|
109
114
|
The hub hands each value to the browser untouched, so what a number, a date
|
|
110
115
|
or a null looks like is decided here, in the query.
|
|
111
116
|
|
|
112
|
-
Return the full answer every time
|
|
113
|
-
|
|
117
|
+
Return the full answer every time. With no `order`, the rows show in the
|
|
118
|
+
order they are returned. Sending only what changed is a request's job — see
|
|
114
119
|
[refresh and patch](#refresh-and-patch).
|
|
115
120
|
|
|
116
121
|
## Requests
|
|
@@ -120,7 +125,7 @@ optional:
|
|
|
120
125
|
|
|
121
126
|
| Key | Runs |
|
|
122
127
|
|---------------|--------------------------------------------------------|
|
|
123
|
-
| `onPageEnter` | Before the page's queries, when the page loads
|
|
128
|
+
| `onPageEnter` | Before the page's queries, when the page loads; may move the URL |
|
|
124
129
|
| `handlers` | The page's declared requests, by request name |
|
|
125
130
|
| `crud` | The requests Loadbare provides, by query name |
|
|
126
131
|
|
|
@@ -132,10 +137,14 @@ name:
|
|
|
132
137
|
| `name` | The request name, from `lb-request` |
|
|
133
138
|
| `query` | The query the request is for |
|
|
134
139
|
| `key` | The key of the row the request is for |
|
|
140
|
+
| `keys` | The keys of the rows selected, in place of `key` |
|
|
141
|
+
| `rows` | A form's nested rows, by query: each `key` and `values` |
|
|
135
142
|
| `values` | The gathered control values, by column |
|
|
136
143
|
|
|
137
144
|
The hub sends `query`, `key` and `values` when it finds them; see
|
|
138
|
-
[Gathering](./data-binding.md#gathering).
|
|
145
|
+
[Gathering](./data-binding.md#gathering). It sends `keys` for a request that
|
|
146
|
+
acts on the rows the user selected; see
|
|
147
|
+
[Selecting rows](./data-binding.md#selecting-rows).
|
|
139
148
|
|
|
140
149
|
### onPageEnter
|
|
141
150
|
|
|
@@ -150,6 +159,12 @@ export const requests: Requests = {
|
|
|
150
159
|
|
|
151
160
|
Declare no refresh set here. The page's queries run afterward.
|
|
152
161
|
|
|
162
|
+
It may return `url()` instead, to move the page to other query parms before
|
|
163
|
+
anything shows, as restoring the filters and order the user last had does.
|
|
164
|
+
The page loads there in the same round trip, and that load does not follow
|
|
165
|
+
`onPageEnter` again. A `url()` leading to the parms already in hand is
|
|
166
|
+
ignored. See [Moving the URL](#moving-the-url).
|
|
167
|
+
|
|
153
168
|
### handlers
|
|
154
169
|
|
|
155
170
|
Declare a request under the name the HTML gives `lb-request`. Pair what it
|
|
@@ -180,10 +195,34 @@ the query they operate on:
|
|
|
180
195
|
|
|
181
196
|
| Request name | Runs | `run` receives |
|
|
182
197
|
|-----------------|-------------|------------------|
|
|
183
|
-
| `lb-row-insert` | `rowInsert` | `query`, `values` |
|
|
184
|
-
| `lb-row-update` | `rowUpdate` | `query`, `key`, `values` |
|
|
198
|
+
| `lb-row-insert` | `rowInsert` | `query`, `values`, and `rows` from a form |
|
|
199
|
+
| `lb-row-update` | `rowUpdate` | `query`, `key`, `values`, and `rows` from a form |
|
|
185
200
|
| `lb-row-delete` | `rowDelete` | `query`, `key` |
|
|
186
201
|
|
|
202
|
+
An `lb-row-update` or `lb-row-delete` carrying `keys` runs `rowUpdate` or
|
|
203
|
+
`rowDelete` once for each key, with that key, so a handler written for one
|
|
204
|
+
row serves several. The patches the runs return are laid together, and the
|
|
205
|
+
refresh set runs once. A `url()` returned for one of several rows is
|
|
206
|
+
reported and ignored. A declared request receives `keys` as it is.
|
|
207
|
+
|
|
208
|
+
`rows` holds the rows of a query nested in the form the request came from,
|
|
209
|
+
by query name, each with its `key` and the `values` of its own controls; see
|
|
210
|
+
[A form over a set of rows](./data-binding.md#a-form-over-a-set-of-rows).
|
|
211
|
+
The handler writes the master and its details together, deciding what each
|
|
212
|
+
row's values mean, such as an empty amount being no row at all:
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
rowInsert: {
|
|
216
|
+
run: async (ctx, { values, rows }) => {
|
|
217
|
+
const id = await ctx.db.insertPaycheck(values);
|
|
218
|
+
for (const { key, values: row } of rows?.deduction_types ?? []) {
|
|
219
|
+
if (row.amount !== "") await ctx.db.insertDeduction(id, key, row.amount);
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
refresh: ["paychecks"],
|
|
223
|
+
},
|
|
224
|
+
```
|
|
225
|
+
|
|
187
226
|
```ts
|
|
188
227
|
// src/pages/directory.requests.ts
|
|
189
228
|
import { patch, type Requests } from "@loadbare/app/server";
|
|
@@ -240,16 +279,14 @@ queries:
|
|
|
240
279
|
|
|
241
280
|
Return a patch for a change the request knows the extent of — one row added,
|
|
242
281
|
one row dropped, one row edited — and leave `refresh` empty. A refreshed
|
|
243
|
-
`rows` query sends every row
|
|
244
|
-
each element and takes focus from the control the user is in.
|
|
282
|
+
`rows` query sends every row to say what one row could.
|
|
245
283
|
|
|
246
284
|
A change that seems to need a refresh usually has a patch:
|
|
247
285
|
|
|
248
|
-
- A
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
[`lb-table`](./widgets.md#lb-table) does by `data-sort`.
|
|
286
|
+
- A row whose position changes: the hub places it by the query's
|
|
287
|
+
[order](./data-binding.md#order).
|
|
288
|
+
- A group that appears or goes: the hub makes a group with its first row
|
|
289
|
+
and removes it with its last, so no row stands in for an empty one.
|
|
253
290
|
- A row whose other columns change with the edit: re-read the row and patch
|
|
254
291
|
it.
|
|
255
292
|
- Rows the database removes with a deleted one: select their keys before the
|
|
@@ -324,3 +361,48 @@ Post/Redirect/Get without the redirect. The refresh set does not run, and
|
|
|
324
361
|
nothing else `run` returned is sent, since both answered for the URL the page
|
|
325
362
|
left. The loaded page reads the new parms through `contextFor`; see
|
|
326
363
|
[the Express server](./server.md#database-layer).
|
|
364
|
+
|
|
365
|
+
### Refusing a request
|
|
366
|
+
|
|
367
|
+
A handler refuses a request by throwing `refusal()`, with words written for
|
|
368
|
+
the user:
|
|
369
|
+
|
|
370
|
+
```ts
|
|
371
|
+
import { refusal, type Requests } from "@loadbare/app/server";
|
|
372
|
+
|
|
373
|
+
export const requests: Requests = {
|
|
374
|
+
handlers: {
|
|
375
|
+
enterPaycheck: {
|
|
376
|
+
run: async (ctx, { values }) => {
|
|
377
|
+
if (Number(values!.amount) <= 0) {
|
|
378
|
+
throw refusal({ amount: "Must be more than zero" });
|
|
379
|
+
}
|
|
380
|
+
const overlap = await ctx.db.overlappingSeries(values!);
|
|
381
|
+
if (overlap) {
|
|
382
|
+
throw refusal(
|
|
383
|
+
`That series already has paychecks from ${overlap.from} through ${overlap.to}.`,
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
await ctx.db.enterPaycheck(values!);
|
|
387
|
+
},
|
|
388
|
+
refresh: ["paychecks"],
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
};
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
| Call | The browser shows |
|
|
395
|
+
|----------------------------------|--------------------------------------------|
|
|
396
|
+
| `refusal("message")` | The message, for the request as a whole |
|
|
397
|
+
| `refusal({ column: "message" })` | Each message on the control for its column |
|
|
398
|
+
| `refusal("message", { ... })` | Both |
|
|
399
|
+
|
|
400
|
+
Throw it, from the handler or from anything the handler calls, and whatever
|
|
401
|
+
the application has open rolls back as for any throw. A column names a
|
|
402
|
+
control the request gathered. See [Refusals](./data-binding.md#refusals)
|
|
403
|
+
for how the browser shows them.
|
|
404
|
+
|
|
405
|
+
A refusal is the only error whose words reach the browser. Anything else a
|
|
406
|
+
handler throws is a failure, answered with nothing in it, so a stack or a
|
|
407
|
+
database message never reaches a page.
|
|
408
|
+
|
package/docs/reference/server.md
CHANGED
|
@@ -72,6 +72,26 @@ path, so the application cannot be hosted under a subpath such as
|
|
|
72
72
|
whole path space through unchanged.
|
|
73
73
|
|
|
74
74
|
Leave `express.json()` to `hubRoutes`, which mounts it on its own routes.
|
|
75
|
+
Pass its options through `hubRoutes` instead.
|
|
76
|
+
|
|
77
|
+
## Options
|
|
78
|
+
|
|
79
|
+
`hubRoutes` takes an optional third argument, an object with one key per
|
|
80
|
+
concern:
|
|
81
|
+
|
|
82
|
+
| Option | Description |
|
|
83
|
+
|--------|----------------------------------------------------------|
|
|
84
|
+
| `json` | Options for `express.json()`, passed to it unchanged |
|
|
85
|
+
|
|
86
|
+
A request body over 100 KB, the `express.json()` default, is refused with a
|
|
87
|
+
413 before any handler runs, and the server log names the option that raises
|
|
88
|
+
it. Raise it for an application whose pages send a file's text as a value:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
app.use(hubRoutes(hub, contextFor, { json: { limit: "5mb" } }));
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The limit covers every page's requests.
|
|
75
95
|
|
|
76
96
|
## Running the server
|
|
77
97
|
|
|
@@ -91,6 +111,10 @@ TypeScript types itself. `dist/pages.ts` imports each `.requests.ts` and
|
|
|
91
111
|
`.queries.ts` file by its full name, extension included, because Node looks
|
|
92
112
|
for exactly the path an import names.
|
|
93
113
|
|
|
114
|
+
The `hub` it exports comes from `createHub`, the only implementation of
|
|
115
|
+
the `Hub` interface. That interface may gain members in any release, so an
|
|
116
|
+
application never implements it.
|
|
117
|
+
|
|
94
118
|
Enable `allowImportingTsExtensions` in the application's `tsconfig.json`
|
|
95
119
|
when `tsc` type-checks the server. Without it, `tsc` rejects the `.ts`
|
|
96
120
|
extensions in `dist/pages.ts`:
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# The Basic Widget Library
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
`lb-unknown-page
|
|
3
|
+
Eleven widgets: `lb-input`, `lb-select`, `lb-options`, `lb-picker`,
|
|
4
|
+
`lb-table`, `lb-unknown-page`, `lb-confirm`, `lb-form`, `lb-insert-dialog`,
|
|
5
|
+
`lb-master` and `lb-checkbox`. Every one of them is an ordinary custom element, written
|
|
5
6
|
against the contracts in [Custom Elements](./custom-elements.md#html) for its
|
|
6
7
|
definition and [Custom Elements](./custom-elements.md#code) for its class.
|
|
7
8
|
|
|
@@ -25,7 +26,9 @@ for where a listed package sits in the cascade.
|
|
|
25
26
|
`lb-input`, `lb-select`, `lb-options` and `lb-picker` are controls:
|
|
26
27
|
form-associated custom elements with a `value` property that fire `change`.
|
|
27
28
|
Each carries `lb-column` and `lb-request` itself, the way an `<input>` does;
|
|
28
|
-
see [Being a control](./custom-elements.md#being-a-control).
|
|
29
|
+
see [Being a control](./custom-elements.md#being-a-control). Each passes a
|
|
30
|
+
refusal's message for its column to the native control inside it; see
|
|
31
|
+
[Refusals](./data-binding.md#refusals).
|
|
29
32
|
|
|
30
33
|
## `lb-input`
|
|
31
34
|
|
|
@@ -43,6 +46,7 @@ write the same edit twice.
|
|
|
43
46
|
| Parameter | Fills |
|
|
44
47
|
|----------------|----------------------------------|
|
|
45
48
|
| `exp-label` | The visible `<label>` text |
|
|
49
|
+
| `exp-type` | The input's `type`, `text` when absent |
|
|
46
50
|
| `exp-readonly` | The input's `readonly` attribute |
|
|
47
51
|
|
|
48
52
|
## `lb-select`
|
|
@@ -67,9 +71,7 @@ writes the row template inside the widget:
|
|
|
67
71
|
|
|
68
72
|
```html
|
|
69
73
|
<lb-options lb-query="statuses" lb-column="status" lb-request="lb-row-update" exp-label="Status">
|
|
70
|
-
<template
|
|
71
|
-
<option lb-column="label"></option>
|
|
72
|
-
</template>
|
|
74
|
+
<template><option lb-column="label"></option></template>
|
|
73
75
|
</lb-options>
|
|
74
76
|
```
|
|
75
77
|
|
|
@@ -79,9 +81,15 @@ writes the row template inside the widget:
|
|
|
79
81
|
|
|
80
82
|
- Each option's `value` is its row's key, the `lb-key-value` the hub stamps
|
|
81
83
|
on the live row, so the widget holds a key and shows a label.
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
- A group template holding an `<optgroup>` puts the options in groups, one
|
|
85
|
+
per run of the query's order's leading term. The widget labels each
|
|
86
|
+
`<optgroup>` from the `lb-group-value` the hub stamps on it:
|
|
87
|
+
|
|
88
|
+
```html
|
|
89
|
+
<template lb-group>
|
|
90
|
+
<optgroup><template><option lb-column="label"></option></template></optgroup>
|
|
91
|
+
</template>
|
|
92
|
+
```
|
|
85
93
|
- Its `value` selects the option with that key, including an option that
|
|
86
94
|
arrives after the value did.
|
|
87
95
|
|
|
@@ -100,7 +108,6 @@ one option showing one column:
|
|
|
100
108
|
lb-request="lb-row-update"
|
|
101
109
|
exp-label="Status"
|
|
102
110
|
exp-column="label"
|
|
103
|
-
exp-group="category"
|
|
104
111
|
></lb-picker>
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -108,10 +115,9 @@ one option showing one column:
|
|
|
108
115
|
|--------------|-----------------------------------------|
|
|
109
116
|
| `exp-label` | The visible `<label>` text |
|
|
110
117
|
| `exp-column` | The column each option shows |
|
|
111
|
-
| `exp-group` | The row template's `data-group` |
|
|
112
118
|
|
|
113
|
-
An option built from two columns,
|
|
114
|
-
`lb-options` with the page's own
|
|
119
|
+
An option built from two columns, a row with a second element, or options
|
|
120
|
+
in groups, is `lb-options` with the page's own templates.
|
|
115
121
|
|
|
116
122
|
## `lb-table`
|
|
117
123
|
|
|
@@ -123,11 +129,14 @@ row, the row template, and optionally a footer, each as a `<template>`:
|
|
|
123
129
|
<template lb-exp-template="head">
|
|
124
130
|
<tr><th>Date</th><th>Amount</th></tr>
|
|
125
131
|
</template>
|
|
126
|
-
<template
|
|
127
|
-
<tr><
|
|
132
|
+
<template lb-group>
|
|
133
|
+
<tr><th colspan="2" lb-column="month"></th></tr>
|
|
134
|
+
<template>
|
|
135
|
+
<tr><td lb-column="date"></td><td lb-column="amount"></td></tr>
|
|
136
|
+
</template>
|
|
128
137
|
</template>
|
|
129
138
|
<template lb-exp-template="foot">
|
|
130
|
-
<tr
|
|
139
|
+
<tr><td>Total</td><td lb-sum="amount"></td></tr>
|
|
131
140
|
</template>
|
|
132
141
|
</lb-table>
|
|
133
142
|
```
|
|
@@ -140,15 +149,99 @@ row, the row template, and optionally a footer, each as a `<template>`:
|
|
|
140
149
|
|-----------------------------------|-----------------------------------------|
|
|
141
150
|
| `<template lb-exp-template="head">` | The `<thead>` |
|
|
142
151
|
| `<template lb-exp-template="foot">` | The `<tfoot>` |
|
|
143
|
-
| Any other `<template>` | The row template, in the `<tbody>`
|
|
144
|
-
|
|
145
|
-
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
| Any other `<template>` | The row or group template, in the `<tbody>` |
|
|
153
|
+
|
|
154
|
+
- The hub places the rows by the query's order and builds its groups. The
|
|
155
|
+
rows land in the one `<tbody>`, so a group here is a heading row with its
|
|
156
|
+
rows after it.
|
|
157
|
+
- The footer is not a row of `ledger`. An aggregate there covers every row;
|
|
158
|
+
a figure that is not a sum of the rows, such as a budget, is a `<tr>`
|
|
159
|
+
naming a `row` query of its own.
|
|
160
|
+
- A `<template lb-exp-template="ghost">` is a blank row for entering a new
|
|
161
|
+
one, in a `<tbody>` of its own. The widget joins its controls to a form
|
|
162
|
+
outside the table, since a `<form>` cannot wrap a `<tr>`, and puts the
|
|
163
|
+
cursor back in it once an insert from it succeeds.
|
|
164
|
+
- After rows land, the widget scrolls the row the page's own request created
|
|
165
|
+
or moved into view.
|
|
166
|
+
|
|
167
|
+
## `lb-confirm`
|
|
168
|
+
|
|
169
|
+
A button that asks before it sends. The page writes the question inside the
|
|
170
|
+
tag, and the request goes on the dialog's confirm button, so nothing reaches
|
|
171
|
+
the hub until the user says yes:
|
|
172
|
+
|
|
173
|
+
```html
|
|
174
|
+
<lb-confirm exp-label="Delete" exp-request="lb-row-delete">
|
|
175
|
+
Delete <b lb-column="name"></b>?
|
|
176
|
+
</lb-confirm>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
| Parameter | Fills |
|
|
180
|
+
|---------------|--------------------------------------------------|
|
|
181
|
+
| `exp-label` | The text of the button that opens the dialog |
|
|
182
|
+
| `exp-request` | The confirm button's `lb-request` |
|
|
183
|
+
| `exp-confirm` | The confirm button's text, `Confirm` when absent |
|
|
184
|
+
|
|
185
|
+
The widget closes the dialog once `lb-request-done` says the request
|
|
186
|
+
succeeded, and leaves it open on a refusal.
|
|
187
|
+
|
|
188
|
+
## `lb-form`
|
|
189
|
+
|
|
190
|
+
A `<form>` over one row's controls. A row with a key saves each control's
|
|
191
|
+
column on `change`; a row whose key is empty is new, and the hub sends no
|
|
192
|
+
update for it, so its controls wait for a submit. A definition only.
|
|
193
|
+
|
|
194
|
+
| Parameter | Fills |
|
|
195
|
+
|-----------|-----------------|
|
|
196
|
+
| `exp-id` | The form's `id` |
|
|
197
|
+
|
|
198
|
+
## `lb-insert-dialog`
|
|
199
|
+
|
|
200
|
+
A row entered in a modal dialog, written once outside every row and opened
|
|
201
|
+
with `commandfor` and `command="show-modal"`. Save is the form's
|
|
202
|
+
`lb-row-insert`; on success the widget chooses the new row in the nearest
|
|
203
|
+
`lb-options` around the button that opened it, and closes. The handler
|
|
204
|
+
answers with a patch holding the new row.
|
|
205
|
+
|
|
206
|
+
| Parameter | Fills |
|
|
207
|
+
|-------------|---------------------------------------------------|
|
|
208
|
+
| `exp-id` | The dialog's `id` |
|
|
209
|
+
| `exp-title` | The dialog's heading |
|
|
210
|
+
| `exp-query` | The form's `lb-query`, which it inserts into |
|
|
211
|
+
| `exp-save` | The Save button's text, `Save` when absent |
|
|
212
|
+
|
|
213
|
+
## `lb-master`
|
|
214
|
+
|
|
215
|
+
A set, one of its rows, and the buttons that act on the set: New, Copy,
|
|
216
|
+
Delete, Save new and Cancel, each shown only for a row on record or a new
|
|
217
|
+
one. A definition only, built from `lb-form` and `lb-confirm`. New sends
|
|
218
|
+
`new` and Copy sends `copy`, requests the page declares; `new` returns
|
|
219
|
+
`url()` emptying the parm that names the row.
|
|
220
|
+
|
|
221
|
+
| Parameter | Fills |
|
|
222
|
+
|---------------|--------------------------------------------|
|
|
223
|
+
| `exp-row` | The `lb-query` of the row the form shows |
|
|
224
|
+
| `exp-form-id` | The form's `id`, `master-form` when absent |
|
|
225
|
+
|
|
226
|
+
## `lb-checkbox`
|
|
227
|
+
|
|
228
|
+
A checkbox and its label as one element, for an application to style. A
|
|
229
|
+
definition only: a native checkbox is already a control (see
|
|
230
|
+
[Checkboxes](./data-binding.md#checkboxes)), so the widget is the markup, a
|
|
231
|
+
`<label>` holding the `<input type="checkbox">` and a `<span>` with the
|
|
232
|
+
text. The column and request go on the checkbox inside, so they arrive as
|
|
233
|
+
expansion attributes.
|
|
234
|
+
|
|
235
|
+
Unlike `lb-input`, it has no script making the tag the control. A value
|
|
236
|
+
that lands before a widget's script has loaded arrives only as the string
|
|
237
|
+
stamp `lb-column-value`, and a script checkbox would read `"false"` as
|
|
238
|
+
checked. The hub sets a native checkbox's `checked` directly.
|
|
239
|
+
|
|
240
|
+
| Parameter | Fills |
|
|
241
|
+
|---------------|-----------------------------------------------|
|
|
242
|
+
| `exp-column` | The checkbox's `lb-column` |
|
|
243
|
+
| `exp-label` | The label's text |
|
|
244
|
+
| `exp-request` | The checkbox's `lb-request`, none when absent |
|
|
152
245
|
|
|
153
246
|
## `lb-unknown-page`
|
|
154
247
|
|
package/docs/roadmap.md
CHANGED
|
@@ -29,12 +29,6 @@ expanding row). [Theory](./theory.md) already flags this as possibly load-bearin
|
|
|
29
29
|
disallowed. Worth a decision-in-principle the first time a master-detail
|
|
30
30
|
page is built, even before the mechanism is needed elsewhere.
|
|
31
31
|
|
|
32
|
-
### Pending appearance
|
|
33
|
-
|
|
34
|
-
A value that hasn't arrived yet is probably derivable from an absent
|
|
35
|
-
`lb-column-value` rather than needing a signal of its own. Not yet needed because
|
|
36
|
-
nothing currently produces that gap in practice — revisit if one does.
|
|
37
|
-
|
|
38
32
|
### Events while a request is in flight
|
|
39
33
|
|
|
40
34
|
The hub ignores a commit on an element carrying `lb-request-pending`.
|
|
@@ -108,6 +102,23 @@ Most valuable against a large imported widget library, where an app uses a
|
|
|
108
102
|
small fraction of what ships. Revisit when a real app's `app.css` is big
|
|
109
103
|
enough to measure.
|
|
110
104
|
|
|
105
|
+
### Options on `createHub`
|
|
106
|
+
|
|
107
|
+
Global hooks, transaction wrapping, error handling and a CSRF token each
|
|
108
|
+
want an option on `createHub`, `hubRoutes`, or both. `hubRoutes` already
|
|
109
|
+
takes a trailing options object, one key per concern. `createHub` takes
|
|
110
|
+
the same shape when its first option arrives, which adds a parameter and
|
|
111
|
+
breaks nothing.
|
|
112
|
+
|
|
113
|
+
### Queries stated by the chrome
|
|
114
|
+
|
|
115
|
+
A custom element in the chrome naming a query forces every page to declare
|
|
116
|
+
that query, since the page load covers one page's set. `lb-url` shows the
|
|
117
|
+
pattern from the framework side, and an application has no equivalent.
|
|
118
|
+
|
|
119
|
+
A chrome-level query set on `createHub` would close this, and it is additive.
|
|
120
|
+
It takes its place in the [options on `createHub`](#options-on-createhub).
|
|
121
|
+
|
|
111
122
|
### Data binding utilities
|
|
112
123
|
|
|
113
124
|
A custom element that finds its own nearest ancestor `lb-query`,
|
package/docs/testing.md
CHANGED
|
@@ -86,6 +86,9 @@ anything ships:
|
|
|
86
86
|
`lb-url-unknown` off a `<dialog>` or outside `<lb-hub>`
|
|
87
87
|
- `lb-show` on a `<template>`, on a row template's root, or with no row
|
|
88
88
|
around it
|
|
89
|
+
- a chrome without exactly one `<lb-hub>` and one empty `<main>` inside it,
|
|
90
|
+
and a page carrying either
|
|
91
|
+
- a widget script declaring an `lb` method Loadbare does not define
|
|
89
92
|
|
|
90
93
|
A page file's `<title>` is lifted out and stamped as `lb-page-title`.
|
|
91
94
|
|
|
@@ -119,6 +122,13 @@ The rest of the build — `assemble`, `elements`, `pages`, `styles`,
|
|
|
119
122
|
`package-css` — is tested the same way and in the same tier, since none of it
|
|
120
123
|
needs a browser either.
|
|
121
124
|
|
|
125
|
+
**The command.** `loadbare-app-build` itself runs in a child process against
|
|
126
|
+
a temporary project, which carries a stand-in `@loadbare/app` pointing at
|
|
127
|
+
the hub's source so the test needs no prior build. It is tested for its
|
|
128
|
+
default `src` and `dist`, every file it writes, `--minify`, a failed build's
|
|
129
|
+
exit code, and `--watch` rebuilding on a change, skipping a file it does not
|
|
130
|
+
watch, and surviving a failed build.
|
|
131
|
+
|
|
122
132
|
## Tier 2 — The engine
|
|
123
133
|
|
|
124
134
|
`createHub` takes a plain object and returns an object. Nothing in
|
|
@@ -163,14 +173,14 @@ evidence here.
|
|
|
163
173
|
the row around it, and the columns inside it are its own query's
|
|
164
174
|
- a query nothing names is reported and skipped; several elements naming one
|
|
165
175
|
query are all filled
|
|
166
|
-
- all rows decide membership
|
|
167
|
-
- a patch disturbs only what it names, in contents and
|
|
176
|
+
- all rows decide membership, so a key that did not arrive is gone
|
|
177
|
+
- a patch disturbs only what it names, in contents, and a row moves only
|
|
178
|
+
when the order puts it somewhere else
|
|
168
179
|
- `lb-query-row-count` is counted from the DOM after reconciliation, so all
|
|
169
180
|
rows and a patch ending in the same state report the same number
|
|
170
|
-
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
what is true now, and is the one that flips if that changes.
|
|
181
|
+
- the order places all rows and a patch alike, groups come and go with
|
|
182
|
+
their rows to any depth, aggregates follow every landing, and every change
|
|
183
|
+
leaves a stamp a stylesheet can see (`lb-order.test.ts`)
|
|
174
184
|
- `lb-show` moves an element into a template and back, and landing reaches
|
|
175
185
|
inside it
|
|
176
186
|
|
|
@@ -223,6 +233,8 @@ What the hub is tested for here:
|
|
|
223
233
|
`lb-request-error` replaces it on failure, and the next request clears
|
|
224
234
|
it; `aria-busy` comes and goes with `lb-request-pending`, and a commit on
|
|
225
235
|
a pending element is ignored
|
|
236
|
+
- a round trip the server never answers is aborted at the ten-second
|
|
237
|
+
deadline, under mocked timers, and fails the way any round trip fails
|
|
226
238
|
- a successful insert gathered from a form resets the form
|
|
227
239
|
- a path with no page reports, lands `lb-page-unknown`, and opens the
|
|
228
240
|
`lb-url-unknown` dialog; two pages for one stub report and take the first
|
|
@@ -235,7 +247,7 @@ What the hub is tested for here:
|
|
|
235
247
|
- an `lb-url` item in a server answer writes the URL and lands the page
|
|
236
248
|
loaded there
|
|
237
249
|
- `hidden` comes off the body once a page has landed, including the page
|
|
238
|
-
that failed to load
|
|
250
|
+
that failed to load, and a link whose page fails to load marks no element
|
|
239
251
|
|
|
240
252
|
Widgets are small and their logic is local, so jsdom carries them: a value
|
|
241
253
|
reaches the control the widget owns, the widget is a form-associated control
|
|
@@ -266,9 +278,8 @@ No browser test runner is installed and none of the following exists. They
|
|
|
266
278
|
are recorded here as the shape of the work, not as coverage:
|
|
267
279
|
|
|
268
280
|
1. a cold load fills `<main>` with no empty flash
|
|
269
|
-
2. the
|
|
270
|
-
3. the
|
|
271
|
-
4. the view-source invariant
|
|
281
|
+
2. the wizard never displays a step the server has not confirmed
|
|
282
|
+
3. the view-source invariant
|
|
272
283
|
|
|
273
284
|
The last is the one worth a browser. Loadbare's central claim is that no
|
|
274
285
|
markup exists in the DOM that is not in view-source, and that the difference
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loadbare/app",
|
|
3
3
|
"description": "High performance web app framework for server-bound applications",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.14.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
@@ -22,8 +22,7 @@
|
|
|
22
22
|
"./constants": "./dist/core/lb-constants.js",
|
|
23
23
|
"./types": "./dist/core/lb-types.js",
|
|
24
24
|
"./server": "./dist/server/lb-server.js",
|
|
25
|
-
"./express": "./dist/server/lb-express.js"
|
|
26
|
-
"./build": "./dist/build/elements.js"
|
|
25
|
+
"./express": "./dist/server/lb-express.js"
|
|
27
26
|
},
|
|
28
27
|
"scripts": {
|
|
29
28
|
"prepublishOnly": "npm run typecheck && npm run test && npm run build",
|