foldkit 0.146.0 → 0.148.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 +5 -2
- package/dist/buildToken.d.ts +3 -0
- package/dist/buildToken.d.ts.map +1 -0
- package/dist/buildToken.js +21 -0
- package/dist/controlledDomState.d.ts +25 -0
- package/dist/controlledDomState.d.ts.map +1 -0
- package/dist/controlledDomState.js +240 -0
- package/dist/cssStyleProperties.d.ts +6 -0
- package/dist/cssStyleProperties.d.ts.map +1 -0
- package/dist/cssStyleProperties.js +91 -0
- package/dist/customElement/index.d.ts.map +1 -1
- package/dist/customElement/index.js +23 -0
- package/dist/domReflection.d.ts +73 -0
- package/dist/domReflection.d.ts.map +1 -0
- package/dist/domReflection.js +557 -0
- package/dist/experimental/index.d.ts +1 -0
- package/dist/experimental/index.d.ts.map +1 -1
- package/dist/experimental/index.js +1 -0
- package/dist/experimental/machine/machine.d.ts +22 -3
- package/dist/experimental/machine/machine.d.ts.map +1 -1
- package/dist/experimental/machine/machine.js +8 -0
- package/dist/experimental/server/entry.d.ts +73 -0
- package/dist/experimental/server/entry.d.ts.map +1 -0
- package/dist/experimental/server/entry.js +41 -0
- package/dist/experimental/server/host.d.ts +136 -0
- package/dist/experimental/server/host.d.ts.map +1 -0
- package/dist/experimental/server/host.js +359 -0
- package/dist/experimental/server/index.d.ts +5 -0
- package/dist/experimental/server/index.d.ts.map +1 -0
- package/dist/experimental/server/index.js +4 -0
- package/dist/experimental/server/public.d.ts +3 -0
- package/dist/experimental/server/public.d.ts.map +1 -0
- package/dist/experimental/server/public.js +1 -0
- package/dist/experimental/server/serialize.d.ts +43 -0
- package/dist/experimental/server/serialize.d.ts.map +1 -0
- package/dist/experimental/server/serialize.js +786 -0
- package/dist/experimental/server/server.d.ts +242 -0
- package/dist/experimental/server/server.d.ts.map +1 -0
- package/dist/experimental/server/server.js +946 -0
- package/dist/experimental/server/template.d.ts +53 -0
- package/dist/experimental/server/template.d.ts.map +1 -0
- package/dist/experimental/server/template.js +617 -0
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +474 -33
- package/dist/hydrate.d.ts +4 -0
- package/dist/hydrate.d.ts.map +1 -0
- package/dist/hydrate.js +850 -0
- package/dist/hydrationMarker.d.ts +10 -0
- package/dist/hydrationMarker.d.ts.map +1 -0
- package/dist/hydrationMarker.js +9 -0
- package/dist/hydrationMarkers.d.ts +15 -0
- package/dist/hydrationMarkers.d.ts.map +1 -0
- package/dist/hydrationMarkers.js +70 -0
- package/dist/nativeInnerHtml.d.ts +13 -0
- package/dist/nativeInnerHtml.d.ts.map +1 -0
- package/dist/nativeInnerHtml.js +30 -0
- package/dist/propertyProvenance.d.ts +33 -0
- package/dist/propertyProvenance.d.ts.map +1 -0
- package/dist/propertyProvenance.js +78 -0
- package/dist/propsModule.d.ts.map +1 -1
- package/dist/propsModule.js +149 -15
- package/dist/runtime/public.d.ts +2 -2
- package/dist/runtime/public.d.ts.map +1 -1
- package/dist/runtime/public.js +1 -1
- package/dist/runtime/runtime.d.ts +99 -36
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +412 -71
- package/dist/snabbdom/attributes.d.ts.map +1 -1
- package/dist/snabbdom/attributes.js +65 -37
- package/dist/snabbdom/h.d.ts +1 -0
- package/dist/snabbdom/h.d.ts.map +1 -1
- package/dist/snabbdom/h.js +85 -4
- package/dist/snabbdom/style.d.ts.map +1 -1
- package/dist/snabbdom/style.js +53 -34
- package/dist/snabbdom/tovnode.d.ts.map +1 -1
- package/dist/snabbdom/tovnode.js +5 -1
- package/dist/tagName.d.ts +6 -0
- package/dist/tagName.d.ts.map +1 -0
- package/dist/tagName.js +11 -0
- package/dist/test/apps/attributes.d.ts +1 -0
- package/dist/test/apps/attributes.d.ts.map +1 -1
- package/dist/test/apps/attributes.js +8 -1
- package/dist/test/apps/login.js +1 -1
- package/dist/test/matchers.d.ts.map +1 -1
- package/dist/test/matchers.js +2 -1
- package/dist/test/scene.d.ts.map +1 -1
- package/dist/test/scene.js +2 -1
- package/dist/vdom.d.ts.map +1 -1
- package/dist/vdom.js +25 -1
- package/package.json +9 -2
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
import { CSS_STYLE_PROPERTIES } from './cssStyleProperties.js';
|
|
2
|
+
// The one description of how a typed attribute builder's DOM property relates
|
|
3
|
+
// to the HTML attribute it is named after.
|
|
4
|
+
//
|
|
5
|
+
// Two mechanisms read this. A server render turns the property into attribute
|
|
6
|
+
// text a parser will read back, and a client render assigns the property to a
|
|
7
|
+
// live element. They agree only where the property is a reflecting IDL
|
|
8
|
+
// attribute of that element, so the same tables decide what the serializer
|
|
9
|
+
// emits and what the builders refuse to build. Keeping one copy is what stops
|
|
10
|
+
// the two from drifting: a property added to the serializer alone would be
|
|
11
|
+
// served as markup no client render reproduces.
|
|
12
|
+
/** DOM properties whose attribute is present or absent rather than valued.
|
|
13
|
+
*
|
|
14
|
+
* @internal */
|
|
15
|
+
export const BOOLEAN_PROPERTIES = new Set([
|
|
16
|
+
'autofocus',
|
|
17
|
+
'autoplay',
|
|
18
|
+
'checked',
|
|
19
|
+
'controls',
|
|
20
|
+
'disabled',
|
|
21
|
+
'formNoValidate',
|
|
22
|
+
'hidden',
|
|
23
|
+
'inert',
|
|
24
|
+
'isMap',
|
|
25
|
+
'loop',
|
|
26
|
+
'multiple',
|
|
27
|
+
'muted',
|
|
28
|
+
'noValidate',
|
|
29
|
+
'open',
|
|
30
|
+
'playsInline',
|
|
31
|
+
'readOnly',
|
|
32
|
+
'required',
|
|
33
|
+
'reversed',
|
|
34
|
+
'selected',
|
|
35
|
+
]);
|
|
36
|
+
/** DOM properties whose name differs from the attribute they reflect.
|
|
37
|
+
*
|
|
38
|
+
* @internal */
|
|
39
|
+
export const RENAMED_PROPERTY_ATTRIBUTES = {
|
|
40
|
+
colSpan: 'colspan',
|
|
41
|
+
dateTime: 'datetime',
|
|
42
|
+
formAction: 'formaction',
|
|
43
|
+
formEnctype: 'formenctype',
|
|
44
|
+
formMethod: 'formmethod',
|
|
45
|
+
formNoValidate: 'formnovalidate',
|
|
46
|
+
formTarget: 'formtarget',
|
|
47
|
+
htmlFor: 'for',
|
|
48
|
+
isMap: 'ismap',
|
|
49
|
+
maxLength: 'maxlength',
|
|
50
|
+
minLength: 'minlength',
|
|
51
|
+
noValidate: 'novalidate',
|
|
52
|
+
playsInline: 'playsinline',
|
|
53
|
+
readOnly: 'readonly',
|
|
54
|
+
rowSpan: 'rowspan',
|
|
55
|
+
tabIndex: 'tabindex',
|
|
56
|
+
};
|
|
57
|
+
/** DOM properties whose value is written as the same-named attribute verbatim.
|
|
58
|
+
*
|
|
59
|
+
* @internal */
|
|
60
|
+
export const PASSTHROUGH_PROPERTIES = new Set([
|
|
61
|
+
'accept',
|
|
62
|
+
'action',
|
|
63
|
+
'alt',
|
|
64
|
+
'autocomplete',
|
|
65
|
+
'cite',
|
|
66
|
+
'cols',
|
|
67
|
+
'dir',
|
|
68
|
+
'download',
|
|
69
|
+
'enctype',
|
|
70
|
+
'high',
|
|
71
|
+
'href',
|
|
72
|
+
'id',
|
|
73
|
+
'label',
|
|
74
|
+
'lang',
|
|
75
|
+
'low',
|
|
76
|
+
'max',
|
|
77
|
+
'method',
|
|
78
|
+
'min',
|
|
79
|
+
'name',
|
|
80
|
+
'optimum',
|
|
81
|
+
'pattern',
|
|
82
|
+
'placeholder',
|
|
83
|
+
'poster',
|
|
84
|
+
'preload',
|
|
85
|
+
'rel',
|
|
86
|
+
'rows',
|
|
87
|
+
'size',
|
|
88
|
+
'span',
|
|
89
|
+
'src',
|
|
90
|
+
'start',
|
|
91
|
+
'step',
|
|
92
|
+
'target',
|
|
93
|
+
'title',
|
|
94
|
+
'type',
|
|
95
|
+
'value',
|
|
96
|
+
'wrap',
|
|
97
|
+
]);
|
|
98
|
+
/** The property names that are universal HTML global attributes.
|
|
99
|
+
*
|
|
100
|
+
* @internal */
|
|
101
|
+
export const GLOBAL_ATTRIBUTE_PROPERTIES = new Set([
|
|
102
|
+
'autofocus',
|
|
103
|
+
'id',
|
|
104
|
+
'title',
|
|
105
|
+
'lang',
|
|
106
|
+
'dir',
|
|
107
|
+
'tabIndex',
|
|
108
|
+
'hidden',
|
|
109
|
+
'inert',
|
|
110
|
+
'draggable',
|
|
111
|
+
]);
|
|
112
|
+
// The properties an SVG or MathML element carries as reflecting IDL attributes,
|
|
113
|
+
// so that assigning one on the client leaves the element in the state parsing
|
|
114
|
+
// the served attribute produces.
|
|
115
|
+
//
|
|
116
|
+
// Everything else is an HTML interface member the foreign element does not
|
|
117
|
+
// have. Assigning `title` or `href` to an SVG element sets an expando or, since
|
|
118
|
+
// bundled code is strict, throws on a readonly `SVGAnimatedString`, while the
|
|
119
|
+
// serializer would have written an attribute; the two never agree. Measured in
|
|
120
|
+
// Chromium across the whole table above on `svg:a`, `svg:rect`, and
|
|
121
|
+
// `math:mtext`: these three reflect on all of them and nothing else reflects on
|
|
122
|
+
// any of them.
|
|
123
|
+
/** @internal */
|
|
124
|
+
export const FOREIGN_REPRESENTABLE_PROPERTIES = new Set([
|
|
125
|
+
'autofocus',
|
|
126
|
+
'id',
|
|
127
|
+
'tabIndex',
|
|
128
|
+
]);
|
|
129
|
+
/** The HTML attribute a typed builder's DOM property reflects, or `undefined`
|
|
130
|
+
* when the property is not one the tables above describe.
|
|
131
|
+
*
|
|
132
|
+
* @internal */
|
|
133
|
+
export const reflectedAttributeName = (propertyName) => {
|
|
134
|
+
const renamed = RENAMED_PROPERTY_ATTRIBUTES[propertyName];
|
|
135
|
+
if (renamed !== undefined) {
|
|
136
|
+
return renamed;
|
|
137
|
+
}
|
|
138
|
+
if (BOOLEAN_PROPERTIES.has(propertyName) ||
|
|
139
|
+
PASSTHROUGH_PROPERTIES.has(propertyName) ||
|
|
140
|
+
propertyName === 'draggable') {
|
|
141
|
+
return propertyName;
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
};
|
|
145
|
+
// HTML attribute names are ASCII case-insensitive: a parser lowercases them,
|
|
146
|
+
// and `setAttribute` on an HTML element does the same. `h.Attribute('MULTIPLE',
|
|
147
|
+
// '')` and `h.Attribute('multiple', '')` therefore name one attribute, and any
|
|
148
|
+
// analysis that compares names verbatim reads the first as an unrelated one.
|
|
149
|
+
// Foreign content is left alone, where `viewBox` and `preserveAspectRatio` are
|
|
150
|
+
// case-sensitive names of their own.
|
|
151
|
+
const ASCII_UPPER = /[A-Z]/g;
|
|
152
|
+
/** @internal */
|
|
153
|
+
export const toHtmlAttributeName = (name) => name.replace(ASCII_UPPER, letter => letter.toLowerCase());
|
|
154
|
+
const SVG_ATTRIBUTE_ADJUSTMENTS = {
|
|
155
|
+
attributename: 'attributeName',
|
|
156
|
+
attributetype: 'attributeType',
|
|
157
|
+
basefrequency: 'baseFrequency',
|
|
158
|
+
baseprofile: 'baseProfile',
|
|
159
|
+
calcmode: 'calcMode',
|
|
160
|
+
clippathunits: 'clipPathUnits',
|
|
161
|
+
diffuseconstant: 'diffuseConstant',
|
|
162
|
+
edgemode: 'edgeMode',
|
|
163
|
+
filterunits: 'filterUnits',
|
|
164
|
+
glyphref: 'glyphRef',
|
|
165
|
+
gradienttransform: 'gradientTransform',
|
|
166
|
+
gradientunits: 'gradientUnits',
|
|
167
|
+
kernelmatrix: 'kernelMatrix',
|
|
168
|
+
kernelunitlength: 'kernelUnitLength',
|
|
169
|
+
keypoints: 'keyPoints',
|
|
170
|
+
keysplines: 'keySplines',
|
|
171
|
+
keytimes: 'keyTimes',
|
|
172
|
+
lengthadjust: 'lengthAdjust',
|
|
173
|
+
limitingconeangle: 'limitingConeAngle',
|
|
174
|
+
markerheight: 'markerHeight',
|
|
175
|
+
markerunits: 'markerUnits',
|
|
176
|
+
markerwidth: 'markerWidth',
|
|
177
|
+
maskcontentunits: 'maskContentUnits',
|
|
178
|
+
maskunits: 'maskUnits',
|
|
179
|
+
numoctaves: 'numOctaves',
|
|
180
|
+
pathlength: 'pathLength',
|
|
181
|
+
patterncontentunits: 'patternContentUnits',
|
|
182
|
+
patterntransform: 'patternTransform',
|
|
183
|
+
patternunits: 'patternUnits',
|
|
184
|
+
pointsatx: 'pointsAtX',
|
|
185
|
+
pointsaty: 'pointsAtY',
|
|
186
|
+
pointsatz: 'pointsAtZ',
|
|
187
|
+
preservealpha: 'preserveAlpha',
|
|
188
|
+
preserveaspectratio: 'preserveAspectRatio',
|
|
189
|
+
primitiveunits: 'primitiveUnits',
|
|
190
|
+
refx: 'refX',
|
|
191
|
+
refy: 'refY',
|
|
192
|
+
repeatcount: 'repeatCount',
|
|
193
|
+
repeatdur: 'repeatDur',
|
|
194
|
+
requiredextensions: 'requiredExtensions',
|
|
195
|
+
requiredfeatures: 'requiredFeatures',
|
|
196
|
+
specularconstant: 'specularConstant',
|
|
197
|
+
specularexponent: 'specularExponent',
|
|
198
|
+
spreadmethod: 'spreadMethod',
|
|
199
|
+
startoffset: 'startOffset',
|
|
200
|
+
stddeviation: 'stdDeviation',
|
|
201
|
+
stitchtiles: 'stitchTiles',
|
|
202
|
+
surfacescale: 'surfaceScale',
|
|
203
|
+
systemlanguage: 'systemLanguage',
|
|
204
|
+
tablevalues: 'tableValues',
|
|
205
|
+
targetx: 'targetX',
|
|
206
|
+
targety: 'targetY',
|
|
207
|
+
textlength: 'textLength',
|
|
208
|
+
viewbox: 'viewBox',
|
|
209
|
+
viewtarget: 'viewTarget',
|
|
210
|
+
xchannelselector: 'xChannelSelector',
|
|
211
|
+
ychannelselector: 'yChannelSelector',
|
|
212
|
+
zoomandpan: 'zoomAndPan',
|
|
213
|
+
};
|
|
214
|
+
export const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
|
215
|
+
export const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
216
|
+
export const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
|
217
|
+
/** The attribute name produced by parsing HTML source in the given namespace.
|
|
218
|
+
*
|
|
219
|
+
* @internal
|
|
220
|
+
*/
|
|
221
|
+
export const parsedAttributeName = (namespace, name) => {
|
|
222
|
+
const lowerName = toHtmlAttributeName(name);
|
|
223
|
+
if (namespace === SVG_NAMESPACE) {
|
|
224
|
+
return SVG_ATTRIBUTE_ADJUSTMENTS[lowerName] ?? lowerName;
|
|
225
|
+
}
|
|
226
|
+
if (namespace === MATHML_NAMESPACE && lowerName === 'definitionurl') {
|
|
227
|
+
return 'definitionURL';
|
|
228
|
+
}
|
|
229
|
+
return lowerName;
|
|
230
|
+
};
|
|
231
|
+
const HTML_PROPERTY_ELEMENTS = {
|
|
232
|
+
accept: new Set(['input']),
|
|
233
|
+
action: new Set(['form']),
|
|
234
|
+
alt: new Set(['area', 'img', 'input']),
|
|
235
|
+
autocomplete: new Set(['form', 'input', 'select', 'textarea']),
|
|
236
|
+
autoplay: new Set(['audio', 'video']),
|
|
237
|
+
checked: new Set(['input']),
|
|
238
|
+
cite: new Set(['blockquote', 'del', 'ins', 'q']),
|
|
239
|
+
cols: new Set(['textarea']),
|
|
240
|
+
colSpan: new Set(['td', 'th']),
|
|
241
|
+
controls: new Set(['audio', 'video']),
|
|
242
|
+
dateTime: new Set(['del', 'ins', 'time']),
|
|
243
|
+
disabled: new Set([
|
|
244
|
+
'button',
|
|
245
|
+
'fieldset',
|
|
246
|
+
'input',
|
|
247
|
+
'link',
|
|
248
|
+
'optgroup',
|
|
249
|
+
'option',
|
|
250
|
+
'select',
|
|
251
|
+
'textarea',
|
|
252
|
+
]),
|
|
253
|
+
download: new Set(['a', 'area']),
|
|
254
|
+
enctype: new Set(['form']),
|
|
255
|
+
formAction: new Set(['button', 'input']),
|
|
256
|
+
formEnctype: new Set(['button', 'input']),
|
|
257
|
+
formMethod: new Set(['button', 'input']),
|
|
258
|
+
formNoValidate: new Set(['button', 'input']),
|
|
259
|
+
formTarget: new Set(['button', 'input']),
|
|
260
|
+
high: new Set(['meter']),
|
|
261
|
+
href: new Set(['a', 'area', 'base', 'link']),
|
|
262
|
+
htmlFor: new Set(['label', 'output', 'script']),
|
|
263
|
+
isMap: new Set(['img']),
|
|
264
|
+
label: new Set(['optgroup', 'option', 'track']),
|
|
265
|
+
loop: new Set(['audio', 'video']),
|
|
266
|
+
low: new Set(['meter']),
|
|
267
|
+
max: new Set(['input', 'meter', 'progress']),
|
|
268
|
+
maxLength: new Set(['input', 'textarea']),
|
|
269
|
+
method: new Set(['form']),
|
|
270
|
+
min: new Set(['input', 'meter']),
|
|
271
|
+
minLength: new Set(['input', 'textarea']),
|
|
272
|
+
multiple: new Set(['input', 'select']),
|
|
273
|
+
muted: new Set(['audio', 'video']),
|
|
274
|
+
name: new Set([
|
|
275
|
+
'a',
|
|
276
|
+
'button',
|
|
277
|
+
'details',
|
|
278
|
+
'embed',
|
|
279
|
+
'fieldset',
|
|
280
|
+
'form',
|
|
281
|
+
'iframe',
|
|
282
|
+
'img',
|
|
283
|
+
'input',
|
|
284
|
+
'map',
|
|
285
|
+
'meta',
|
|
286
|
+
'object',
|
|
287
|
+
'output',
|
|
288
|
+
'param',
|
|
289
|
+
'select',
|
|
290
|
+
'slot',
|
|
291
|
+
'textarea',
|
|
292
|
+
]),
|
|
293
|
+
noValidate: new Set(['form']),
|
|
294
|
+
open: new Set(['details', 'dialog']),
|
|
295
|
+
optimum: new Set(['meter']),
|
|
296
|
+
pattern: new Set(['input']),
|
|
297
|
+
placeholder: new Set(['input', 'textarea']),
|
|
298
|
+
playsInline: new Set(['video']),
|
|
299
|
+
poster: new Set(['video']),
|
|
300
|
+
preload: new Set(['audio', 'video']),
|
|
301
|
+
readOnly: new Set(['input', 'textarea']),
|
|
302
|
+
rel: new Set(['a', 'area', 'form', 'link']),
|
|
303
|
+
required: new Set(['input', 'select', 'textarea']),
|
|
304
|
+
reversed: new Set(['ol']),
|
|
305
|
+
rows: new Set(['textarea']),
|
|
306
|
+
rowSpan: new Set(['td', 'th']),
|
|
307
|
+
selected: new Set(['option']),
|
|
308
|
+
size: new Set(['hr', 'input', 'select']),
|
|
309
|
+
span: new Set(['col', 'colgroup']),
|
|
310
|
+
src: new Set([
|
|
311
|
+
'audio',
|
|
312
|
+
'embed',
|
|
313
|
+
'iframe',
|
|
314
|
+
'img',
|
|
315
|
+
'input',
|
|
316
|
+
'script',
|
|
317
|
+
'source',
|
|
318
|
+
'track',
|
|
319
|
+
'video',
|
|
320
|
+
]),
|
|
321
|
+
start: new Set(['ol']),
|
|
322
|
+
step: new Set(['input']),
|
|
323
|
+
target: new Set(['a', 'area', 'base', 'form', 'link']),
|
|
324
|
+
type: new Set([
|
|
325
|
+
'a',
|
|
326
|
+
'button',
|
|
327
|
+
'embed',
|
|
328
|
+
'input',
|
|
329
|
+
'li',
|
|
330
|
+
'link',
|
|
331
|
+
'object',
|
|
332
|
+
'ol',
|
|
333
|
+
'param',
|
|
334
|
+
'script',
|
|
335
|
+
'source',
|
|
336
|
+
'style',
|
|
337
|
+
'ul',
|
|
338
|
+
]),
|
|
339
|
+
value: new Set([
|
|
340
|
+
'button',
|
|
341
|
+
'data',
|
|
342
|
+
'input',
|
|
343
|
+
'li',
|
|
344
|
+
'meter',
|
|
345
|
+
'option',
|
|
346
|
+
'output',
|
|
347
|
+
'param',
|
|
348
|
+
'progress',
|
|
349
|
+
'select',
|
|
350
|
+
'textarea',
|
|
351
|
+
]),
|
|
352
|
+
wrap: new Set(['textarea']),
|
|
353
|
+
};
|
|
354
|
+
/** Whether assigning a typed property can be represented by parsed HTML for
|
|
355
|
+
* the target element.
|
|
356
|
+
*
|
|
357
|
+
* @internal
|
|
358
|
+
*/
|
|
359
|
+
export const isHtmlPropertyRepresentable = (tagName, propertyName) => GLOBAL_ATTRIBUTE_PROPERTIES.has(propertyName) ||
|
|
360
|
+
(Object.hasOwn(HTML_PROPERTY_ELEMENTS, propertyName) &&
|
|
361
|
+
HTML_PROPERTY_ELEMENTS[propertyName]?.has(tagName.toLowerCase()) === true);
|
|
362
|
+
const CANONICAL_NUMBER_PROPERTIES = {
|
|
363
|
+
li: new Set(['value']),
|
|
364
|
+
meter: new Set(['high', 'low', 'max', 'min', 'optimum', 'value']),
|
|
365
|
+
progress: new Set(['max', 'value']),
|
|
366
|
+
};
|
|
367
|
+
/** The attribute spelling produced by assigning a typed property on a fresh
|
|
368
|
+
* element.
|
|
369
|
+
*
|
|
370
|
+
* @internal
|
|
371
|
+
*/
|
|
372
|
+
export const serializedHtmlPropertyValue = (tagName, propertyName, value) => {
|
|
373
|
+
const lowerTagName = tagName.toLowerCase();
|
|
374
|
+
if (lowerTagName === 'textarea' && propertyName === 'cols' && value === 0) {
|
|
375
|
+
return '20';
|
|
376
|
+
}
|
|
377
|
+
if (lowerTagName === 'textarea' && propertyName === 'rows' && value === 0) {
|
|
378
|
+
return '2';
|
|
379
|
+
}
|
|
380
|
+
if (CANONICAL_NUMBER_PROPERTIES[lowerTagName]?.has(propertyName) === true) {
|
|
381
|
+
return String(Number(value));
|
|
382
|
+
}
|
|
383
|
+
return String(value);
|
|
384
|
+
};
|
|
385
|
+
const STYLE_LIFECYCLE_KEYS = new Set([
|
|
386
|
+
'delayed',
|
|
387
|
+
'destroy',
|
|
388
|
+
'remove',
|
|
389
|
+
]);
|
|
390
|
+
const CUSTOM_STYLE_PROPERTY_NAME = /^--(?:[A-Za-z0-9_-]|[^\u0000-\u007f])+$/;
|
|
391
|
+
const STYLE_PROPERTY_NAME = /^-?[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
392
|
+
const canonicalStylePropertyName = (name) => name.startsWith('Webkit') ? `webkit${name.slice('Webkit'.length)}` : name;
|
|
393
|
+
const cssDeclarationName = (name) => {
|
|
394
|
+
if (name.startsWith('--')) {
|
|
395
|
+
return name;
|
|
396
|
+
}
|
|
397
|
+
if (name === 'cssFloat') {
|
|
398
|
+
return 'float';
|
|
399
|
+
}
|
|
400
|
+
const canonicalName = canonicalStylePropertyName(name);
|
|
401
|
+
const kebabName = canonicalName
|
|
402
|
+
.replace(ASCII_UPPER, letter => `-${letter}`)
|
|
403
|
+
.toLowerCase();
|
|
404
|
+
if (kebabName.startsWith('webkit-') || kebabName.startsWith('ms-')) {
|
|
405
|
+
return `-${kebabName}`;
|
|
406
|
+
}
|
|
407
|
+
return kebabName;
|
|
408
|
+
};
|
|
409
|
+
const CSS_DECLARATION_PROPERTIES = new Set(Array.from(CSS_STYLE_PROPERTIES, cssDeclarationName));
|
|
410
|
+
const hasUnsafeStyleSyntax = (value) => {
|
|
411
|
+
let quote;
|
|
412
|
+
let parentheses = 0;
|
|
413
|
+
let isComment = false;
|
|
414
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
415
|
+
const character = value.charAt(index);
|
|
416
|
+
const next = value.charAt(index + 1);
|
|
417
|
+
if (isComment) {
|
|
418
|
+
if (character === '*' && next === '/') {
|
|
419
|
+
isComment = false;
|
|
420
|
+
index += 1;
|
|
421
|
+
}
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
if (character === '\\') {
|
|
425
|
+
if (next === '') {
|
|
426
|
+
return true;
|
|
427
|
+
}
|
|
428
|
+
index += 1;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (quote !== undefined) {
|
|
432
|
+
if (character === quote) {
|
|
433
|
+
quote = undefined;
|
|
434
|
+
}
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
if (character === '/' && next === '*') {
|
|
438
|
+
isComment = true;
|
|
439
|
+
index += 1;
|
|
440
|
+
}
|
|
441
|
+
else if (character === '"' || character === "'") {
|
|
442
|
+
quote = character;
|
|
443
|
+
}
|
|
444
|
+
else if (character === '(') {
|
|
445
|
+
parentheses += 1;
|
|
446
|
+
}
|
|
447
|
+
else if (character === ')') {
|
|
448
|
+
if (parentheses === 0) {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
parentheses -= 1;
|
|
452
|
+
}
|
|
453
|
+
else if (parentheses === 0 && (character === ';' || character === '!')) {
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return quote !== undefined || parentheses !== 0 || isComment;
|
|
458
|
+
};
|
|
459
|
+
/** Refuses style entries whose property assignment and serialized declaration
|
|
460
|
+
* can describe different CSS.
|
|
461
|
+
*
|
|
462
|
+
* @internal
|
|
463
|
+
*/
|
|
464
|
+
export const assertStyleIsRepresentable = (style) => {
|
|
465
|
+
const declarationOwners = new Map();
|
|
466
|
+
for (const name of Object.keys(style)) {
|
|
467
|
+
if (STYLE_LIFECYCLE_KEYS.has(name)) {
|
|
468
|
+
throw new Error(`[foldkit] h.Style property ${JSON.stringify(name)} is a Snabbdom ` +
|
|
469
|
+
'lifecycle control rather than a CSS property. Foldkit h.Style ' +
|
|
470
|
+
'accepts only declarations applied while the element exists.');
|
|
471
|
+
}
|
|
472
|
+
if (name === 'cssText' ||
|
|
473
|
+
(name.startsWith('--')
|
|
474
|
+
? !CUSTOM_STYLE_PROPERTY_NAME.test(name)
|
|
475
|
+
: !STYLE_PROPERTY_NAME.test(name))) {
|
|
476
|
+
throw new Error(`[foldkit] h.Style property ${JSON.stringify(name)} cannot be ` +
|
|
477
|
+
'represented as one inline CSS declaration. Use a CSS property ' +
|
|
478
|
+
'name without declaration delimiters.');
|
|
479
|
+
}
|
|
480
|
+
const canonicalName = canonicalStylePropertyName(name);
|
|
481
|
+
if (!name.startsWith('--') &&
|
|
482
|
+
!CSS_STYLE_PROPERTIES.has(canonicalName) &&
|
|
483
|
+
!CSS_DECLARATION_PROPERTIES.has(name)) {
|
|
484
|
+
throw new Error(`[foldkit] h.Style property ${JSON.stringify(name)} is not a ` +
|
|
485
|
+
'CSSStyleDeclaration property supported by Foldkit. Use a known ' +
|
|
486
|
+
'camel-case or declaration name, or a custom property beginning --.');
|
|
487
|
+
}
|
|
488
|
+
const declarationName = cssDeclarationName(name);
|
|
489
|
+
const existingOwner = declarationOwners.get(declarationName);
|
|
490
|
+
if (existingOwner !== undefined) {
|
|
491
|
+
throw new Error(`[foldkit] h.Style properties ${JSON.stringify(existingOwner)} and ` +
|
|
492
|
+
`${JSON.stringify(name)} both name the ${JSON.stringify(declarationName)} ` +
|
|
493
|
+
'CSS declaration. Keep one spelling so the server, fresh client, ' +
|
|
494
|
+
'and hydration have one owner for it.');
|
|
495
|
+
}
|
|
496
|
+
declarationOwners.set(declarationName, name);
|
|
497
|
+
const value = style[name];
|
|
498
|
+
if (typeof value !== 'string') {
|
|
499
|
+
throw new Error(`[foldkit] h.Style value for ${JSON.stringify(name)} must be a ` +
|
|
500
|
+
'string. Browser CSSOM assignment coerces other values while server ' +
|
|
501
|
+
'serialization cannot preserve the same authored declaration.');
|
|
502
|
+
}
|
|
503
|
+
if (hasUnsafeStyleSyntax(value)) {
|
|
504
|
+
throw new Error(`[foldkit] h.Style value for ${JSON.stringify(name)} contains a ` +
|
|
505
|
+
'unsafe CSS declaration syntax. Assigning one DOM style ' +
|
|
506
|
+
'property rejects that value, while serializing it into a style ' +
|
|
507
|
+
'attribute could activate additional or !important declarations. ' +
|
|
508
|
+
'Keep the value to one declaration.');
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
/** The CSS declaration name corresponding to a CSSStyleDeclaration property.
|
|
513
|
+
*
|
|
514
|
+
* @internal
|
|
515
|
+
*/
|
|
516
|
+
export const serializedStylePropertyName = (name) => {
|
|
517
|
+
return cssDeclarationName(name);
|
|
518
|
+
};
|
|
519
|
+
/** A style object keyed by the declaration names shared by CSSOM and HTML.
|
|
520
|
+
*
|
|
521
|
+
* @internal
|
|
522
|
+
*/
|
|
523
|
+
export const normalizedStyleProperties = (style) => {
|
|
524
|
+
assertStyleIsRepresentable(style);
|
|
525
|
+
return Object.fromEntries(Object.entries(style).map(([name, value]) => [
|
|
526
|
+
cssDeclarationName(name),
|
|
527
|
+
String(value),
|
|
528
|
+
]));
|
|
529
|
+
};
|
|
530
|
+
/** Inline style source whose parsed declarations match fresh CSSOM property
|
|
531
|
+
* assignment, excluding Snabbdom lifecycle controls.
|
|
532
|
+
*
|
|
533
|
+
* @internal
|
|
534
|
+
*/
|
|
535
|
+
export const serializedStyleAttribute = (style) => {
|
|
536
|
+
const declarations = Object.entries(style).flatMap(([name, value]) => STYLE_LIFECYCLE_KEYS.has(name) || typeof value !== 'string' || value === ''
|
|
537
|
+
? []
|
|
538
|
+
: [`${cssDeclarationName(name)}: ${value}`]);
|
|
539
|
+
const serialized = declarations.join('; ');
|
|
540
|
+
return serialized === '' ? undefined : serialized;
|
|
541
|
+
};
|
|
542
|
+
/** The value of an HTML attribute written under any ASCII casing, or
|
|
543
|
+
* `undefined` when no spelling of it is present.
|
|
544
|
+
*
|
|
545
|
+
* @internal */
|
|
546
|
+
export const htmlAttributeValue = (attributes, name) => {
|
|
547
|
+
if (attributes === undefined) {
|
|
548
|
+
return undefined;
|
|
549
|
+
}
|
|
550
|
+
let value;
|
|
551
|
+
for (const written of Object.keys(attributes)) {
|
|
552
|
+
if (toHtmlAttributeName(written) === name) {
|
|
553
|
+
value = attributes[written];
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return value;
|
|
557
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/experimental/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/experimental/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAC7C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAA"}
|
|
@@ -63,6 +63,8 @@ type GuardValueOf<GuardResult> = [GuardResult] extends [boolean] ? void : Option
|
|
|
63
63
|
* from the table, and Messages absent from a state's `on` record, are
|
|
64
64
|
* ignored: {@link Machine.step} reports them as `Ignored` rather than
|
|
65
65
|
* transitioning.
|
|
66
|
+
*
|
|
67
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
66
68
|
*/
|
|
67
69
|
export type TransitionTable<State extends Tagged, Message extends Tagged, R = never> = Readonly<{
|
|
68
70
|
[SourceTag in TagOf<State>]?: Readonly<{
|
|
@@ -83,6 +85,8 @@ export type TransitionTable<State extends Tagged, Message extends Tagged, R = ne
|
|
|
83
85
|
*
|
|
84
86
|
* Only meaningful inside a {@link TransitionTable}: the source and trigger
|
|
85
87
|
* types flow in from the table position contextually.
|
|
88
|
+
*
|
|
89
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
86
90
|
*/
|
|
87
91
|
export declare const to: <State extends Tagged, Message extends Tagged, SourceState extends State, TriggerMessage extends Message, const TargetTag extends TagOf<State>, R = never>(target: TargetTag, build: (input: NoInfer<EdgeInput<SourceState, TriggerMessage>>) => NoInfer<Variant<State, TargetTag>>, commands?: (input: NoInfer<EdgeInput<SourceState, TriggerMessage>>) => ReadonlyArray<Command<NoInfer<Message>, never, R>>) => Edge<State, Message, SourceState, TriggerMessage, void, R>;
|
|
88
92
|
/**
|
|
@@ -95,12 +99,16 @@ export declare const to: <State extends Tagged, Message extends Tagged, SourceSt
|
|
|
95
99
|
*
|
|
96
100
|
* The state and Message parameters are `NoInfer` so they resolve from the
|
|
97
101
|
* guard list's table position alone.
|
|
102
|
+
*
|
|
103
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
98
104
|
*/
|
|
99
105
|
export declare const when: <State extends Tagged, Message extends Tagged, SourceState extends State, TriggerMessage extends Message, GuardResult extends Option.Option<unknown> | boolean, const TargetTag extends TagOf<State>, R = never>(guard: (state: NoInfer<SourceState>, message: NoInfer<TriggerMessage>) => GuardResult, target: TargetTag, build: (input: NoInfer<EdgeInput<SourceState, TriggerMessage, GuardValueOf<GuardResult>>>) => NoInfer<Variant<State, TargetTag>>, commands?: (input: NoInfer<EdgeInput<SourceState, TriggerMessage, GuardValueOf<GuardResult>>>) => ReadonlyArray<Command<NoInfer<Message>, never, R>>) => When<State, Message, SourceState, TriggerMessage, GuardValueOf<GuardResult>, R>;
|
|
100
106
|
/**
|
|
101
107
|
* The unconditional fallback at the end of a guard list. Its edge may carry
|
|
102
108
|
* Commands whose Effects need services, threading their requirements into the
|
|
103
109
|
* Machine's `R` the same way {@link to} and {@link when} do.
|
|
110
|
+
*
|
|
111
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
104
112
|
*/
|
|
105
113
|
export declare const otherwise: <State extends Tagged, Message extends Tagged, SourceState extends State, TriggerMessage extends Message, R = never>(edge: Edge<State, Message, SourceState, TriggerMessage, void, R>) => Otherwise<State, Message, SourceState, TriggerMessage, R>;
|
|
106
114
|
/** A step that matched an Edge: the next state plus any transition-time Commands. */
|
|
@@ -119,7 +127,10 @@ export type Ignored<State extends Tagged, Message extends Tagged> = Readonly<{
|
|
|
119
127
|
messageTag: TagOf<Message>;
|
|
120
128
|
state: State;
|
|
121
129
|
}>;
|
|
122
|
-
/** The observable outcome of one step: `Transitioned` or `Ignored`.
|
|
130
|
+
/** The observable outcome of one step: `Transitioned` or `Ignored`.
|
|
131
|
+
*
|
|
132
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
133
|
+
*/
|
|
123
134
|
export type TransitionResult<State extends Tagged, Message extends Tagged, R = never> = Transitioned<State, Message, R> | Ignored<State, Message>;
|
|
124
135
|
/** Which guard construct an Edge sits under, with its position in the guard list. */
|
|
125
136
|
export type EdgeGuard = Readonly<{
|
|
@@ -145,7 +156,10 @@ export type DeadTransition<State extends Tagged, Message extends Tagged> = Reado
|
|
|
145
156
|
edge: EdgeSummary<State, Message>;
|
|
146
157
|
reason: DeadTransitionReason;
|
|
147
158
|
}>;
|
|
148
|
-
/** A compiled state Machine: a pure transition function plus static analysis over the Edge set.
|
|
159
|
+
/** A compiled state Machine: a pure transition function plus static analysis over the Edge set.
|
|
160
|
+
*
|
|
161
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
162
|
+
*/
|
|
149
163
|
export type Machine<State extends Tagged, Message extends Tagged, R = never> = Readonly<{
|
|
150
164
|
initial: State;
|
|
151
165
|
stateTags: ReadonlyArray<TagOf<State>>;
|
|
@@ -171,7 +185,10 @@ export type MachineSchemas<State extends Tagged, Message extends Tagged> = Reado
|
|
|
171
185
|
Type: Message;
|
|
172
186
|
}>;
|
|
173
187
|
}>;
|
|
174
|
-
/** The Machine definition: the initial state and the transition table.
|
|
188
|
+
/** The Machine definition: the initial state and the transition table.
|
|
189
|
+
*
|
|
190
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
191
|
+
*/
|
|
175
192
|
export type MachineDefinition<State extends Tagged, Message extends Tagged, R = never> = Readonly<{
|
|
176
193
|
initial: State;
|
|
177
194
|
states: TransitionTable<State, Message, R>;
|
|
@@ -216,6 +233,8 @@ export type MachineDefinition<State extends Tagged, Message extends Tagged, R =
|
|
|
216
233
|
* })
|
|
217
234
|
* // machine.transition(...) returns Commands typed with UploadsClient in R.
|
|
218
235
|
* ```
|
|
236
|
+
*
|
|
237
|
+
* @experimental Ships from `foldkit/experimental/machine`; expect breaking changes while the API settles.
|
|
219
238
|
*/
|
|
220
239
|
export declare const define: <State extends Tagged, Message extends Tagged>(schemas: MachineSchemas<State, Message>) => <R = never>(definition: MachineDefinition<State, Message, R>) => Machine<State, Message, R>;
|
|
221
240
|
export {};
|