@loadbare/app 0.11.0 → 0.13.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 +61 -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 +26 -1
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +79 -0
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +58 -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 +44 -16
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +694 -49
- 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 +168 -36
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/server/lb-express.d.ts +6 -4
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +32 -14
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +49 -10
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +87 -28
- package/dist/server/lb-server.js.map +1 -1
- package/docs/TECHREF-1.0.md +364 -72
- package/docs/comparison.md +16 -10
- package/docs/possible-ideas.md +188 -0
- package/docs/reference/chrome.md +22 -1
- package/docs/reference/custom-elements.md +90 -29
- package/docs/reference/data-binding.md +132 -7
- package/docs/reference/page-files.md +48 -11
- package/docs/reference/server.md +4 -0
- package/docs/reference/widgets.md +94 -24
- package/docs/roadmap.md +10 -6
- package/docs/testing.md +21 -10
- package/package.json +2 -3
- package/skills/loadbare-app/SKILL.md +85 -12
- package/skills/loadbare-app/references/TECHREF-1.0.md +364 -72
- package/skills/loadbare-app/references/chrome.md +22 -1
- package/skills/loadbare-app/references/custom-elements.md +90 -29
- package/skills/loadbare-app/references/data-binding.md +132 -7
- package/skills/loadbare-app/references/page-files.md +48 -11
- package/skills/loadbare-app/references/server.md +4 -0
- package/skills/loadbare-app/references/widgets.md +94 -24
|
@@ -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
|
|
|
@@ -150,6 +155,12 @@ export const requests: Requests = {
|
|
|
150
155
|
|
|
151
156
|
Declare no refresh set here. The page's queries run afterward.
|
|
152
157
|
|
|
158
|
+
It may return `url()` instead, to move the page to other query parms before
|
|
159
|
+
anything shows, as restoring the filters and order the user last had does.
|
|
160
|
+
The page loads there in the same round trip, and that load does not follow
|
|
161
|
+
`onPageEnter` again. A `url()` leading to the parms already in hand is
|
|
162
|
+
ignored. See [Moving the URL](#moving-the-url).
|
|
163
|
+
|
|
153
164
|
### handlers
|
|
154
165
|
|
|
155
166
|
Declare a request under the name the HTML gives `lb-request`. Pair what it
|
|
@@ -223,6 +234,9 @@ Every value in `values` is a string, as a control's value is.
|
|
|
223
234
|
### refresh and patch
|
|
224
235
|
|
|
225
236
|
List in `refresh` every query whose whole answer the request changed.
|
|
237
|
+
Never list one only to fill what the request's answer creates, such as the
|
|
238
|
+
picker in a new row: the hub fills that from the query's last answer. See
|
|
239
|
+
[What arrives later](./data-binding.md#what-arrives-later).
|
|
226
240
|
|
|
227
241
|
Return answers from `run` to state a narrower change than re-running a query
|
|
228
242
|
would. What `run` returns is keyed by query name and laid over the refreshed
|
|
@@ -236,8 +250,31 @@ queries:
|
|
|
236
250
|
| `patch({ drop: [...] })` | These keys are gone; the rest stand |
|
|
237
251
|
|
|
238
252
|
Return a patch for a change the request knows the extent of — one row added,
|
|
239
|
-
one row dropped, one row edited — and leave `refresh` empty.
|
|
240
|
-
|
|
253
|
+
one row dropped, one row edited — and leave `refresh` empty. A refreshed
|
|
254
|
+
`rows` query sends every row to say what one row could.
|
|
255
|
+
|
|
256
|
+
A change that seems to need a refresh usually has a patch:
|
|
257
|
+
|
|
258
|
+
- A row whose position changes: the hub places it by the query's
|
|
259
|
+
[order](./data-binding.md#order).
|
|
260
|
+
- A group that appears or goes: the hub makes a group with its first row
|
|
261
|
+
and removes it with its last, so no row stands in for an empty one.
|
|
262
|
+
- A row whose other columns change with the edit: re-read the row and patch
|
|
263
|
+
it.
|
|
264
|
+
- Rows the database removes with a deleted one: select their keys before the
|
|
265
|
+
delete and drop them too.
|
|
266
|
+
|
|
267
|
+
An update or a delete always has a patch, since it names its row by key and
|
|
268
|
+
removing a row never reorders the rest. `createHub` refuses at startup a
|
|
269
|
+
`crud` `rowUpdate` or `rowDelete` on a `rows` query whose `refresh` names
|
|
270
|
+
that same query. An insert may refresh its own query: where a new row goes
|
|
271
|
+
depends on whether its host places it, which the server cannot see.
|
|
272
|
+
|
|
273
|
+
Each request's `refresh` is its own, and every query in it needs its own
|
|
274
|
+
reason. A list shared by several requests is a warning sign.
|
|
275
|
+
|
|
276
|
+
Re-run the query when membership or order changed in a way the request
|
|
277
|
+
cannot name:
|
|
241
278
|
|
|
242
279
|
```ts
|
|
243
280
|
resetRoster: {
|
package/docs/reference/server.md
CHANGED
|
@@ -91,6 +91,10 @@ TypeScript types itself. `dist/pages.ts` imports each `.requests.ts` and
|
|
|
91
91
|
`.queries.ts` file by its full name, extension included, because Node looks
|
|
92
92
|
for exactly the path an import names.
|
|
93
93
|
|
|
94
|
+
The `hub` it exports comes from `createHub`, the only implementation of
|
|
95
|
+
the `Hub` interface. That interface may gain members in any release, so an
|
|
96
|
+
application never implements it.
|
|
97
|
+
|
|
94
98
|
Enable `allowImportingTsExtensions` in the application's `tsconfig.json`
|
|
95
99
|
when `tsc` type-checks the server. Without it, `tsc` rejects the `.ts`
|
|
96
100
|
extensions in `dist/pages.ts`:
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# The Basic Widget Library
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
`lb-unknown-page
|
|
3
|
+
Ten widgets: `lb-input`, `lb-select`, `lb-options`, `lb-picker`, `lb-table`,
|
|
4
|
+
`lb-unknown-page`, `lb-confirm`, `lb-form`, `lb-insert-dialog` and
|
|
5
|
+
`lb-master`. 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
|
|
|
@@ -43,6 +44,7 @@ write the same edit twice.
|
|
|
43
44
|
| Parameter | Fills |
|
|
44
45
|
|----------------|----------------------------------|
|
|
45
46
|
| `exp-label` | The visible `<label>` text |
|
|
47
|
+
| `exp-type` | The input's `type`, `text` when absent |
|
|
46
48
|
| `exp-readonly` | The input's `readonly` attribute |
|
|
47
49
|
|
|
48
50
|
## `lb-select`
|
|
@@ -67,9 +69,7 @@ writes the row template inside the widget:
|
|
|
67
69
|
|
|
68
70
|
```html
|
|
69
71
|
<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>
|
|
72
|
+
<template><option lb-column="label"></option></template>
|
|
73
73
|
</lb-options>
|
|
74
74
|
```
|
|
75
75
|
|
|
@@ -79,9 +79,15 @@ writes the row template inside the widget:
|
|
|
79
79
|
|
|
80
80
|
- Each option's `value` is its row's key, the `lb-key-value` the hub stamps
|
|
81
81
|
on the live row, so the widget holds a key and shows a label.
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
- A group template holding an `<optgroup>` puts the options in groups, one
|
|
83
|
+
per run of the query's order's leading term. The widget labels each
|
|
84
|
+
`<optgroup>` from the `lb-group-value` the hub stamps on it:
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<template lb-group>
|
|
88
|
+
<optgroup><template><option lb-column="label"></option></template></optgroup>
|
|
89
|
+
</template>
|
|
90
|
+
```
|
|
85
91
|
- Its `value` selects the option with that key, including an option that
|
|
86
92
|
arrives after the value did.
|
|
87
93
|
|
|
@@ -100,7 +106,6 @@ one option showing one column:
|
|
|
100
106
|
lb-request="lb-row-update"
|
|
101
107
|
exp-label="Status"
|
|
102
108
|
exp-column="label"
|
|
103
|
-
exp-group="category"
|
|
104
109
|
></lb-picker>
|
|
105
110
|
```
|
|
106
111
|
|
|
@@ -108,10 +113,9 @@ one option showing one column:
|
|
|
108
113
|
|--------------|-----------------------------------------|
|
|
109
114
|
| `exp-label` | The visible `<label>` text |
|
|
110
115
|
| `exp-column` | The column each option shows |
|
|
111
|
-
| `exp-group` | The row template's `data-group` |
|
|
112
116
|
|
|
113
|
-
An option built from two columns,
|
|
114
|
-
`lb-options` with the page's own
|
|
117
|
+
An option built from two columns, a row with a second element, or options
|
|
118
|
+
in groups, is `lb-options` with the page's own templates.
|
|
115
119
|
|
|
116
120
|
## `lb-table`
|
|
117
121
|
|
|
@@ -123,11 +127,14 @@ row, the row template, and optionally a footer, each as a `<template>`:
|
|
|
123
127
|
<template lb-exp-template="head">
|
|
124
128
|
<tr><th>Date</th><th>Amount</th></tr>
|
|
125
129
|
</template>
|
|
126
|
-
<template
|
|
127
|
-
<tr><
|
|
130
|
+
<template lb-group>
|
|
131
|
+
<tr><th colspan="2" lb-column="month"></th></tr>
|
|
132
|
+
<template>
|
|
133
|
+
<tr><td lb-column="date"></td><td lb-column="amount"></td></tr>
|
|
134
|
+
</template>
|
|
128
135
|
</template>
|
|
129
136
|
<template lb-exp-template="foot">
|
|
130
|
-
<tr
|
|
137
|
+
<tr><td>Total</td><td lb-sum="amount"></td></tr>
|
|
131
138
|
</template>
|
|
132
139
|
</lb-table>
|
|
133
140
|
```
|
|
@@ -140,15 +147,78 @@ row, the row template, and optionally a footer, each as a `<template>`:
|
|
|
140
147
|
|-----------------------------------|-----------------------------------------|
|
|
141
148
|
| `<template lb-exp-template="head">` | The `<thead>` |
|
|
142
149
|
| `<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
|
-
|
|
150
|
+
| Any other `<template>` | The row or group template, in the `<tbody>` |
|
|
151
|
+
|
|
152
|
+
- The hub places the rows by the query's order and builds its groups. The
|
|
153
|
+
rows land in the one `<tbody>`, so a group here is a heading row with its
|
|
154
|
+
rows after it.
|
|
155
|
+
- The footer is not a row of `ledger`. An aggregate there covers every row;
|
|
156
|
+
a figure that is not a sum of the rows, such as a budget, is a `<tr>`
|
|
157
|
+
naming a `row` query of its own.
|
|
158
|
+
- A `<template lb-exp-template="ghost">` is a blank row for entering a new
|
|
159
|
+
one, in a `<tbody>` of its own. The widget joins its controls to a form
|
|
160
|
+
outside the table, since a `<form>` cannot wrap a `<tr>`, and puts the
|
|
161
|
+
cursor back in it once an insert from it succeeds.
|
|
162
|
+
- After rows land, the widget scrolls the row the page's own request created
|
|
163
|
+
or moved into view.
|
|
164
|
+
|
|
165
|
+
## `lb-confirm`
|
|
166
|
+
|
|
167
|
+
A button that asks before it sends. The page writes the question inside the
|
|
168
|
+
tag, and the request goes on the dialog's confirm button, so nothing reaches
|
|
169
|
+
the hub until the user says yes:
|
|
170
|
+
|
|
171
|
+
```html
|
|
172
|
+
<lb-confirm exp-label="Delete" exp-request="lb-row-delete">
|
|
173
|
+
Delete <b lb-column="name"></b>?
|
|
174
|
+
</lb-confirm>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
| Parameter | Fills |
|
|
178
|
+
|---------------|--------------------------------------------------|
|
|
179
|
+
| `exp-label` | The text of the button that opens the dialog |
|
|
180
|
+
| `exp-request` | The confirm button's `lb-request` |
|
|
181
|
+
| `exp-confirm` | The confirm button's text, `Confirm` when absent |
|
|
182
|
+
|
|
183
|
+
The widget closes the dialog once `lb-request-done` says the request
|
|
184
|
+
succeeded, and leaves it open on a refusal.
|
|
185
|
+
|
|
186
|
+
## `lb-form`
|
|
187
|
+
|
|
188
|
+
A `<form>` over one row's controls. A row with a key saves each control's
|
|
189
|
+
column on `change`; a row whose key is empty is new, and the widget stops an
|
|
190
|
+
`lb-row-update` that carries no key, so its controls wait for a submit.
|
|
191
|
+
|
|
192
|
+
| Parameter | Fills |
|
|
193
|
+
|-----------|-----------------|
|
|
194
|
+
| `exp-id` | The form's `id` |
|
|
195
|
+
|
|
196
|
+
## `lb-insert-dialog`
|
|
197
|
+
|
|
198
|
+
A row entered in a modal dialog, written once outside every row and opened
|
|
199
|
+
with `commandfor` and `command="show-modal"`. Save is the form's
|
|
200
|
+
`lb-row-insert`; on success the widget chooses the new row in the nearest
|
|
201
|
+
`lb-options` around the button that opened it, and closes. The handler
|
|
202
|
+
answers with a patch holding the new row.
|
|
203
|
+
|
|
204
|
+
| Parameter | Fills |
|
|
205
|
+
|-------------|---------------------------------------------------|
|
|
206
|
+
| `exp-id` | The dialog's `id` |
|
|
207
|
+
| `exp-title` | The dialog's heading |
|
|
208
|
+
| `exp-query` | The form's `lb-query`, which it inserts into |
|
|
209
|
+
| `exp-save` | The Save button's text, `Save` when absent |
|
|
210
|
+
|
|
211
|
+
## `lb-master`
|
|
212
|
+
|
|
213
|
+
A set, one of its rows, and the buttons that act on the set: Copy, Delete,
|
|
214
|
+
Save new and Cancel, each shown only for a row on record or a new one. A
|
|
215
|
+
definition only, built from `lb-form` and `lb-confirm`. Copy sends `copy`, a
|
|
216
|
+
request the page declares.
|
|
217
|
+
|
|
218
|
+
| Parameter | Fills |
|
|
219
|
+
|---------------|--------------------------------------------|
|
|
220
|
+
| `exp-row` | The `lb-query` of the row the form shows |
|
|
221
|
+
| `exp-form-id` | The form's `id`, `master-form` when absent |
|
|
152
222
|
|
|
153
223
|
## `lb-unknown-page`
|
|
154
224
|
|
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,16 @@ 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
|
+
### Queries stated by the chrome
|
|
106
|
+
|
|
107
|
+
A custom element in the chrome naming a query forces every page to declare
|
|
108
|
+
that query, since the page load covers one page's set. `lb-url` shows the
|
|
109
|
+
pattern from the framework side, and an application has no equivalent.
|
|
110
|
+
|
|
111
|
+
A chrome-level query set on `createHub` would close this, and it is additive.
|
|
112
|
+
It takes its place in the options argument whose shape is a 1.0 blocker in
|
|
113
|
+
[TECHREF-1.0](./TECHREF-1.0.md#the-server-api).
|
|
114
|
+
|
|
111
115
|
### Data binding utilities
|
|
112
116
|
|
|
113
117
|
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.13.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",
|
|
@@ -159,7 +159,9 @@ row template lands on the element itself. A `rows` query with no row
|
|
|
159
159
|
template lands nothing, which is what an insert form naming its query is. A
|
|
160
160
|
condition is `lb-show="<column>"`: write every possibility into the page and
|
|
161
161
|
let a column decide which is present. The column is a boolean or null; the
|
|
162
|
-
string `"false"` counts as present.
|
|
162
|
+
string `"false"` counts as present. `lb-show="!<column>"` is present when
|
|
163
|
+
the column is not, so one column decides both sides and the query never
|
|
164
|
+
sends a flag and its opposite.
|
|
163
165
|
|
|
164
166
|
**`{{placeholder}}` is build time only.** It reads an `exp-` attribute on
|
|
165
167
|
the tag, never data. Write it as an entire attribute value or an entire
|
|
@@ -174,9 +176,34 @@ from it.
|
|
|
174
176
|
|
|
175
177
|
**A column never holds rows.** Master-detail is a `row` query and a `rows`
|
|
176
178
|
query under two names. Many masters with their details is one `rows` query
|
|
177
|
-
of joined rows,
|
|
179
|
+
of joined rows, ordered by the master first and shown in groups. A
|
|
178
180
|
query nested inside another query's row template receives the same rows in
|
|
179
|
-
every outer row; use it for a picker, never for per-row detail.
|
|
181
|
+
every outer row; use it for a picker, never for per-row detail. A new outer
|
|
182
|
+
row is filled from the nested query's last answer, whatever order they land
|
|
183
|
+
in.
|
|
184
|
+
|
|
185
|
+
**A `rows` query declares its order, and the hub places every row by it.**
|
|
186
|
+
`rows("id", run, { order: "category_order,name" })`; a column after `-` sorts
|
|
187
|
+
descending, and values compare by JSON type, so a numeric sort column is a
|
|
188
|
+
JSON number. The parm `lb-order-<query>` replaces the order, and a control
|
|
189
|
+
writing it inside `lb-query="lb-url"` re-sorts with no round trip. A query
|
|
190
|
+
that pages or limits reads the parm itself and declares
|
|
191
|
+
`serverSortedByUrl: true`. Never sort in a widget, and never send a
|
|
192
|
+
placeholder row to hold a place.
|
|
193
|
+
|
|
194
|
+
**Groups are templates.** A `<template lb-group>` holds a heading and one
|
|
195
|
+
nested `<template>`, the next level or the row template; the nth breaks on
|
|
196
|
+
the order's nth term, to any depth. Contents land before the nested
|
|
197
|
+
template, so put it inside the heading's element for a container and beside
|
|
198
|
+
the heading for a heading row. `<tbody>` and `<optgroup>` do not nest. The
|
|
199
|
+
heading is filled from the group's first row. `lb-count`, `lb-sum="col"`,
|
|
200
|
+
`lb-avg`, `lb-min` and `lb-max` total the nearest group, or the whole list
|
|
201
|
+
outside any.
|
|
202
|
+
|
|
203
|
+
**Animate with CSS.** The hub stamps `lb-row-created`, `lb-row-changed`,
|
|
204
|
+
`lb-row-moved`, and `lb-row-requested` for this page's request, and marks a
|
|
205
|
+
leaving row or group `lb-row-leaving` or `lb-group-leaving`, removing it once
|
|
206
|
+
its animations end. Scrolling to a row is script, in `lbRowsLanded`.
|
|
180
207
|
|
|
181
208
|
**Every request has one shape.** `lb-request` names the request, and the
|
|
182
209
|
hub sends `{ name, query, key, values }` as present: `query` from the
|
|
@@ -201,6 +228,12 @@ elsewhere with the HTML `form` attribute. Checkboxes, radio buttons and
|
|
|
201
228
|
file inputs are not controls here: they receive no value and are not
|
|
202
229
|
gathered.
|
|
203
230
|
|
|
231
|
+
**A form that adds to a set chosen elsewhere is written once, outside every
|
|
232
|
+
row.** A form cannot sit inside another form or in a table row, so a dialog
|
|
233
|
+
that creates an account while a posting's picker is choosing one goes at the
|
|
234
|
+
end of the page, and each row opens it with `commandfor`. The dialog learns
|
|
235
|
+
the new key from `lb-request-done`.
|
|
236
|
+
|
|
204
237
|
**Three requests are Loadbare's.** `lb-row-insert` needs `query` and
|
|
205
238
|
`values`, `lb-row-update` needs `query`, `key` and `values`, and
|
|
206
239
|
`lb-row-delete` needs `query` and `key`. The page permits each under
|
|
@@ -216,8 +249,28 @@ page may edit.
|
|
|
216
249
|
|
|
217
250
|
**Return a patch when the change has a known extent.** `patch({ rows })`
|
|
218
251
|
for rows added or edited, `patch({ drop })` for keys removed, with
|
|
219
|
-
`refresh: []`.
|
|
220
|
-
|
|
252
|
+
`refresh: []`. A refreshed `rows` query sends every row to say what one row
|
|
253
|
+
could. List a query in `refresh` only when its membership changed in a way
|
|
254
|
+
the handler cannot name. Never list one only to fill the
|
|
255
|
+
picker in a row the request adds: its answer did not change, and the hub
|
|
256
|
+
fills a new row from the last one.
|
|
257
|
+
|
|
258
|
+
**The usual reasons for a refresh each have a patch.**
|
|
259
|
+
- A row whose position changes: the hub places it by the query's order.
|
|
260
|
+
- A group that appears or goes: the hub makes it with its first row and
|
|
261
|
+
removes it with its last.
|
|
262
|
+
- A row whose other columns change with the edit: re-read the row and patch
|
|
263
|
+
it.
|
|
264
|
+
- Rows the database removes with a deleted one: select their keys before
|
|
265
|
+
the delete and drop them too.
|
|
266
|
+
|
|
267
|
+
An update or a delete names its row by key, and removing a row never
|
|
268
|
+
reorders the rest, so each always has a patch: `createHub` refuses at
|
|
269
|
+
startup a `rowUpdate` or `rowDelete` whose `refresh` names its own `rows`
|
|
270
|
+
query. An insert may refresh its own query, though a patch of the new row
|
|
271
|
+
lands in its place by the order.
|
|
272
|
+
Each handler's `refresh` is its own, and every query in it needs its own
|
|
273
|
+
reason. A list shared by several handlers is a warning sign.
|
|
221
274
|
|
|
222
275
|
**A page's queries are its view model, not a data layer.** Each answers
|
|
223
276
|
one page's elements in the form they show: formatted dates and amounts, and
|
|
@@ -247,6 +300,12 @@ puts parms onto `ctx`, and a query reads them there. Read them from
|
|
|
247
300
|
request. A parm is user input, so validate it where it is read. Do not
|
|
248
301
|
keep a selection in server state set by a handler.
|
|
249
302
|
|
|
303
|
+
**Where focus starts is the hub's.** On entering a page, once its queries
|
|
304
|
+
have landed, the hub focuses the first control in `<main>` the user can
|
|
305
|
+
operate; a change of query parm leaves focus where it is. Order the page so
|
|
306
|
+
that control is the one to start in, and write no `autofocus` and no script
|
|
307
|
+
that focuses on load.
|
|
308
|
+
|
|
250
309
|
**A handler moves the URL with `url()`.** After an insert, only the server
|
|
251
310
|
knows the new key; after a delete, only the server knows the parm should
|
|
252
311
|
go. Have `run` return `url({ acct: String(id) })`, or `url({ acct: "" })`
|
|
@@ -286,12 +345,25 @@ on `change`. Any other custom element keeps its content and receives the
|
|
|
286
345
|
column as its `lb-column-value` attribute.
|
|
287
346
|
|
|
288
347
|
**A custom element connects many times.** It is moved, never rebuilt: the
|
|
289
|
-
hub
|
|
290
|
-
|
|
291
|
-
|
|
348
|
+
hub moves a live row the order puts elsewhere, and parks an `lb-show`
|
|
349
|
+
element in a template while it is off, so `connectedCallback` runs on every
|
|
350
|
+
move. Listen on the element itself in the constructor, look a
|
|
292
351
|
child up when it is needed, and in a control take up `lb-column-value` once,
|
|
293
352
|
on first connect, since a value can land before the element upgrades.
|
|
294
353
|
|
|
354
|
+
**The hub and a custom element talk in four ways, one per kind of
|
|
355
|
+
message.** State the hub gives an element is an attribute stamp, or `value`
|
|
356
|
+
on a control. Work the hub needs done while landing is an optional `lb`
|
|
357
|
+
method: `lbRowsLanded`. A moment is a bubbling event: an
|
|
358
|
+
element sends `lb-request`, and the hub answers on the same element with
|
|
359
|
+
`lb-request-done`, carrying the request and the response items that landed,
|
|
360
|
+
or the error. Listen for `lb-request-done` on whichever ancestor needs the
|
|
361
|
+
outcome, such as a dialog choosing the row its form just created.
|
|
362
|
+
|
|
363
|
+
**A widget that holds rows may sit under `lb-show`.** Rows that land while
|
|
364
|
+
it is away are placed by the hub, and its `lbRowsLanded` runs once it first
|
|
365
|
+
appears, so hide a table with `lb-show`, not with a stylesheet rule.
|
|
366
|
+
|
|
295
367
|
**Name a custom element script `<tag>.browser.ts`.** A plain `<tag>.ts`
|
|
296
368
|
stays on the server and the tag goes unregistered.
|
|
297
369
|
|
|
@@ -318,12 +390,13 @@ parser loses the tag before the build can report it.
|
|
|
318
390
|
|
|
319
391
|
Reach for one only when plain HTML cannot do the job. A set of rows, a form
|
|
320
392
|
and a condition need none. A custom element exists to be a control of its
|
|
321
|
-
own, or to
|
|
322
|
-
`
|
|
393
|
+
own, or to act on rows once they land through the hook the hub calls,
|
|
394
|
+
`lbRowsLanded` (the `RowsHost` interface).
|
|
323
395
|
|
|
324
396
|
Before writing one, check `@loadbare/widgets`: `lb-input`, `lb-select`,
|
|
325
|
-
`lb-options`, `lb-picker`, `lb-table`, `lb-unknown-page
|
|
326
|
-
|
|
397
|
+
`lb-options`, `lb-picker`, `lb-table`, `lb-unknown-page`, `lb-confirm`,
|
|
398
|
+
`lb-form`, `lb-insert-dialog`, `lb-master`. The first four are
|
|
399
|
+
form-associated controls that carry `lb-column` and `lb-request`
|
|
327
400
|
themselves. Install the package and list it in `src/imports.ts`:
|
|
328
401
|
|
|
329
402
|
```ts
|