xote 6.3.0 → 7.0.0-beta.1

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 (48) hide show
  1. package/README.md +132 -33
  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 +1450 -2459
  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 +233 -39
  40. package/src/View.res.mjs +309 -32
  41. package/src/XoteJSX.res +214 -0
  42. package/src/XoteJSX.res.mjs +63 -0
  43. package/src/jsx-dev-runtime.mjs +7 -0
  44. package/src/jsx-runtime.mjs +276 -0
  45. package/src/Node.res +0 -2
  46. package/src/Node.res.mjs +0 -82
  47. package/src/ReactiveProp.res +0 -2
  48. 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,21 @@ module Render = {
117
120
  }
118
121
 
119
122
  let getKeyedChildren = (children: array<node>): option<array<keyedChild>> => {
120
- let keyedChildren = []
121
- let allKeyed = ref(true)
122
-
123
- children->Array.forEach(child => {
124
- switch child {
125
- | Keyed({key, identity, child}) =>
126
- keyedChildren->Array.push({key, identity, child})->ignore
127
- | _ => allKeyed := false
128
- }
129
- })
130
-
131
- if allKeyed.contents {
132
- Some(keyedChildren)
133
- } else {
123
+ if children->Core.Array.length == 0 {
134
124
  None
125
+ } else {
126
+ let keyedChildren = children->Core.Array.filterMap(child => {
127
+ switch child {
128
+ | Keyed({key, identity, child}) => Some({key, identity, child})
129
+ | _ => None
130
+ }
131
+ })
132
+
133
+ if keyedChildren->Core.Array.length == children->Core.Array.length {
134
+ Some(keyedChildren)
135
+ } else {
136
+ None
137
+ }
135
138
  }
136
139
  }
137
140
 
@@ -284,8 +287,7 @@ module Render = {
284
287
  clearKeyedItems(keyedItems)
285
288
 
286
289
  /* Dispose existing children */
287
- let childNodes: array<Dom.element> = %raw(`Array.from(container.childNodes || [])`)
288
- childNodes->Array.forEach(disposeElement)
290
+ container->DOM.childNodesToArray->Array.forEach(disposeElement)
289
291
 
290
292
  /* Clear existing children */
291
293
  DOM.setInnerHTML(container, "")
@@ -543,11 +545,21 @@ let int = (value: int): node => Text(Int.toString(value))
543
545
 
544
546
  let float = (value: float): node => Text(Float.toString(value))
545
547
 
548
+ let bool = (value: bool): node => Text(value ? "true" : "false")
549
+
546
550
  /* Fragments */
547
551
  let fragment = (children: array<node>): node => Fragment(children)
548
552
 
549
553
  let signalFragment = (signal: Signal.t<array<node>>): node => SignalFragment(signal)
550
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
+
551
563
  /* Lists */
552
564
  let each = (signal: Signal.t<array<'a>>, renderItem: 'a => node): node => {
553
565
  let nodesSignal = Computed.make(() => {
@@ -556,8 +568,6 @@ let each = (signal: Signal.t<array<'a>>, renderItem: 'a => node): node => {
556
568
  SignalFragment(nodesSignal)
557
569
  }
558
570
 
559
- let list = each
560
-
561
571
  let eachWithKey = (
562
572
  signal: Signal.t<array<'a>>,
563
573
  keyFn: 'a => string,
@@ -570,14 +580,116 @@ let eachWithKey = (
570
580
  })
571
581
  }
572
582
 
573
- 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
+ }
574
686
 
575
687
  /* Element constructor */
576
688
  let element = (
577
689
  tag: string,
578
- ~attrs: array<(string, attrValue)>=[]->Array.map(x => x),
579
- ~events: array<(string, Dom.event => unit)>=[]->Array.map(x => x),
580
- ~children: array<node>=[]->Array.map(x => x),
690
+ ~attrs: array<(string, attrValue)>=[],
691
+ ~events: array<(string, Dom.event => unit)>=[],
692
+ ~children: array<node>=[],
581
693
  (),
582
694
  ): node => Element({tag, attrs, events, children})
583
695
 
@@ -597,3 +709,85 @@ let mountById = (node: node, containerId: string): unit => {
597
709
  | None => Console.error("Container element not found: " ++ containerId)
598
710
  }
599
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
+ }