@colisweb/rescript-toolkit 3.2.5 → 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.5",
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
+ }
@@ -19,6 +19,7 @@ module IconButton = Toolkit__Ui_IconButton
19
19
  module Tag = Toolkit__Ui_Tag
20
20
  module Select = Toolkit__Ui_Select
21
21
  module SelectPolyvariant = Toolkit__Ui_SelectPolyvariant
22
+ module Listbox = Toolkit__Ui_Listbox
22
23
  module Table = Toolkit__Ui_Table
23
24
  module Reference = Toolkit__Ui_Reference
24
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