domma-js 0.56.0 → 0.58.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 +2 -2
- package/assets/types/generated/public/assets/flags/africa.d.ts +6 -0
- package/assets/types/generated/public/assets/flags/americas.d.ts +6 -0
- package/assets/types/generated/public/assets/flags/asia.d.ts +6 -0
- package/assets/types/generated/public/assets/flags/europe.d.ts +9 -0
- package/assets/types/generated/public/assets/flags/index.d.ts +11 -0
- package/assets/types/generated/public/assets/flags/oceania.d.ts +2 -0
- package/assets/types/generated/public/assets/icons/buildings.d.ts +6 -0
- package/assets/types/generated/public/assets/icons/code.d.ts +2 -0
- package/assets/types/generated/public/assets/icons/commerce.d.ts +7 -0
- package/assets/types/generated/public/assets/icons/communication.d.ts +7 -0
- package/assets/types/generated/public/assets/icons/devices.d.ts +6 -0
- package/assets/types/generated/public/assets/icons/emojis.d.ts +6 -0
- package/assets/types/generated/public/assets/icons/files.d.ts +7 -0
- package/assets/types/generated/public/assets/icons/finance.d.ts +6 -0
- package/assets/types/generated/public/assets/icons/forms.d.ts +5 -0
- package/assets/types/generated/public/assets/icons/health.d.ts +6 -0
- package/assets/types/generated/public/assets/icons/index.d.ts +24 -0
- package/assets/types/generated/public/assets/icons/media.d.ts +7 -0
- package/assets/types/generated/public/assets/icons/navigation.d.ts +7 -0
- package/assets/types/generated/public/assets/icons/seasonal.d.ts +6 -0
- package/assets/types/generated/public/assets/icons/social.d.ts +7 -0
- package/assets/types/generated/public/assets/icons/sport.d.ts +6 -0
- package/assets/types/generated/public/assets/icons/status.d.ts +7 -0
- package/assets/types/generated/public/assets/icons/transport.d.ts +7 -0
- package/assets/types/generated/public/assets/icons/ui.d.ts +7 -0
- package/assets/types/generated/public/assets/icons/weather.d.ts +6 -0
- package/assets/types/generated/src/auth.d.ts +424 -0
- package/assets/types/generated/src/avatar.d.ts +270 -0
- package/assets/types/generated/src/binding-source.d.ts +58 -0
- package/assets/types/generated/src/butterfly-drawing.d.ts +2 -0
- package/assets/types/generated/src/component-factory.d.ts +150 -0
- package/assets/types/generated/src/component.d.ts +162 -0
- package/assets/types/generated/src/components/back-to-top.d.ts +150 -0
- package/assets/types/generated/src/components/badge.d.ts +208 -0
- package/assets/types/generated/src/components/card.d.ts +189 -0
- package/assets/types/generated/src/components/command-palette.d.ts +352 -0
- package/assets/types/generated/src/components/dropzone.d.ts +342 -0
- package/assets/types/generated/src/components/focus-trap.d.ts +238 -0
- package/assets/types/generated/src/components/loader.d.ts +133 -0
- package/assets/types/generated/src/components/modal.d.ts +339 -0
- package/assets/types/generated/src/components/range-slider.d.ts +267 -0
- package/assets/types/generated/src/components/shared.d.ts +91 -0
- package/assets/types/generated/src/components/split-pane.d.ts +239 -0
- package/assets/types/generated/src/components/toast.d.ts +284 -0
- package/assets/types/generated/src/components/tooltip.d.ts +200 -0
- package/assets/types/generated/src/components/virtual-list.d.ts +340 -0
- package/assets/types/generated/src/config.d.ts +193 -0
- package/assets/types/generated/src/context-cursor.d.ts +69 -0
- package/assets/types/generated/src/context-menu.d.ts +596 -0
- package/assets/types/generated/src/dates.d.ts +367 -0
- package/assets/types/generated/src/dom.d.ts +1221 -0
- package/assets/types/generated/src/effects.d.ts +1281 -0
- package/assets/types/generated/src/elements.d.ts +4994 -0
- package/assets/types/generated/src/escape.d.ts +5 -0
- package/assets/types/generated/src/flags-bundle.d.ts +4 -0
- package/assets/types/generated/src/flags.d.ts +338 -0
- package/assets/types/generated/src/forms.d.ts +1060 -0
- package/assets/types/generated/src/globals.d.ts +45 -0
- package/assets/types/generated/src/http.d.ts +131 -0
- package/assets/types/generated/src/i18n.d.ts +261 -0
- package/assets/types/generated/src/icons.d.ts +213 -0
- package/assets/types/generated/src/index.d.ts +249 -0
- package/assets/types/generated/src/input-group.d.ts +135 -0
- package/assets/types/generated/src/models.d.ts +968 -0
- package/assets/types/generated/src/popover.d.ts +413 -0
- package/assets/types/generated/src/router.d.ts +344 -0
- package/assets/types/generated/src/safe-url.d.ts +10 -0
- package/assets/types/generated/src/sanitize.d.ts +97 -0
- package/assets/types/generated/src/schema-builder.d.ts +420 -0
- package/assets/types/generated/src/skeleton.d.ts +135 -0
- package/assets/types/generated/src/smooth-caret.d.ts +61 -0
- package/assets/types/generated/src/sortable.d.ts +368 -0
- package/assets/types/generated/src/storage.d.ts +93 -0
- package/assets/types/generated/src/tables.d.ts +901 -0
- package/assets/types/generated/src/theme.d.ts +262 -0
- package/assets/types/generated/src/ticker-tape-drawing.d.ts +2 -0
- package/assets/types/generated/src/treeview.d.ts +504 -0
- package/assets/types/generated/src/utils.d.ts +1667 -0
- package/assets/types/generated/src/web-components/base/domma-element.d.ts +134 -0
- package/assets/types/generated/src/web-components/index.d.ts +14 -0
- package/assets/types/generated/vendor/domma-reactive.d.ts +587 -0
- package/assets/types/index.d.ts +104 -226
- package/package.json +5 -2
- package/public/dist/bundles/domma-complete.css +20 -14
- package/public/dist/bundles/domma-data-focused.css +20 -14
- package/public/dist/bundles/domma-essentials.css +20 -14
- package/public/dist/bundles/domma-full.css +20 -14
- package/public/dist/bundles/domma-minimal.css +8 -8
- package/public/dist/domma-flags.esm.js +3 -3
- package/public/dist/domma-flags.esm.js.map +1 -1
- package/public/dist/domma-flags.min.js +3 -3
- package/public/dist/domma-flags.min.js.map +1 -1
- package/public/dist/domma-syntax.min.js +3 -3
- package/public/dist/domma.css +3 -3
- package/public/dist/domma.esm.js +5 -5
- package/public/dist/domma.esm.js.map +1 -1
- package/public/dist/domma.min.js +5 -5
- package/public/dist/domma.min.js.map +1 -1
- package/public/dist/elements.css +9 -3
- package/public/dist/grid.css +3 -3
- package/public/dist/syntax.css +3 -3
- package/public/dist/themes/domma-themes.css +3 -3
- package/templates/kickstart/.claude/snippets.md +1 -1
- package/templates/kickstart/CLAUDE.md +1 -1
- package/templates/kickstart/frontend/types/domma.d.ts +7 -4
- package/templates/kickstart-spa/.claude/snippets.md +1 -1
- package/assets/types/config.d.ts +0 -136
- package/assets/types/dates.d.ts +0 -209
- package/assets/types/dom.d.ts +0 -448
- package/assets/types/elements.d.ts +0 -1168
- package/assets/types/flags.d.ts +0 -130
- package/assets/types/http.d.ts +0 -97
- package/assets/types/i18n.d.ts +0 -99
- package/assets/types/icons.d.ts +0 -147
- package/assets/types/models.d.ts +0 -260
- package/assets/types/smooth-caret.d.ts +0 -12
- package/assets/types/storage.d.ts +0 -93
- package/assets/types/tables.d.ts +0 -327
- package/assets/types/theme.d.ts +0 -137
- package/assets/types/utils.d.ts +0 -675
|
@@ -0,0 +1,968 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A type check for a field's value (`M.types.*`).
|
|
3
|
+
* @callback TypeValidator
|
|
4
|
+
* @param {any} value
|
|
5
|
+
* @returns {boolean}
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* One field of a blueprint. Forms (`F.create`) read further keys from the same object
|
|
9
|
+
* (`label`, `options`, `formConfig`, ...), so any other key is allowed.
|
|
10
|
+
* @typedef {object} FieldDefinition
|
|
11
|
+
* @property {'string'|'number'|'boolean'|'array'|'object'|'date'|'any'|(string & {})} [type] Checked with
|
|
12
|
+
* `M.types[type]` when the value is not empty; a type with no validator (e.g. a form's `email`) is not checked
|
|
13
|
+
* @property {any} [default] Initial value when the data gives none (otherwise `null`)
|
|
14
|
+
* @property {boolean} [required] `null`, `undefined` and `''` fail
|
|
15
|
+
* @property {number} [min] Minimum, for a number value
|
|
16
|
+
* @property {number} [max] Maximum, for a number value
|
|
17
|
+
* @property {number} [minLength] Minimum length, for a string value
|
|
18
|
+
* @property {number} [maxLength] Maximum length, for a string value
|
|
19
|
+
* @property {RegExp} [pattern] Pattern a string value must match
|
|
20
|
+
* @property {(value: any) => boolean|string|void} [validate] Custom check: `false` fails, a string fails with
|
|
21
|
+
* that message, anything else passes
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* A blueprint: field name -> definition.
|
|
25
|
+
* @typedef {{[field: string]: FieldDefinition & {[key: string]: any}}} Schema
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* @typedef {object} ValidationResult
|
|
29
|
+
* @property {boolean} valid
|
|
30
|
+
* @property {Array<{field: string, error: string}>} errors
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* @typedef {object} ModelOptions
|
|
34
|
+
* @property {string} [persist] localStorage key (stored as `model:<persist>`); loaded on creation and saved on change
|
|
35
|
+
* @property {boolean} [autoSave=true] Save on every change when `persist` is set
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {object} ChangeEvent
|
|
39
|
+
* @property {string} field
|
|
40
|
+
* @property {any} newValue
|
|
41
|
+
* @property {any} oldValue
|
|
42
|
+
* @property {Model} model
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* @callback ChangeCallback
|
|
46
|
+
* @param {ChangeEvent} event
|
|
47
|
+
* @returns {void}
|
|
48
|
+
*/
|
|
49
|
+
/**
|
|
50
|
+
* @callback FieldChangeCallback
|
|
51
|
+
* @param {any} newValue
|
|
52
|
+
* @param {any} oldValue
|
|
53
|
+
* @param {Model} model
|
|
54
|
+
* @returns {void}
|
|
55
|
+
*/
|
|
56
|
+
/** @typedef {() => void} UnsubscribeFn */
|
|
57
|
+
/**
|
|
58
|
+
* Options for `M.bind()`.
|
|
59
|
+
* @typedef {object} BindingOptions
|
|
60
|
+
* @property {(value: any) => any} [format] Model value -> what the element shows
|
|
61
|
+
* @property {(value: any) => any} [parse] Element value -> what the model stores (two-way only)
|
|
62
|
+
* @property {boolean} [twoWay=false] Write the element's input back to the model
|
|
63
|
+
*/
|
|
64
|
+
/**
|
|
65
|
+
* A single reactive value (`M.observable()`), from domma-reactive.
|
|
66
|
+
* @template [T=any]
|
|
67
|
+
* @typedef {import('../vendor/domma-reactive.js').Observable<T>} Observable
|
|
68
|
+
*/
|
|
69
|
+
/**
|
|
70
|
+
* A reactive array (`M.observableArray()`), from domma-reactive.
|
|
71
|
+
* @template [T=any]
|
|
72
|
+
* @typedef {import('../vendor/domma-reactive.js').ObservableArray<T>} ObservableArray
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* @template [T=any]
|
|
76
|
+
* @typedef {import('../vendor/domma-reactive.js').ObservableOptions<T>} ObservableOptions
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* A lazily-evaluated, dependency-tracked derived value (`M.computed()`).
|
|
80
|
+
* @template [T=any]
|
|
81
|
+
* @typedef {object} ComputedRef
|
|
82
|
+
* @property {T} value The same read as `get()`, spelled as a property - the only one a template expression can
|
|
83
|
+
* use. Assigning hands the value to the derivation's `write` (warns and changes nothing without one).
|
|
84
|
+
* @property {() => T} get Current value, recomputing only if a dependency changed
|
|
85
|
+
* @property {(next: T) => void} set Imperative alias for assigning `.value`
|
|
86
|
+
* @property {() => T} peek Current value without registering a dependency on the caller
|
|
87
|
+
* @property {() => void} dispose Unlink from the dependency graph
|
|
88
|
+
*/
|
|
89
|
+
/**
|
|
90
|
+
* @template [T=any]
|
|
91
|
+
* @typedef {object} ComputedOptions
|
|
92
|
+
* @property {string} [label] Debug label used in warnings
|
|
93
|
+
* @property {(value: T, computation: import('../vendor/domma-reactive.js').Computation<T>) => void} [onChange] Called with the
|
|
94
|
+
* new value whenever it changes
|
|
95
|
+
*/
|
|
96
|
+
/**
|
|
97
|
+
* A writable computed: where a write should land.
|
|
98
|
+
* @template T
|
|
99
|
+
* @typedef {object} WritableComputedDefinition
|
|
100
|
+
* @property {() => T} read
|
|
101
|
+
* @property {(next: T) => void} write
|
|
102
|
+
*/
|
|
103
|
+
/**
|
|
104
|
+
* @typedef {object} EffectOptions
|
|
105
|
+
* @property {string} [label] Debug label used in warnings
|
|
106
|
+
*/
|
|
107
|
+
/**
|
|
108
|
+
* Options for `M.applyBindings()`.
|
|
109
|
+
* @typedef {object} ApplyBindingsOptions
|
|
110
|
+
* @property {Record<string, (...args: any[]) => any>} [methods] Handlers for `data-on-*`. Looked up only when the
|
|
111
|
+
* data has no such key.
|
|
112
|
+
* @property {import('../vendor/domma-reactive.js').RenderFn} [render] Template renderer for `data-each` item bodies.
|
|
113
|
+
* Defaults to `utils.render`.
|
|
114
|
+
* @property {string} [template] A name for this subtree, used in warnings
|
|
115
|
+
*/
|
|
116
|
+
/**
|
|
117
|
+
* One activated binding record, from domma-reactive. `deps` are the names its expression reads.
|
|
118
|
+
* @typedef {import('../vendor/domma-reactive.js').Binding} ActiveBinding
|
|
119
|
+
*/
|
|
120
|
+
/**
|
|
121
|
+
* What `M.applyBindings()` returns; call `dispose()` when the markup is done with.
|
|
122
|
+
* @typedef {import('../vendor/domma-reactive.js').BindingsHandle} BindingHandle
|
|
123
|
+
*/
|
|
124
|
+
/**
|
|
125
|
+
* A binding kind for `M.registerBinding()`. Only `update` is required.
|
|
126
|
+
* @typedef {import('../vendor/domma-reactive.js').BindingHandler} BindingHandler
|
|
127
|
+
*/
|
|
128
|
+
/**
|
|
129
|
+
* A named store (`M.store()`).
|
|
130
|
+
* @typedef {object} Store
|
|
131
|
+
* @property {Record<string, any>} state The current state (replaced, never mutated, by setState)
|
|
132
|
+
* @property {Set<(state: Record<string, any>, oldState: Record<string, any>) => void>} listeners
|
|
133
|
+
* @property {() => Record<string, any>} getState Get a copy of the current state
|
|
134
|
+
* @property {(updates: Record<string, any>) => void} setState Merge partial updates and notify
|
|
135
|
+
* @property {(listener: (state: Record<string, any>, oldState: Record<string, any>) => void) => () => boolean} subscribe
|
|
136
|
+
* Subscribe to state changes; returns the unsubscribe function
|
|
137
|
+
* @property {(newState?: Record<string, any>) => void} reset Reset to the initial state, or to `newState`
|
|
138
|
+
* (listeners receive `{}` as the old state)
|
|
139
|
+
*/
|
|
140
|
+
/**
|
|
141
|
+
* @typedef {object} TypeValidators
|
|
142
|
+
* @property {TypeValidator} string
|
|
143
|
+
* @property {TypeValidator} number Not NaN
|
|
144
|
+
* @property {TypeValidator} boolean
|
|
145
|
+
* @property {TypeValidator} array
|
|
146
|
+
* @property {TypeValidator} object A non-null, non-array object
|
|
147
|
+
* @property {TypeValidator} date A valid `Date`, or ISO-8601 date / date-time text
|
|
148
|
+
* @property {TypeValidator} any
|
|
149
|
+
*/
|
|
150
|
+
/**
|
|
151
|
+
* Reactive Model Class
|
|
152
|
+
*/
|
|
153
|
+
export class Model {
|
|
154
|
+
/**
|
|
155
|
+
* @param {Schema} schema Field definitions
|
|
156
|
+
* @param {Record<string, any>} [data={}] Initial data values
|
|
157
|
+
* @param {ModelOptions} [options={}]
|
|
158
|
+
*/
|
|
159
|
+
constructor(schema: Schema, data?: Record<string, any>, options?: ModelOptions);
|
|
160
|
+
/** @private */
|
|
161
|
+
private _schema;
|
|
162
|
+
/** @private */
|
|
163
|
+
private _initialData;
|
|
164
|
+
/** @private */
|
|
165
|
+
private _bindings;
|
|
166
|
+
/**
|
|
167
|
+
* @type {Set<ChangeCallback>}
|
|
168
|
+
* @private
|
|
169
|
+
*/
|
|
170
|
+
private _changeCallbacks;
|
|
171
|
+
/**
|
|
172
|
+
* @type {Map<string, Set<FieldChangeCallback>>}
|
|
173
|
+
* @private
|
|
174
|
+
*/
|
|
175
|
+
private _fieldCallbacks;
|
|
176
|
+
/**
|
|
177
|
+
* @type {Map<string, Observable<any>>}
|
|
178
|
+
* @private
|
|
179
|
+
*/
|
|
180
|
+
private _fields;
|
|
181
|
+
/**
|
|
182
|
+
* @type {Record<string, any>|null}
|
|
183
|
+
* @private
|
|
184
|
+
*/
|
|
185
|
+
private _trackedView;
|
|
186
|
+
/**
|
|
187
|
+
* @type {string|null}
|
|
188
|
+
* @private
|
|
189
|
+
*/
|
|
190
|
+
private _persistKey;
|
|
191
|
+
/** @private */
|
|
192
|
+
private _autoSave;
|
|
193
|
+
/**
|
|
194
|
+
* Read a field, or the whole data object when called with no argument.
|
|
195
|
+
*
|
|
196
|
+
* Reads performed inside a computed or effect are tracked, so the caller is
|
|
197
|
+
* re-run when that field changes. Reading the whole object tracks every
|
|
198
|
+
* field currently present - the conservative choice, since the reader could
|
|
199
|
+
* touch any of them.
|
|
200
|
+
*
|
|
201
|
+
* @overload
|
|
202
|
+
* @returns {Record<string, any>} Every field
|
|
203
|
+
*/
|
|
204
|
+
get(): Record<string, any>;
|
|
205
|
+
/**
|
|
206
|
+
* @overload
|
|
207
|
+
* @param {string} field
|
|
208
|
+
* @returns {any} The field's value (`undefined` for an unknown field)
|
|
209
|
+
*/
|
|
210
|
+
get(field: string): any;
|
|
211
|
+
/**
|
|
212
|
+
* Get (creating if absent) the observable backing a field.
|
|
213
|
+
*
|
|
214
|
+
* Fields not declared in the schema are created on first write, matching
|
|
215
|
+
* the previous behaviour where _data accepted any key.
|
|
216
|
+
*
|
|
217
|
+
* @param {string} name
|
|
218
|
+
* @returns {Observable<any>}
|
|
219
|
+
* @private
|
|
220
|
+
*/
|
|
221
|
+
private _field;
|
|
222
|
+
/**
|
|
223
|
+
* Plain-object view of every field, read WITHOUT tracking.
|
|
224
|
+
*
|
|
225
|
+
* Used by toJSON(), persistence and validation - render-time and
|
|
226
|
+
* serialisation reads must not register dependencies.
|
|
227
|
+
*
|
|
228
|
+
* @returns {Record<string, any>}
|
|
229
|
+
* @private
|
|
230
|
+
*/
|
|
231
|
+
private _snapshot;
|
|
232
|
+
/**
|
|
233
|
+
* A read-tracked, write-through view of the model's data.
|
|
234
|
+
*
|
|
235
|
+
* Property reads register a dependency; property writes are routed through
|
|
236
|
+
* set(), so validation, change notification and persistence all still run.
|
|
237
|
+
*
|
|
238
|
+
* const state = model.tracked();
|
|
239
|
+
* M.effect(() => console.log(state.count)); // re-runs when count changes
|
|
240
|
+
* state.count = 5; // validated + notified
|
|
241
|
+
*
|
|
242
|
+
* @returns {Record<string, any>}
|
|
243
|
+
*/
|
|
244
|
+
tracked(): Record<string, any>;
|
|
245
|
+
/**
|
|
246
|
+
* @overload
|
|
247
|
+
* @param {string} field
|
|
248
|
+
* @param {any} value
|
|
249
|
+
* @returns {this}
|
|
250
|
+
*/
|
|
251
|
+
set(field: string, value: any): this;
|
|
252
|
+
/**
|
|
253
|
+
* @overload
|
|
254
|
+
* @param {Record<string, any>} data Several fields at once
|
|
255
|
+
* @returns {this}
|
|
256
|
+
*/
|
|
257
|
+
set(data: Record<string, any>): this;
|
|
258
|
+
/**
|
|
259
|
+
* @param {string} field
|
|
260
|
+
* @param {any} value
|
|
261
|
+
* @private
|
|
262
|
+
*/
|
|
263
|
+
private _setField;
|
|
264
|
+
/**
|
|
265
|
+
* @param {string} field
|
|
266
|
+
* @param {any} value
|
|
267
|
+
* @returns {{valid: boolean, error?: string}}
|
|
268
|
+
* @private
|
|
269
|
+
*/
|
|
270
|
+
private _validateField;
|
|
271
|
+
/**
|
|
272
|
+
* Validate all fields
|
|
273
|
+
* @returns {ValidationResult}
|
|
274
|
+
*/
|
|
275
|
+
validate(): ValidationResult;
|
|
276
|
+
/**
|
|
277
|
+
* Get model data as a plain object (untracked)
|
|
278
|
+
* @returns {Record<string, any>}
|
|
279
|
+
*/
|
|
280
|
+
toJSON(): Record<string, any>;
|
|
281
|
+
/**
|
|
282
|
+
* Subscribe to changes.
|
|
283
|
+
*
|
|
284
|
+
* onChange(cb) - every field; cb receives {field, newValue, oldValue, model}
|
|
285
|
+
* onChange(field, cb) - one field only; cb receives the same change object
|
|
286
|
+
*
|
|
287
|
+
* For positional arguments (newValue, oldValue, model), use onFieldChange().
|
|
288
|
+
*
|
|
289
|
+
* @overload
|
|
290
|
+
* @param {ChangeCallback} callback
|
|
291
|
+
* @returns {UnsubscribeFn}
|
|
292
|
+
*/
|
|
293
|
+
onChange(callback: ChangeCallback): UnsubscribeFn;
|
|
294
|
+
/**
|
|
295
|
+
* @overload
|
|
296
|
+
* @param {string} field
|
|
297
|
+
* @param {ChangeCallback} callback
|
|
298
|
+
* @returns {UnsubscribeFn}
|
|
299
|
+
*/
|
|
300
|
+
onChange(field: string, callback: ChangeCallback): UnsubscribeFn;
|
|
301
|
+
/**
|
|
302
|
+
* Subscribe to one field's changes, with positional arguments (newValue, oldValue, model)
|
|
303
|
+
* @param {string} field
|
|
304
|
+
* @param {FieldChangeCallback} callback
|
|
305
|
+
* @returns {UnsubscribeFn} Unsubscribe function
|
|
306
|
+
*/
|
|
307
|
+
onFieldChange(field: string, callback: FieldChangeCallback): UnsubscribeFn;
|
|
308
|
+
/**
|
|
309
|
+
* @private
|
|
310
|
+
*/
|
|
311
|
+
private _notifyChange;
|
|
312
|
+
/**
|
|
313
|
+
* @private
|
|
314
|
+
*/
|
|
315
|
+
private _updateBindings;
|
|
316
|
+
/**
|
|
317
|
+
* @param {string} field
|
|
318
|
+
* @param {Binding} binding
|
|
319
|
+
* @private
|
|
320
|
+
*/
|
|
321
|
+
private _addBinding;
|
|
322
|
+
/**
|
|
323
|
+
* @param {string} field
|
|
324
|
+
* @param {Binding} binding
|
|
325
|
+
* @private
|
|
326
|
+
*/
|
|
327
|
+
private _removeBinding;
|
|
328
|
+
/**
|
|
329
|
+
* Reset every field to its initial value
|
|
330
|
+
* @param {boolean} [clearStorage=false] Also clear the persisted copy
|
|
331
|
+
* @returns {this}
|
|
332
|
+
*/
|
|
333
|
+
reset(clearStorage?: boolean): this;
|
|
334
|
+
/**
|
|
335
|
+
* Destroy model and clean up: drops every listener, binding and observable
|
|
336
|
+
* @param {boolean} [clearStorage=false] Also clear the persisted copy
|
|
337
|
+
* @returns {void}
|
|
338
|
+
*/
|
|
339
|
+
destroy(clearStorage?: boolean): void;
|
|
340
|
+
/**
|
|
341
|
+
* Manually save model to localStorage
|
|
342
|
+
* @returns {boolean} - True if successful
|
|
343
|
+
*/
|
|
344
|
+
save(): boolean;
|
|
345
|
+
/**
|
|
346
|
+
* Manually load model from localStorage
|
|
347
|
+
* @returns {boolean} - True if data was loaded
|
|
348
|
+
*/
|
|
349
|
+
load(): boolean;
|
|
350
|
+
/**
|
|
351
|
+
* Clear persisted data from localStorage
|
|
352
|
+
* @returns {boolean} - True if successful
|
|
353
|
+
*/
|
|
354
|
+
clearStorage(): boolean;
|
|
355
|
+
/**
|
|
356
|
+
* Get the persistence key
|
|
357
|
+
* @returns {string|null}
|
|
358
|
+
*/
|
|
359
|
+
getPersistKey(): string | null;
|
|
360
|
+
/**
|
|
361
|
+
* Check if model is persisted
|
|
362
|
+
* @returns {boolean}
|
|
363
|
+
*/
|
|
364
|
+
isPersisted(): boolean;
|
|
365
|
+
/**
|
|
366
|
+
* Save model data to localStorage
|
|
367
|
+
* @returns {boolean}
|
|
368
|
+
* @private
|
|
369
|
+
*/
|
|
370
|
+
private _saveToStorage;
|
|
371
|
+
/**
|
|
372
|
+
* Load model data from localStorage
|
|
373
|
+
* @returns {boolean} - True if data was loaded
|
|
374
|
+
* @private
|
|
375
|
+
*/
|
|
376
|
+
private _loadFromStorage;
|
|
377
|
+
}
|
|
378
|
+
export namespace models {
|
|
379
|
+
export let _events: Map<string, Set<(data: any) => void>>;
|
|
380
|
+
/**
|
|
381
|
+
* Subscribe to an event
|
|
382
|
+
* @param {string} event
|
|
383
|
+
* @param {(data: any) => void} callback
|
|
384
|
+
* @returns {UnsubscribeFn}
|
|
385
|
+
*/
|
|
386
|
+
export function subscribe(event: string, callback: (data: any) => void): UnsubscribeFn;
|
|
387
|
+
/**
|
|
388
|
+
* Alias for subscribe
|
|
389
|
+
* @param {string} event
|
|
390
|
+
* @param {(data: any) => void} callback
|
|
391
|
+
* @returns {UnsubscribeFn}
|
|
392
|
+
*/
|
|
393
|
+
export function on(event: string, callback: (data: any) => void): UnsubscribeFn;
|
|
394
|
+
/**
|
|
395
|
+
* Unsubscribe from an event
|
|
396
|
+
* @param {string} event
|
|
397
|
+
* @param {(data: any) => void} callback
|
|
398
|
+
* @returns {void}
|
|
399
|
+
*/
|
|
400
|
+
export function unsubscribe(event: string, callback: (data: any) => void): void;
|
|
401
|
+
/**
|
|
402
|
+
* Alias for unsubscribe
|
|
403
|
+
* @param {string} event
|
|
404
|
+
* @param {(data: any) => void} callback
|
|
405
|
+
* @returns {void}
|
|
406
|
+
*/
|
|
407
|
+
export function off(event: string, callback: (data: any) => void): void;
|
|
408
|
+
/**
|
|
409
|
+
* Publish an event
|
|
410
|
+
* @param {string} event
|
|
411
|
+
* @param {any} [data]
|
|
412
|
+
* @returns {void}
|
|
413
|
+
*/
|
|
414
|
+
export function publish(event: string, data?: any): void;
|
|
415
|
+
/**
|
|
416
|
+
* Alias for publish
|
|
417
|
+
* @param {string} event
|
|
418
|
+
* @param {any} [data]
|
|
419
|
+
* @returns {void}
|
|
420
|
+
*/
|
|
421
|
+
export function emit(event: string, data?: any): void;
|
|
422
|
+
/**
|
|
423
|
+
* Subscribe to an event once
|
|
424
|
+
* @param {string} event
|
|
425
|
+
* @param {(data: any) => void} callback
|
|
426
|
+
* @returns {UnsubscribeFn}
|
|
427
|
+
*/
|
|
428
|
+
export function once(event: string, callback: (data: any) => void): UnsubscribeFn;
|
|
429
|
+
/**
|
|
430
|
+
* Clear one event's listeners, or every event's
|
|
431
|
+
* @param {string} [event]
|
|
432
|
+
* @returns {void}
|
|
433
|
+
*/
|
|
434
|
+
export function clear(event?: string): void;
|
|
435
|
+
/**
|
|
436
|
+
* Create a new reactive model
|
|
437
|
+
* @param {Schema} schema - Field definitions
|
|
438
|
+
* @param {Record<string, any>} [initialData={}] - Initial data values
|
|
439
|
+
* @param {ModelOptions} [options={}] - Options (persist, autoSave)
|
|
440
|
+
* @returns {Model}
|
|
441
|
+
*/
|
|
442
|
+
export function create(schema: Schema, initialData?: Record<string, any>, options?: ModelOptions): Model;
|
|
443
|
+
/**
|
|
444
|
+
* Extend a blueprint with additional fields
|
|
445
|
+
* @param {...Schema} blueprints - Blueprints to merge (left-to-right)
|
|
446
|
+
* @returns {Schema} - A new merged blueprint
|
|
447
|
+
*/
|
|
448
|
+
export function extend(...blueprints: Schema[]): Schema;
|
|
449
|
+
/**
|
|
450
|
+
* Pick specific fields from a blueprint
|
|
451
|
+
* @template {Schema} S
|
|
452
|
+
* @template {keyof S & string} K
|
|
453
|
+
* @param {S} blueprint - Source blueprint
|
|
454
|
+
* @param {K[]} fields - Array of field names to pick
|
|
455
|
+
* @returns {Pick<S, K>} - New blueprint with only specified fields
|
|
456
|
+
*/
|
|
457
|
+
export function pick<S extends Schema, K extends keyof S & string>(blueprint: S, fields: K[]): Pick<S, K>;
|
|
458
|
+
/**
|
|
459
|
+
* Omit specific fields from a blueprint
|
|
460
|
+
* @template {Schema} S
|
|
461
|
+
* @template {keyof S & string} K
|
|
462
|
+
* @param {S} blueprint - Source blueprint
|
|
463
|
+
* @param {K[]} fields - Array of field names to omit
|
|
464
|
+
* @returns {Omit<S, K>} - New blueprint without specified fields
|
|
465
|
+
*/
|
|
466
|
+
export function omit<S extends Schema, K extends keyof S & string>(blueprint: S, fields: K[]): Omit<S, K>;
|
|
467
|
+
export { observable };
|
|
468
|
+
export { observableArray };
|
|
469
|
+
/**
|
|
470
|
+
* Create a lazily-evaluated derived value that tracks whatever it reads.
|
|
471
|
+
*
|
|
472
|
+
* The body is not run until `.get()` is called, and afterwards the cached
|
|
473
|
+
* value is reused until one of the fields it read actually changes.
|
|
474
|
+
*
|
|
475
|
+
* const model = M.create(blueprint, {price: 10, qty: 3});
|
|
476
|
+
* const total = M.computed(() => model.get('price') * model.get('qty'));
|
|
477
|
+
* total.get(); // 30 - evaluated now
|
|
478
|
+
* total.get(); // 30 - cached, body not re-run
|
|
479
|
+
* model.set('qty', 4);
|
|
480
|
+
* total.get(); // 40 - re-evaluated on demand
|
|
481
|
+
*
|
|
482
|
+
* The body must be synchronous: tracking stops at the first `await`.
|
|
483
|
+
*
|
|
484
|
+
* A computed is read-only unless you say where a write should land:
|
|
485
|
+
*
|
|
486
|
+
* const celsius = M.observable(100);
|
|
487
|
+
* const fahrenheit = M.computed({
|
|
488
|
+
* read: () => celsius.value * 9 / 5 + 32,
|
|
489
|
+
* write: (f) => { celsius.value = (f - 32) * 5 / 9; }
|
|
490
|
+
* });
|
|
491
|
+
* fahrenheit.value = 32; // celsius.value === 0
|
|
492
|
+
*
|
|
493
|
+
* That is what lets `data-model` bind a derived value. Assigning to one
|
|
494
|
+
* with no `write` warns and changes nothing, rather than storing into the
|
|
495
|
+
* read cache where the next recompute would silently drop it.
|
|
496
|
+
*
|
|
497
|
+
* @template [T=any]
|
|
498
|
+
* @overload
|
|
499
|
+
* @param {() => T} fn Derivation (read-only).
|
|
500
|
+
* @param {ComputedOptions<T>} [options]
|
|
501
|
+
* @returns {ComputedRef<T>}
|
|
502
|
+
*/
|
|
503
|
+
export function computed<T = any>(fn: () => T, options?: ComputedOptions<T>): ComputedRef<T>;
|
|
504
|
+
/**
|
|
505
|
+
* @template [T=any]
|
|
506
|
+
* @overload
|
|
507
|
+
* @param {WritableComputedDefinition<T>} fn {read, write}: a writable computed.
|
|
508
|
+
* @param {ComputedOptions<T>} [options]
|
|
509
|
+
* @returns {ComputedRef<T>}
|
|
510
|
+
*/
|
|
511
|
+
export function computed<T = any>(fn: WritableComputedDefinition<T>, options?: ComputedOptions<T>): ComputedRef<T>;
|
|
512
|
+
/**
|
|
513
|
+
* Run a function now, and again whenever any field it read changes.
|
|
514
|
+
*
|
|
515
|
+
* Dependencies are re-collected on every run, so an effect whose branches
|
|
516
|
+
* change stops listening to the branch it no longer takes.
|
|
517
|
+
*
|
|
518
|
+
* const stop = M.effect(() => {
|
|
519
|
+
* $('#total').text(model.get('price') * model.get('qty'));
|
|
520
|
+
* });
|
|
521
|
+
* stop(); // unsubscribe
|
|
522
|
+
*
|
|
523
|
+
* Re-runs are batched: a burst of writes in the same tick produces a single
|
|
524
|
+
* run on the next microtask, not one per write.
|
|
525
|
+
*
|
|
526
|
+
* @param {() => unknown} fn Synchronous body.
|
|
527
|
+
* @param {EffectOptions} [options]
|
|
528
|
+
* @returns {UnsubscribeFn} Call to stop the effect.
|
|
529
|
+
*/
|
|
530
|
+
export function effect(fn: () => unknown, options?: EffectOptions): UnsubscribeFn;
|
|
531
|
+
/**
|
|
532
|
+
* Read values without registering them as dependencies of the enclosing
|
|
533
|
+
* computed or effect.
|
|
534
|
+
*
|
|
535
|
+
* @template T
|
|
536
|
+
* @param {() => T} fn
|
|
537
|
+
* @returns {T}
|
|
538
|
+
*/
|
|
539
|
+
export function untracked<T>(fn: () => T): T;
|
|
540
|
+
/**
|
|
541
|
+
* Settle all pending reactive work immediately rather than waiting for the
|
|
542
|
+
* microtask flush. Mainly useful in tests and when code must observe a
|
|
543
|
+
* derived value synchronously after a write.
|
|
544
|
+
* @returns {void}
|
|
545
|
+
*/
|
|
546
|
+
export function flush(): void;
|
|
547
|
+
export let types: TypeValidators;
|
|
548
|
+
/**
|
|
549
|
+
* Bind a model field to DOM element(s): the element shows the field, and with `twoWay` writes back to it
|
|
550
|
+
* @param {Model} model
|
|
551
|
+
* @param {string} field
|
|
552
|
+
* @param {string|HTMLElement} selector Selector (every match is bound) or element
|
|
553
|
+
* @param {BindingOptions} [options]
|
|
554
|
+
* @returns {UnsubscribeFn} Unbind function
|
|
555
|
+
*/
|
|
556
|
+
export function bind(model: Model, field: string, selector: string | HTMLElement, options?: BindingOptions): UnsubscribeFn;
|
|
557
|
+
/**
|
|
558
|
+
* Bring markup that already exists to life.
|
|
559
|
+
*
|
|
560
|
+
* `M.bind()` wires ONE field to ONE element. This activates every binding
|
|
561
|
+
* attribute under a root at once, and is the counterpart to the template
|
|
562
|
+
* bindings a `Domma.component()` already gets: a component owns its markup
|
|
563
|
+
* and renders it, a server-rendered page owns its markup and wants
|
|
564
|
+
* behaviour added to it.
|
|
565
|
+
*
|
|
566
|
+
* <div id="app">
|
|
567
|
+
* <h1 data-bind-text="title">Rendered by the server</h1>
|
|
568
|
+
* <input data-model="query">
|
|
569
|
+
* <p data-if="showHelp">Help text.</p>
|
|
570
|
+
* <button data-on-click="save">Save</button>
|
|
571
|
+
* <ul data-each="rows key=id">
|
|
572
|
+
* <li data-bind-text="name">template row</li>
|
|
573
|
+
* </ul>
|
|
574
|
+
* </div>
|
|
575
|
+
*
|
|
576
|
+
* const model = M.create(blueprint, {title: 'Live', query: '', rows: []});
|
|
577
|
+
* const handle = M.applyBindings(model, '#app', {
|
|
578
|
+
* methods: { save() { H.post('/api/save', model.toJSON()); } }
|
|
579
|
+
* });
|
|
580
|
+
*
|
|
581
|
+
* Pass a Model and every binding reads and writes through it - `data-model`
|
|
582
|
+
* lands in the model, with validation and change notification, and any
|
|
583
|
+
* other binding on that field updates. A plain object works too, but only
|
|
584
|
+
* the parts of it that are observable will be reactive.
|
|
585
|
+
*
|
|
586
|
+
* `{{ }}` is deliberately NOT interpolated in markup that already exists;
|
|
587
|
+
* `data-bind-text` is the supported spelling. The one exception is the
|
|
588
|
+
* contents of a `data-each`, which are a template rather than rendered
|
|
589
|
+
* output. See docs/Bindings.md.
|
|
590
|
+
*
|
|
591
|
+
* Applying twice over the same region is safe: elements already bound are
|
|
592
|
+
* skipped, with one warning naming the root.
|
|
593
|
+
*
|
|
594
|
+
* @param {Model|Record<string, any>} data A Model, or a plain object.
|
|
595
|
+
* @param {string|Element|import('./dom.js').DommaCollection|ArrayLike<Element>} root Selector, element or
|
|
596
|
+
* collection (its first element).
|
|
597
|
+
* @param {ApplyBindingsOptions} [options] `methods` (handlers for `data-on-*`),
|
|
598
|
+
* `render` (template renderer for list
|
|
599
|
+
* items - defaults to `utils.render`, so
|
|
600
|
+
* `{{ }}` inside a `data-each` behaves as
|
|
601
|
+
* it does everywhere else in Domma) and
|
|
602
|
+
* `template` (a name used in warnings).
|
|
603
|
+
* @returns {BindingHandle}
|
|
604
|
+
* @throws {TypeError} When no element is found for `root`.
|
|
605
|
+
*/
|
|
606
|
+
export function applyBindings(data: Model | Record<string, any>, root: string | Element | import("./dom.js").DommaCollection | ArrayLike<Element>, options?: ApplyBindingsOptions): BindingHandle;
|
|
607
|
+
/**
|
|
608
|
+
* Add a binding kind, usable as `data-<name>` wherever bindings are.
|
|
609
|
+
*
|
|
610
|
+
* Not a side door: every built-in - text, attr, raw, if, event, bind,
|
|
611
|
+
* model - is registered through this same function, so a custom binding can
|
|
612
|
+
* do anything a built-in can.
|
|
613
|
+
*
|
|
614
|
+
* M.registerBinding('uppercase', {
|
|
615
|
+
* attribute: 'data-uppercase',
|
|
616
|
+
* expression: true, // parse the attribute value
|
|
617
|
+
* tracks: true, // re-run when what it reads changes
|
|
618
|
+
* primes: true, // run once after the first paint
|
|
619
|
+
* update({binding, nodes, context}) {
|
|
620
|
+
* const value = binding.evaluate(context);
|
|
621
|
+
* for (const el of nodes) el.textContent = String(value).toUpperCase();
|
|
622
|
+
* return true;
|
|
623
|
+
* }
|
|
624
|
+
* });
|
|
625
|
+
* // <p data-uppercase="name"></p>
|
|
626
|
+
*
|
|
627
|
+
* `update` receives every node the binding owns at once, not one per call,
|
|
628
|
+
* so a handler that re-renders a region does so once however many regions
|
|
629
|
+
* it owns.
|
|
630
|
+
*
|
|
631
|
+
* @template {BindingHandler} H
|
|
632
|
+
* @param {string} name The binding kind, which becomes `binding.kind`.
|
|
633
|
+
* @param {H} handler `{attribute|attributePrefix, expression, tracks,
|
|
634
|
+
* region, capturesBody, primes, update, attach,
|
|
635
|
+
* detach}` - see docs/Bindings.md.
|
|
636
|
+
* @returns {H} The handler
|
|
637
|
+
*/
|
|
638
|
+
export function registerBinding<H extends BindingHandler>(name: string, handler: H): H;
|
|
639
|
+
/**
|
|
640
|
+
* Remove a binding kind added with registerBinding().
|
|
641
|
+
*
|
|
642
|
+
* @param {string} name
|
|
643
|
+
* @returns {boolean} whether anything was removed
|
|
644
|
+
*/
|
|
645
|
+
export function unregisterBinding(name: string): boolean;
|
|
646
|
+
/**
|
|
647
|
+
* Add an extender, callable as `M.observable(x).extend({name: value})`.
|
|
648
|
+
*
|
|
649
|
+
* `rateLimit`, `throttle` and `notify` are registered through this same
|
|
650
|
+
* function, so an extender you add is not a second-class citizen - the
|
|
651
|
+
* built-ins have no privileged path.
|
|
652
|
+
*
|
|
653
|
+
* M.registerExtender('trace', (control, label) => {
|
|
654
|
+
* control.intercept((next) => (value) => {
|
|
655
|
+
* console.log(label, value);
|
|
656
|
+
* next(value);
|
|
657
|
+
* });
|
|
658
|
+
* });
|
|
659
|
+
*
|
|
660
|
+
* const count = M.observable(0).extend({trace: 'count'});
|
|
661
|
+
*
|
|
662
|
+
* The control surface an extender is handed has exactly two powers:
|
|
663
|
+
* `setEquals(fn)` replaces the change gate, and `intercept(wrap)` wraps the
|
|
664
|
+
* announcement. Neither can touch the stored value, which is what keeps the
|
|
665
|
+
* guarantee that a write always lands immediately - even under a rate
|
|
666
|
+
* limit, where only the notification waits.
|
|
667
|
+
*
|
|
668
|
+
* @template {import('../vendor/domma-reactive.js').Extender} F
|
|
669
|
+
* @param {string} name
|
|
670
|
+
* @param {F} fn `(control, value) => void`
|
|
671
|
+
* @returns {F} The extender
|
|
672
|
+
*/
|
|
673
|
+
export function registerExtender<F extends import("../vendor/domma-reactive.js").Extender>(name: string, fn: F): F;
|
|
674
|
+
/**
|
|
675
|
+
* Remove an extender added with registerExtender().
|
|
676
|
+
* The built-ins are refused.
|
|
677
|
+
*
|
|
678
|
+
* @param {string} name
|
|
679
|
+
* @returns {boolean} whether anything was removed
|
|
680
|
+
*/
|
|
681
|
+
export function unregisterExtender(name: string): boolean;
|
|
682
|
+
/**
|
|
683
|
+
* Add a function callable from a binding expression.
|
|
684
|
+
*
|
|
685
|
+
* Expressions cannot call methods on your data - `{{total.get()}}` will not
|
|
686
|
+
* parse - because arbitrary calls are how an expression language turns into
|
|
687
|
+
* an execution surface. A registered helper is the supported way to shape a
|
|
688
|
+
* value in the markup:
|
|
689
|
+
*
|
|
690
|
+
* M.registerHelper('upper', (s) => String(s).toUpperCase());
|
|
691
|
+
* // <p data-bind-text="upper(name)"></p>
|
|
692
|
+
*
|
|
693
|
+
* Helpers are shared by every binding and every component template.
|
|
694
|
+
*
|
|
695
|
+
* @template {(...args: any[]) => unknown} F
|
|
696
|
+
* @param {string} name
|
|
697
|
+
* @param {F} fn Pure, synchronous.
|
|
698
|
+
* @returns {F} The helper
|
|
699
|
+
*/
|
|
700
|
+
export function registerHelper<F extends (...args: any[]) => unknown>(name: string, fn: F): F;
|
|
701
|
+
/**
|
|
702
|
+
* Remove a helper added with registerHelper().
|
|
703
|
+
*
|
|
704
|
+
* @param {string} name
|
|
705
|
+
* @returns {boolean} whether anything was removed
|
|
706
|
+
*/
|
|
707
|
+
export function unregisterHelper(name: string): boolean;
|
|
708
|
+
export let _stores: Map<string, Store>;
|
|
709
|
+
/**
|
|
710
|
+
* Get or create a named store (`initialState` is used only when it is created)
|
|
711
|
+
* @param {string} name
|
|
712
|
+
* @param {Record<string, any>} [initialState={}]
|
|
713
|
+
* @returns {Store}
|
|
714
|
+
*/
|
|
715
|
+
export function store(name: string, initialState?: Record<string, any>): Store;
|
|
716
|
+
/**
|
|
717
|
+
* Get an existing store
|
|
718
|
+
* @param {string} name
|
|
719
|
+
* @returns {Store|undefined}
|
|
720
|
+
*/
|
|
721
|
+
export function getStore(name: string): Store | undefined;
|
|
722
|
+
/**
|
|
723
|
+
* Remove a store
|
|
724
|
+
* @param {string} name
|
|
725
|
+
* @returns {void}
|
|
726
|
+
*/
|
|
727
|
+
export function removeStore(name: string): void;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* A type check for a field's value (`M.types.*`).
|
|
731
|
+
*/
|
|
732
|
+
export type TypeValidator = (value: any) => boolean;
|
|
733
|
+
/**
|
|
734
|
+
* One field of a blueprint. Forms (`F.create`) read further keys from the same object
|
|
735
|
+
* (`label`, `options`, `formConfig`, ...), so any other key is allowed.
|
|
736
|
+
*/
|
|
737
|
+
export type FieldDefinition = {
|
|
738
|
+
/**
|
|
739
|
+
* Checked with
|
|
740
|
+
* `M.types[type]` when the value is not empty; a type with no validator (e.g. a form's `email`) is not checked
|
|
741
|
+
*/
|
|
742
|
+
type?: "string" | "number" | "boolean" | "array" | "object" | "date" | "any" | (string & {});
|
|
743
|
+
/**
|
|
744
|
+
* Initial value when the data gives none (otherwise `null`)
|
|
745
|
+
*/
|
|
746
|
+
default?: any;
|
|
747
|
+
/**
|
|
748
|
+
* `null`, `undefined` and `''` fail
|
|
749
|
+
*/
|
|
750
|
+
required?: boolean;
|
|
751
|
+
/**
|
|
752
|
+
* Minimum, for a number value
|
|
753
|
+
*/
|
|
754
|
+
min?: number;
|
|
755
|
+
/**
|
|
756
|
+
* Maximum, for a number value
|
|
757
|
+
*/
|
|
758
|
+
max?: number;
|
|
759
|
+
/**
|
|
760
|
+
* Minimum length, for a string value
|
|
761
|
+
*/
|
|
762
|
+
minLength?: number;
|
|
763
|
+
/**
|
|
764
|
+
* Maximum length, for a string value
|
|
765
|
+
*/
|
|
766
|
+
maxLength?: number;
|
|
767
|
+
/**
|
|
768
|
+
* Pattern a string value must match
|
|
769
|
+
*/
|
|
770
|
+
pattern?: RegExp;
|
|
771
|
+
/**
|
|
772
|
+
* Custom check: `false` fails, a string fails with
|
|
773
|
+
* that message, anything else passes
|
|
774
|
+
*/
|
|
775
|
+
validate?: (value: any) => boolean | string | void;
|
|
776
|
+
};
|
|
777
|
+
/**
|
|
778
|
+
* A blueprint: field name -> definition.
|
|
779
|
+
*/
|
|
780
|
+
export type Schema = {
|
|
781
|
+
[field: string]: FieldDefinition & {
|
|
782
|
+
[key: string]: any;
|
|
783
|
+
};
|
|
784
|
+
};
|
|
785
|
+
export type ValidationResult = {
|
|
786
|
+
valid: boolean;
|
|
787
|
+
errors: Array<{
|
|
788
|
+
field: string;
|
|
789
|
+
error: string;
|
|
790
|
+
}>;
|
|
791
|
+
};
|
|
792
|
+
export type ModelOptions = {
|
|
793
|
+
/**
|
|
794
|
+
* localStorage key (stored as `model:<persist>`); loaded on creation and saved on change
|
|
795
|
+
*/
|
|
796
|
+
persist?: string;
|
|
797
|
+
/**
|
|
798
|
+
* Save on every change when `persist` is set
|
|
799
|
+
*/
|
|
800
|
+
autoSave?: boolean;
|
|
801
|
+
};
|
|
802
|
+
export type ChangeEvent = {
|
|
803
|
+
field: string;
|
|
804
|
+
newValue: any;
|
|
805
|
+
oldValue: any;
|
|
806
|
+
model: Model;
|
|
807
|
+
};
|
|
808
|
+
export type ChangeCallback = (event: ChangeEvent) => void;
|
|
809
|
+
export type FieldChangeCallback = (newValue: any, oldValue: any, model: Model) => void;
|
|
810
|
+
export type UnsubscribeFn = () => void;
|
|
811
|
+
/**
|
|
812
|
+
* Options for `M.bind()`.
|
|
813
|
+
*/
|
|
814
|
+
export type BindingOptions = {
|
|
815
|
+
/**
|
|
816
|
+
* Model value -> what the element shows
|
|
817
|
+
*/
|
|
818
|
+
format?: (value: any) => any;
|
|
819
|
+
/**
|
|
820
|
+
* Element value -> what the model stores (two-way only)
|
|
821
|
+
*/
|
|
822
|
+
parse?: (value: any) => any;
|
|
823
|
+
/**
|
|
824
|
+
* Write the element's input back to the model
|
|
825
|
+
*/
|
|
826
|
+
twoWay?: boolean;
|
|
827
|
+
};
|
|
828
|
+
/**
|
|
829
|
+
* A single reactive value (`M.observable()`), from domma-reactive.
|
|
830
|
+
*/
|
|
831
|
+
export type Observable<T = any> = import("../vendor/domma-reactive.js").Observable<T>;
|
|
832
|
+
/**
|
|
833
|
+
* A reactive array (`M.observableArray()`), from domma-reactive.
|
|
834
|
+
*/
|
|
835
|
+
export type ObservableArray<T = any> = import("../vendor/domma-reactive.js").ObservableArray<T>;
|
|
836
|
+
export type ObservableOptions<T = any> = import("../vendor/domma-reactive.js").ObservableOptions<T>;
|
|
837
|
+
/**
|
|
838
|
+
* A lazily-evaluated, dependency-tracked derived value (`M.computed()`).
|
|
839
|
+
*/
|
|
840
|
+
export type ComputedRef<T = any> = {
|
|
841
|
+
/**
|
|
842
|
+
* The same read as `get()`, spelled as a property - the only one a template expression can
|
|
843
|
+
* use. Assigning hands the value to the derivation's `write` (warns and changes nothing without one).
|
|
844
|
+
*/
|
|
845
|
+
value: T;
|
|
846
|
+
/**
|
|
847
|
+
* Current value, recomputing only if a dependency changed
|
|
848
|
+
*/
|
|
849
|
+
get: () => T;
|
|
850
|
+
/**
|
|
851
|
+
* Imperative alias for assigning `.value`
|
|
852
|
+
*/
|
|
853
|
+
set: (next: T) => void;
|
|
854
|
+
/**
|
|
855
|
+
* Current value without registering a dependency on the caller
|
|
856
|
+
*/
|
|
857
|
+
peek: () => T;
|
|
858
|
+
/**
|
|
859
|
+
* Unlink from the dependency graph
|
|
860
|
+
*/
|
|
861
|
+
dispose: () => void;
|
|
862
|
+
};
|
|
863
|
+
export type ComputedOptions<T = any> = {
|
|
864
|
+
/**
|
|
865
|
+
* Debug label used in warnings
|
|
866
|
+
*/
|
|
867
|
+
label?: string;
|
|
868
|
+
/**
|
|
869
|
+
* Called with the
|
|
870
|
+
* new value whenever it changes
|
|
871
|
+
*/
|
|
872
|
+
onChange?: (value: T, computation: import("../vendor/domma-reactive.js").Computation<T>) => void;
|
|
873
|
+
};
|
|
874
|
+
/**
|
|
875
|
+
* A writable computed: where a write should land.
|
|
876
|
+
*/
|
|
877
|
+
export type WritableComputedDefinition<T> = {
|
|
878
|
+
read: () => T;
|
|
879
|
+
write: (next: T) => void;
|
|
880
|
+
};
|
|
881
|
+
export type EffectOptions = {
|
|
882
|
+
/**
|
|
883
|
+
* Debug label used in warnings
|
|
884
|
+
*/
|
|
885
|
+
label?: string;
|
|
886
|
+
};
|
|
887
|
+
/**
|
|
888
|
+
* Options for `M.applyBindings()`.
|
|
889
|
+
*/
|
|
890
|
+
export type ApplyBindingsOptions = {
|
|
891
|
+
/**
|
|
892
|
+
* Handlers for `data-on-*`. Looked up only when the
|
|
893
|
+
* data has no such key.
|
|
894
|
+
*/
|
|
895
|
+
methods?: Record<string, (...args: any[]) => any>;
|
|
896
|
+
/**
|
|
897
|
+
* Template renderer for `data-each` item bodies.
|
|
898
|
+
* Defaults to `utils.render`.
|
|
899
|
+
*/
|
|
900
|
+
render?: import("../vendor/domma-reactive.js").RenderFn;
|
|
901
|
+
/**
|
|
902
|
+
* A name for this subtree, used in warnings
|
|
903
|
+
*/
|
|
904
|
+
template?: string;
|
|
905
|
+
};
|
|
906
|
+
/**
|
|
907
|
+
* One activated binding record, from domma-reactive. `deps` are the names its expression reads.
|
|
908
|
+
*/
|
|
909
|
+
export type ActiveBinding = import("../vendor/domma-reactive.js").Binding;
|
|
910
|
+
/**
|
|
911
|
+
* What `M.applyBindings()` returns; call `dispose()` when the markup is done with.
|
|
912
|
+
*/
|
|
913
|
+
export type BindingHandle = import("../vendor/domma-reactive.js").BindingsHandle;
|
|
914
|
+
/**
|
|
915
|
+
* A binding kind for `M.registerBinding()`. Only `update` is required.
|
|
916
|
+
*/
|
|
917
|
+
export type BindingHandler = import("../vendor/domma-reactive.js").BindingHandler;
|
|
918
|
+
/**
|
|
919
|
+
* A named store (`M.store()`).
|
|
920
|
+
*/
|
|
921
|
+
export type Store = {
|
|
922
|
+
/**
|
|
923
|
+
* The current state (replaced, never mutated, by setState)
|
|
924
|
+
*/
|
|
925
|
+
state: Record<string, any>;
|
|
926
|
+
listeners: Set<(state: Record<string, any>, oldState: Record<string, any>) => void>;
|
|
927
|
+
/**
|
|
928
|
+
* Get a copy of the current state
|
|
929
|
+
*/
|
|
930
|
+
getState: () => Record<string, any>;
|
|
931
|
+
/**
|
|
932
|
+
* Merge partial updates and notify
|
|
933
|
+
*/
|
|
934
|
+
setState: (updates: Record<string, any>) => void;
|
|
935
|
+
/**
|
|
936
|
+
* Subscribe to state changes; returns the unsubscribe function
|
|
937
|
+
*/
|
|
938
|
+
subscribe: (listener: (state: Record<string, any>, oldState: Record<string, any>) => void) => () => boolean;
|
|
939
|
+
/**
|
|
940
|
+
* Reset to the initial state, or to `newState`
|
|
941
|
+
* (listeners receive `{}` as the old state)
|
|
942
|
+
*/
|
|
943
|
+
reset: (newState?: Record<string, any>) => void;
|
|
944
|
+
};
|
|
945
|
+
export type TypeValidators = {
|
|
946
|
+
string: TypeValidator;
|
|
947
|
+
/**
|
|
948
|
+
* Not NaN
|
|
949
|
+
*/
|
|
950
|
+
number: TypeValidator;
|
|
951
|
+
boolean: TypeValidator;
|
|
952
|
+
array: TypeValidator;
|
|
953
|
+
/**
|
|
954
|
+
* A non-null, non-array object
|
|
955
|
+
*/
|
|
956
|
+
object: TypeValidator;
|
|
957
|
+
/**
|
|
958
|
+
* A valid `Date`, or ISO-8601 date / date-time text
|
|
959
|
+
*/
|
|
960
|
+
date: TypeValidator;
|
|
961
|
+
any: TypeValidator;
|
|
962
|
+
};
|
|
963
|
+
/**
|
|
964
|
+
* The models module (`M`): pub/sub, reactive models, dependency-tracked reactivity, DOM bindings and stores.
|
|
965
|
+
*/
|
|
966
|
+
export type Models = typeof models;
|
|
967
|
+
import { observable } from '../vendor/domma-reactive.js';
|
|
968
|
+
import { observableArray } from '../vendor/domma-reactive.js';
|