xote 6.4.0 → 7.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.
Files changed (46) hide show
  1. package/README.md +146 -36
  2. package/dist/RuntimeAttr.res-Cr5Qmz0i.js +1 -0
  3. package/dist/RuntimeAttr.res-DAZkL5CF.mjs +539 -0
  4. package/dist/RuntimeHydrationMarkers.res-C5-ieaOS.js +1 -0
  5. package/dist/RuntimeHydrationMarkers.res-DHikAvHr.mjs +6 -0
  6. package/dist/RuntimeJsxProp.res-A6N-qWoK.js +1 -0
  7. package/dist/RuntimeJsxProp.res-D3W5GXqT.mjs +64 -0
  8. package/dist/Stdlib_Array-1YCQzU_Y.mjs +22 -0
  9. package/dist/Stdlib_Array-BeBVUIuY.js +1 -0
  10. package/dist/View.res-C36--SJD.js +1 -0
  11. package/dist/View.res-SuqJrQPC.mjs +777 -0
  12. package/dist/client.cjs +1 -0
  13. package/dist/client.mjs +131 -0
  14. package/dist/hydration.cjs +1 -0
  15. package/dist/hydration.mjs +385 -0
  16. package/dist/mdx.cjs +1 -0
  17. package/dist/mdx.mjs +50 -0
  18. package/dist/router.cjs +1 -0
  19. package/dist/router.mjs +276 -0
  20. package/dist/ssr.cjs +17 -0
  21. package/dist/ssr.mjs +321 -0
  22. package/dist/xote.cjs +1 -17
  23. package/dist/xote.mjs +1456 -2467
  24. package/dist/xote.umd.js +1 -17
  25. package/package.json +42 -10
  26. package/rescript.json +2 -2
  27. package/src/Mdx.res +77 -0
  28. package/src/Mdx.res.mjs +93 -0
  29. package/src/Router.res +62 -8
  30. package/src/Router.res.mjs +60 -6
  31. package/src/RuntimeDom.res +7 -0
  32. package/src/RuntimeDom.res.mjs +8 -0
  33. package/src/RuntimeJsxProp.res +5 -8
  34. package/src/RuntimeJsxProp.res.mjs +9 -10
  35. package/src/RuntimeValue.res +35 -0
  36. package/src/RuntimeValue.res.mjs +67 -0
  37. package/src/SSRState.res +1 -4
  38. package/src/SSRState.res.mjs +4 -10
  39. package/src/View.res +224 -34
  40. package/src/View.res.mjs +306 -32
  41. package/src/jsx-dev-runtime.mjs +7 -0
  42. package/src/jsx-runtime.mjs +276 -0
  43. package/src/Node.res +0 -2
  44. package/src/Node.res.mjs +0 -82
  45. package/src/ReactiveProp.res +0 -2
  46. package/src/ReactiveProp.res.mjs +0 -19
package/src/View.res CHANGED
@@ -1,5 +1,6 @@
1
1
  module DOM = RuntimeDom
2
2
  module Reactivity = RuntimeOwner
3
+ module Core = RescriptCore
3
4
 
4
5
  /* ============================================================================
5
6
  * Type Definitions
@@ -85,30 +86,32 @@ module Render = {
85
86
  }
86
87
 
87
88
  /* Recursively dispose children */
88
- let childNodes: array<Dom.element> = %raw(`Array.from(el.childNodes || [])`)
89
- childNodes->Array.forEach(disposeElement)
89
+ el->DOM.childNodesToArray->Array.forEach(disposeElement)
90
90
  }
91
91
 
92
92
  let shallowEqualIdentity = (a: Obj.t, b: Obj.t): bool =>
