xote 6.1.2 → 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 +10 -10
- package/dist/xote.mjs +1491 -1330
- package/dist/xote.umd.js +8 -8
- 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 -594
- package/src/Node.res.mjs +31 -535
- 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/Hydration.res
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
module DOM =
|
|
2
|
-
module Reactivity =
|
|
1
|
+
module DOM = View.DOM
|
|
2
|
+
module Reactivity = View.Reactivity
|
|
3
|
+
module Markers = RuntimeHydrationMarkers
|
|
3
4
|
|
|
4
5
|
/* ============================================================================
|
|
5
6
|
* Hydration Options
|
|
@@ -15,7 +16,7 @@ type hydrateOptions = {
|
|
|
15
16
|
* ============================================================================ */
|
|
16
17
|
|
|
17
18
|
module DOMWalker = {
|
|
18
|
-
/*
|
|
19
|
+
/* View types */
|
|
19
20
|
let elementNode = 1
|
|
20
21
|
let textNode = 3
|
|
21
22
|
let commentNode = 8
|
|
@@ -66,7 +67,8 @@ module DOMWalker = {
|
|
|
66
67
|
let extractKey = (node: Dom.element): option<string> => {
|
|
67
68
|
if nodeType(node) == commentNode {
|
|
68
69
|
switch nodeValue(node)->Nullable.toOption {
|
|
69
|
-
| Some(value) if String.startsWith(value,
|
|
70
|
+
| Some(value) if String.startsWith(value, Markers.keyedItemPrefixContent) =>
|
|
71
|
+
Some(String.slice(value, ~start=String.length(Markers.keyedItemPrefixContent)))
|
|
70
72
|
| _ => None
|
|
71
73
|
}
|
|
72
74
|
} else {
|
|
@@ -155,12 +157,12 @@ let logHydrationWarning = (msg: string): unit => {
|
|
|
155
157
|
* ============================================================================ */
|
|
156
158
|
|
|
157
159
|
/* Hydrate a single node, attaching reactivity to existing DOM */
|
|
158
|
-
let rec hydrateNode = (node:
|
|
160
|
+
let rec hydrateNode = (node: View.node, domNode: Dom.element): unit => {
|
|
159
161
|
switch node {
|
|
160
|
-
|
|
|
162
|
+
| View.Text(_content) => /* Static text - nothing to hydrate, DOM already has the content */
|
|
161
163
|
()
|
|
162
164
|
|
|
163
|
-
|
|
|
165
|
+
| View.SignalText(signal) => {
|
|
164
166
|
/*
|
|
165
167
|
* Server rendered: <!--$-->text<!--/$-->
|
|
166
168
|
* We need to find the text node between markers and attach an effect
|
|
@@ -177,7 +179,7 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
177
179
|
})
|
|
178
180
|
}
|
|
179
181
|
|
|
180
|
-
|
|
|
182
|
+
| View.Fragment(children) => {
|
|
181
183
|
/* Fragment children are directly in the parent - hydrate each */
|
|
182
184
|
let walker = DOMWalker.make(domNode)
|
|
183
185
|
children->Array.forEach(child => {
|
|
@@ -185,36 +187,60 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
185
187
|
})
|
|
186
188
|
}
|
|
187
189
|
|
|
188
|
-
|
|
|
190
|
+
| View.SignalFragment(signal) => {
|
|
189
191
|
/*
|
|
190
192
|
* Server rendered: <!--#-->...children...<!--/#-->
|
|
191
193
|
* We need to replace the content when the signal changes
|
|
192
194
|
*/
|
|
193
195
|
let owner = Reactivity.createOwner()
|
|
194
196
|
Reactivity.setOwner(domNode, owner)
|
|
197
|
+
let keyedItems: Dict.t<View.Render.keyedItem<Obj.t>> = Dict.make()
|
|
198
|
+
let initialized = ref(false)
|
|
195
199
|
|
|
196
200
|
Reactivity.runWithOwner(owner, () => {
|
|
197
201
|
let disposer = Effect.runWithDisposer(() => {
|
|
198
202
|
let children = Signal.get(signal)
|
|
199
203
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
switch View.Render.getKeyedChildren(children) {
|
|
205
|
+
| Some(keyedChildren) if initialized.contents =>
|
|
206
|
+
View.Render.reconcileKeyedChildren(~keyedChildren, ~keyedItems, ~parent=domNode)
|
|
207
|
+
| keyedChildrenOpt => {
|
|
208
|
+
View.Render.clearKeyedItems(keyedItems)
|
|
209
|
+
|
|
210
|
+
/* Clear existing children */
|
|
211
|
+
let childNodes: array<Dom.element> = %raw(`Array.from(domNode.childNodes || [])`)
|
|
212
|
+
childNodes->Array.forEach(
|
|
213
|
+
child => {
|
|
214
|
+
Reactivity.disposeOwner(
|
|
215
|
+
Reactivity.getOwner(child)->Option.getOr(Reactivity.createOwner()),
|
|
216
|
+
)
|
|
217
|
+
},
|
|
206
218
|
)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
219
|
+
DOM.setInnerHTML(domNode, "")
|
|
220
|
+
|
|
221
|
+
switch keyedChildrenOpt {
|
|
222
|
+
| Some(keyedChildren) =>
|
|
223
|
+
keyedChildren->Array.forEach(keyedChild => {
|
|
224
|
+
let childEl = View.Render.render(keyedChild.child)
|
|
225
|
+
keyedItems->Dict.set(keyedChild.key, {
|
|
226
|
+
key: keyedChild.key,
|
|
227
|
+
item: keyedChild.identity,
|
|
228
|
+
element: childEl,
|
|
229
|
+
})
|
|
230
|
+
domNode->DOM.appendChild(childEl)
|
|
231
|
+
})
|
|
232
|
+
| None =>
|
|
233
|
+
children->Array.forEach(
|
|
234
|
+
child => {
|
|
235
|
+
let childEl = View.Render.render(child)
|
|
236
|
+
domNode->DOM.appendChild(childEl)
|
|
237
|
+
},
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
initialized := true
|
|
242
|
+
}
|
|
243
|
+
}
|
|
218
244
|
|
|
219
245
|
None
|
|
220
246
|
})
|
|
@@ -222,7 +248,9 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
222
248
|
})
|
|
223
249
|
}
|
|
224
250
|
|
|
225
|
-
|
|
|
251
|
+
| View.Keyed({child, key: _, identity: _}) => hydrateNode(child, domNode)
|
|
252
|
+
|
|
253
|
+
| View.Element({attrs, events, children}) => {
|
|
226
254
|
let owner = Reactivity.createOwner()
|
|
227
255
|
Reactivity.setOwner(domNode, owner)
|
|
228
256
|
|
|
@@ -230,8 +258,8 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
230
258
|
/* Hydrate reactive attributes */
|
|
231
259
|
attrs->Array.forEach(((key, value)) => {
|
|
232
260
|
switch value {
|
|
233
|
-
|
|
|
234
|
-
|
|
|
261
|
+
| View.Static(_) => () /* Already rendered, nothing to do */
|
|
262
|
+
| View.SignalValue(signal) => {
|
|
235
263
|
let disposer = Effect.runWithDisposer(
|
|
236
264
|
() => {
|
|
237
265
|
DOM.setAttrOrProp(domNode, key, Signal.get(signal))
|
|
@@ -240,7 +268,7 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
240
268
|
)
|
|
241
269
|
Reactivity.addDisposer(owner, disposer)
|
|
242
270
|
}
|
|
243
|
-
|
|
|
271
|
+
| View.Compute(compute) => {
|
|
244
272
|
let disposer = Effect.runWithDisposer(
|
|
245
273
|
() => {
|
|
246
274
|
DOM.setAttrOrProp(domNode, key, compute())
|
|
@@ -265,7 +293,7 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
265
293
|
})
|
|
266
294
|
}
|
|
267
295
|
|
|
268
|
-
|
|
|
296
|
+
| View.LazyComponent(fn) => {
|
|
269
297
|
/* Execute lazy component and hydrate its result */
|
|
270
298
|
let owner = Reactivity.createOwner()
|
|
271
299
|
let childNode = Reactivity.runWithOwner(owner, fn)
|
|
@@ -273,7 +301,7 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
273
301
|
hydrateNode(childNode, domNode)
|
|
274
302
|
}
|
|
275
303
|
|
|
276
|
-
|
|
|
304
|
+
| View.KeyedList({signal, keyFn, renderItem}) => {
|
|
277
305
|
/*
|
|
278
306
|
* Server rendered: <!--kl--><!--k:key1-->item1<!--/k--><!--k:key2-->item2<!--/k--><!--/kl-->
|
|
279
307
|
* We need to set up the reconciliation effect
|
|
@@ -282,21 +310,21 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
282
310
|
Reactivity.setOwner(domNode, owner)
|
|
283
311
|
|
|
284
312
|
/* Build initial key -> element map from existing DOM */
|
|
285
|
-
let keyedItems: Dict.t<
|
|
313
|
+
let keyedItems: Dict.t<View.Render.keyedItem<Obj.t>> = Dict.make()
|
|
286
314
|
let walker = DOMWalker.make(domNode)
|
|
287
315
|
|
|
288
316
|
/* Skip to list start marker */
|
|
289
|
-
let _ = DOMWalker.skipUntilMarker(walker,
|
|
317
|
+
let _ = DOMWalker.skipUntilMarker(walker, Markers.keyedListStartContent)
|
|
290
318
|
|
|
291
319
|
/* Parse existing keyed items */
|
|
292
320
|
let rec parseKeyedItems = () => {
|
|
293
321
|
switch DOMWalker.peek(walker) {
|
|
294
|
-
| Some(node) if DOMWalker.isMarkerPrefix(node,
|
|
322
|
+
| Some(node) if DOMWalker.isMarkerPrefix(node, Markers.keyedItemPrefixContent) => {
|
|
295
323
|
let key = DOMWalker.extractKey(node)->Option.getOr("")
|
|
296
324
|
let _ = DOMWalker.next(walker) // consume start marker
|
|
297
325
|
|
|
298
326
|
/* Collect item elements until end marker */
|
|
299
|
-
let itemElements = DOMWalker.collectUntilMarker(walker,
|
|
327
|
+
let itemElements = DOMWalker.collectUntilMarker(walker, Markers.keyedItemEndContent)
|
|
300
328
|
|
|
301
329
|
/* Get the first actual element (skip text nodes) */
|
|
302
330
|
switch itemElements->Array.find(el => DOMWalker.nodeType(el) == DOMWalker.elementNode) {
|
|
@@ -311,7 +339,7 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
311
339
|
|
|
312
340
|
parseKeyedItems()
|
|
313
341
|
}
|
|
314
|
-
| Some(node) if DOMWalker.isMarker(node,
|
|
342
|
+
| Some(node) if DOMWalker.isMarker(node, Markers.keyedListEndContent) => {
|
|
315
343
|
let _ = DOMWalker.next(walker) // consume end marker
|
|
316
344
|
}
|
|
317
345
|
| _ => ()
|
|
@@ -353,8 +381,8 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
353
381
|
keysToRemove->Array.forEach(key => {
|
|
354
382
|
switch keyedItems->Dict.get(key) {
|
|
355
383
|
| Some(keyedItem) => {
|
|
356
|
-
|
|
357
|
-
|
|
384
|
+
View.Render.disposeElement(keyedItem.element)
|
|
385
|
+
keyedItem.element->DOM.remove
|
|
358
386
|
keyedItems->Dict.delete(key)->ignore
|
|
359
387
|
}
|
|
360
388
|
| None => ()
|
|
@@ -362,7 +390,7 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
362
390
|
})
|
|
363
391
|
|
|
364
392
|
/* Build new order */
|
|
365
|
-
let newOrder: array<
|
|
393
|
+
let newOrder: array<View.Render.keyedItem<Obj.t>> = []
|
|
366
394
|
let elementsToReplace: Dict.t<bool> = Dict.make()
|
|
367
395
|
|
|
368
396
|
newItems->Array.forEach(item => {
|
|
@@ -373,8 +401,8 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
373
401
|
if existing.item !== item {
|
|
374
402
|
elementsToReplace->Dict.set(key, true)
|
|
375
403
|
let node = renderItem(item)
|
|
376
|
-
let element =
|
|
377
|
-
let keyedItem:
|
|
404
|
+
let element = View.Render.render(node)
|
|
405
|
+
let keyedItem: View.Render.keyedItem<Obj.t> = {key, item, element}
|
|
378
406
|
newOrder->Array.push(keyedItem)->ignore
|
|
379
407
|
keyedItems->Dict.set(key, keyedItem)
|
|
380
408
|
} else {
|
|
@@ -382,8 +410,8 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
382
410
|
}
|
|
383
411
|
| None => {
|
|
384
412
|
let node = renderItem(item)
|
|
385
|
-
let element =
|
|
386
|
-
let keyedItem:
|
|
413
|
+
let element = View.Render.render(node)
|
|
414
|
+
let keyedItem: View.Render.keyedItem<Obj.t> = {key, item, element}
|
|
387
415
|
newOrder->Array.push(keyedItem)->ignore
|
|
388
416
|
keyedItems->Dict.set(key, keyedItem)
|
|
389
417
|
}
|
|
@@ -405,7 +433,7 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
405
433
|
elementsToReplace->Dict.get(keyedItem.key)->Option.getOr(false)
|
|
406
434
|
|
|
407
435
|
if needsReplacement {
|
|
408
|
-
|
|
436
|
+
View.Render.disposeElement(elem)
|
|
409
437
|
DOM.replaceChild(domNode, keyedItem.element, elem)
|
|
410
438
|
marker := DOM.getNextSibling(keyedItem.element)
|
|
411
439
|
} else {
|
|
@@ -429,16 +457,16 @@ let rec hydrateNode = (node: Node.node, domNode: Dom.element): unit => {
|
|
|
429
457
|
}
|
|
430
458
|
|
|
431
459
|
/* Hydrate using a walker (for traversing children) */
|
|
432
|
-
and hydrateNodeWithWalker = (node:
|
|
460
|
+
and hydrateNodeWithWalker = (node: View.node, walker: DOMWalker.t): unit => {
|
|
433
461
|
switch node {
|
|
434
|
-
|
|
|
462
|
+
| View.Text(_) => {
|
|
435
463
|
/* Skip text node in DOM */
|
|
436
464
|
let _ = DOMWalker.next(walker)
|
|
437
465
|
}
|
|
438
466
|
|
|
439
|
-
|
|
|
467
|
+
| View.SignalText(signal) => {
|
|
440
468
|
/* Find the marker, then hydrate the text node */
|
|
441
|
-
let _ = DOMWalker.skipUntilMarker(walker,
|
|
469
|
+
let _ = DOMWalker.skipUntilMarker(walker, Markers.signalTextStartContent)
|
|
442
470
|
|
|
443
471
|
/* Get the text node */
|
|
444
472
|
switch DOMWalker.next(walker) {
|
|
@@ -455,24 +483,24 @@ and hydrateNodeWithWalker = (node: Node.node, walker: DOMWalker.t): unit => {
|
|
|
455
483
|
})
|
|
456
484
|
|
|
457
485
|
/* Skip end marker */
|
|
458
|
-
let _ = DOMWalker.skipUntilMarker(walker,
|
|
486
|
+
let _ = DOMWalker.skipUntilMarker(walker, Markers.signalTextEndContent)
|
|
459
487
|
}
|
|
460
488
|
| None => logHydrationWarning("Missing text node for SignalText")
|
|
461
489
|
}
|
|
462
490
|
}
|
|
463
491
|
|
|
464
|
-
|
|
|
492
|
+
| View.Fragment(children) =>
|
|
465
493
|
/* Fragment children are inline - hydrate each */
|
|
466
494
|
children->Array.forEach(child => {
|
|
467
495
|
hydrateNodeWithWalker(child, walker)
|
|
468
496
|
})
|
|
469
497
|
|
|
470
|
-
|
|
|
498
|
+
| View.SignalFragment(signal) => {
|
|
471
499
|
/* Find the container (div with display:contents in SSR, markers in comments) */
|
|
472
|
-
let _ = DOMWalker.skipUntilMarker(walker,
|
|
500
|
+
let _ = DOMWalker.skipUntilMarker(walker, Markers.signalFragmentStartContent)
|
|
473
501
|
|
|
474
502
|
/* Collect all nodes until end marker - these become the container's content */
|
|
475
|
-
let contentNodes = DOMWalker.collectUntilMarker(walker,
|
|
503
|
+
let contentNodes = DOMWalker.collectUntilMarker(walker, Markers.signalFragmentEndContent)
|
|
476
504
|
|
|
477
505
|
/* Create a container div to hold the signal fragment */
|
|
478
506
|
let container = DOM.createElement("div")
|
|
@@ -502,22 +530,47 @@ and hydrateNodeWithWalker = (node: Node.node, walker: DOMWalker.t): unit => {
|
|
|
502
530
|
/* Set up reactivity */
|
|
503
531
|
let owner = Reactivity.createOwner()
|
|
504
532
|
Reactivity.setOwner(container, owner)
|
|
533
|
+
let keyedItems: Dict.t<View.Render.keyedItem<Obj.t>> = Dict.make()
|
|
534
|
+
let initialized = ref(false)
|
|
505
535
|
|
|
506
536
|
Reactivity.runWithOwner(owner, () => {
|
|
507
537
|
let disposer = Effect.runWithDisposer(() => {
|
|
508
538
|
let children = Signal.get(signal)
|
|
509
539
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
540
|
+
switch View.Render.getKeyedChildren(children) {
|
|
541
|
+
| Some(keyedChildren) if initialized.contents =>
|
|
542
|
+
View.Render.reconcileKeyedChildren(~keyedChildren, ~keyedItems, ~parent=container)
|
|
543
|
+
| keyedChildrenOpt => {
|
|
544
|
+
View.Render.clearKeyedItems(keyedItems)
|
|
545
|
+
|
|
546
|
+
/* Clear and re-render */
|
|
547
|
+
let childNodes: array<Dom.element> = %raw(`Array.from(container.childNodes || [])`)
|
|
548
|
+
childNodes->Array.forEach(View.Render.disposeElement)
|
|
549
|
+
DOM.setInnerHTML(container, "")
|
|
550
|
+
|
|
551
|
+
switch keyedChildrenOpt {
|
|
552
|
+
| Some(keyedChildren) =>
|
|
553
|
+
keyedChildren->Array.forEach(keyedChild => {
|
|
554
|
+
let childEl = View.Render.render(keyedChild.child)
|
|
555
|
+
keyedItems->Dict.set(keyedChild.key, {
|
|
556
|
+
key: keyedChild.key,
|
|
557
|
+
item: keyedChild.identity,
|
|
558
|
+
element: childEl,
|
|
559
|
+
})
|
|
560
|
+
container->DOM.appendChild(childEl)
|
|
561
|
+
})
|
|
562
|
+
| None =>
|
|
563
|
+
children->Array.forEach(
|
|
564
|
+
child => {
|
|
565
|
+
let childEl = View.Render.render(child)
|
|
566
|
+
container->DOM.appendChild(childEl)
|
|
567
|
+
},
|
|
568
|
+
)
|
|
569
|
+
}
|
|
514
570
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
container->DOM.appendChild(childEl)
|
|
519
|
-
},
|
|
520
|
-
)
|
|
571
|
+
initialized := true
|
|
572
|
+
}
|
|
573
|
+
}
|
|
521
574
|
|
|
522
575
|
None
|
|
523
576
|
})
|
|
@@ -525,7 +578,9 @@ and hydrateNodeWithWalker = (node: Node.node, walker: DOMWalker.t): unit => {
|
|
|
525
578
|
})
|
|
526
579
|
}
|
|
527
580
|
|
|
528
|
-
|
|
|
581
|
+
| View.Keyed({child, key: _, identity: _}) => hydrateNodeWithWalker(child, walker)
|
|
582
|
+
|
|
583
|
+
| View.Element({attrs, events, children}) =>
|
|
529
584
|
switch DOMWalker.next(walker) {
|
|
530
585
|
| Some(domNode) => {
|
|
531
586
|
let owner = Reactivity.createOwner()
|
|
@@ -535,8 +590,8 @@ and hydrateNodeWithWalker = (node: Node.node, walker: DOMWalker.t): unit => {
|
|
|
535
590
|
/* Hydrate reactive attributes */
|
|
536
591
|
attrs->Array.forEach(((key, value)) => {
|
|
537
592
|
switch value {
|
|
538
|
-
|
|
|
539
|
-
|
|
|
593
|
+
| View.Static(_) => ()
|
|
594
|
+
| View.SignalValue(signal) => {
|
|
540
595
|
let disposer = Effect.runWithDisposer(
|
|
541
596
|
() => {
|
|
542
597
|
DOM.setAttrOrProp(domNode, key, Signal.get(signal))
|
|
@@ -545,7 +600,7 @@ and hydrateNodeWithWalker = (node: Node.node, walker: DOMWalker.t): unit => {
|
|
|
545
600
|
)
|
|
546
601
|
Reactivity.addDisposer(owner, disposer)
|
|
547
602
|
}
|
|
548
|
-
|
|
|
603
|
+
| View.Compute(compute) => {
|
|
549
604
|
let disposer = Effect.runWithDisposer(
|
|
550
605
|
() => {
|
|
551
606
|
DOM.setAttrOrProp(domNode, key, compute())
|
|
@@ -572,30 +627,30 @@ and hydrateNodeWithWalker = (node: Node.node, walker: DOMWalker.t): unit => {
|
|
|
572
627
|
| None => logHydrationWarning("Missing DOM element for Element node")
|
|
573
628
|
}
|
|
574
629
|
|
|
575
|
-
|
|
|
630
|
+
| View.LazyComponent(fn) => {
|
|
576
631
|
/* Skip the lazy component markers and hydrate the content */
|
|
577
|
-
let _ = DOMWalker.skipUntilMarker(walker,
|
|
632
|
+
let _ = DOMWalker.skipUntilMarker(walker, Markers.lazyComponentStartContent)
|
|
578
633
|
|
|
579
634
|
let childNode = fn()
|
|
580
635
|
hydrateNodeWithWalker(childNode, walker)
|
|
581
636
|
|
|
582
|
-
let _ = DOMWalker.skipUntilMarker(walker,
|
|
637
|
+
let _ = DOMWalker.skipUntilMarker(walker, Markers.lazyComponentEndContent)
|
|
583
638
|
}
|
|
584
639
|
|
|
585
|
-
|
|
|
640
|
+
| View.KeyedList({signal, keyFn, renderItem: _}) => {
|
|
586
641
|
/* Find the keyed list in the DOM */
|
|
587
|
-
let _ = DOMWalker.skipUntilMarker(walker,
|
|
642
|
+
let _ = DOMWalker.skipUntilMarker(walker, Markers.keyedListStartContent)
|
|
588
643
|
|
|
589
644
|
/* Parse existing keyed items from DOM */
|
|
590
|
-
let keyedItems: Dict.t<
|
|
645
|
+
let keyedItems: Dict.t<View.Render.keyedItem<Obj.t>> = Dict.make()
|
|
591
646
|
|
|
592
647
|
let rec parseKeyedItems = () => {
|
|
593
648
|
switch DOMWalker.peek(walker) {
|
|
594
|
-
| Some(node) if DOMWalker.isMarkerPrefix(node,
|
|
649
|
+
| Some(node) if DOMWalker.isMarkerPrefix(node, Markers.keyedItemPrefixContent) => {
|
|
595
650
|
let key = DOMWalker.extractKey(node)->Option.getOr("")
|
|
596
651
|
let _ = DOMWalker.next(walker)
|
|
597
652
|
|
|
598
|
-
let itemElements = DOMWalker.collectUntilMarker(walker,
|
|
653
|
+
let itemElements = DOMWalker.collectUntilMarker(walker, Markers.keyedItemEndContent)
|
|
599
654
|
|
|
600
655
|
switch itemElements->Array.find(el => DOMWalker.nodeType(el) == DOMWalker.elementNode) {
|
|
601
656
|
| Some(element) => {
|
|
@@ -609,7 +664,7 @@ and hydrateNodeWithWalker = (node: Node.node, walker: DOMWalker.t): unit => {
|
|
|
609
664
|
|
|
610
665
|
parseKeyedItems()
|
|
611
666
|
}
|
|
612
|
-
| Some(node) if DOMWalker.isMarker(node,
|
|
667
|
+
| Some(node) if DOMWalker.isMarker(node, Markers.keyedListEndContent) => {
|
|
613
668
|
let _ = DOMWalker.next(walker)
|
|
614
669
|
}
|
|
615
670
|
| _ => ()
|
|
@@ -629,7 +684,7 @@ and hydrateNodeWithWalker = (node: Node.node, walker: DOMWalker.t): unit => {
|
|
|
629
684
|
|
|
630
685
|
/* Hydrate a server-rendered component */
|
|
631
686
|
let hydrate = (
|
|
632
|
-
component: unit =>
|
|
687
|
+
component: unit => View.node,
|
|
633
688
|
container: Dom.element,
|
|
634
689
|
~options: hydrateOptions={},
|
|
635
690
|
): unit => {
|
|
@@ -664,7 +719,7 @@ let hydrate = (
|
|
|
664
719
|
|
|
665
720
|
/* Hydrate by element ID */
|
|
666
721
|
let hydrateById = (
|
|
667
|
-
component: unit =>
|
|
722
|
+
component: unit => View.node,
|
|
668
723
|
containerId: string,
|
|
669
724
|
~options: hydrateOptions={},
|
|
670
725
|
): unit => {
|