xote 6.1.1 → 6.2.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 +90 -10
- package/dist/xote.cjs +9 -9
- package/dist/xote.mjs +1485 -1317
- package/dist/xote.umd.js +9 -9
- package/package.json +16 -1
- package/rescript.json +2 -0
- package/src/Html.res +13 -13
- package/src/Html.res.mjs +13 -13
- package/src/Hydration.res +134 -79
- package/src/Hydration.res.mjs +255 -186
- package/src/Node.res +2 -578
- package/src/Node.res.mjs +31 -518
- package/src/Prop.res +16 -0
- package/src/Prop.res.mjs +35 -0
- package/src/ReactiveProp.res +2 -14
- package/src/ReactiveProp.res.mjs +7 -20
- package/src/Route.res +4 -0
- package/src/Route.res.mjs +9 -0
- package/src/Router.res +25 -49
- package/src/Router.res.mjs +22 -34
- package/src/RuntimeAttr.res +21 -0
- package/src/RuntimeAttr.res.mjs +42 -0
- package/src/RuntimeDom.res +95 -0
- package/src/RuntimeDom.res.mjs +101 -0
- package/src/RuntimeHtml.res +27 -0
- package/src/RuntimeHtml.res.mjs +34 -0
- package/src/RuntimeHydrationMarkers.res +24 -0
- package/src/RuntimeHydrationMarkers.res.mjs +68 -0
- package/src/RuntimeJsxProp.res +46 -0
- package/src/RuntimeJsxProp.res.mjs +52 -0
- package/src/RuntimeOwner.res +43 -0
- package/src/RuntimeOwner.res.mjs +51 -0
- package/src/SSR.res +25 -93
- package/src/SSR.res.mjs +59 -126
- package/src/SSRState.res +3 -0
- package/src/SSRState.res.mjs +8 -2
- package/src/View.res +599 -0
- package/src/View.res.mjs +614 -0
- package/src/XoteJSX.res +64 -118
- package/src/XoteJSX.res.mjs +79 -118
package/src/Route.res.mjs
CHANGED
|
@@ -48,9 +48,18 @@ function match(pattern, pathname) {
|
|
|
48
48
|
return matchPath(parsePattern(pattern), pathname);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
let compile = parsePattern;
|
|
52
|
+
|
|
53
|
+
let matchCompiled = matchPath;
|
|
54
|
+
|
|
55
|
+
let matchPathname = match;
|
|
56
|
+
|
|
51
57
|
export {
|
|
52
58
|
parsePattern,
|
|
53
59
|
matchPath,
|
|
54
60
|
match,
|
|
61
|
+
compile,
|
|
62
|
+
matchCompiled,
|
|
63
|
+
matchPathname,
|
|
55
64
|
}
|
|
56
65
|
/* No side effect */
|
package/src/Router.res
CHANGED
|
@@ -309,11 +309,11 @@ let replace = (pathname: string, ~search: string="", ~hash: string="", ()): unit
|
|
|
309
309
|
// Route definition for routes() component
|
|
310
310
|
type routeConfig = {
|
|
311
311
|
pattern: string,
|
|
312
|
-
render: Route.params =>
|
|
312
|
+
render: Route.params => View.node,
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
// Single route component - renders if pattern matches
|
|
316
|
-
let route = (pattern: string, render: Route.params =>
|
|
316
|
+
let route = (pattern: string, render: Route.params => View.node): View.node => {
|
|
317
317
|
warnIfNotInitialized("Router.route()")
|
|
318
318
|
|
|
319
319
|
let signal = Computed.make(() => {
|
|
@@ -323,11 +323,11 @@ let route = (pattern: string, render: Route.params => Node.node): Node.node => {
|
|
|
323
323
|
| NoMatch => []
|
|
324
324
|
}
|
|
325
325
|
})
|
|
326
|
-
|
|
326
|
+
View.signalFragment(signal)
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
// Routes component - renders first matching route
|
|
330
|
-
let routes = (configs: array<routeConfig>):
|
|
330
|
+
let routes = (configs: array<routeConfig>): View.node => {
|
|
331
331
|
warnIfNotInitialized("Router.routes()")
|
|
332
332
|
|
|
333
333
|
let signal = Computed.make(() => {
|
|
@@ -344,16 +344,16 @@ let routes = (configs: array<routeConfig>): Node.node => {
|
|
|
344
344
|
| None => [] // No matching route - render nothing
|
|
345
345
|
}
|
|
346
346
|
})
|
|
347
|
-
|
|
347
|
+
View.signalFragment(signal)
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
// Link component - handles navigation without page reload
|
|
351
351
|
let link = (
|
|
352
352
|
~to: string,
|
|
353
|
-
~attrs: array<(string,
|
|
354
|
-
~children: array<
|
|
353
|
+
~attrs: array<(string, View.attrValue)>=[],
|
|
354
|
+
~children: array<View.node>=[],
|
|
355
355
|
(),
|
|
356
|
-
):
|
|
356
|
+
): View.node => {
|
|
357
357
|
warnIfNotInitialized("Router.link()")
|
|
358
358
|
|
|
359
359
|
let handleClick = (_evt: Dom.event) => {
|
|
@@ -362,7 +362,7 @@ let link = (
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
Html.a(
|
|
365
|
-
~attrs=Array.concat(attrs, [
|
|
365
|
+
~attrs=Array.concat(attrs, [View.attr("href", addBasePath(to))]),
|
|
366
366
|
~events=[("click", handleClick)],
|
|
367
367
|
~children,
|
|
368
368
|
(),
|
|
@@ -371,7 +371,7 @@ let link = (
|
|
|
371
371
|
|
|
372
372
|
// JSX Link component
|
|
373
373
|
module Link = {
|
|
374
|
-
module
|
|
374
|
+
module Prop = Prop
|
|
375
375
|
|
|
376
376
|
type props<'class, 'id, 'style, 'target, 'ariaLabel> = {
|
|
377
377
|
/* Required navigation prop */
|
|
@@ -385,61 +385,35 @@ module Link = {
|
|
|
385
385
|
/* Event handlers */
|
|
386
386
|
onClick?: Dom.event => unit,
|
|
387
387
|
/* Children */
|
|
388
|
-
children?:
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/* Helper to detect if a value is a ReactiveProp variant */
|
|
392
|
-
let isReactiveProp = (value: 'a): bool => {
|
|
393
|
-
ignore(value)
|
|
394
|
-
%raw(`value && typeof value === 'object' && ('TAG' in value) && (value.TAG === 'Static' || value.TAG === 'Reactive')`)
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/* Helper to convert string attribute value */
|
|
398
|
-
let convertAttrValue = (key: string, value: 'a): (string, Node.attrValue) => {
|
|
399
|
-
if isReactiveProp(value) {
|
|
400
|
-
let rp: ReactiveProp.t<string> = Obj.magic(value)
|
|
401
|
-
switch rp {
|
|
402
|
-
| Static(s) => Node.attr(key, s)
|
|
403
|
-
| Reactive(signal) => Node.signalAttr(key, signal)
|
|
404
|
-
}
|
|
405
|
-
} else if typeof(value) == #function {
|
|
406
|
-
let f: unit => string = Obj.magic(value)
|
|
407
|
-
Node.computedAttr(key, f)
|
|
408
|
-
} else if typeof(value) == #object {
|
|
409
|
-
let sig: Signal.t<string> = Obj.magic(value)
|
|
410
|
-
Node.signalAttr(key, sig)
|
|
411
|
-
} else {
|
|
412
|
-
let s: string = Obj.magic(value)
|
|
413
|
-
Node.attr(key, s)
|
|
414
|
-
}
|
|
388
|
+
children?: View.node,
|
|
415
389
|
}
|
|
416
390
|
|
|
417
391
|
/* Convert props to attrs array */
|
|
418
|
-
let propsToAttrs = (props): array<(string,
|
|
392
|
+
let propsToAttrs = (props): array<(string, View.attrValue)> => {
|
|
419
393
|
let attrs = []
|
|
420
394
|
|
|
421
395
|
switch props.class {
|
|
422
|
-
| Some(v) => attrs->Array.push(
|
|
396
|
+
| Some(v) => attrs->Array.push(RuntimeJsxProp.toStringAttr("class", v))
|
|
423
397
|
| None => ()
|
|
424
398
|
}
|
|
425
399
|
|
|
426
400
|
switch props.id {
|
|
427
|
-
| Some(v) => attrs->Array.push(
|
|
401
|
+
| Some(v) => attrs->Array.push(RuntimeJsxProp.toStringAttr("id", v))
|
|
428
402
|
| None => ()
|
|
429
403
|
}
|
|
430
404
|
|
|
431
405
|
switch props.style {
|
|
432
|
-
| Some(v) => attrs->Array.push(
|
|
406
|
+
| Some(v) => attrs->Array.push(RuntimeJsxProp.toStringAttr("style", v))
|
|
433
407
|
| None => ()
|
|
434
408
|
}
|
|
435
409
|
|
|
436
410
|
switch props.target {
|
|
437
|
-
| Some(v) => attrs->Array.push(
|
|
411
|
+
| Some(v) => attrs->Array.push(RuntimeJsxProp.toStringAttr("target", v))
|
|
438
412
|
| None => ()
|
|
439
413
|
}
|
|
440
414
|
|
|
441
415
|
switch props.ariaLabel {
|
|
442
|
-
| Some(v) => attrs->Array.push(
|
|
416
|
+
| Some(v) => attrs->Array.push(RuntimeJsxProp.toStringAttr("aria-label", v))
|
|
443
417
|
| None => ()
|
|
444
418
|
}
|
|
445
419
|
|
|
@@ -447,16 +421,16 @@ module Link = {
|
|
|
447
421
|
}
|
|
448
422
|
|
|
449
423
|
/* Extract children from props */
|
|
450
|
-
let getChildren = (props): array<
|
|
424
|
+
let getChildren = (props): array<View.node> => {
|
|
451
425
|
switch props.children {
|
|
452
|
-
| Some(
|
|
426
|
+
| Some(View.Fragment(children)) => children
|
|
453
427
|
| Some(child) => [child]
|
|
454
428
|
| None => []
|
|
455
429
|
}
|
|
456
430
|
}
|
|
457
431
|
|
|
458
432
|
/* JSX component function */
|
|
459
|
-
let make = (props):
|
|
433
|
+
let make = (props): View.node => {
|
|
460
434
|
warnIfNotInitialized("Router.Link")
|
|
461
435
|
|
|
462
436
|
let handleClick = (evt: Dom.event) => {
|
|
@@ -471,7 +445,7 @@ module Link = {
|
|
|
471
445
|
}
|
|
472
446
|
|
|
473
447
|
Html.a(
|
|
474
|
-
~attrs=Array.concat(propsToAttrs(props), [
|
|
448
|
+
~attrs=Array.concat(propsToAttrs(props), [View.attr("href", addBasePath(props.to))]),
|
|
475
449
|
~events=[("click", handleClick)],
|
|
476
450
|
~children=getChildren(props),
|
|
477
451
|
(),
|
|
@@ -482,8 +456,10 @@ module Link = {
|
|
|
482
456
|
let jsx = make
|
|
483
457
|
let jsxs = make
|
|
484
458
|
let jsxKeyed = (props, ~key: option<string>=?, _: unit) => {
|
|
485
|
-
|
|
486
|
-
make(props)
|
|
459
|
+
switch key {
|
|
460
|
+
| Some(key) => View.Keyed({key, identity: Obj.magic(props), child: make(props)})
|
|
461
|
+
| None => make(props)
|
|
462
|
+
}
|
|
487
463
|
}
|
|
488
464
|
let jsxsKeyed = jsxKeyed
|
|
489
465
|
}
|
package/src/Router.res.mjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Html$Xote from "./Html.res.mjs";
|
|
4
|
-
import * as
|
|
4
|
+
import * as View$Xote from "./View.res.mjs";
|
|
5
5
|
import * as Route$Xote from "./Route.res.mjs";
|
|
6
6
|
import * as Signal$Xote from "./Signal.res.mjs";
|
|
7
7
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
8
8
|
import * as Computed$Xote from "./Computed.res.mjs";
|
|
9
9
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
10
|
+
import * as RuntimeJsxProp$Xote from "./RuntimeJsxProp.res.mjs";
|
|
10
11
|
|
|
11
12
|
function getSymbolKey() {
|
|
12
13
|
return Symbol.for("xote.router.state");
|
|
@@ -213,7 +214,7 @@ function replace(pathname, searchOpt, hashOpt, param) {
|
|
|
213
214
|
|
|
214
215
|
function route(pattern, render) {
|
|
215
216
|
warnIfNotInitialized("Router.route()");
|
|
216
|
-
return
|
|
217
|
+
return View$Xote.signalFragment(Computed$Xote.make(() => {
|
|
217
218
|
let loc = Signal$Xote.get(getGlobalState().location);
|
|
218
219
|
let params = Route$Xote.match(pattern, loc.pathname);
|
|
219
220
|
if (typeof params !== "object") {
|
|
@@ -226,7 +227,7 @@ function route(pattern, render) {
|
|
|
226
227
|
|
|
227
228
|
function routes(configs) {
|
|
228
229
|
warnIfNotInitialized("Router.routes()");
|
|
229
|
-
return
|
|
230
|
+
return View$Xote.signalFragment(Computed$Xote.make(() => {
|
|
230
231
|
let loc = Signal$Xote.get(getGlobalState().location);
|
|
231
232
|
let matched = Stdlib_Array.findMap(configs, config => {
|
|
232
233
|
let params = Route$Xote.match(config.pattern, loc.pathname);
|
|
@@ -252,53 +253,33 @@ function link(to, attrsOpt, childrenOpt, param) {
|
|
|
252
253
|
((_evt.preventDefault()));
|
|
253
254
|
push(to, undefined, undefined, undefined);
|
|
254
255
|
};
|
|
255
|
-
return Html$Xote.a(attrs.concat([
|
|
256
|
+
return Html$Xote.a(attrs.concat([View$Xote.attr("href", addBasePath(to))]), [[
|
|
256
257
|
"click",
|
|
257
258
|
handleClick
|
|
258
259
|
]], children, undefined);
|
|
259
260
|
}
|
|
260
261
|
|
|
261
|
-
function isReactiveProp(value) {
|
|
262
|
-
return (value && typeof value === 'object' && ('TAG' in value) && (value.TAG === 'Static' || value.TAG === 'Reactive'));
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function convertAttrValue(key, value) {
|
|
266
|
-
if (isReactiveProp(value)) {
|
|
267
|
-
if (value.TAG === "Reactive") {
|
|
268
|
-
return Node$Xote.signalAttr(key, value._0);
|
|
269
|
-
} else {
|
|
270
|
-
return Node$Xote.attr(key, value._0);
|
|
271
|
-
}
|
|
272
|
-
} else if (typeof value === "function") {
|
|
273
|
-
return Node$Xote.computedAttr(key, value);
|
|
274
|
-
} else if (typeof value === "object") {
|
|
275
|
-
return Node$Xote.signalAttr(key, value);
|
|
276
|
-
} else {
|
|
277
|
-
return Node$Xote.attr(key, value);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
262
|
function propsToAttrs(props) {
|
|
282
263
|
let attrs = [];
|
|
283
264
|
let v = props.class;
|
|
284
265
|
if (v !== undefined) {
|
|
285
|
-
attrs.push(
|
|
266
|
+
attrs.push(RuntimeJsxProp$Xote.toStringAttr("class", Primitive_option.valFromOption(v)));
|
|
286
267
|
}
|
|
287
268
|
let v$1 = props.id;
|
|
288
269
|
if (v$1 !== undefined) {
|
|
289
|
-
attrs.push(
|
|
270
|
+
attrs.push(RuntimeJsxProp$Xote.toStringAttr("id", Primitive_option.valFromOption(v$1)));
|
|
290
271
|
}
|
|
291
272
|
let v$2 = props.style;
|
|
292
273
|
if (v$2 !== undefined) {
|
|
293
|
-
attrs.push(
|
|
274
|
+
attrs.push(RuntimeJsxProp$Xote.toStringAttr("style", Primitive_option.valFromOption(v$2)));
|
|
294
275
|
}
|
|
295
276
|
let v$3 = props.target;
|
|
296
277
|
if (v$3 !== undefined) {
|
|
297
|
-
attrs.push(
|
|
278
|
+
attrs.push(RuntimeJsxProp$Xote.toStringAttr("target", Primitive_option.valFromOption(v$3)));
|
|
298
279
|
}
|
|
299
280
|
let v$4 = props["aria-label"];
|
|
300
281
|
if (v$4 !== undefined) {
|
|
301
|
-
attrs.push(
|
|
282
|
+
attrs.push(RuntimeJsxProp$Xote.toStringAttr("aria-label", Primitive_option.valFromOption(v$4)));
|
|
302
283
|
}
|
|
303
284
|
return attrs;
|
|
304
285
|
}
|
|
@@ -326,20 +307,27 @@ function make(props) {
|
|
|
326
307
|
return handler(evt);
|
|
327
308
|
}
|
|
328
309
|
};
|
|
329
|
-
return Html$Xote.a(propsToAttrs(props).concat([
|
|
310
|
+
return Html$Xote.a(propsToAttrs(props).concat([View$Xote.attr("href", addBasePath(props.to))]), [[
|
|
330
311
|
"click",
|
|
331
312
|
handleClick
|
|
332
313
|
]], getChildren(props), undefined);
|
|
333
314
|
}
|
|
334
315
|
|
|
335
316
|
function jsxKeyed(props, key, param) {
|
|
336
|
-
|
|
317
|
+
if (key !== undefined) {
|
|
318
|
+
return {
|
|
319
|
+
TAG: "Keyed",
|
|
320
|
+
key: key,
|
|
321
|
+
identity: props,
|
|
322
|
+
child: make(props)
|
|
323
|
+
};
|
|
324
|
+
} else {
|
|
325
|
+
return make(props);
|
|
326
|
+
}
|
|
337
327
|
}
|
|
338
328
|
|
|
339
329
|
let Link = {
|
|
340
|
-
|
|
341
|
-
isReactiveProp: isReactiveProp,
|
|
342
|
-
convertAttrValue: convertAttrValue,
|
|
330
|
+
Prop: undefined,
|
|
343
331
|
propsToAttrs: propsToAttrs,
|
|
344
332
|
getChildren: getChildren,
|
|
345
333
|
make: make,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
let booleanAttributes = [
|
|
2
|
+
"checked",
|
|
3
|
+
"disabled",
|
|
4
|
+
"required",
|
|
5
|
+
"readonly",
|
|
6
|
+
"multiple",
|
|
7
|
+
"aria-hidden",
|
|
8
|
+
"aria-expanded",
|
|
9
|
+
"aria-selected",
|
|
10
|
+
"draggable",
|
|
11
|
+
"hidden",
|
|
12
|
+
"contenteditable",
|
|
13
|
+
"spellcheck",
|
|
14
|
+
"autofocus",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
let isBoolean = (key: string): bool => booleanAttributes->Array.includes(key)
|
|
18
|
+
|
|
19
|
+
let boolToString = (value: bool): string => value ? "true" : "false"
|
|
20
|
+
|
|
21
|
+
let shouldRenderBoolean = (value: string): bool => value == "true"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
let booleanAttributes = [
|
|
5
|
+
"checked",
|
|
6
|
+
"disabled",
|
|
7
|
+
"required",
|
|
8
|
+
"readonly",
|
|
9
|
+
"multiple",
|
|
10
|
+
"aria-hidden",
|
|
11
|
+
"aria-expanded",
|
|
12
|
+
"aria-selected",
|
|
13
|
+
"draggable",
|
|
14
|
+
"hidden",
|
|
15
|
+
"contenteditable",
|
|
16
|
+
"spellcheck",
|
|
17
|
+
"autofocus"
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
function isBoolean(key) {
|
|
21
|
+
return booleanAttributes.includes(key);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function boolToString(value) {
|
|
25
|
+
if (value) {
|
|
26
|
+
return "true";
|
|
27
|
+
} else {
|
|
28
|
+
return "false";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function shouldRenderBoolean(value) {
|
|
33
|
+
return value === "true";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
booleanAttributes,
|
|
38
|
+
isBoolean,
|
|
39
|
+
boolToString,
|
|
40
|
+
shouldRenderBoolean,
|
|
41
|
+
}
|
|
42
|
+
/* No side effect */
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
let svgNamespace = "http://www.w3.org/2000/svg"
|
|
2
|
+
|
|
3
|
+
let svgTags = [
|
|
4
|
+
"svg",
|
|
5
|
+
"path",
|
|
6
|
+
"circle",
|
|
7
|
+
"ellipse",
|
|
8
|
+
"line",
|
|
9
|
+
"polygon",
|
|
10
|
+
"polyline",
|
|
11
|
+
"rect",
|
|
12
|
+
"g",
|
|
13
|
+
"defs",
|
|
14
|
+
"clipPath",
|
|
15
|
+
"mask",
|
|
16
|
+
"pattern",
|
|
17
|
+
"marker",
|
|
18
|
+
"symbol",
|
|
19
|
+
"use",
|
|
20
|
+
"text",
|
|
21
|
+
"tspan",
|
|
22
|
+
"image",
|
|
23
|
+
"foreignObject",
|
|
24
|
+
"linearGradient",
|
|
25
|
+
"radialGradient",
|
|
26
|
+
"stop",
|
|
27
|
+
"filter",
|
|
28
|
+
"feBlend",
|
|
29
|
+
"feColorMatrix",
|
|
30
|
+
"feComposite",
|
|
31
|
+
"feFlood",
|
|
32
|
+
"feGaussianBlur",
|
|
33
|
+
"feMerge",
|
|
34
|
+
"feMergeNode",
|
|
35
|
+
"feOffset",
|
|
36
|
+
"animate",
|
|
37
|
+
"animateTransform",
|
|
38
|
+
"desc",
|
|
39
|
+
"title",
|
|
40
|
+
"metadata",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
let svgTagSet: Dict.t<bool> = {
|
|
44
|
+
let d = Dict.make()
|
|
45
|
+
svgTags->Array.forEach(tag => d->Dict.set(tag, true))
|
|
46
|
+
d
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let isSvgTag = (tag: string): bool => svgTagSet->Dict.get(tag)->Option.isSome
|
|
50
|
+
|
|
51
|
+
@val @scope("document") external createElement: string => Dom.element = "createElement"
|
|
52
|
+
@val @scope("document")
|
|
53
|
+
external createElementNS: (string, string) => Dom.element = "createElementNS"
|
|
54
|
+
@val @scope("document") external createTextNode: string => Dom.element = "createTextNode"
|
|
55
|
+
@val @scope("document")
|
|
56
|
+
external createDocumentFragment: unit => Dom.element = "createDocumentFragment"
|
|
57
|
+
@val @scope("document") external createComment: string => Dom.element = "createComment"
|
|
58
|
+
@val @scope("document")
|
|
59
|
+
external getElementById: string => Nullable.t<Dom.element> = "getElementById"
|
|
60
|
+
|
|
61
|
+
@get external getNextSibling: Dom.element => Nullable.t<Dom.element> = "nextSibling"
|
|
62
|
+
@get external getFirstChild: Dom.element => Nullable.t<Dom.element> = "firstChild"
|
|
63
|
+
@get external getParentNode: Dom.element => Nullable.t<Dom.element> = "parentNode"
|
|
64
|
+
|
|
65
|
+
@send
|
|
66
|
+
external addEventListener: (Dom.element, string, Dom.event => unit) => unit = "addEventListener"
|
|
67
|
+
@send external appendChild: (Dom.element, Dom.element) => unit = "appendChild"
|
|
68
|
+
@send external remove: Dom.element => unit = "remove"
|
|
69
|
+
@send external setAttribute: (Dom.element, string, string) => unit = "setAttribute"
|
|
70
|
+
@send external removeAttribute: (Dom.element, string) => unit = "removeAttribute"
|
|
71
|
+
@send external replaceChild: (Dom.element, Dom.element, Dom.element) => unit = "replaceChild"
|
|
72
|
+
@send external insertBefore: (Dom.element, Dom.element, Dom.element) => unit = "insertBefore"
|
|
73
|
+
@set external setTextContent: (Dom.element, string) => unit = "textContent"
|
|
74
|
+
@set external setInnerHTML: (Dom.element, string) => unit = "innerHTML"
|
|
75
|
+
@set external setValue: (Dom.element, string) => unit = "value"
|
|
76
|
+
@set external setChecked: (Dom.element, bool) => unit = "checked"
|
|
77
|
+
@set external setDisabled: (Dom.element, bool) => unit = "disabled"
|
|
78
|
+
|
|
79
|
+
let createElementForTag = (tag: string): Dom.element =>
|
|
80
|
+
isSvgTag(tag) ? createElementNS(svgNamespace, tag) : createElement(tag)
|
|
81
|
+
|
|
82
|
+
let setAttrOrProp = (el: Dom.element, key: string, value: string): unit => {
|
|
83
|
+
switch key {
|
|
84
|
+
| "value" => setValue(el, value)
|
|
85
|
+
| "checked" => setChecked(el, value == "true")
|
|
86
|
+
| "disabled" => setDisabled(el, value == "true")
|
|
87
|
+
| _ if RuntimeAttr.isBoolean(key) =>
|
|
88
|
+
if RuntimeAttr.shouldRenderBoolean(value) {
|
|
89
|
+
setAttribute(el, key, "")
|
|
90
|
+
} else {
|
|
91
|
+
removeAttribute(el, key)
|
|
92
|
+
}
|
|
93
|
+
| _ => setAttribute(el, key, value)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
import * as RuntimeAttr$Xote from "./RuntimeAttr.res.mjs";
|
|
5
|
+
|
|
6
|
+
let svgNamespace = "http://www.w3.org/2000/svg";
|
|
7
|
+
|
|
8
|
+
let svgTags = [
|
|
9
|
+
"svg",
|
|
10
|
+
"path",
|
|
11
|
+
"circle",
|
|
12
|
+
"ellipse",
|
|
13
|
+
"line",
|
|
14
|
+
"polygon",
|
|
15
|
+
"polyline",
|
|
16
|
+
"rect",
|
|
17
|
+
"g",
|
|
18
|
+
"defs",
|
|
19
|
+
"clipPath",
|
|
20
|
+
"mask",
|
|
21
|
+
"pattern",
|
|
22
|
+
"marker",
|
|
23
|
+
"symbol",
|
|
24
|
+
"use",
|
|
25
|
+
"text",
|
|
26
|
+
"tspan",
|
|
27
|
+
"image",
|
|
28
|
+
"foreignObject",
|
|
29
|
+
"linearGradient",
|
|
30
|
+
"radialGradient",
|
|
31
|
+
"stop",
|
|
32
|
+
"filter",
|
|
33
|
+
"feBlend",
|
|
34
|
+
"feColorMatrix",
|
|
35
|
+
"feComposite",
|
|
36
|
+
"feFlood",
|
|
37
|
+
"feGaussianBlur",
|
|
38
|
+
"feMerge",
|
|
39
|
+
"feMergeNode",
|
|
40
|
+
"feOffset",
|
|
41
|
+
"animate",
|
|
42
|
+
"animateTransform",
|
|
43
|
+
"desc",
|
|
44
|
+
"title",
|
|
45
|
+
"metadata"
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
let d = {};
|
|
49
|
+
|
|
50
|
+
svgTags.forEach(tag => {
|
|
51
|
+
d[tag] = true;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function isSvgTag(tag) {
|
|
55
|
+
return Stdlib_Option.isSome(d[tag]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createElementForTag(tag) {
|
|
59
|
+
if (Stdlib_Option.isSome(d[tag])) {
|
|
60
|
+
return document.createElementNS(svgNamespace, tag);
|
|
61
|
+
} else {
|
|
62
|
+
return document.createElement(tag);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function setAttrOrProp(el, key, value) {
|
|
67
|
+
switch (key) {
|
|
68
|
+
case "checked" :
|
|
69
|
+
el.checked = value === "true";
|
|
70
|
+
return;
|
|
71
|
+
case "disabled" :
|
|
72
|
+
el.disabled = value === "true";
|
|
73
|
+
return;
|
|
74
|
+
case "value" :
|
|
75
|
+
el.value = value;
|
|
76
|
+
return;
|
|
77
|
+
default:
|
|
78
|
+
if (RuntimeAttr$Xote.isBoolean(key)) {
|
|
79
|
+
if (RuntimeAttr$Xote.shouldRenderBoolean(value)) {
|
|
80
|
+
el.setAttribute(key, "");
|
|
81
|
+
} else {
|
|
82
|
+
el.removeAttribute(key);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
el.setAttribute(key, value);
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let svgTagSet = d;
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
svgNamespace,
|
|
95
|
+
svgTags,
|
|
96
|
+
svgTagSet,
|
|
97
|
+
isSvgTag,
|
|
98
|
+
createElementForTag,
|
|
99
|
+
setAttrOrProp,
|
|
100
|
+
}
|
|
101
|
+
/* Not a pure module */
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
let escape = (str: string): string => {
|
|
2
|
+
str
|
|
3
|
+
->String.replaceAll("&", "&")
|
|
4
|
+
->String.replaceAll("<", "<")
|
|
5
|
+
->String.replaceAll(">", ">")
|
|
6
|
+
->String.replaceAll("\"", """)
|
|
7
|
+
->String.replaceAll("'", "'")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let voidElements = [
|
|
11
|
+
"area",
|
|
12
|
+
"base",
|
|
13
|
+
"br",
|
|
14
|
+
"col",
|
|
15
|
+
"embed",
|
|
16
|
+
"hr",
|
|
17
|
+
"img",
|
|
18
|
+
"input",
|
|
19
|
+
"link",
|
|
20
|
+
"meta",
|
|
21
|
+
"param",
|
|
22
|
+
"source",
|
|
23
|
+
"track",
|
|
24
|
+
"wbr",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
let isVoidElement = (tag: string): bool => voidElements->Array.includes(tag)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function escape(str) {
|
|
5
|
+
return str.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let voidElements = [
|
|
9
|
+
"area",
|
|
10
|
+
"base",
|
|
11
|
+
"br",
|
|
12
|
+
"col",
|
|
13
|
+
"embed",
|
|
14
|
+
"hr",
|
|
15
|
+
"img",
|
|
16
|
+
"input",
|
|
17
|
+
"link",
|
|
18
|
+
"meta",
|
|
19
|
+
"param",
|
|
20
|
+
"source",
|
|
21
|
+
"track",
|
|
22
|
+
"wbr"
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
function isVoidElement(tag) {
|
|
26
|
+
return voidElements.includes(tag);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
escape,
|
|
31
|
+
voidElements,
|
|
32
|
+
isVoidElement,
|
|
33
|
+
}
|
|
34
|
+
/* No side effect */
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
let signalTextStart = "<!--$-->"
|
|
2
|
+
let signalTextEnd = "<!--/$-->"
|
|
3
|
+
let signalTextStartContent = "$"
|
|
4
|
+
let signalTextEndContent = "/$"
|
|
5
|
+
|
|
6
|
+
let signalFragmentStart = "<!--#-->"
|
|
7
|
+
let signalFragmentEnd = "<!--/#-->"
|
|
8
|
+
let signalFragmentStartContent = "#"
|
|
9
|
+
let signalFragmentEndContent = "/#"
|
|
10
|
+
|
|
11
|
+
let keyedListStart = "<!--kl-->"
|
|
12
|
+
let keyedListEnd = "<!--/kl-->"
|
|
13
|
+
let keyedListStartContent = "kl"
|
|
14
|
+
let keyedListEndContent = "/kl"
|
|
15
|
+
|
|
16
|
+
let keyedItemPrefixContent = "k:"
|
|
17
|
+
let keyedItemStart = (key: string): string => `<!--${keyedItemPrefixContent}${key}-->`
|
|
18
|
+
let keyedItemEnd = "<!--/k-->"
|
|
19
|
+
let keyedItemEndContent = "/k"
|
|
20
|
+
|
|
21
|
+
let lazyComponentStart = "<!--lc-->"
|
|
22
|
+
let lazyComponentEnd = "<!--/lc-->"
|
|
23
|
+
let lazyComponentStartContent = "lc"
|
|
24
|
+
let lazyComponentEndContent = "/lc"
|