93
93
  if a === b {
94
94
  true
95
- } else if typeof(a) != #object || typeof(b) != #object {
96
- false
97
95
  } else {
98
- let dictA: Dict.t<Obj.t> = Obj.magic(a)
99
- let dictB: Dict.t<Obj.t> = Obj.magic(b)
100
- let keysA = dictA->Dict.keysToArray
101
- let keysB = dictB->Dict.keysToArray
102
-
103
- if keysA->Array.length !== keysB->Array.length {
104
- false
105
- } else {
106
- keysA->Array.every(key =>
107
- switch (dictA->Dict.get(key), dictB->Dict.get(key)) {
108
- | (Some(valueA), Some(valueB)) => valueA === valueB
109
- | _ => false
96
+ switch (a->Core.Type.Classify.classify, b->Core.Type.Classify.classify) {
97
+ | (Object(objA), Object(objB)) => {
98
+ let dictA: Dict.t<Obj.t> = Obj.magic(objA)
99
+ let dictB: Dict.t<Obj.t> = Obj.magic(objB)
100
+ let keysA = dictA->Dict.keysToArray
101
+ let keysB = dictB->Dict.keysToArray
102
+
103
+ if keysA->Array.length !== keysB->Array.length {
104
+ false
105
+ } else {
106
+ keysA->Array.every(key =>
107
+ switch (dictA->Dict.get(key), dictB->Dict.get(key)) {
108
+ | (Some(valueA), Some(valueB)) => valueA === valueB
109
+ | _ => false
110
+ }
111
+ )
110
112
  }
111
- )
113
+ }
114
+ | _ => false
112
115
  }
113
116
  }
114
117
 
@@ -117,21 +120,17 @@ module Render = {
117
120
  }
118
121
 
119
122
  let getKeyedChildren = (children: array<node>): option<array<keyedChild>> => {
120
- if Array.length(children) == 0 {
123
+ if children->Core.Array.length == 0 {
121
124
  None
122
125
  } else {
123
- let keyedChildren = []
124
- let allKeyed = ref(true)
125
-
126
- children->Array.forEach(child => {
126
+ let keyedChildren = children->Core.Array.filterMap(child => {
127
127
  switch child {
128
- | Keyed({key, identity, child}) =>
129
- keyedChildren->Array.push({key, identity, child})->ignore
130
- | _ => allKeyed := false
128
+ | Keyed({key, identity, child}) => Some({key, identity, child})
129
+ | _ => None
131
130
  }
132
131
  })
133
132
 
134
- if allKeyed.contents {
133
+ if keyedChildren->Core.Array.length == children->Core.Array.length {
135
134
  Some(keyedChildren)
136
135
  } else {
137
136
  None
@@ -288,8 +287,7 @@ module Render = {
288
287
  clearKeyedItems(keyedItems)
289
288
 
290
289
  /* Dispose existing children */
291
- let childNodes: array<Dom.element> = %raw(`Array.from(container.childNodes || [])`)
292
- childNodes->Array.forEach(disposeElement)
290
+ container->DOM.childNodesToArray->Array.forEach(disposeElement)
293
291
 
294
292
  /* Clear existing children */
295
293
  DOM.setInnerHTML(container, "")
@@ -547,11 +545,21 @@ let int = (value: int): node => Text(Int.toString(value))
547
545
 
548
546
  let float = (value: float): node => Text(Float.toString(value))
549
547
 
548
+ let bool = (value: bool): node => Text(value ? "true" : "false")
549
+
550
550
  /* Fragments */
551
551
  let fragment = (children: array<node>): node => Fragment(children)
552
552
 
553
553
  let signalFragment = (signal: Signal.t<array<node>>): node => SignalFragment(signal)
554
554
 
555
+ let childrenToArray = (child: option<node>): array<node> => {
556
+ switch child {
557
+ | Some(Fragment(children)) => children
558
+ | Some(child) => [child]
559
+ | None => []
560
+ }
561
+ }
562
+
555
563
  /* Lists */
556
564
  let each = (signal: Signal.t<array<'a>>, renderItem: 'a => node): node => {
557
565
  let nodesSignal = Computed.make(() => {
@@ -560,8 +568,6 @@ let each = (signal: Signal.t<array<'a>>, renderItem: 'a => node): node => {
560
568
  SignalFragment(nodesSignal)
561
569
  }
562
570
 
563
- let list = each
564
-
565
571
  let eachWithKey = (
566
572
  signal: Signal.t<array<'a>>,
567
573
  keyFn: 'a => string,
@@ -574,14 +580,116 @@ let eachWithKey = (
574
580
  })
575
581
  }
576
582
 
577
- let keyedList = eachWithKey
583
+ /* JSX rendering primitives */
584
+ module For = {
585
+ type props<'item> = {
586
+ each: Prop.t<array<'item>>,
587
+ by?: 'item => string,
588
+ render: 'item => node,
589
+ }
590
+
591
+ let make = (props: props<'item>): node => {
592
+ switch (props.each, props.by) {
593
+ | (Static(items), Some(keyFn)) =>
594
+ fragment(
595
+ items->Array.map(item =>
596
+ Keyed({key: keyFn(item), identity: Obj.magic(item), child: props.render(item)})
597
+ ),
598
+ )
599
+ | (Static(items), None) => fragment(items->Array.map(props.render))
600
+ | (Reactive(signal), Some(keyFn)) => eachWithKey(signal, keyFn, props.render)
601
+ | (Reactive(signal), None) => each(signal, props.render)
602
+ }
603
+ }
604
+ }
605
+
606
+ module KeyedFor = {
607
+ type props<'item> = {
608
+ each: Prop.t<array<'item>>,
609
+ by: 'item => string,
610
+ render: 'item => node,
611
+ }
612
+
613
+ let make = (props: props<'item>): node => {
614
+ switch props.each {
615
+ | Static(items) =>
616
+ fragment(
617
+ items->Array.map(item =>
618
+ Keyed({key: props.by(item), identity: Obj.magic(item), child: props.render(item)})
619
+ ),
620
+ )
621
+ | Reactive(signal) => eachWithKey(signal, props.by, props.render)
622
+ }
623
+ }
624
+ }
625
+
626
+ module Show = {
627
+ type props = {
628
+ when_: Prop.t<bool>,
629
+ children?: node,
630
+ fallback?: node,
631
+ }
632
+
633
+ let make = (props: props): node => {
634
+ switch props.when_ {
635
+ | Static(true) => fragment(childrenToArray(props.children))
636
+ | Static(false) => fragment(childrenToArray(props.fallback))
637
+ | Reactive(signal) =>
638
+ signalFragment(
639
+ Computed.make(() =>
640
+ if Signal.get(signal) {
641
+ childrenToArray(props.children)
642
+ } else {
643
+ childrenToArray(props.fallback)
644
+ }
645
+ ),
646
+ )
647
+ }
648
+ }
649
+ }
650
+
651
+ module Maybe = {
652
+ type props<'value> = {
653
+ value: Prop.t<option<'value>>,
654
+ render: 'value => node,
655
+ fallback?: node,
656
+ }
657
+
658
+ let renderValue = (props: props<'value>, value: option<'value>): array<node> => {
659
+ switch value {
660
+ | Some(value) => [props.render(value)]
661
+ | None => childrenToArray(props.fallback)
662
+ }
663
+ }
664
+
665
+ let make = (props: props<'value>): node => {
666
+ switch props.value {
667
+ | Static(value) => fragment(renderValue(props, value))
668
+ | Reactive(signal) => signalFragment(Computed.make(() => renderValue(props, Signal.get(signal))))
669
+ }
670
+ }
671
+ }
672
+
673
+ module Value = {
674
+ type props<'value> = {
675
+ value: Prop.t<'value>,
676
+ render: 'value => node,
677
+ }
678
+
679
+ let make = (props: props<'value>): node => {
680
+ switch props.value {
681
+ | Static(value) => props.render(value)
682
+ | Reactive(signal) => signalFragment(Computed.make(() => [props.render(Signal.get(signal))]))
683
+ }
684
+ }
685
+ }
578
686
 
579
687
  /* Element constructor */
580
688
  let element = (
581
689
  tag: string,
582
- ~attrs: array<(string, attrValue)>=[]->Array.map(x => x),
583
- ~events: array<(string, Dom.event => unit)>=[]->Array.map(x => x),
584
- ~children: array<node>=[]->Array.map(x => x),
690
+ ~attrs: array<(string, attrValue)>=[],
691
+ ~events: array<(string, Dom.event => unit)>=[],
692
+ ~children: array<node>=[],
585
693
  (),
586
694
  ): node => Element({tag, attrs, events, children})
587
695
 
@@ -601,3 +709,85 @@ let mountById = (node: node, containerId: string): unit => {
601
709
  | None => Console.error("Container element not found: " ++ containerId)
602
710
  }
603
711
  }
712
+
713
+ let isReactiveProp = RuntimeValue.isReactiveProp
714
+
715
+ let valuePrimitive = (value: 'input, stringify: 'value => string): node => {
716
+ if isReactiveProp(value) {
717
+ let prop: Prop.t<'value> = Obj.magic(value)
718
+ switch prop {
719
+ | Static(value) => text(stringify(value))
720
+ | Reactive(signal) => SignalText(Computed.make(() => stringify(Signal.get(signal))))
721
+ }
722
+ } else {
723
+ switch value->Core.Type.Classify.classify {
724
+ | Function(_) => {
725
+ let compute: unit => 'value = Obj.magic(value)
726
+ signalText(() => stringify(compute()))
727
+ }
728
+ | Object(_) => {
729
+ let signal: Signal.t<'value> = Obj.magic(value)
730
+ SignalText(Computed.make(() => stringify(Signal.get(signal))))
731
+ }
732
+ | Null | Undefined => null()
733
+ | _ => {
734
+ let value: 'value = Obj.magic(value)
735
+ text(stringify(value))
736
+ }
737
+ }
738
+ }
739
+ }
740
+
741
+ let renderValuePrimitiveProps = (props: 'props, stringify: 'scalar => string): node => {
742
+ switch (props->RuntimeValue.getField("children"), props->RuntimeValue.getField("value")) {
743
+ | (Some(children), _) => valuePrimitive(children, stringify)
744
+ | (None, Some(value)) => valuePrimitive(value, stringify)
745
+ | (None, None) => null()
746
+ }
747
+ }
748
+
749
+ module Text = {
750
+ type props<'value, 'children> = {
751
+ value?: 'value,
752
+ children?: 'children,
753
+ }
754
+
755
+ let make = (props: props<'value, 'children>): node => {
756
+ renderValuePrimitiveProps(props, value => value)
757
+ }
758
+ }
759
+
760
+ module Int = {
761
+ type props<'value, 'children> = {
762
+ value?: 'value,
763
+ children?: 'children,
764
+ }
765
+
766
+ let make = (props: props<'value, 'children>): node => {
767
+ renderValuePrimitiveProps(props, value => value->Int.toString)
768
+ }
769
+ }
770
+
771
+ module Float = {
772
+ type props<'value, 'children> = {
773
+ value?: 'value,
774
+ children?: 'children,
775
+ }
776
+
777
+ let make = (props: props<'value, 'children>): node => {
778
+ renderValuePrimitiveProps(props, value => value->Float.toString)
779
+ }
780
+ }
781
+
782
+ module Bool = {
783
+ type props<'value, 'children> = {
784
+ value?: 'value,
785
+ children?: 'children,
786
+ }
787
+
788
+ let toString = value => value ? "true" : "false"
789
+
790
+ let make = (props: props<'value, 'children>): node => {
791
+ renderValuePrimitiveProps(props, toString)
792
+ }
793
+ }