xote 4.16.1 → 6.0.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 +19 -11
- package/dist/xote.cjs +9 -9
- package/dist/xote.mjs +1282 -1199
- package/dist/xote.umd.js +10 -10
- package/package.json +3 -3
- package/rescript.json +18 -3
- package/src/Computed.res +1 -0
- package/src/Computed.res.mjs +13 -0
- package/src/Effect.res +1 -0
- package/src/Effect.res.mjs +13 -0
- package/src/Html.res +28 -0
- package/src/Html.res.mjs +62 -0
- package/src/{Xote__Hydration.res → Hydration.res} +52 -50
- package/src/{Xote__Hydration.res.mjs → Hydration.res.mjs} +66 -68
- package/src/{Xote__Component.res → Node.res} +8 -31
- package/src/{Xote__Component.res.mjs → Node.res.mjs} +26 -88
- package/src/{Xote__ReactiveProp.res → ReactiveProp.res} +0 -1
- package/src/{Xote__ReactiveProp.res.mjs → ReactiveProp.res.mjs} +2 -2
- package/src/{Xote__Router.res → Router.res} +38 -32
- package/src/{Xote__Router.res.mjs → Router.res.mjs} +28 -28
- package/src/{Xote__SSR.res → SSR.res} +16 -18
- package/src/{Xote__SSR.res.mjs → SSR.res.mjs} +5 -8
- package/src/{Xote__SSRState.res → SSRState.res} +7 -6
- package/src/{Xote__SSRState.res.mjs → SSRState.res.mjs} +12 -12
- package/src/Signal.res +1 -0
- package/src/Signal.res.mjs +31 -0
- package/src/{Xote__JSX.res → XoteJSX.res} +22 -23
- package/src/{Xote__JSX.res.mjs → XoteJSX.res.mjs} +22 -24
- package/src/Xote.res +0 -43
- package/src/Xote.res.mjs +0 -114
- /package/src/{Xote__Route.res → Route.res} +0 -0
- /package/src/{Xote__Route.res.mjs → Route.res.mjs} +0 -0
- /package/src/{Xote__SSRContext.res → SSRContext.res} +0 -0
- /package/src/{Xote__SSRContext.res.mjs → SSRContext.res.mjs} +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
open Signals
|
|
2
1
|
|
|
3
2
|
/* ============================================================================
|
|
4
3
|
* DOM Bindings
|
|
@@ -246,7 +245,7 @@ module Render = {
|
|
|
246
245
|
setOwner(textNode, owner)
|
|
247
246
|
|
|
248
247
|
runWithOwner(owner, () => {
|
|
249
|
-
let disposer = Effect.
|
|
248
|
+
let disposer = Effect.runWithDisposer(() => {
|
|
250
249
|
DOM.setTextContent(textNode, Signal.get(signal))
|
|
251
250
|
None
|
|
252
251
|
})
|
|
@@ -272,7 +271,7 @@ module Render = {
|
|
|
272
271
|
setOwner(container, owner)
|
|
273
272
|
|
|
274
273
|
runWithOwner(owner, () => {
|
|
275
|
-
let disposer = Effect.
|
|
274
|
+
let disposer = Effect.runWithDisposer(() => {
|
|
276
275
|
let children = Signal.get(signal)
|
|
277
276
|
|
|
278
277
|
/* Dispose existing children */
|
|
@@ -315,7 +314,7 @@ module Render = {
|
|
|
315
314
|
| Static(v) => DOM.setAttrOrProp(el, key, v)
|
|
316
315
|
| SignalValue(signal) => {
|
|
317
316
|
DOM.setAttrOrProp(el, key, Signal.peek(signal))
|
|
318
|
-
let disposer = Effect.
|
|
317
|
+
let disposer = Effect.runWithDisposer(
|
|
319
318
|
() => {
|
|
320
319
|
DOM.setAttrOrProp(el, key, Signal.get(signal))
|
|
321
320
|
None
|
|
@@ -324,7 +323,7 @@ module Render = {
|
|
|
324
323
|
addDisposer(owner, disposer)
|
|
325
324
|
}
|
|
326
325
|
| Compute(compute) => {
|
|
327
|
-
let disposer = Effect.
|
|
326
|
+
let disposer = Effect.runWithDisposer(
|
|
328
327
|
() => {
|
|
329
328
|
DOM.setAttrOrProp(el, key, compute())
|
|
330
329
|
None
|
|
@@ -479,7 +478,7 @@ module Render = {
|
|
|
479
478
|
fragment->DOM.appendChild(endAnchor)
|
|
480
479
|
|
|
481
480
|
runWithOwner(owner, () => {
|
|
482
|
-
let disposer = Effect.
|
|
481
|
+
let disposer = Effect.runWithDisposer(() => {
|
|
483
482
|
reconcile()
|
|
484
483
|
None
|
|
485
484
|
})
|
|
@@ -499,23 +498,17 @@ module Render = {
|
|
|
499
498
|
/* Text nodes */
|
|
500
499
|
let text = (content: string): node => Text(content)
|
|
501
500
|
|
|
502
|
-
let
|
|
501
|
+
let signalText = (compute: unit => string): node => {
|
|
503
502
|
let signal = Computed.make(compute)
|
|
504
503
|
SignalText(signal)
|
|
505
504
|
}
|
|
506
505
|
|
|
507
|
-
|
|
508
|
-
let reactiveString = (compute: unit => string): node => {
|
|
509
|
-
let signal = Computed.make(compute)
|
|
510
|
-
SignalText(signal)
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
let reactiveInt = (compute: unit => int): node => {
|
|
506
|
+
let signalInt = (compute: unit => int): node => {
|
|
514
507
|
let signal = Computed.make(() => compute()->Int.toString)
|
|
515
508
|
SignalText(signal)
|
|
516
509
|
}
|
|
517
510
|
|
|
518
|
-
let
|
|
511
|
+
let signalFloat = (compute: unit => float): node => {
|
|
519
512
|
let signal = Computed.make(() => compute()->Float.toString)
|
|
520
513
|
SignalText(signal)
|
|
521
514
|
}
|
|
@@ -559,22 +552,6 @@ let element = (
|
|
|
559
552
|
(),
|
|
560
553
|
): node => Element({tag, attrs, events, children})
|
|
561
554
|
|
|
562
|
-
/* Common elements */
|
|
563
|
-
let div = (~attrs=?, ~events=?, ~children=?, ()) =>
|
|
564
|
-
element("div", ~attrs?, ~events?, ~children?, ())
|
|
565
|
-
let span = (~attrs=?, ~events=?, ~children=?, ()) =>
|
|
566
|
-
element("span", ~attrs?, ~events?, ~children?, ())
|
|
567
|
-
let button = (~attrs=?, ~events=?, ~children=?, ()) =>
|
|
568
|
-
element("button", ~attrs?, ~events?, ~children?, ())
|
|
569
|
-
let input = (~attrs=?, ~events=?, ()) => element("input", ~attrs?, ~events?, ())
|
|
570
|
-
let h1 = (~attrs=?, ~events=?, ~children=?, ()) => element("h1", ~attrs?, ~events?, ~children?, ())
|
|
571
|
-
let h2 = (~attrs=?, ~events=?, ~children=?, ()) => element("h2", ~attrs?, ~events?, ~children?, ())
|
|
572
|
-
let h3 = (~attrs=?, ~events=?, ~children=?, ()) => element("h3", ~attrs?, ~events?, ~children?, ())
|
|
573
|
-
let p = (~attrs=?, ~events=?, ~children=?, ()) => element("p", ~attrs?, ~events?, ~children?, ())
|
|
574
|
-
let ul = (~attrs=?, ~events=?, ~children=?, ()) => element("ul", ~attrs?, ~events?, ~children?, ())
|
|
575
|
-
let li = (~attrs=?, ~events=?, ~children=?, ()) => element("li", ~attrs?, ~events?, ~children?, ())
|
|
576
|
-
let a = (~attrs=?, ~events=?, ~children=?, ()) => element("a", ~attrs?, ~events?, ~children?, ())
|
|
577
|
-
|
|
578
555
|
/* Null representation */
|
|
579
556
|
let null = () => text("")
|
|
580
557
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Effect$Xote from "./Effect.res.mjs";
|
|
4
|
+
import * as Signal$Xote from "./Signal.res.mjs";
|
|
4
5
|
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
6
|
+
import * as Computed$Xote from "./Computed.res.mjs";
|
|
5
7
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
8
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
7
9
|
|
|
@@ -115,7 +117,7 @@ function addDisposer(owner, disposer) {
|
|
|
115
117
|
|
|
116
118
|
function disposeOwner(owner) {
|
|
117
119
|
owner.disposers.forEach(disposer => disposer.dispose());
|
|
118
|
-
owner.computeds.forEach(
|
|
120
|
+
owner.computeds.forEach(Computed$Xote.dispose);
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
function setOwner(element, owner) {
|
|
@@ -203,14 +205,14 @@ function render(node) {
|
|
|
203
205
|
return setAttrOrProp(el, key, value._0);
|
|
204
206
|
case "SignalValue" :
|
|
205
207
|
let signal = value._0;
|
|
206
|
-
setAttrOrProp(el, key,
|
|
207
|
-
let disposer =
|
|
208
|
-
setAttrOrProp(el, key,
|
|
208
|
+
setAttrOrProp(el, key, Signal$Xote.peek(signal));
|
|
209
|
+
let disposer = Effect$Xote.runWithDisposer(() => {
|
|
210
|
+
setAttrOrProp(el, key, Signal$Xote.get(signal));
|
|
209
211
|
}, undefined);
|
|
210
212
|
return addDisposer(owner, disposer);
|
|
211
213
|
case "Compute" :
|
|
212
214
|
let compute = value._0;
|
|
213
|
-
let disposer$1 =
|
|
215
|
+
let disposer$1 = Effect$Xote.runWithDisposer(() => {
|
|
214
216
|
setAttrOrProp(el, key, compute());
|
|
215
217
|
}, undefined);
|
|
216
218
|
return addDisposer(owner, disposer$1);
|
|
@@ -229,15 +231,15 @@ function render(node) {
|
|
|
229
231
|
return document.createTextNode(node._0);
|
|
230
232
|
case "SignalText" :
|
|
231
233
|
let signal = node._0;
|
|
232
|
-
let textNode = document.createTextNode(
|
|
234
|
+
let textNode = document.createTextNode(Signal$Xote.peek(signal));
|
|
233
235
|
let owner$1 = {
|
|
234
236
|
disposers: [],
|
|
235
237
|
computeds: []
|
|
236
238
|
};
|
|
237
239
|
setOwner(textNode, owner$1);
|
|
238
240
|
runWithOwner(owner$1, () => {
|
|
239
|
-
let disposer =
|
|
240
|
-
textNode.textContent =
|
|
241
|
+
let disposer = Effect$Xote.runWithDisposer(() => {
|
|
242
|
+
textNode.textContent = Signal$Xote.get(signal);
|
|
241
243
|
}, undefined);
|
|
242
244
|
addDisposer(owner$1, disposer);
|
|
243
245
|
});
|
|
@@ -259,8 +261,8 @@ function render(node) {
|
|
|
259
261
|
container.setAttribute("style", "display: contents");
|
|
260
262
|
setOwner(container, owner$2);
|
|
261
263
|
runWithOwner(owner$2, () => {
|
|
262
|
-
let disposer =
|
|
263
|
-
let children =
|
|
264
|
+
let disposer = Effect$Xote.runWithDisposer(() => {
|
|
265
|
+
let children = Signal$Xote.get(signal$1);
|
|
264
266
|
let childNodes = (Array.from(container.childNodes || []));
|
|
265
267
|
childNodes.forEach(disposeElement);
|
|
266
268
|
((container.innerHTML = ''));
|
|
@@ -298,7 +300,7 @@ function render(node) {
|
|
|
298
300
|
if (parentOpt == null) {
|
|
299
301
|
return;
|
|
300
302
|
}
|
|
301
|
-
let newItems =
|
|
303
|
+
let newItems = Signal$Xote.get(signal$2);
|
|
302
304
|
let newKeyMap = {};
|
|
303
305
|
newItems.forEach(item => {
|
|
304
306
|
newKeyMap[keyFn(item)] = item;
|
|
@@ -384,7 +386,7 @@ function render(node) {
|
|
|
384
386
|
};
|
|
385
387
|
let fragment$1 = document.createDocumentFragment();
|
|
386
388
|
fragment$1.appendChild(startAnchor);
|
|
387
|
-
let initialItems =
|
|
389
|
+
let initialItems = Signal$Xote.peek(signal$2);
|
|
388
390
|
initialItems.forEach(item => {
|
|
389
391
|
let key = keyFn(item);
|
|
390
392
|
let node = renderItem(item);
|
|
@@ -399,7 +401,7 @@ function render(node) {
|
|
|
399
401
|
});
|
|
400
402
|
fragment$1.appendChild(endAnchor);
|
|
401
403
|
runWithOwner(owner$4, () => {
|
|
402
|
-
let disposer =
|
|
404
|
+
let disposer = Effect$Xote.runWithDisposer(() => {
|
|
403
405
|
reconcile();
|
|
404
406
|
}, undefined);
|
|
405
407
|
addDisposer(owner$4, disposer);
|
|
@@ -420,32 +422,24 @@ function text(content) {
|
|
|
420
422
|
};
|
|
421
423
|
}
|
|
422
424
|
|
|
423
|
-
function
|
|
424
|
-
let signal =
|
|
425
|
+
function signalText(compute) {
|
|
426
|
+
let signal = Computed$Xote.make(compute, undefined);
|
|
425
427
|
return {
|
|
426
428
|
TAG: "SignalText",
|
|
427
429
|
_0: signal
|
|
428
430
|
};
|
|
429
431
|
}
|
|
430
432
|
|
|
431
|
-
function
|
|
432
|
-
let signal =
|
|
433
|
+
function signalInt(compute) {
|
|
434
|
+
let signal = Computed$Xote.make(() => compute().toString(), undefined);
|
|
433
435
|
return {
|
|
434
436
|
TAG: "SignalText",
|
|
435
437
|
_0: signal
|
|
436
438
|
};
|
|
437
439
|
}
|
|
438
440
|
|
|
439
|
-
function
|
|
440
|
-
let signal =
|
|
441
|
-
return {
|
|
442
|
-
TAG: "SignalText",
|
|
443
|
-
_0: signal
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
function reactiveFloat(compute) {
|
|
448
|
-
let signal = Signals.Computed.make(() => compute().toString(), undefined);
|
|
441
|
+
function signalFloat(compute) {
|
|
442
|
+
let signal = Computed$Xote.make(() => compute().toString(), undefined);
|
|
449
443
|
return {
|
|
450
444
|
TAG: "SignalText",
|
|
451
445
|
_0: signal
|
|
@@ -481,7 +475,7 @@ function signalFragment(signal) {
|
|
|
481
475
|
}
|
|
482
476
|
|
|
483
477
|
function list(signal, renderItem) {
|
|
484
|
-
let nodesSignal =
|
|
478
|
+
let nodesSignal = Computed$Xote.make(() => Signal$Xote.get(signal).map(renderItem), undefined);
|
|
485
479
|
return {
|
|
486
480
|
TAG: "SignalFragment",
|
|
487
481
|
_0: nodesSignal
|
|
@@ -510,50 +504,6 @@ function element(tag, attrsOpt, eventsOpt, childrenOpt, param) {
|
|
|
510
504
|
};
|
|
511
505
|
}
|
|
512
506
|
|
|
513
|
-
function div(attrs, events, children, param) {
|
|
514
|
-
return element("div", attrs, events, children, undefined);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
function span(attrs, events, children, param) {
|
|
518
|
-
return element("span", attrs, events, children, undefined);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
function button(attrs, events, children, param) {
|
|
522
|
-
return element("button", attrs, events, children, undefined);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
function input(attrs, events, param) {
|
|
526
|
-
return element("input", attrs, events, undefined, undefined);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
function h1(attrs, events, children, param) {
|
|
530
|
-
return element("h1", attrs, events, children, undefined);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
function h2(attrs, events, children, param) {
|
|
534
|
-
return element("h2", attrs, events, children, undefined);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
function h3(attrs, events, children, param) {
|
|
538
|
-
return element("h3", attrs, events, children, undefined);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
function p(attrs, events, children, param) {
|
|
542
|
-
return element("p", attrs, events, children, undefined);
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
function ul(attrs, events, children, param) {
|
|
546
|
-
return element("ul", attrs, events, children, undefined);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
function li(attrs, events, children, param) {
|
|
550
|
-
return element("li", attrs, events, children, undefined);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
function a(attrs, events, children, param) {
|
|
554
|
-
return element("a", attrs, events, children, undefined);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
507
|
function $$null() {
|
|
558
508
|
return {
|
|
559
509
|
TAG: "Text",
|
|
@@ -597,10 +547,9 @@ export {
|
|
|
597
547
|
computedAttr,
|
|
598
548
|
Render,
|
|
599
549
|
text,
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
reactiveFloat,
|
|
550
|
+
signalText,
|
|
551
|
+
signalInt,
|
|
552
|
+
signalFloat,
|
|
604
553
|
int,
|
|
605
554
|
float,
|
|
606
555
|
fragment,
|
|
@@ -608,17 +557,6 @@ export {
|
|
|
608
557
|
list,
|
|
609
558
|
keyedList,
|
|
610
559
|
element,
|
|
611
|
-
div,
|
|
612
|
-
span,
|
|
613
|
-
button,
|
|
614
|
-
input,
|
|
615
|
-
h1,
|
|
616
|
-
h2,
|
|
617
|
-
h3,
|
|
618
|
-
p,
|
|
619
|
-
ul,
|
|
620
|
-
li,
|
|
621
|
-
a,
|
|
622
560
|
$$null,
|
|
623
561
|
mount,
|
|
624
562
|
mountById,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Signal$Xote from "./Signal.res.mjs";
|
|
4
4
|
|
|
5
5
|
function get(value) {
|
|
6
6
|
if (value.TAG === "Reactive") {
|
|
7
|
-
return
|
|
7
|
+
return Signal$Xote.get(value._0);
|
|
8
8
|
} else {
|
|
9
9
|
return value._0;
|
|
10
10
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
module Component = Xote__Component
|
|
3
|
-
module Route = Xote__Route
|
|
1
|
+
module Route = Route
|
|
4
2
|
|
|
5
3
|
// Browser location type
|
|
6
4
|
type location = {
|
|
@@ -57,7 +55,8 @@ let getGlobalState = (): globalRouterState => {
|
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
// Store in globalThis using the same symbol
|
|
60
|
-
|
|
58
|
+
ignore(state)
|
|
59
|
+
let _: unit = %raw(`globalThis[Symbol.for("xote.router.state")] = state`)
|
|
61
60
|
state
|
|
62
61
|
}
|
|
63
62
|
}
|
|
@@ -72,7 +71,8 @@ let basePath = (): ref<string> => getGlobalState().basePath
|
|
|
72
71
|
let warnIfNotInitialized = (methodName: string): unit => {
|
|
73
72
|
let state = getGlobalState()
|
|
74
73
|
if !state.initialized {
|
|
75
|
-
|
|
74
|
+
ignore(methodName)
|
|
75
|
+
let _: unit = %raw(`console.warn(
|
|
76
76
|
'[Xote Router] ' + methodName + ' called before Router.init(). ' +
|
|
77
77
|
'Make sure to call Router.init() at your app entry point. ' +
|
|
78
78
|
'This may cause incorrect routing behavior.'
|
|
@@ -147,11 +147,15 @@ let getScrollPosition = (): (float, float) => {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
let scrollTo = (x: float, y: float): unit => {
|
|
150
|
-
|
|
150
|
+
ignore(x)
|
|
151
|
+
ignore(y)
|
|
152
|
+
let _: unit = %raw(`window.scrollTo(x, y)`)
|
|
151
153
|
}
|
|
152
154
|
|
|
153
155
|
// Create history state with scroll position
|
|
154
156
|
let makeHistoryState = (scrollX: float, scrollY: float): historyState => {
|
|
157
|
+
ignore(scrollX)
|
|
158
|
+
ignore(scrollY)
|
|
155
159
|
%raw(`({ scrollX: scrollX, scrollY: scrollY })`)
|
|
156
160
|
}
|
|
157
161
|
|
|
@@ -161,6 +165,7 @@ let emptyHistoryState = (): historyState => {
|
|
|
161
165
|
|
|
162
166
|
// Extract scroll position from history state
|
|
163
167
|
let getScrollFromState = (state: historyState): option<(float, float)> => {
|
|
168
|
+
ignore(state)
|
|
164
169
|
let scrollX: Nullable.t<float> = %raw(`state && state.scrollX`)
|
|
165
170
|
let scrollY: Nullable.t<float> = %raw(`state && state.scrollY`)
|
|
166
171
|
switch (Nullable.toOption(scrollX), Nullable.toOption(scrollY)) {
|
|
@@ -298,11 +303,11 @@ let replace = (pathname: string, ~search: string="", ~hash: string="", ()): unit
|
|
|
298
303
|
// Route definition for routes() component
|
|
299
304
|
type routeConfig = {
|
|
300
305
|
pattern: string,
|
|
301
|
-
render: Route.params =>
|
|
306
|
+
render: Route.params => Node.node,
|
|
302
307
|
}
|
|
303
308
|
|
|
304
309
|
// Single route component - renders if pattern matches
|
|
305
|
-
let route = (pattern: string, render: Route.params =>
|
|
310
|
+
let route = (pattern: string, render: Route.params => Node.node): Node.node => {
|
|
306
311
|
warnIfNotInitialized("Router.route()")
|
|
307
312
|
|
|
308
313
|
let signal = Computed.make(() => {
|
|
@@ -312,11 +317,11 @@ let route = (pattern: string, render: Route.params => Component.node): Component
|
|
|
312
317
|
| NoMatch => []
|
|
313
318
|
}
|
|
314
319
|
})
|
|
315
|
-
|
|
320
|
+
Node.signalFragment(signal)
|
|
316
321
|
}
|
|
317
322
|
|
|
318
323
|
// Routes component - renders first matching route
|
|
319
|
-
let routes = (configs: array<routeConfig>):
|
|
324
|
+
let routes = (configs: array<routeConfig>): Node.node => {
|
|
320
325
|
warnIfNotInitialized("Router.routes()")
|
|
321
326
|
|
|
322
327
|
let signal = Computed.make(() => {
|
|
@@ -333,25 +338,25 @@ let routes = (configs: array<routeConfig>): Component.node => {
|
|
|
333
338
|
| None => [] // No matching route - render nothing
|
|
334
339
|
}
|
|
335
340
|
})
|
|
336
|
-
|
|
341
|
+
Node.signalFragment(signal)
|
|
337
342
|
}
|
|
338
343
|
|
|
339
344
|
// Link component - handles navigation without page reload
|
|
340
345
|
let link = (
|
|
341
346
|
~to: string,
|
|
342
|
-
~attrs: array<(string,
|
|
343
|
-
~children: array<
|
|
347
|
+
~attrs: array<(string, Node.attrValue)>=[],
|
|
348
|
+
~children: array<Node.node>=[],
|
|
344
349
|
(),
|
|
345
|
-
):
|
|
350
|
+
): Node.node => {
|
|
346
351
|
warnIfNotInitialized("Router.link()")
|
|
347
352
|
|
|
348
353
|
let handleClick = (_evt: Dom.event) => {
|
|
349
|
-
%raw(`_evt.preventDefault()`)
|
|
354
|
+
let _: unit = %raw(`_evt.preventDefault()`)
|
|
350
355
|
push(to, ())
|
|
351
356
|
}
|
|
352
357
|
|
|
353
|
-
|
|
354
|
-
~attrs=Array.concat(attrs, [
|
|
358
|
+
Html.a(
|
|
359
|
+
~attrs=Array.concat(attrs, [Node.attr("href", addBasePath(to))]),
|
|
355
360
|
~events=[("click", handleClick)],
|
|
356
361
|
~children,
|
|
357
362
|
(),
|
|
@@ -360,7 +365,7 @@ let link = (
|
|
|
360
365
|
|
|
361
366
|
// JSX Link component
|
|
362
367
|
module Link = {
|
|
363
|
-
module ReactiveProp =
|
|
368
|
+
module ReactiveProp = ReactiveProp
|
|
364
369
|
|
|
365
370
|
type props<'class, 'id, 'style, 'target, 'ariaLabel> = {
|
|
366
371
|
/* Required navigation prop */
|
|
@@ -374,36 +379,37 @@ module Link = {
|
|
|
374
379
|
/* Event handlers */
|
|
375
380
|
onClick?: Dom.event => unit,
|
|
376
381
|
/* Children */
|
|
377
|
-
children?:
|
|
382
|
+
children?: Node.node,
|
|
378
383
|
}
|
|
379
384
|
|
|
380
385
|
/* Helper to detect if a value is a ReactiveProp variant */
|
|
381
386
|
let isReactiveProp = (value: 'a): bool => {
|
|
387
|
+
ignore(value)
|
|
382
388
|
%raw(`value && typeof value === 'object' && ('TAG' in value) && (value.TAG === 'Static' || value.TAG === 'Reactive')`)
|
|
383
389
|
}
|
|
384
390
|
|
|
385
391
|
/* Helper to convert string attribute value */
|
|
386
|
-
let convertAttrValue = (key: string, value: 'a): (string,
|
|
392
|
+
let convertAttrValue = (key: string, value: 'a): (string, Node.attrValue) => {
|
|
387
393
|
if isReactiveProp(value) {
|
|
388
394
|
let rp: ReactiveProp.t<string> = Obj.magic(value)
|
|
389
395
|
switch rp {
|
|
390
|
-
| Static(s) =>
|
|
391
|
-
| Reactive(signal) =>
|
|
396
|
+
| Static(s) => Node.attr(key, s)
|
|
397
|
+
| Reactive(signal) => Node.signalAttr(key, signal)
|
|
392
398
|
}
|
|
393
399
|
} else if typeof(value) == #function {
|
|
394
400
|
let f: unit => string = Obj.magic(value)
|
|
395
|
-
|
|
401
|
+
Node.computedAttr(key, f)
|
|
396
402
|
} else if typeof(value) == #object {
|
|
397
403
|
let sig: Signal.t<string> = Obj.magic(value)
|
|
398
|
-
|
|
404
|
+
Node.signalAttr(key, sig)
|
|
399
405
|
} else {
|
|
400
406
|
let s: string = Obj.magic(value)
|
|
401
|
-
|
|
407
|
+
Node.attr(key, s)
|
|
402
408
|
}
|
|
403
409
|
}
|
|
404
410
|
|
|
405
411
|
/* Convert props to attrs array */
|
|
406
|
-
let propsToAttrs = (props: props<_, _, _, _, _>): array<(string,
|
|
412
|
+
let propsToAttrs = (props: props<_, _, _, _, _>): array<(string, Node.attrValue)> => {
|
|
407
413
|
let attrs = []
|
|
408
414
|
|
|
409
415
|
switch props.class {
|
|
@@ -435,20 +441,20 @@ module Link = {
|
|
|
435
441
|
}
|
|
436
442
|
|
|
437
443
|
/* Extract children from props */
|
|
438
|
-
let getChildren = (props: props<_, _, _, _, _>): array<
|
|
444
|
+
let getChildren = (props: props<_, _, _, _, _>): array<Node.node> => {
|
|
439
445
|
switch props.children {
|
|
440
|
-
| Some(
|
|
446
|
+
| Some(Node.Fragment(children)) => children
|
|
441
447
|
| Some(child) => [child]
|
|
442
448
|
| None => []
|
|
443
449
|
}
|
|
444
450
|
}
|
|
445
451
|
|
|
446
452
|
/* JSX component function */
|
|
447
|
-
let make = (props: props<_, _, _, _, _>):
|
|
453
|
+
let make = (props: props<_, _, _, _, _>): Node.node => {
|
|
448
454
|
warnIfNotInitialized("Router.Link")
|
|
449
455
|
|
|
450
456
|
let handleClick = (evt: Dom.event) => {
|
|
451
|
-
%raw(`evt.preventDefault()`)
|
|
457
|
+
let _: unit = %raw(`evt.preventDefault()`)
|
|
452
458
|
push(props.to, ())
|
|
453
459
|
|
|
454
460
|
// Call user's onClick if provided
|
|
@@ -458,8 +464,8 @@ module Link = {
|
|
|
458
464
|
}
|
|
459
465
|
}
|
|
460
466
|
|
|
461
|
-
|
|
462
|
-
~attrs=Array.concat(propsToAttrs(props), [
|
|
467
|
+
Html.a(
|
|
468
|
+
~attrs=Array.concat(propsToAttrs(props), [Node.attr("href", addBasePath(props.to))]),
|
|
463
469
|
~events=[("click", handleClick)],
|
|
464
470
|
~children=getChildren(props),
|
|
465
471
|
(),
|