@colisweb/rescript-toolkit 3.2.4 → 3.3.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.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colisweb/rescript-toolkit",
3
- "version": "3.2.4",
3
+ "version": "3.3.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "clean": "rescript clean",
@@ -31,6 +31,7 @@
31
31
  "@colisweb/react-day-picker": "7.4.16",
32
32
  "@colisweb/restorative": "1.0.0",
33
33
  "@datadog/browser-rum": "4.26.0",
34
+ "@headlessui/react": "^1.7.14",
34
35
  "@reach/accordion": "0.18.0",
35
36
  "@reach/alert-dialog": "0.18.0",
36
37
  "@reach/auto-id": "0.18.0",
@@ -36,6 +36,7 @@ let components: array<(string, module(Config))> = [
36
36
  ("Combobox", module(Playground_Combobox)),
37
37
  ("IconButton", module(Playground_IconButton)),
38
38
  ("CopyWrapper", module(Playground_CopyWrapper)),
39
+ ("Listbox", module(Playground_Listbox)),
39
40
  ]
40
41
 
41
42
  module List = {
@@ -0,0 +1,61 @@
1
+ open Toolkit__Ui
2
+
3
+ @module("@root/src/ui/Toolkit__Ui_Listbox.resi?raw")
4
+ external resi: string = "default"
5
+
6
+ @module("@root/playground/components/Playground_Listbox.res?raw")
7
+ external codeExample: string = "default"
8
+
9
+ @react.component
10
+ let make = () => {
11
+ let (uncontrolledValue, setUncontrolledValue) = React.useState((): option<
12
+ Toolkit__Ui_Listbox.selectOption<string>,
13
+ > => None)
14
+
15
+ let options: Toolkit__Ui_Listbox.options<string> = [
16
+ {
17
+ label: "Label1",
18
+ value: "1",
19
+ },
20
+ {
21
+ label: "Label2",
22
+ value: "2",
23
+ },
24
+ {
25
+ label: "Label3 disabled",
26
+ value: "3",
27
+ disabled: true,
28
+ },
29
+ ]
30
+
31
+ <div className="flex flex-col gap-6">
32
+ <div>
33
+ <Label htmlFor="test" optionalMessage={"Optional"->React.string}>
34
+ {"Listbox uncontrolled"->React.string}
35
+ </Label>
36
+ <Listbox
37
+ placeholder="This is a placeholder"
38
+ compare={ValueEquality}
39
+ onChange={value => setUncontrolledValue(_ => Some(value))}
40
+ options
41
+ />
42
+ <div className="mt-4">
43
+ <p> {"selected value :"->React.string} </p>
44
+ {uncontrolledValue->Option.mapWithDefault(React.null, value =>
45
+ <p> {value.label->React.string} </p>
46
+ )}
47
+ </div>
48
+ </div>
49
+ <div>
50
+ <Label htmlFor="test" optionalMessage={"Optional"->React.string}>
51
+ {"Listbox uncontrolled defaultOption selected"->React.string}
52
+ </Label>
53
+ <Listbox
54
+ placeholder="This is a placeholder"
55
+ compare={ValueEquality}
56
+ defaultOption=?{options[1]}
57
+ options
58
+ />
59
+ </div>
60
+ </div>
61
+ }
@@ -18,6 +18,8 @@ module Alert = Toolkit__Ui_Alert
18
18
  module IconButton = Toolkit__Ui_IconButton
19
19
  module Tag = Toolkit__Ui_Tag
20
20
  module Select = Toolkit__Ui_Select
21
+ module SelectPolyvariant = Toolkit__Ui_SelectPolyvariant
22
+ module Listbox = Toolkit__Ui_Listbox
21
23
  module Table = Toolkit__Ui_Table
22
24
  module Reference = Toolkit__Ui_Reference
23
25
  module RichText = Toolkit__Ui_RichText
@@ -0,0 +1,185 @@
1
+ type selectOption<'value> = {
2
+ label: string,
3
+ value: 'value,
4
+ disabled?: bool,
5
+ }
6
+
7
+ type options<'value> = array<selectOption<'value>>
8
+
9
+ type compare<'value> =
10
+ | Key(string)
11
+ | ValueEquality
12
+ | Function((option<selectOption<'value>>, selectOption<'value>) => bool)
13
+
14
+ module Listbox = {
15
+ type renderProps = {
16
+ @as("open")
17
+ isOpen: bool,
18
+ }
19
+
20
+ @module("@headlessui/react") @react.component
21
+ external make: (
22
+ ~children: renderProps => React.element,
23
+ ~value: 'value,
24
+ ~defaultValue: selectOption<'value>=?,
25
+ ~onChange: selectOption<'value> => unit=?,
26
+ ~disabled: bool=?,
27
+ ~by: 'a=?,
28
+ ~name: string=?,
29
+ ~className: string=?,
30
+ ) => React.element = "Listbox"
31
+
32
+ module Button = {
33
+ type renderProps<'value> = {value: 'value}
34
+ @module("@headlessui/react") @scope("Listbox") @react.component
35
+ external make: (
36
+ ~children: renderProps<'value> => React.element,
37
+ ~className: string=?,
38
+ ) => React.element = "Button"
39
+ }
40
+ module Options = {
41
+ @module("@headlessui/react") @scope("Listbox") @react.component
42
+ external make: (
43
+ ~children: React.element,
44
+ ~className: string=?,
45
+ ~static: bool=?,
46
+ ) => React.element = "Options"
47
+ }
48
+ module Option = {
49
+ type renderProps = {
50
+ active: bool,
51
+ selected: bool,
52
+ }
53
+
54
+ @module("@headlessui/react") @scope("Listbox") @react.component
55
+ external make: (
56
+ ~children: renderProps => React.element,
57
+ ~value: 'value=?,
58
+ ~disabled: bool=?,
59
+ ~className: string=?,
60
+ ) => React.element = "Option"
61
+ }
62
+ }
63
+
64
+ module Transition = {
65
+ @module("@headlessui/react") @react.component
66
+ external make: (
67
+ ~show: bool,
68
+ ~children: React.element,
69
+ ~enter: string=?,
70
+ ~enterFrom: string=?,
71
+ ~enterTo: string=?,
72
+ ~leave: string=?,
73
+ ~leaveFrom: string=?,
74
+ ~leaveTo: string=?,
75
+ ~className: string=?,
76
+ ) => React.element = "Transition"
77
+ }
78
+
79
+ @react.component
80
+ let make = (
81
+ ~options: options<'value>,
82
+ ~compare: compare<'value>,
83
+ ~onChange: option<selectOption<'value> => unit>=?,
84
+ ~placeholder=?,
85
+ ~defaultOption: option<selectOption<'value>>=?,
86
+ ~isDisabled=?,
87
+ ~value=?,
88
+ ~name=?,
89
+ ) => {
90
+ <div className="relative">
91
+ <Listbox
92
+ value
93
+ by={switch compare {
94
+ | Key(objectKey) => objectKey
95
+ | ValueEquality =>
96
+ (
97
+ (selectedValue, v2) => {
98
+ selectedValue->Option.mapWithDefault(false, selectedOption =>
99
+ selectedOption.value === v2.value
100
+ )
101
+ }
102
+ )->Obj.magic
103
+
104
+ | Function(fn) => fn->Obj.magic
105
+ }}
106
+ onChange={value => {
107
+ onChange->Option.forEach(fn => {
108
+ fn({...value, value: value.value->Option.getUnsafe})
109
+ })
110
+ }}
111
+ disabled=?{isDisabled}
112
+ ?name
113
+ defaultValue=?{defaultOption->Obj.magic}>
114
+ {props => {
115
+ <>
116
+ <Listbox.Button
117
+ className="relative w-full cursor-default rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm">
118
+ {props => {
119
+ switch (props.value, placeholder) {
120
+ | (None, Some(p)) => p->React.string
121
+ | (Some(Some(selectedOption)), _) => selectedOption.label->React.string
122
+
123
+ | _ => React.null
124
+ }
125
+ }}
126
+ </Listbox.Button>
127
+ <Transition
128
+ show={props.isOpen}
129
+ className="relative z-20"
130
+ enter="transition duration-100 ease-out"
131
+ enterFrom="transform scale-95 opacity-0"
132
+ enterTo="transform scale-100 opacity-100"
133
+ leave="transition duration-75 ease-out"
134
+ leaveFrom="transform scale-100 opacity-100"
135
+ leaveTo="transform scale-95 opacity-0">
136
+ <Listbox.Options
137
+ static={true}
138
+ className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm z-20">
139
+ {options
140
+ ->Array.mapWithIndex((i, option) => {
141
+ <Listbox.Option
142
+ key={`listbox-${i->Int.toString}`} value={option} disabled=?{option.disabled}>
143
+ {props => {
144
+ <div
145
+ className={cx([
146
+ "relative cursor-default select-none py-2 pl-4 pr-4 text-gray-900 flex flex-row items-center gap-2",
147
+ props.active ? "bg-primary-50" : "bg-white",
148
+ switch option.disabled {
149
+ | Some(true) => "text-gray-500"
150
+ | _ => "text-gray-900"
151
+ },
152
+ ])}>
153
+ {props.selected
154
+ ? <div
155
+ className={cx([
156
+ "w-6 h-6 rounded-full border inline-flex items-center justify-center",
157
+ switch option.disabled {
158
+ | Some(true) => "bg-gray-100 border-gray-200"
159
+ | _ => "bg-white border-gray-500"
160
+ },
161
+ ])}>
162
+ <div className="w-4 h-4 rounded-full bg-primary-700" />
163
+ </div>
164
+ : <div
165
+ className={cx([
166
+ "w-6 h-6 rounded-full border border-gray-500 bg-white",
167
+ switch option.disabled {
168
+ | Some(true) => "border-gray-200"
169
+ | _ => "bg-white border-gray-500"
170
+ },
171
+ ])}
172
+ />}
173
+ {option.label->React.string}
174
+ </div>
175
+ }}
176
+ </Listbox.Option>
177
+ })
178
+ ->React.array}
179
+ </Listbox.Options>
180
+ </Transition>
181
+ </>
182
+ }}
183
+ </Listbox>
184
+ </div>
185
+ }
@@ -0,0 +1,24 @@
1
+ type selectOption<'value> = {
2
+ label: string,
3
+ value: 'value,
4
+ disabled?: bool,
5
+ }
6
+
7
+ type options<'value> = array<selectOption<'value>>
8
+
9
+ type compare<'value> =
10
+ | Key(string)
11
+ | ValueEquality
12
+ | Function((option<selectOption<'value>>, selectOption<'value>) => bool)
13
+
14
+ @react.component
15
+ let make: (
16
+ ~options: options<'value>,
17
+ ~compare: compare<'value>,
18
+ ~onChange: selectOption<'value> => unit=?,
19
+ ~placeholder: string=?,
20
+ ~defaultOption: selectOption<'value>=?,
21
+ ~isDisabled: bool=?,
22
+ ~value: 'value=?,
23
+ ~name: string=?,
24
+ ) => React.element
@@ -36,7 +36,7 @@ let make = (
36
36
  ?placeholder
37
37
  value=?{value->Option.map(encodeValueToString)}
38
38
  defaultValue=?{defaultValue->Option.map(encodeValueToString)}
39
- options={options->Array.map((option): Toolkit__Ui.Select.selectOption => {
39
+ options={options->Array.map((option): Toolkit__Ui_Select.selectOption => {
40
40
  label: option.label,
41
41
  value: option.value->encodeValueToString,
42
42
  disabled: ?option.disabled,
@@ -27,7 +27,7 @@ module MakeFeature = (C: Config) => {
27
27
  type t = config<C.argument>
28
28
 
29
29
  let exec = (var: C.input) =>
30
- Axios.get(C.envUrl ++ C.featureName, ())
30
+ Axios.get(C.envUrl ++ C.featureName,~config={Axios.makeConfig()}, ())
31
31
  ->Promise.Js.toResult
32
32
  ->Promise.flatMapOk(({data}) => {
33
33
  Promise.resolved(t_decode(data))
@@ -72,30 +72,25 @@ external makeConfig: (
72
72
  ) => config = ""
73
73
 
74
74
  @module("axios")
75
- external get: (string, ~config: config=?, unit) => Promise.Js.t<response<'data>, 'err> = "get"
75
+ external get: (string, ~config: config, unit) => Promise.Js.t<response<'data>, 'err> = "get"
76
76
 
77
77
  @module("axios")
78
- external post: (string, ~data: 'a, ~config: config=?, unit) => Promise.Js.t<response<'data>, 'err> =
78
+ external post: (string, ~data: 'a, ~config: config, unit) => Promise.Js.t<response<'data>, 'err> =
79
79
  "post"
80
80
 
81
81
  @module("axios")
82
- external put: (string, ~data: 'a, ~config: config=?, unit) => Promise.Js.t<response<'data>, 'err> =
82
+ external put: (string, ~data: 'a, ~config: config, unit) => Promise.Js.t<response<'data>, 'err> =
83
83
  "put"
84
84
 
85
85
  @module("axios")
86
- external patch: (
87
- string,
88
- ~data: 'a,
89
- ~config: config=?,
90
- unit,
91
- ) => Promise.Js.t<response<'data>, 'err> = "patch"
86
+ external patch: (string, ~data: 'a, ~config: config, unit) => Promise.Js.t<response<'data>, 'err> =
87
+ "patch"
92
88
 
93
89
  @module("axios")
94
- external delete: (string, ~config: config=?, unit) => Promise.Js.t<response<'data>, 'err> = "delete"
90
+ external delete: (string, ~config: config, unit) => Promise.Js.t<response<'data>, 'err> = "delete"
95
91
 
96
92
  @module("axios")
97
- external options: (string, ~config: config=?, unit) => Promise.Js.t<response<'data>, 'err> =
98
- "options"
93
+ external options: (string, ~config: config, unit) => Promise.Js.t<response<'data>, 'err> = "options"
99
94
 
100
95
  module Instance = {
101
96
  type t
@@ -104,14 +99,14 @@ module Instance = {
104
99
  external create: config => t = "create"
105
100
 
106
101
  @send
107
- external get: (t, string, ~config: config=?, unit) => Promise.Js.t<response<'data>, 'err> = "get"
102
+ external get: (t, string, ~config: config, unit) => Promise.Js.t<response<'data>, 'err> = "get"
108
103
 
109
104
  @send
110
105
  external post: (
111
106
  t,
112
107
  string,
113
108
  ~data: 'a,
114
- ~config: config=?,
109
+ ~config: config,
115
110
  unit,
116
111
  ) => Promise.Js.t<response<'data>, 'err> = "post"
117
112
 
@@ -120,7 +115,7 @@ module Instance = {
120
115
  t,
121
116
  string,
122
117
  ~data: 'a,
123
- ~config: config=?,
118
+ ~config: config,
124
119
  unit,
125
120
  ) => Promise.Js.t<response<'data>, 'err> = "put"
126
121
 
@@ -129,16 +124,16 @@ module Instance = {
129
124
  t,
130
125
  string,
131
126
  ~data: 'a,
132
- ~config: config=?,
127
+ ~config: config,
133
128
  unit,
134
129
  ) => Promise.Js.t<response<'data>, 'err> = "patch"
135
130
 
136
131
  @send
137
- external delete: (t, string, ~config: config=?, unit) => Promise.Js.t<response<'data>, 'err> =
132
+ external delete: (t, string, ~config: config, unit) => Promise.Js.t<response<'data>, 'err> =
138
133
  "delete"
139
134
 
140
135
  @send
141
- external options: (t, string, ~config: config=?, unit) => Promise.Js.t<response<'data>, 'err> =
136
+ external options: (t, string, ~config: config, unit) => Promise.Js.t<response<'data>, 'err> =
142
137
  "options"
143
138
 
144
139
  module Interceptors = {
@@ -206,82 +201,82 @@ module WithResult = {
206
201
 
207
202
  let get = (
208
203
  ~instance=?,
209
- ~config=?,
204
+ ~config,
210
205
  ~decodeData: decodeData<'newData>,
211
206
  ~mapError: option<mapError<'a, 'response, 'headers, 'request>>=?,
212
207
  string,
213
208
  ) =>
214
209
  switch instance {
215
- | None => get(string, ~config?, ())->toResult(~decodeData, ~mapError)
210
+ | None => get(string, ~config, ())->toResult(~decodeData, ~mapError)
216
211
  | Some(instance) =>
217
- instance->Instance.get(string, ~config?, ())->toResult(~decodeData, ~mapError)
212
+ instance->Instance.get(string, ~config, ())->toResult(~decodeData, ~mapError)
218
213
  }
219
214
 
220
215
  let post = (
221
216
  ~instance=?,
222
217
  ~data,
223
- ~config=?,
218
+ ~config,
224
219
  ~decodeData: decodeData<'newData>,
225
220
  ~mapError: option<mapError<'a, 'response, 'headers, 'request>>=?,
226
221
  string,
227
222
  ) =>
228
223
  switch instance {
229
- | None => post(string, ~data, ~config?, ())->toResult(~decodeData, ~mapError)
224
+ | None => post(string, ~data, ~config, ())->toResult(~decodeData, ~mapError)
230
225
  | Some(instance) =>
231
- instance->Instance.post(string, ~data, ~config?, ())->toResult(~decodeData, ~mapError)
226
+ instance->Instance.post(string, ~data, ~config, ())->toResult(~decodeData, ~mapError)
232
227
  }
233
228
 
234
229
  let put = (
235
230
  ~instance=?,
236
231
  ~data,
237
- ~config=?,
232
+ ~config,
238
233
  ~decodeData: decodeData<'newData>,
239
234
  ~mapError: option<mapError<'a, 'response, 'headers, 'request>>=?,
240
235
  string,
241
236
  ) =>
242
237
  switch instance {
243
- | None => put(string, ~data, ~config?, ())->toResult(~decodeData, ~mapError)
238
+ | None => put(string, ~data, ~config, ())->toResult(~decodeData, ~mapError)
244
239
  | Some(instance) =>
245
- instance->Instance.put(string, ~data, ~config?, ())->toResult(~decodeData, ~mapError)
240
+ instance->Instance.put(string, ~data, ~config, ())->toResult(~decodeData, ~mapError)
246
241
  }
247
242
 
248
243
  let patch = (
249
244
  ~instance=?,
250
245
  ~data,
251
- ~config=?,
246
+ ~config,
252
247
  ~decodeData: decodeData<'newData>,
253
248
  ~mapError: option<mapError<'a, 'response, 'headers, 'request>>=?,
254
249
  string,
255
250
  ) =>
256
251
  switch instance {
257
- | None => patch(string, ~data, ~config?, ())->toResult(~decodeData, ~mapError)
252
+ | None => patch(string, ~data, ~config, ())->toResult(~decodeData, ~mapError)
258
253
  | Some(instance) =>
259
- instance->Instance.patch(string, ~data, ~config?, ())->toResult(~decodeData, ~mapError)
254
+ instance->Instance.patch(string, ~data, ~config, ())->toResult(~decodeData, ~mapError)
260
255
  }
261
256
 
262
257
  let delete = (
263
258
  ~instance=?,
264
- ~config=?,
259
+ ~config,
265
260
  ~decodeData: decodeData<'newData>,
266
261
  ~mapError: option<mapError<'a, 'response, 'headers, 'request>>=?,
267
262
  string,
268
263
  ) =>
269
264
  switch instance {
270
- | None => delete(string, ~config?, ())->toResult(~decodeData, ~mapError)
265
+ | None => delete(string, ~config, ())->toResult(~decodeData, ~mapError)
271
266
  | Some(instance) =>
272
- instance->Instance.delete(string, ~config?, ())->toResult(~decodeData, ~mapError)
267
+ instance->Instance.delete(string, ~config, ())->toResult(~decodeData, ~mapError)
273
268
  }
274
269
 
275
270
  let options = (
276
271
  ~instance=?,
277
- ~config=?,
272
+ ~config,
278
273
  ~decodeData: decodeData<'newData>,
279
274
  ~mapError: option<mapError<'a, 'response, 'headers, 'request>>=?,
280
275
  string,
281
276
  ) =>
282
277
  switch instance {
283
- | None => options(string, ~config?, ())->toResult(~decodeData, ~mapError)
278
+ | None => options(string, ~config, ())->toResult(~decodeData, ~mapError)
284
279
  | Some(instance) =>
285
- instance->Instance.options(string, ~config?, ())->toResult(~decodeData, ~mapError)
280
+ instance->Instance.options(string, ~config, ())->toResult(~decodeData, ~mapError)
286
281
  }
287
282
  }