xote 4.3.0 → 4.4.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 -5
- package/package.json +6 -2
- package/rescript.json +30 -0
- package/src/Xote.res +23 -0
- package/src/Xote.res.mjs +88 -0
- package/src/Xote__Component.res +495 -0
- package/src/Xote__Component.res.mjs +487 -0
- package/src/Xote__JSX.res +677 -0
- package/src/Xote__JSX.res.mjs +356 -0
- package/src/Xote__Route.res +62 -0
- package/src/Xote__Route.res.mjs +56 -0
- package/src/Xote__Router.res +130 -0
- package/src/Xote__Router.res.mjs +116 -0
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
open Signals
|
|
2
|
+
module Component = Xote__Component
|
|
3
|
+
|
|
4
|
+
/* ReScript JSX transform type aliases */
|
|
5
|
+
type element = Component.node
|
|
6
|
+
|
|
7
|
+
type component<'props> = 'props => element
|
|
8
|
+
|
|
9
|
+
type componentLike<'props, 'return> = 'props => 'return
|
|
10
|
+
|
|
11
|
+
/* JSX functions for component creation */
|
|
12
|
+
let jsx = (component: component<'props>, props: 'props): element => component(props)
|
|
13
|
+
|
|
14
|
+
let jsxs = (component: component<'props>, props: 'props): element => component(props)
|
|
15
|
+
|
|
16
|
+
let jsxKeyed = (
|
|
17
|
+
component: component<'props>,
|
|
18
|
+
props: 'props,
|
|
19
|
+
~key: option<string>=?,
|
|
20
|
+
_: unit,
|
|
21
|
+
): element => {
|
|
22
|
+
let _ = key /* TODO: Implement key support for list reconciliation */
|
|
23
|
+
component(props)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let jsxsKeyed = (
|
|
27
|
+
component: component<'props>,
|
|
28
|
+
props: 'props,
|
|
29
|
+
~key: option<string>=?,
|
|
30
|
+
_: unit,
|
|
31
|
+
): element => {
|
|
32
|
+
let _ = key
|
|
33
|
+
component(props)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Fragment support */
|
|
37
|
+
type fragmentProps = {children?: element}
|
|
38
|
+
|
|
39
|
+
let jsxFragment = (props: fragmentProps): element => {
|
|
40
|
+
switch props.children {
|
|
41
|
+
| Some(child) => child
|
|
42
|
+
| None => Component.fragment([])
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Element converters for JSX expressions */
|
|
47
|
+
let array = (children: array<element>): element => Component.fragment(children)
|
|
48
|
+
|
|
49
|
+
let null = (): element => Component.text("")
|
|
50
|
+
|
|
51
|
+
/* Elements module for lowercase HTML tags */
|
|
52
|
+
module Elements = {
|
|
53
|
+
/* Attribute value type that can be static, signal, or computed */
|
|
54
|
+
@unboxed
|
|
55
|
+
type rec attributeValue = Any('a): attributeValue
|
|
56
|
+
|
|
57
|
+
/* Automatic conversion from string to attributeValue */
|
|
58
|
+
external fromString: string => attributeValue = "%identity"
|
|
59
|
+
|
|
60
|
+
/* Helper to convert a signal to an attributeValue */
|
|
61
|
+
let signal = (s: Signals.Signal.t<string>): attributeValue => Any(s)
|
|
62
|
+
|
|
63
|
+
/* Helper to convert a computed function to an attributeValue */
|
|
64
|
+
let computed = (f: unit => string): attributeValue => Any(f)
|
|
65
|
+
|
|
66
|
+
/* Props type for HTML elements - supports common attributes and events
|
|
67
|
+
* String-like attributes use polymorphic types to accept strings, signals, or computed functions
|
|
68
|
+
*/
|
|
69
|
+
type props<
|
|
70
|
+
'id,
|
|
71
|
+
'class,
|
|
72
|
+
'style,
|
|
73
|
+
'typ,
|
|
74
|
+
'name,
|
|
75
|
+
'value,
|
|
76
|
+
'placeholder,
|
|
77
|
+
'min,
|
|
78
|
+
'max,
|
|
79
|
+
'step,
|
|
80
|
+
'pattern,
|
|
81
|
+
'autoComplete,
|
|
82
|
+
'accept,
|
|
83
|
+
'forAttr,
|
|
84
|
+
'href,
|
|
85
|
+
'target,
|
|
86
|
+
'src,
|
|
87
|
+
'alt,
|
|
88
|
+
'width,
|
|
89
|
+
'height,
|
|
90
|
+
'role,
|
|
91
|
+
'ariaLabel,
|
|
92
|
+
> = {
|
|
93
|
+
/* Standard attributes - can be static strings, signals, or computed values */
|
|
94
|
+
id?: 'id,
|
|
95
|
+
class?: 'class,
|
|
96
|
+
style?: 'style,
|
|
97
|
+
/* Form/Input attributes */
|
|
98
|
+
@as("type") type_?: 'typ,
|
|
99
|
+
name?: 'name,
|
|
100
|
+
value?: 'value,
|
|
101
|
+
placeholder?: 'placeholder,
|
|
102
|
+
disabled?: bool,
|
|
103
|
+
checked?: bool,
|
|
104
|
+
required?: bool,
|
|
105
|
+
readOnly?: bool,
|
|
106
|
+
maxLength?: int,
|
|
107
|
+
minLength?: int,
|
|
108
|
+
min?: 'min,
|
|
109
|
+
max?: 'max,
|
|
110
|
+
step?: 'step,
|
|
111
|
+
pattern?: 'pattern,
|
|
112
|
+
autoComplete?: 'autoComplete,
|
|
113
|
+
multiple?: bool,
|
|
114
|
+
accept?: 'accept,
|
|
115
|
+
rows?: int,
|
|
116
|
+
cols?: int,
|
|
117
|
+
/* Label attributes */
|
|
118
|
+
@as("for") for_?: 'forAttr,
|
|
119
|
+
/* Link attributes */
|
|
120
|
+
href?: 'href,
|
|
121
|
+
target?: 'target,
|
|
122
|
+
/* Image attributes */
|
|
123
|
+
src?: 'src,
|
|
124
|
+
alt?: 'alt,
|
|
125
|
+
width?: 'width,
|
|
126
|
+
height?: 'height,
|
|
127
|
+
/* Accessibility attributes */
|
|
128
|
+
role?: 'role,
|
|
129
|
+
tabIndex?: int,
|
|
130
|
+
@as("aria-label") ariaLabel?: 'ariaLabel,
|
|
131
|
+
@as("aria-hidden") ariaHidden?: bool,
|
|
132
|
+
@as("aria-expanded") ariaExpanded?: bool,
|
|
133
|
+
@as("aria-selected") ariaSelected?: bool,
|
|
134
|
+
/* Data attributes */
|
|
135
|
+
data?: Obj.t,
|
|
136
|
+
/* Event handlers */
|
|
137
|
+
onClick?: Dom.event => unit,
|
|
138
|
+
onInput?: Dom.event => unit,
|
|
139
|
+
onChange?: Dom.event => unit,
|
|
140
|
+
onSubmit?: Dom.event => unit,
|
|
141
|
+
onFocus?: Dom.event => unit,
|
|
142
|
+
onBlur?: Dom.event => unit,
|
|
143
|
+
onKeyDown?: Dom.event => unit,
|
|
144
|
+
onKeyUp?: Dom.event => unit,
|
|
145
|
+
onMouseEnter?: Dom.event => unit,
|
|
146
|
+
onMouseLeave?: Dom.event => unit,
|
|
147
|
+
/* Children */
|
|
148
|
+
children?: element,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* Helper to detect if a value is a signal (has an id property) */
|
|
152
|
+
@get external hasId: 'a => option<int> = "id"
|
|
153
|
+
|
|
154
|
+
/* Helper to convert any value to Component.attrValue */
|
|
155
|
+
let convertAttrValue = (key: string, value: 'a): (string, Component.attrValue) => {
|
|
156
|
+
// Check if it's a function (computed)
|
|
157
|
+
if typeof(value) == #function {
|
|
158
|
+
// It's a computed function
|
|
159
|
+
let f: unit => string = Obj.magic(value)
|
|
160
|
+
Component.computedAttr(key, f)
|
|
161
|
+
} else if typeof(value) == #object && hasId(value)->Option.isSome {
|
|
162
|
+
// It's a signal (has an id property)
|
|
163
|
+
let sig: Signal.t<string> = Obj.magic(value)
|
|
164
|
+
Component.signalAttr(key, sig)
|
|
165
|
+
} else {
|
|
166
|
+
// It's a static string
|
|
167
|
+
let s: string = Obj.magic(value)
|
|
168
|
+
Component.attr(key, s)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Convert props to attrs array */
|
|
173
|
+
let propsToAttrs = (
|
|
174
|
+
props: props<
|
|
175
|
+
'id,
|
|
176
|
+
'class,
|
|
177
|
+
'style,
|
|
178
|
+
'typ,
|
|
179
|
+
'name,
|
|
180
|
+
'value,
|
|
181
|
+
'placeholder,
|
|
182
|
+
'min,
|
|
183
|
+
'max,
|
|
184
|
+
'step,
|
|
185
|
+
'pattern,
|
|
186
|
+
'autoComplete,
|
|
187
|
+
'accept,
|
|
188
|
+
'forAttr,
|
|
189
|
+
'href,
|
|
190
|
+
'target,
|
|
191
|
+
'src,
|
|
192
|
+
'alt,
|
|
193
|
+
'width,
|
|
194
|
+
'height,
|
|
195
|
+
'role,
|
|
196
|
+
'ariaLabel,
|
|
197
|
+
>,
|
|
198
|
+
): array<(string, Component.attrValue)> => {
|
|
199
|
+
let attrs = []
|
|
200
|
+
|
|
201
|
+
/* Standard attributes */
|
|
202
|
+
switch props.id {
|
|
203
|
+
| Some(v) => attrs->Array.push(convertAttrValue("id", v))
|
|
204
|
+
| None => ()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
switch props.class {
|
|
208
|
+
| Some(v) => attrs->Array.push(convertAttrValue("class", v))
|
|
209
|
+
| None => ()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
switch props.style {
|
|
213
|
+
| Some(v) => attrs->Array.push(convertAttrValue("style", v))
|
|
214
|
+
| None => ()
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* Form/Input attributes */
|
|
218
|
+
switch props.type_ {
|
|
219
|
+
| Some(v) => attrs->Array.push(convertAttrValue("type", v))
|
|
220
|
+
| None => ()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
switch props.name {
|
|
224
|
+
| Some(v) => attrs->Array.push(convertAttrValue("name", v))
|
|
225
|
+
| None => ()
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
switch props.value {
|
|
229
|
+
| Some(v) => attrs->Array.push(convertAttrValue("value", v))
|
|
230
|
+
| None => ()
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
switch props.placeholder {
|
|
234
|
+
| Some(v) => attrs->Array.push(convertAttrValue("placeholder", v))
|
|
235
|
+
| None => ()
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
switch props.disabled {
|
|
239
|
+
| Some(true) => attrs->Array.push(Component.attr("disabled", "true"))
|
|
240
|
+
| _ => ()
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
switch props.checked {
|
|
244
|
+
| Some(true) => attrs->Array.push(Component.attr("checked", "true"))
|
|
245
|
+
| _ => ()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
switch props.required {
|
|
249
|
+
| Some(true) => attrs->Array.push(Component.attr("required", "true"))
|
|
250
|
+
| _ => ()
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
switch props.readOnly {
|
|
254
|
+
| Some(true) => attrs->Array.push(Component.attr("readonly", "true"))
|
|
255
|
+
| _ => ()
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
switch props.maxLength {
|
|
259
|
+
| Some(v) => attrs->Array.push(Component.attr("maxlength", Int.toString(v)))
|
|
260
|
+
| None => ()
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
switch props.minLength {
|
|
264
|
+
| Some(v) => attrs->Array.push(Component.attr("minlength", Int.toString(v)))
|
|
265
|
+
| None => ()
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
switch props.min {
|
|
269
|
+
| Some(v) => attrs->Array.push(convertAttrValue("min", v))
|
|
270
|
+
| None => ()
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
switch props.max {
|
|
274
|
+
| Some(v) => attrs->Array.push(convertAttrValue("max", v))
|
|
275
|
+
| None => ()
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
switch props.step {
|
|
279
|
+
| Some(v) => attrs->Array.push(convertAttrValue("step", v))
|
|
280
|
+
| None => ()
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
switch props.pattern {
|
|
284
|
+
| Some(v) => attrs->Array.push(convertAttrValue("pattern", v))
|
|
285
|
+
| None => ()
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
switch props.autoComplete {
|
|
289
|
+
| Some(v) => attrs->Array.push(convertAttrValue("autocomplete", v))
|
|
290
|
+
| None => ()
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
switch props.multiple {
|
|
294
|
+
| Some(true) => attrs->Array.push(Component.attr("multiple", "true"))
|
|
295
|
+
| _ => ()
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
switch props.accept {
|
|
299
|
+
| Some(v) => attrs->Array.push(convertAttrValue("accept", v))
|
|
300
|
+
| None => ()
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
switch props.rows {
|
|
304
|
+
| Some(v) => attrs->Array.push(Component.attr("rows", Int.toString(v)))
|
|
305
|
+
| None => ()
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
switch props.cols {
|
|
309
|
+
| Some(v) => attrs->Array.push(Component.attr("cols", Int.toString(v)))
|
|
310
|
+
| None => ()
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* Label attributes */
|
|
314
|
+
switch props.for_ {
|
|
315
|
+
| Some(v) => attrs->Array.push(convertAttrValue("for", v))
|
|
316
|
+
| None => ()
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* Link attributes */
|
|
320
|
+
switch props.href {
|
|
321
|
+
| Some(v) => attrs->Array.push(convertAttrValue("href", v))
|
|
322
|
+
| None => ()
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
switch props.target {
|
|
326
|
+
| Some(v) => attrs->Array.push(convertAttrValue("target", v))
|
|
327
|
+
| None => ()
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* Image attributes */
|
|
331
|
+
switch props.src {
|
|
332
|
+
| Some(v) => attrs->Array.push(convertAttrValue("src", v))
|
|
333
|
+
| None => ()
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
switch props.alt {
|
|
337
|
+
| Some(v) => attrs->Array.push(convertAttrValue("alt", v))
|
|
338
|
+
| None => ()
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
switch props.width {
|
|
342
|
+
| Some(v) => attrs->Array.push(convertAttrValue("width", v))
|
|
343
|
+
| None => ()
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
switch props.height {
|
|
347
|
+
| Some(v) => attrs->Array.push(convertAttrValue("height", v))
|
|
348
|
+
| None => ()
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* Accessibility attributes */
|
|
352
|
+
switch props.role {
|
|
353
|
+
| Some(v) => attrs->Array.push(convertAttrValue("role", v))
|
|
354
|
+
| None => ()
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
switch props.tabIndex {
|
|
358
|
+
| Some(v) => attrs->Array.push(Component.attr("tabindex", Int.toString(v)))
|
|
359
|
+
| None => ()
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
switch props.ariaLabel {
|
|
363
|
+
| Some(v) => attrs->Array.push(convertAttrValue("aria-label", v))
|
|
364
|
+
| None => ()
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
switch props.ariaHidden {
|
|
368
|
+
| Some(true) => attrs->Array.push(Component.attr("aria-hidden", "true"))
|
|
369
|
+
| Some(false) => attrs->Array.push(Component.attr("aria-hidden", "false"))
|
|
370
|
+
| None => ()
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
switch props.ariaExpanded {
|
|
374
|
+
| Some(true) => attrs->Array.push(Component.attr("aria-expanded", "true"))
|
|
375
|
+
| Some(false) => attrs->Array.push(Component.attr("aria-expanded", "false"))
|
|
376
|
+
| None => ()
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
switch props.ariaSelected {
|
|
380
|
+
| Some(true) => attrs->Array.push(Component.attr("aria-selected", "true"))
|
|
381
|
+
| Some(false) => attrs->Array.push(Component.attr("aria-selected", "false"))
|
|
382
|
+
| None => ()
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/* Data attributes */
|
|
386
|
+
switch props.data {
|
|
387
|
+
| Some(_dataObj) => {
|
|
388
|
+
let _ = %raw(`
|
|
389
|
+
Object.entries(_dataObj).forEach(([key, value]) => {
|
|
390
|
+
attrs.push(convertAttrValue("data-" + key, value))
|
|
391
|
+
})
|
|
392
|
+
`)
|
|
393
|
+
}
|
|
394
|
+
| None => ()
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
attrs
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* Convert props to events array */
|
|
401
|
+
let propsToEvents = (
|
|
402
|
+
props: props<
|
|
403
|
+
'id,
|
|
404
|
+
'class,
|
|
405
|
+
'style,
|
|
406
|
+
'typ,
|
|
407
|
+
'name,
|
|
408
|
+
'value,
|
|
409
|
+
'placeholder,
|
|
410
|
+
'min,
|
|
411
|
+
'max,
|
|
412
|
+
'step,
|
|
413
|
+
'pattern,
|
|
414
|
+
'autoComplete,
|
|
415
|
+
'accept,
|
|
416
|
+
'forAttr,
|
|
417
|
+
'href,
|
|
418
|
+
'target,
|
|
419
|
+
'src,
|
|
420
|
+
'alt,
|
|
421
|
+
'width,
|
|
422
|
+
'height,
|
|
423
|
+
'role,
|
|
424
|
+
'ariaLabel,
|
|
425
|
+
>,
|
|
426
|
+
): array<(string, Dom.event => unit)> => {
|
|
427
|
+
let events = []
|
|
428
|
+
|
|
429
|
+
switch props.onClick {
|
|
430
|
+
| Some(handler) => events->Array.push(("click", handler))
|
|
431
|
+
| None => ()
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
switch props.onInput {
|
|
435
|
+
| Some(handler) => events->Array.push(("input", handler))
|
|
436
|
+
| None => ()
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
switch props.onChange {
|
|
440
|
+
| Some(handler) => events->Array.push(("change", handler))
|
|
441
|
+
| None => ()
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
switch props.onSubmit {
|
|
445
|
+
| Some(handler) => events->Array.push(("submit", handler))
|
|
446
|
+
| None => ()
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
switch props.onFocus {
|
|
450
|
+
| Some(handler) => events->Array.push(("focus", handler))
|
|
451
|
+
| None => ()
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
switch props.onBlur {
|
|
455
|
+
| Some(handler) => events->Array.push(("blur", handler))
|
|
456
|
+
| None => ()
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
switch props.onKeyDown {
|
|
460
|
+
| Some(handler) => events->Array.push(("keydown", handler))
|
|
461
|
+
| None => ()
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
switch props.onKeyUp {
|
|
465
|
+
| Some(handler) => events->Array.push(("keyup", handler))
|
|
466
|
+
| None => ()
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
switch props.onMouseEnter {
|
|
470
|
+
| Some(handler) => events->Array.push(("mouseenter", handler))
|
|
471
|
+
| None => ()
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
switch props.onMouseLeave {
|
|
475
|
+
| Some(handler) => events->Array.push(("mouseleave", handler))
|
|
476
|
+
| None => ()
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
events
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/* Extract children from props */
|
|
483
|
+
let getChildren = (
|
|
484
|
+
props: props<
|
|
485
|
+
'id,
|
|
486
|
+
'class,
|
|
487
|
+
'style,
|
|
488
|
+
'typ,
|
|
489
|
+
'name,
|
|
490
|
+
'value,
|
|
491
|
+
'placeholder,
|
|
492
|
+
'min,
|
|
493
|
+
'max,
|
|
494
|
+
'step,
|
|
495
|
+
'pattern,
|
|
496
|
+
'autoComplete,
|
|
497
|
+
'accept,
|
|
498
|
+
'forAttr,
|
|
499
|
+
'href,
|
|
500
|
+
'target,
|
|
501
|
+
'src,
|
|
502
|
+
'alt,
|
|
503
|
+
'width,
|
|
504
|
+
'height,
|
|
505
|
+
'role,
|
|
506
|
+
'ariaLabel,
|
|
507
|
+
>,
|
|
508
|
+
): array<element> => {
|
|
509
|
+
switch props.children {
|
|
510
|
+
| Some(Fragment(children)) => children
|
|
511
|
+
| Some(child) => [child]
|
|
512
|
+
| None => []
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/* Create an element from a tag string and props */
|
|
517
|
+
let createElement = (
|
|
518
|
+
tag: string,
|
|
519
|
+
props: props<
|
|
520
|
+
'id,
|
|
521
|
+
'class,
|
|
522
|
+
'style,
|
|
523
|
+
'typ,
|
|
524
|
+
'name,
|
|
525
|
+
'value,
|
|
526
|
+
'placeholder,
|
|
527
|
+
'min,
|
|
528
|
+
'max,
|
|
529
|
+
'step,
|
|
530
|
+
'pattern,
|
|
531
|
+
'autoComplete,
|
|
532
|
+
'accept,
|
|
533
|
+
'forAttr,
|
|
534
|
+
'href,
|
|
535
|
+
'target,
|
|
536
|
+
'src,
|
|
537
|
+
'alt,
|
|
538
|
+
'width,
|
|
539
|
+
'height,
|
|
540
|
+
'role,
|
|
541
|
+
'ariaLabel,
|
|
542
|
+
>,
|
|
543
|
+
): element => {
|
|
544
|
+
Component.Element({
|
|
545
|
+
tag,
|
|
546
|
+
attrs: propsToAttrs(props),
|
|
547
|
+
events: propsToEvents(props),
|
|
548
|
+
children: getChildren(props),
|
|
549
|
+
})
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/* JSX functions for HTML elements */
|
|
553
|
+
let jsx = (
|
|
554
|
+
tag: string,
|
|
555
|
+
props: props<
|
|
556
|
+
'id,
|
|
557
|
+
'class,
|
|
558
|
+
'style,
|
|
559
|
+
'typ,
|
|
560
|
+
'name,
|
|
561
|
+
'value,
|
|
562
|
+
'placeholder,
|
|
563
|
+
'min,
|
|
564
|
+
'max,
|
|
565
|
+
'step,
|
|
566
|
+
'pattern,
|
|
567
|
+
'autoComplete,
|
|
568
|
+
'accept,
|
|
569
|
+
'forAttr,
|
|
570
|
+
'href,
|
|
571
|
+
'target,
|
|
572
|
+
'src,
|
|
573
|
+
'alt,
|
|
574
|
+
'width,
|
|
575
|
+
'height,
|
|
576
|
+
'role,
|
|
577
|
+
'ariaLabel,
|
|
578
|
+
>,
|
|
579
|
+
): element => createElement(tag, props)
|
|
580
|
+
|
|
581
|
+
let jsxs = (
|
|
582
|
+
tag: string,
|
|
583
|
+
props: props<
|
|
584
|
+
'id,
|
|
585
|
+
'class,
|
|
586
|
+
'style,
|
|
587
|
+
'typ,
|
|
588
|
+
'name,
|
|
589
|
+
'value,
|
|
590
|
+
'placeholder,
|
|
591
|
+
'min,
|
|
592
|
+
'max,
|
|
593
|
+
'step,
|
|
594
|
+
'pattern,
|
|
595
|
+
'autoComplete,
|
|
596
|
+
'accept,
|
|
597
|
+
'forAttr,
|
|
598
|
+
'href,
|
|
599
|
+
'target,
|
|
600
|
+
'src,
|
|
601
|
+
'alt,
|
|
602
|
+
'width,
|
|
603
|
+
'height,
|
|
604
|
+
'role,
|
|
605
|
+
'ariaLabel,
|
|
606
|
+
>,
|
|
607
|
+
): element => createElement(tag, props)
|
|
608
|
+
|
|
609
|
+
let jsxKeyed = (
|
|
610
|
+
tag: string,
|
|
611
|
+
props: props<
|
|
612
|
+
'id,
|
|
613
|
+
'class,
|
|
614
|
+
'style,
|
|
615
|
+
'typ,
|
|
616
|
+
'name,
|
|
617
|
+
'value,
|
|
618
|
+
'placeholder,
|
|
619
|
+
'min,
|
|
620
|
+
'max,
|
|
621
|
+
'step,
|
|
622
|
+
'pattern,
|
|
623
|
+
'autoComplete,
|
|
624
|
+
'accept,
|
|
625
|
+
'forAttr,
|
|
626
|
+
'href,
|
|
627
|
+
'target,
|
|
628
|
+
'src,
|
|
629
|
+
'alt,
|
|
630
|
+
'width,
|
|
631
|
+
'height,
|
|
632
|
+
'role,
|
|
633
|
+
'ariaLabel,
|
|
634
|
+
>,
|
|
635
|
+
~key: option<string>=?,
|
|
636
|
+
_: unit,
|
|
637
|
+
): element => {
|
|
638
|
+
let _ = key
|
|
639
|
+
createElement(tag, props)
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
let jsxsKeyed = (
|
|
643
|
+
tag: string,
|
|
644
|
+
props: props<
|
|
645
|
+
'id,
|
|
646
|
+
'class,
|
|
647
|
+
'style,
|
|
648
|
+
'typ,
|
|
649
|
+
'name,
|
|
650
|
+
'value,
|
|
651
|
+
'placeholder,
|
|
652
|
+
'min,
|
|
653
|
+
'max,
|
|
654
|
+
'step,
|
|
655
|
+
'pattern,
|
|
656
|
+
'autoComplete,
|
|
657
|
+
'accept,
|
|
658
|
+
'forAttr,
|
|
659
|
+
'href,
|
|
660
|
+
'target,
|
|
661
|
+
'src,
|
|
662
|
+
'alt,
|
|
663
|
+
'width,
|
|
664
|
+
'height,
|
|
665
|
+
'role,
|
|
666
|
+
'ariaLabel,
|
|
667
|
+
>,
|
|
668
|
+
~key: option<string>=?,
|
|
669
|
+
_: unit,
|
|
670
|
+
): element => {
|
|
671
|
+
let _ = key
|
|
672
|
+
createElement(tag, props)
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/* Element helper for ReScript JSX type checking */
|
|
676
|
+
external someElement: element => option<element> = "%identity"
|
|
677
|
+
}
|