@colisweb/rescript-toolkit 4.12.1 → 4.14.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/locale/fr.json CHANGED
@@ -1,4 +1,9 @@
1
1
  [
2
+ {
3
+ "id": "_0475def8",
4
+ "defaultMessage": "Fin",
5
+ "message": "Fin"
6
+ },
2
7
  {
3
8
  "id": "_04eadf92",
4
9
  "defaultMessage": "L'email est invalide.",
@@ -39,11 +44,6 @@
39
44
  "defaultMessage": "Volume total",
40
45
  "message": "Volume total"
41
46
  },
42
- {
43
- "id": "_2f765479",
44
- "defaultMessage": "Choisir",
45
- "message": "Choisir"
46
- },
47
47
  {
48
48
  "id": "_337be526",
49
49
  "defaultMessage": "Jeudi",
@@ -64,6 +64,16 @@
64
64
  "defaultMessage": "Samedi",
65
65
  "message": "Samedi"
66
66
  },
67
+ {
68
+ "id": "_4df46058",
69
+ "defaultMessage": "Semaine {number}",
70
+ "message": "Semaine {number}"
71
+ },
72
+ {
73
+ "id": "_4f2a1035",
74
+ "defaultMessage": "Début",
75
+ "message": "Début"
76
+ },
67
77
  {
68
78
  "id": "_5689ac4d",
69
79
  "defaultMessage": "Masquer le mot de passe",
@@ -74,6 +84,11 @@
74
84
  "defaultMessage": "Non",
75
85
  "message": "Non"
76
86
  },
87
+ {
88
+ "id": "_6a661ab6",
89
+ "defaultMessage": "Aujourd'hui",
90
+ "message": "Aujourd'hui"
91
+ },
77
92
  {
78
93
  "id": "_6ef34790",
79
94
  "defaultMessage": "Une erreur est survenue lors de la recherche",
@@ -94,11 +109,21 @@
94
109
  "defaultMessage": "<lat></lat>, <lng></lng>",
95
110
  "message": "<lat></lat>, <lng></lng>"
96
111
  },
112
+ {
113
+ "id": "_7cd2a589",
114
+ "defaultMessage": "Cette semaine",
115
+ "message": "Cette semaine"
116
+ },
97
117
  {
98
118
  "id": "_7e01b0f2",
99
119
  "defaultMessage": "Réinitialiser",
100
120
  "message": "Réinitialiser"
101
121
  },
122
+ {
123
+ "id": "_7e345c99",
124
+ "defaultMessage": "Ce mois",
125
+ "message": "Ce mois"
126
+ },
102
127
  {
103
128
  "id": "_8f8eb0df",
104
129
  "defaultMessage": "Vendredi",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colisweb/rescript-toolkit",
3
- "version": "4.12.1",
3
+ "version": "4.14.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "clean": "rescript clean",
@@ -28,7 +28,6 @@
28
28
  "license": "MIT",
29
29
  "dependencies": {
30
30
  "@colisweb/bs-react-intl-extractor-bin": "0.12.2",
31
- "@colisweb/react-day-picker": "7.4.16",
32
31
  "@colisweb/restorative": "1.0.0",
33
32
  "@datadog/browser-rum": "4.46.0",
34
33
  "@headlessui/react": "1.7.16",
@@ -53,6 +52,7 @@
53
52
  "react": "18.2.0",
54
53
  "react-big-calendar": "1.5.2",
55
54
  "react-datepicker": "3.8.0",
55
+ "react-day-picker": "8.8.0",
56
56
  "react-dom": "18.2.0",
57
57
  "react-error-boundary": "4.0.10",
58
58
  "react-helmet": "6.1.0",
@@ -638,107 +638,7 @@ module Make = (StateLenses: Config) => {
638
638
  }
639
639
 
640
640
  module DatePicker = {
641
- module Picker = {
642
- @react.component
643
- let make = (
644
- ~value,
645
- ~handleChange,
646
- ~containerClassName,
647
- ~placeholder,
648
- ~disabledBefore: option<Js.Date.t>=?,
649
- ~revalidate,
650
- ) => {
651
- let (date, setDate) = React.useState((): option<Js.Date.t> => value)
652
- let intl = useIntl()
653
-
654
- <div>
655
- <Toolkit__Ui_PortalDropdown
656
- buttonClassName="!border-0 w-full !p-0"
657
- label={switch value {
658
- | None =>
659
- <div className={cx(["text-left w-full", containerClassName])}>
660
- <div className="border p-2 rounded text-neutral-400 font-normal">
661
- {placeholder->Option.getWithDefault(
662
- <FormattedMessage defaultMessage={"Choisissez une date"} />,
663
- )}
664
- </div>
665
- </div>
666
- | Some(date) =>
667
- <div
668
- className={cx([
669
- "border rounded-lg p-2 flex flex-row items-center justify-between gap-6 font-normal text-neutral-700 w-full",
670
- containerClassName,
671
- ])}>
672
- <span>
673
- <FormattedDate
674
- value={date} weekday=#long day=#numeric month=#long year=#numeric
675
- />
676
- </span>
677
- <div
678
- className="border inline-flex items-center justify-center w-8 h-8 rounded border-primary-700 text-primary-700">
679
- <ReactIcons.FaPencilAlt size={18} />
680
- </div>
681
- </div>
682
- }}>
683
- {disclosure => {
684
- <div className="flex flex-col">
685
- <ReactDayPicker.ReactDayPicker.DayPicker
686
- className="cw-Datepicker"
687
- showOutsideDays=true
688
- modifiers={disabledBefore->Option.mapWithDefault(
689
- Js.Obj.empty()->Obj.magic,
690
- disabledBefore => {
691
- {
692
- "disabled": {
693
- "before": disabledBefore,
694
- },
695
- }->Obj.magic
696
- },
697
- )}
698
- locale={intl->Intl.locale}
699
- months=Toolkit__LocalesHelpers.DatePicker.Fr.months
700
- weekdaysShort=Toolkit__LocalesHelpers.DatePicker.Fr.weekdaysShort
701
- firstDayOfWeek=1
702
- selectedDays=(date->Obj.magic, {from: Js.Nullable.null, to_: Js.Nullable.null})
703
- onDayClick={(
704
- (day, modifiers) => {
705
- let disabled: option<bool> = (modifiers->Obj.magic)["disabled"]
706
-
707
- switch disabled {
708
- | Some(true) => ()
709
- | _ => setDate(_ => Some(day))
710
- }
711
- }
712
- )->Obj.magic}
713
- />
714
- <div className="flex flex-row justify-between">
715
- <Toolkit__Ui_Button
716
- type_="button"
717
- disabled={date->Option.isNone}
718
- onClick={_ => {
719
- revalidate()
720
- setDate(_ => None)
721
- }}>
722
- <FormattedMessage defaultMessage={"Réinitialiser"} />
723
- </Toolkit__Ui_Button>
724
- <Toolkit__Ui_Button
725
- color=#primary
726
- type_="button"
727
- disabled={date->Option.isNone}
728
- onClick={_ => {
729
- disclosure.hide()
730
- revalidate()
731
- handleChange(date)
732
- }}>
733
- <FormattedMessage defaultMessage={"Choisir"} />
734
- </Toolkit__Ui_Button>
735
- </div>
736
- </div>
737
- }}
738
- </Toolkit__Ui_PortalDropdown>
739
- </div>
740
- }
741
- }
641
+ open ReactDayPicker
742
642
  @react.component
743
643
  let make = (
744
644
  ~field,
@@ -751,14 +651,7 @@ module Make = (StateLenses: Config) => {
751
651
  ) => {
752
652
  <Field
753
653
  field
754
- render={({handleChange, value, error, state, validate}) => {
755
- let revalidate = () => {
756
- switch state {
757
- | Pristine => ()
758
- | _ => validate()
759
- }
760
- }
761
-
654
+ render={({handleChange, value, error}) => {
762
655
  <>
763
656
  {switch label {
764
657
  | None => React.null
@@ -771,7 +664,39 @@ module Make = (StateLenses: Config) => {
771
664
  label
772
665
  </Toolkit__Ui_Label>
773
666
  }}
774
- <Picker value handleChange containerClassName placeholder ?disabledBefore revalidate />
667
+ <ReactDayPicker.SingleDayPickerInput
668
+ ?value
669
+ onChange={v => handleChange(v)}
670
+ allowEmpty=?isOptional
671
+ buttonClassName="w-full"
672
+ labelClassName={cx([
673
+ "flex flex-row items-center gap-4 font-normal text-neutral-700 w-full",
674
+ containerClassName,
675
+ ])}
676
+ modifiers=?{disabledBefore->Option.map((disabledBefore): ReactDayPicker.modifiers => {
677
+ disabled: [
678
+ ReactDayPicker.Matcher.interval({
679
+ before: disabledBefore,
680
+ }),
681
+ ],
682
+ })}
683
+ placeholder={placeholder->Option.getWithDefault(
684
+ <FormattedMessage defaultMessage="Choisissez une date" />,
685
+ )}
686
+ labelFormatter={date => {
687
+ <>
688
+ <span>
689
+ <FormattedDate
690
+ value={date} weekday=#long day=#numeric month=#long year=#numeric
691
+ />
692
+ </span>
693
+ <div
694
+ className="border inline-flex items-center justify-center w-8 h-8 rounded border-primary-700 text-primary-700">
695
+ <ReactIcons.FaPencilAlt size={18} />
696
+ </div>
697
+ </>
698
+ }}
699
+ />
775
700
  <ErrorMessage ?error />
776
701
  </>
777
702
  }}
@@ -31,6 +31,7 @@ module Layout = Toolkit__Ui_Layout
31
31
  module SpinnerFullScreen = Toolkit__Ui_SpinnerFullScreen
32
32
  module MultiSelect = Toolkit__Ui_MultiSelect
33
33
  module MultiSelectWithValidation = Toolkit__Ui_MultiSelectWithValidation
34
+ module SelectWithValidation = Toolkit__Ui_SelectWithValidation
34
35
  module Notice = Toolkit__Ui_Notice
35
36
  module NativeDatePicker = Toolkit__Ui_NativeDatePicker
36
37
  module ErrorBoundary = Toolkit__Ui_ErrorBoundary
@@ -0,0 +1,150 @@
1
+ open ReactIntl
2
+
3
+ type item = {
4
+ itemLabel?: React.element,
5
+ label: string,
6
+ value: string,
7
+ }
8
+
9
+ type options = array<item>
10
+
11
+ module Footer = {
12
+ @react.component
13
+ let make = (~onCancel, ~onValidateClick) => {
14
+ let dropdownContext = React.useContext(Toolkit__Ui_Dropdown.dropdownContext)
15
+
16
+ <footer className="bg-white p-1 flex flex-row justify-between">
17
+ <Toolkit__Ui_Button
18
+ type_="button"
19
+ onClick={_ => {
20
+ dropdownContext.hide()
21
+ onCancel()
22
+ }}>
23
+ <FormattedMessage defaultMessage={"Annuler"} />
24
+ </Toolkit__Ui_Button>
25
+ <Toolkit__Ui_Button
26
+ color=#primary
27
+ type_="button"
28
+ onClick={_ => {
29
+ onValidateClick()
30
+ dropdownContext.hide()
31
+ }}>
32
+ <FormattedMessage defaultMessage={"Valider"} />
33
+ </Toolkit__Ui_Button>
34
+ </footer>
35
+ }
36
+ }
37
+
38
+ module Options = {
39
+ @react.component
40
+ let make = (~options, ~deferredSearch, ~itemClassName, ~setSelectedOption, ~selectedOption) => {
41
+ options
42
+ ->Array.keep(({label}) =>
43
+ deferredSearch == "" ||
44
+ label->Toolkit__Primitives.String.normalizeForSearch->Js.String2.includes(deferredSearch)
45
+ )
46
+ ->Array.mapWithIndex((i, item) => {
47
+ let {label, value} = item
48
+
49
+ <div
50
+ key={`multiselectoption-${label}-${value}-${i->Int.toString}`}
51
+ className={cx([
52
+ "group flex flex-row items-center gap-2 pt-3 text-left relative",
53
+ i > 0 ? "mt-3" : "",
54
+ itemClassName,
55
+ ])}>
56
+ <Toolkit__Ui_Radio
57
+ value
58
+ className="w-full flex-shrink-0 relative"
59
+ checked={selectedOption->Option.mapWithDefault(false, selectedOption => {
60
+ item.label == selectedOption.label && item.value == selectedOption.value
61
+ })}
62
+ onChange={_ => {
63
+ setSelectedOption(_ => {
64
+ Some(item)
65
+ })
66
+ }}>
67
+ {item.itemLabel->Option.getWithDefault(label->React.string)}
68
+ </Toolkit__Ui_Radio>
69
+ </div>
70
+ })
71
+ ->React.array
72
+ }
73
+ }
74
+
75
+ @react.component
76
+ let make = (
77
+ ~options: options,
78
+ ~placeholder: React.element,
79
+ ~buttonClassName="",
80
+ ~dropdownClassName="",
81
+ ~itemClassName="",
82
+ ~searchPlaceholder: option<string>=?,
83
+ ~allowFilter=true,
84
+ ~defaultValue: option<item>=?,
85
+ ~onValidate: item => unit,
86
+ ~disabled: option<bool>=?,
87
+ ~onCancel: option<unit => unit>=?,
88
+ ) => {
89
+ let (selectedOption, setSelectedOption) = React.useState(() => defaultValue)
90
+ let previousDefaultValue = Toolkit__Hooks.usePrevious(defaultValue)
91
+ let (search, setSearch) = React.useState(() => "")
92
+ let deferredSearch = React.useDeferredValue(search)
93
+ let allowFilter = options->Array.length > 5 && allowFilter
94
+
95
+ React.useEffect2(() => {
96
+ switch (previousDefaultValue, defaultValue) {
97
+ | (Some(Some(v)), Some(v2)) if v !== v2 => setSelectedOption(_ => defaultValue)
98
+ | _ => ()
99
+ }
100
+
101
+ None
102
+ }, (previousDefaultValue, defaultValue))
103
+
104
+ <Toolkit__Ui_Dropdown
105
+ ?disabled
106
+ buttonClassName
107
+ onClose={_ => setSelectedOption(_ => defaultValue)}
108
+ dropdownClassName
109
+ position=#bottom
110
+ label={switch selectedOption {
111
+ | None =>
112
+ <p className="flex flex-row gap-2 w-full items-center relative">
113
+ <span className="ml-1"> {placeholder} </span>
114
+ <span className="absolute inset-y-0 right-0 flex items-center">
115
+ <ReactIcons.FaAngleDown />
116
+ </span>
117
+ </p>
118
+ | Some({label}) =>
119
+ <div className="table table-fixed w-full" title={label}>
120
+ <span className="table-cell truncate text-left"> {label->React.string} </span>
121
+ </div>
122
+ }}>
123
+ <div className="py-2 pl-2 pr-1 max-h-[300px] overflow-y-scroll">
124
+ {allowFilter
125
+ ? <div className="mb-3">
126
+ <Toolkit__Ui_TextInput
127
+ id="search"
128
+ autoFocus={true}
129
+ placeholder=?{searchPlaceholder}
130
+ allowWhiteSpace={true}
131
+ value={search}
132
+ onChange={event => {
133
+ let target = event->ReactEvent.Form.currentTarget
134
+
135
+ setSearch(_ => target["value"]->Toolkit__Primitives.String.normalizeForSearch)
136
+ }}
137
+ />
138
+ </div>
139
+ : React.null}
140
+ <Options deferredSearch options setSelectedOption selectedOption itemClassName />
141
+ </div>
142
+ <Footer
143
+ onCancel={() => {
144
+ setSelectedOption(_ => defaultValue)
145
+ onCancel->Option.forEach(fn => fn())
146
+ }}
147
+ onValidateClick={() => selectedOption->Option.forEach(onValidate)}
148
+ />
149
+ </Toolkit__Ui_Dropdown>
150
+ }
@@ -0,0 +1,17 @@
1
+ type item = {itemLabel?: React.element, label: string, value: string}
2
+ type options = array<item>
3
+
4
+ @react.component
5
+ let make: (
6
+ ~options: options,
7
+ ~placeholder: React.element,
8
+ ~buttonClassName: string=?,
9
+ ~dropdownClassName: string=?,
10
+ ~itemClassName: string=?,
11
+ ~searchPlaceholder: string=?,
12
+ ~allowFilter: bool=?,
13
+ ~defaultValue: item=?,
14
+ ~onValidate: item => unit,
15
+ ~disabled: bool=?,
16
+ ~onCancel: unit => unit=?,
17
+ ) => React.element