@fieldia/core 0.10.0 → 0.12.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/README.md +204 -0
- package/package.json +1 -1
- package/schema/page.schema.json +4700 -904
- package/src/index.d.mts +2 -1
- package/src/index.d.ts +2 -1
- package/src/index.js +7 -1
- package/src/index.js.map +1 -1
- package/src/index.mjs +2 -1
- package/src/index.mjs.map +1 -1
- package/src/lib/expression/built-ins.d.mts +4 -0
- package/src/lib/expression/built-ins.d.ts +4 -0
- package/src/lib/expression/built-ins.js +8 -0
- package/src/lib/expression/built-ins.js.map +1 -0
- package/src/lib/expression/built-ins.mjs +5 -0
- package/src/lib/expression/built-ins.mjs.map +1 -0
- package/src/lib/expression/evaluator.js +17 -7
- package/src/lib/expression/evaluator.js.map +1 -1
- package/src/lib/expression/evaluator.mjs +17 -7
- package/src/lib/expression/evaluator.mjs.map +1 -1
- package/src/lib/expression/expression.d.mts +7 -0
- package/src/lib/expression/expression.d.ts +7 -0
- package/src/lib/expression/expression.js +2 -0
- package/src/lib/expression/expression.js.map +1 -1
- package/src/lib/expression/expression.mjs +3 -1
- package/src/lib/expression/expression.mjs.map +1 -1
- package/src/lib/expression/functions.d.mts +2 -0
- package/src/lib/expression/functions.d.ts +2 -0
- package/src/lib/expression/functions.js +38 -5
- package/src/lib/expression/functions.js.map +1 -1
- package/src/lib/expression/functions.mjs +38 -5
- package/src/lib/expression/functions.mjs.map +1 -1
- package/src/lib/expression/modifier.d.mts +7 -0
- package/src/lib/expression/modifier.d.ts +7 -0
- package/src/lib/expression/modifier.js +3 -1
- package/src/lib/expression/modifier.js.map +1 -1
- package/src/lib/expression/modifier.mjs +4 -2
- package/src/lib/expression/modifier.mjs.map +1 -1
- package/src/lib/expression/parser.d.mts +8 -1
- package/src/lib/expression/parser.d.ts +8 -1
- package/src/lib/expression/parser.js +30 -2
- package/src/lib/expression/parser.js.map +1 -1
- package/src/lib/expression/parser.mjs +30 -2
- package/src/lib/expression/parser.mjs.map +1 -1
- package/src/lib/expression/reads.d.mts +7 -0
- package/src/lib/expression/reads.d.ts +7 -0
- package/src/lib/expression/reads.js +23 -0
- package/src/lib/expression/reads.js.map +1 -1
- package/src/lib/expression/reads.mjs +21 -0
- package/src/lib/expression/reads.mjs.map +1 -1
- package/src/lib/format/actions.d.mts +1176 -0
- package/src/lib/format/actions.d.ts +1176 -0
- package/src/lib/format/actions.js +62 -0
- package/src/lib/format/actions.js.map +1 -0
- package/src/lib/format/actions.mjs +59 -0
- package/src/lib/format/actions.mjs.map +1 -0
- package/src/lib/format/check-page.d.mts +7 -2
- package/src/lib/format/check-page.d.ts +7 -2
- package/src/lib/format/check-page.js +6 -3
- package/src/lib/format/check-page.js.map +1 -1
- package/src/lib/format/check-page.mjs +6 -3
- package/src/lib/format/check-page.mjs.map +1 -1
- package/src/lib/format/field.d.mts +3285 -214
- package/src/lib/format/field.d.ts +3285 -214
- package/src/lib/format/field.js +105 -16
- package/src/lib/format/field.js.map +1 -1
- package/src/lib/format/field.mjs +104 -15
- package/src/lib/format/field.mjs.map +1 -1
- package/src/lib/format/hotkeys.d.mts +6 -0
- package/src/lib/format/hotkeys.d.ts +6 -0
- package/src/lib/format/hotkeys.js +11 -0
- package/src/lib/format/hotkeys.js.map +1 -0
- package/src/lib/format/hotkeys.mjs +7 -0
- package/src/lib/format/hotkeys.mjs.map +1 -0
- package/src/lib/format/layout.d.mts +4773 -211
- package/src/lib/format/layout.d.ts +4773 -211
- package/src/lib/format/layout.js +147 -21
- package/src/lib/format/layout.js.map +1 -1
- package/src/lib/format/layout.mjs +146 -20
- package/src/lib/format/layout.mjs.map +1 -1
- package/src/lib/format/layout.types.d.mts +2 -1
- package/src/lib/format/layout.types.d.ts +2 -1
- package/src/lib/format/page.d.mts +3563 -222
- package/src/lib/format/page.d.ts +3563 -222
- package/src/lib/format/page.js +19 -2
- package/src/lib/format/page.js.map +1 -1
- package/src/lib/format/page.mjs +20 -3
- package/src/lib/format/page.mjs.map +1 -1
- package/src/lib/format/part-look.d.mts +36 -0
- package/src/lib/format/part-look.d.ts +36 -0
- package/src/lib/format/part-look.js +23 -0
- package/src/lib/format/part-look.js.map +1 -0
- package/src/lib/format/part-look.mjs +20 -0
- package/src/lib/format/part-look.mjs.map +1 -0
- package/src/lib/format/references.d.mts +54 -2
- package/src/lib/format/references.d.ts +54 -2
- package/src/lib/format/references.js +450 -43
- package/src/lib/format/references.js.map +1 -1
- package/src/lib/format/references.mjs +450 -43
- package/src/lib/format/references.mjs.map +1 -1
- package/src/lib/format/translate.js +5 -3
- package/src/lib/format/translate.js.map +1 -1
- package/src/lib/format/translate.mjs +5 -3
- package/src/lib/format/translate.mjs.map +1 -1
- package/src/lib/format/words.d.mts +9 -0
- package/src/lib/format/words.d.ts +9 -0
- package/src/lib/format/words.js +35 -0
- package/src/lib/format/words.js.map +1 -0
- package/src/lib/format/words.mjs +30 -0
- package/src/lib/format/words.mjs.map +1 -0
- package/src/lib/record/cells.d.mts +37 -0
- package/src/lib/record/cells.d.ts +37 -0
- package/src/lib/record/cells.js +59 -0
- package/src/lib/record/cells.js.map +1 -0
- package/src/lib/record/cells.mjs +54 -0
- package/src/lib/record/cells.mjs.map +1 -0
- package/src/lib/record/compute.d.mts +5 -4
- package/src/lib/record/compute.d.ts +5 -4
- package/src/lib/record/compute.js +11 -10
- package/src/lib/record/compute.js.map +1 -1
- package/src/lib/record/compute.mjs +12 -11
- package/src/lib/record/compute.mjs.map +1 -1
- package/src/lib/record/data-source.d.mts +37 -3
- package/src/lib/record/data-source.d.ts +37 -3
- package/src/lib/record/data-source.js.map +1 -1
- package/src/lib/record/data-source.mjs.map +1 -1
- package/src/lib/record/env.d.mts +38 -1
- package/src/lib/record/env.d.ts +38 -1
- package/src/lib/record/env.js +41 -3
- package/src/lib/record/env.js.map +1 -1
- package/src/lib/record/env.mjs +38 -3
- package/src/lib/record/env.mjs.map +1 -1
- package/src/lib/record/filter.d.mts +10 -0
- package/src/lib/record/filter.d.ts +10 -0
- package/src/lib/record/filter.js +49 -0
- package/src/lib/record/filter.js.map +1 -1
- package/src/lib/record/filter.mjs +48 -0
- package/src/lib/record/filter.mjs.map +1 -1
- package/src/lib/record/form.d.mts +226 -25
- package/src/lib/record/form.d.ts +226 -25
- package/src/lib/record/form.js +785 -83
- package/src/lib/record/form.js.map +1 -1
- package/src/lib/record/form.mjs +787 -85
- package/src/lib/record/form.mjs.map +1 -1
- package/src/lib/record/locales/ar.js +3 -0
- package/src/lib/record/locales/ar.js.map +1 -1
- package/src/lib/record/locales/ar.mjs +3 -0
- package/src/lib/record/locales/ar.mjs.map +1 -1
- package/src/lib/record/locales/de.js +3 -0
- package/src/lib/record/locales/de.js.map +1 -1
- package/src/lib/record/locales/de.mjs +3 -0
- package/src/lib/record/locales/de.mjs.map +1 -1
- package/src/lib/record/locales/fr.js +3 -0
- package/src/lib/record/locales/fr.js.map +1 -1
- package/src/lib/record/locales/fr.mjs +3 -0
- package/src/lib/record/locales/fr.mjs.map +1 -1
- package/src/lib/record/memory-data-source.d.mts +26 -2
- package/src/lib/record/memory-data-source.d.ts +26 -2
- package/src/lib/record/memory-data-source.js +98 -7
- package/src/lib/record/memory-data-source.js.map +1 -1
- package/src/lib/record/memory-data-source.mjs +98 -7
- package/src/lib/record/memory-data-source.mjs.map +1 -1
- package/src/lib/record/messages.d.mts +5 -0
- package/src/lib/record/messages.d.ts +5 -0
- package/src/lib/record/messages.js +3 -0
- package/src/lib/record/messages.js.map +1 -1
- package/src/lib/record/messages.mjs +3 -0
- package/src/lib/record/messages.mjs.map +1 -1
- package/src/lib/record/roles.d.mts +10 -0
- package/src/lib/record/roles.d.ts +10 -0
- package/src/lib/record/roles.js +21 -0
- package/src/lib/record/roles.js.map +1 -0
- package/src/lib/record/roles.mjs +18 -0
- package/src/lib/record/roles.mjs.map +1 -0
- package/src/lib/record/rules.js +30 -0
- package/src/lib/record/rules.js.map +1 -1
- package/src/lib/record/rules.mjs +31 -1
- package/src/lib/record/rules.mjs.map +1 -1
- package/src/lib/record/run.d.mts +248 -0
- package/src/lib/record/run.d.ts +248 -0
- package/src/lib/record/run.js +455 -0
- package/src/lib/record/run.js.map +1 -0
- package/src/lib/record/run.mjs +450 -0
- package/src/lib/record/run.mjs.map +1 -0
- package/src/lib/record/set-when.d.mts +5 -2
- package/src/lib/record/set-when.d.ts +5 -2
- package/src/lib/record/set-when.js +28 -12
- package/src/lib/record/set-when.js.map +1 -1
- package/src/lib/record/set-when.mjs +30 -14
- package/src/lib/record/set-when.mjs.map +1 -1
- package/src/lib/record/value-map.d.mts +41 -0
- package/src/lib/record/value-map.d.ts +41 -0
- package/src/lib/record/value-map.js +80 -0
- package/src/lib/record/value-map.js.map +1 -0
- package/src/lib/record/value-map.mjs +73 -0
- package/src/lib/record/value-map.mjs.map +1 -0
- package/src/lib/record/values.d.mts +10 -0
- package/src/lib/record/values.d.ts +10 -0
- package/src/lib/record/values.js.map +1 -1
- package/src/lib/record/values.mjs.map +1 -1
- package/src/runtime.d.mts +11 -4
- package/src/runtime.d.ts +11 -4
- package/src/runtime.js +13 -1
- package/src/runtime.js.map +1 -1
- package/src/runtime.mjs +4 -0
- package/src/runtime.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -28,5 +28,209 @@ list of records — that your app implements;
|
|
|
28
28
|
The page format is also a JSON Schema, for editors and other languages:
|
|
29
29
|
`@fieldia/core/page.schema.json`.
|
|
30
30
|
|
|
31
|
+
A page's `look` sets its accent, font, spacing, corners, labels and light or
|
|
32
|
+
dark scheme, and, under `parts`, a look for each kind of part over it — the
|
|
33
|
+
settings each kind has are `PART_LOOKS`:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
"look": {
|
|
37
|
+
"accent": "#1f7a4d",
|
|
38
|
+
"parts": {
|
|
39
|
+
"inputs": { "background": "#fff7e6", "border": "#c4320a", "corners": "round", "textSize": "large", "accent": "#c4320a" },
|
|
40
|
+
"choices": { "accent": "#1f7a4d", "background": "#f0f7ff", "border": "#1677ff", "corners": "soft", "textSize": "small" },
|
|
41
|
+
"groups": { "background": "#fbfaf7", "border": "#d6cfc2", "corners": "round" },
|
|
42
|
+
"buttons": { "accent": "#6941c6", "corners": "round", "textSize": "large" },
|
|
43
|
+
"tables": { "background": "#eef2f7", "border": "#9aa3ad", "textSize": "small" }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## A saved form placed in another
|
|
49
|
+
|
|
50
|
+
A block made once — an address, a contact person, a consent — is a page of its
|
|
51
|
+
own, placed in any other by its id with a `form` part:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{ "type": "form", "id": "home", "page": "address", "name": "home_address", "title": "Home address" }
|
|
55
|
+
{ "type": "form", "id": "billing", "page": "address", "version": 2, "name": "billing_address" }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- `page` is the saved page's id; `version` keeps to one published version, and
|
|
59
|
+
left out means the latest.
|
|
60
|
+
- `name` is where its answers go: the values hold them under it as an object,
|
|
61
|
+
`{ "home_address": { "street": "12 Nile Street", "city": "Cairo" } }`, so two
|
|
62
|
+
copies of one form never mix. It must not be a field of the page, nor another
|
|
63
|
+
copy's name.
|
|
64
|
+
- `title` is the words over it: the saved page's own title when left out, none
|
|
65
|
+
when empty. `colspan`, `invisible` and `readonly` work as on a section.
|
|
66
|
+
|
|
67
|
+
Only a page of `sections` or `tabs` can be placed; a page cannot be placed in
|
|
68
|
+
itself. The page's own conditions cannot read inside a saved form's answers.
|
|
69
|
+
|
|
70
|
+
A form is given the saved page once the app has found it —
|
|
71
|
+
`form.embed(partId, page)`, as the viewer does — and returns the inner form.
|
|
72
|
+
From then the saved page's own required fields, answer rules, conditions and
|
|
73
|
+
worked-out values hold inside it: the outer form refuses to save or send while
|
|
74
|
+
one fails (the error under `home_address.street`, shown on the inner form beside
|
|
75
|
+
its field), sends only the copies on show, tells `home_address` as changed when
|
|
76
|
+
anything inside changes, and loads, puts back and saves the nested answers. A
|
|
77
|
+
data source sees each copy's answers as one JSON value under its name.
|
|
78
|
+
|
|
79
|
+
## What a press or a moment does
|
|
80
|
+
|
|
81
|
+
A button — in the body, a record's header, a stat button or a list's actions —
|
|
82
|
+
runs `steps`, in order, each plain data and never code; and the page's `on`
|
|
83
|
+
runs them at its moments:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{ "type": "button", "id": "new-customer", "label": "New customer", "steps": [
|
|
87
|
+
{ "do": "open", "page": "customer", "as": "panel", "values": { "name": "customer_name" },
|
|
88
|
+
"into": { "customer_id": "id" }, "then": [{ "do": "say", "message": "Customer added", "tone": "success" }] }
|
|
89
|
+
] }
|
|
90
|
+
|
|
91
|
+
"on": {
|
|
92
|
+
"change": { "product": [{ "do": "call", "action": "check_stock" }] },
|
|
93
|
+
"beforeSave": [{ "do": "check" }, { "do": "ask", "message": "Send the order?" }],
|
|
94
|
+
"afterSave": [{ "do": "say", "message": "Order sent", "tone": "success" }]
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- `open` another page in a `dialog` (the default), a `panel` beside this form,
|
|
99
|
+
or in its `page`; on a `record` (an expression giving its id) or a new one with
|
|
100
|
+
`values`. A panel comes from its `side`: `end` (the default: the end of the
|
|
101
|
+
line, the right or, right to left, the left) or `start`, as the page reads;
|
|
102
|
+
or `left`, `right`, `top` or `bottom`, whatever its direction — a side on a
|
|
103
|
+
dialog or a page in its place is refused. Once it is saved or sent, `into`
|
|
104
|
+
sets this form's fields from its answers (`id` is the record it saved) and
|
|
105
|
+
`then` runs here.
|
|
106
|
+
- `set` a field from an expression, `clear` one, `addLine` to a table of lines.
|
|
107
|
+
- `check` the form or some fields, `save` (a page of responses sends), `reset`.
|
|
108
|
+
- `goTo` a tab or a wizard step, `say` something in a tone, `ask` Yes or No.
|
|
109
|
+
- `call` one of the app's own actions by name, with `params`; `close` the dialog
|
|
110
|
+
or panel the form was opened in.
|
|
111
|
+
- `openUrl` a web address an expression gives, in a new tab unless `newTab` is
|
|
112
|
+
false; `reload` the record from the data source after the app changed it —
|
|
113
|
+
an app's answer may ask for that with `reload: true`. An `open` of a list
|
|
114
|
+
page may give a `filter` — `valueFrom` reading this form — so it shows only
|
|
115
|
+
the records related to this one.
|
|
116
|
+
|
|
117
|
+
Any step may run only `when` a condition holds. A step that fails or is refused
|
|
118
|
+
stops the ones after it: a check that finds problems, No to a question, a save
|
|
119
|
+
that cannot be made, the app saying stop, a page closed without saving. The
|
|
120
|
+
moments are `open`, `change` (by field: a person's change, never a step's or a
|
|
121
|
+
rule's), `beforeSave` (a step that stops keeps it unsaved), `afterSave` and
|
|
122
|
+
`show` (by tab or wizard step id). A button may still name only an `action`,
|
|
123
|
+
handed to the app as before.
|
|
124
|
+
|
|
125
|
+
### Running steps
|
|
126
|
+
|
|
127
|
+
A press runs with `form.runAction(id)`: the button's `confirm` asked first,
|
|
128
|
+
then its `steps`, then its `action`, when it names one, as a final `call`.
|
|
129
|
+
The app runs its own with `form.run(steps, { id })`. Each run ends with a
|
|
130
|
+
`RunResult`:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
const result = await form.run([{ do: 'check' }, { do: 'save' }]);
|
|
134
|
+
// { done: true }
|
|
135
|
+
// { done: false, stoppedAt: 0, step: { do: 'check' }, reason: 'check', message: 'Email is required' }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- `reason` is why it stopped: `check` (problems found, and shown), `no` (a
|
|
139
|
+
question answered No), `save` (refused: the first problem, or the backend's
|
|
140
|
+
words), `app` (the app said stop, or threw — `error` holds what), `closed`
|
|
141
|
+
(a page opened and closed without saving), `cannot` (it cannot run here: no
|
|
142
|
+
host to open with, a field the page lacks).
|
|
143
|
+
- `stoppedAt` is its place among the steps run — for a step of an `open`'s
|
|
144
|
+
`then`, the open step's; for a button's `action`, one past its steps; none
|
|
145
|
+
when the `confirm` was answered No — and `step` is the step itself.
|
|
146
|
+
|
|
147
|
+
What the core cannot draw it asks of a host, which the viewer gives:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const form = createForm({
|
|
151
|
+
page,
|
|
152
|
+
dataSource,
|
|
153
|
+
host: {
|
|
154
|
+
open: (request) => showPage(request), // { page, version?, as, side?, title?, recordId, values? } → { saved, recordId?, values?, label? }
|
|
155
|
+
say: (message, tone) => toast(message, tone),
|
|
156
|
+
ask: (message) => askYesOrNo(message), // Promise<boolean>
|
|
157
|
+
close: () => panel.close(), // the dialog or panel this form was opened in
|
|
158
|
+
show: (tab) => tabs.pick(tab), // and the viewer calls form.shown(tab), as for a tab picked by hand
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Without a host, `say` says nothing, `ask` asks the form's `confirm` option — or
|
|
164
|
+
goes on as though answered Yes, so a form run from code is never held by a
|
|
165
|
+
question — and `open`, `close` and a `goTo` of a tab stop with `cannot`.
|
|
166
|
+
|
|
167
|
+
An `open` step reads `record` and `values` against this form; a field named
|
|
168
|
+
alone goes whole, a link with its name. Once the page is saved, `into` reads
|
|
169
|
+
the opened form's values, `id` being the record it saved; a link set to that
|
|
170
|
+
record is named by the host's `label` (its page's title field), else the
|
|
171
|
+
values' `display_name`, else their `name`, else the id.
|
|
172
|
+
|
|
173
|
+
### The app's actions
|
|
174
|
+
|
|
175
|
+
`onAction` gets each `call`: `{ id, action, params, recordId, values, recordIds }`.
|
|
176
|
+
`id` is the button's, or the moment's (`on.open`, `on.change.<field>`,
|
|
177
|
+
`on.beforeSave`, `on.afterSave`, `on.show.<id>`), or what `form.run` was
|
|
178
|
+
given (`run` when nothing); `recordIds` are the records chosen in a list, for
|
|
179
|
+
every call of that run. Fieldia waits for the answer, which may be an
|
|
180
|
+
`ActionResult`:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
onAction: async ({ action, values }) => {
|
|
184
|
+
if (action === 'price') return { values: { price: await priceOf(values.product_id) }, say: 'Priced' };
|
|
185
|
+
if (action === 'reserve' && !(await inStock(values))) return { stop: 'Out of stock' };
|
|
186
|
+
if (action === 'pick') return { open: { page: 'customer', as: 'panel', into: { customer_id: 'id' } } };
|
|
187
|
+
},
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`values` are set as a `set` step sets them (a link may be given by its id);
|
|
191
|
+
`say` is said, as words or `{ message, tone }`; `open` runs as an `open` step;
|
|
192
|
+
`stop` stops the steps after it, and its words, if any, are said as a
|
|
193
|
+
warning. Nothing answered means go on: an `onAction` that returns nothing
|
|
194
|
+
works as it always did.
|
|
195
|
+
|
|
196
|
+
### The moments
|
|
197
|
+
|
|
198
|
+
- `open` runs once the form has its values: as soon as a new one is made, and
|
|
199
|
+
after each `load()` of a record.
|
|
200
|
+
- `change` runs for a person's change only — `setValue(name, value)`, and a
|
|
201
|
+
table's lines added, edited, moved or removed. `setValue(name, value, { by: 'app' })`,
|
|
202
|
+
`setValues(values)`, steps, worked-out values, `setWhen` and the data
|
|
203
|
+
source's onchange never run it, so steps never chase each other round.
|
|
204
|
+
- `beforeSave` runs before the save's own check, so it can fill in what is
|
|
205
|
+
asked for. A stop keeps it unsaved: `save()` gives false; a check's
|
|
206
|
+
problems show as the save's own would; any other stop leaves
|
|
207
|
+
`status: 'error'` and `saveProblem: { kind: 'stopped', reason, message }`.
|
|
208
|
+
- `afterSave` runs once saved or sent.
|
|
209
|
+
- `show` runs as a wizard's step is entered — the first once `open` has run —
|
|
210
|
+
and as the viewer calls `form.shown(tabId)` for a tab.
|
|
211
|
+
|
|
212
|
+
Each moment runs one at a time. Set off again while it runs, `open`, `change`
|
|
213
|
+
and `show` run once more after it, with the values as they are then, however
|
|
214
|
+
often they were set off meanwhile. `beforeSave` and `afterSave` do not run
|
|
215
|
+
again: a save made meanwhile — a step of their own, or the app saving inside a
|
|
216
|
+
call — goes ahead without them, so nothing waits on itself. A moment set off
|
|
217
|
+
by its own run, as a `show` whose `goTo` leads back, does not run.
|
|
218
|
+
|
|
219
|
+
### Events
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
const off = form.on('change', ({ field, value, values, by }) => {}); // by: 'person' | 'step' | 'app'
|
|
223
|
+
form.on('save', ({ recordId, values }) => {});
|
|
224
|
+
form.on('send', ({ values }) => {}); // a page of responses: the answers sent
|
|
225
|
+
form.on('action', ({ request, result }) => {}); // the app answered a call
|
|
226
|
+
form.on('run', ({ id, steps, result }) => {}); // a run ended
|
|
227
|
+
form.on('step', ({ step }) => {}); // a wizard's step entered
|
|
228
|
+
form.on('open', ({ recordId, values }) => {});
|
|
229
|
+
off();
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
`subscribe` still hears every change of the form's state; `settled()` now
|
|
233
|
+
waits for runs too, a question still unanswered among them.
|
|
234
|
+
|
|
31
235
|
To show a page, use [`@fieldia/viewer`](https://www.npmjs.com/package/@fieldia/viewer)
|
|
32
236
|
or a framework binding. MIT licensed.
|
package/package.json
CHANGED