@colisweb/rescript-toolkit 3.2.5 → 3.3.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.
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.1",
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 pretty long",
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 className="w-32">
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,189 @@
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 flex flex-row items-center justify-between w-full cursor-default rounded-md font-semibold bg-white py-2 pl-3 pr-4 text-left border border-gray-300">
118
+ {props => {
119
+ <>
120
+ <span className="table-cell truncate text-left">
121
+ {switch (props.value, placeholder) {
122
+ | (None, Some(p)) => p->React.string
123
+ | (Some(Some(selectedOption)), _) => selectedOption.label->React.string
124
+ | _ => React.null
125
+ }}
126
+ </span>
127
+ <ReactIcons.FaAngleDown size={20} />
128
+ </>
129
+ }}
130
+ </Listbox.Button>
131
+ <Transition
132
+ show={props.isOpen}
133
+ className="relative z-20"
134
+ enter="transition duration-100 ease-out"
135
+ enterFrom="transform scale-95 opacity-0"
136
+ enterTo="transform scale-100 opacity-100"
137
+ leave="transition duration-75 ease-out"
138
+ leaveFrom="transform scale-100 opacity-100"
139
+ leaveTo="transform scale-95 opacity-0">
140
+ <Listbox.Options
141
+ static={true}
142
+ className="absolute min-w-[250px] 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">
143
+ {options
144
+ ->Array.mapWithIndex((i, option) => {
145
+ <Listbox.Option
146
+ key={`listbox-${i->Int.toString}`} value={option} disabled=?{option.disabled}>
147
+ {props => {
148
+ <div
149
+ className={cx([
150
+ "relative cursor-default select-none py-2 pl-4 pr-4 text-gray-900 flex flex-row items-center gap-2",
151
+ props.active ? "bg-primary-50" : "bg-white",
152
+ switch option.disabled {
153
+ | Some(true) => "text-gray-500"
154
+ | _ => "text-gray-900"
155
+ },
156
+ ])}>
157
+ {props.selected
158
+ ? <div
159
+ className={cx([
160
+ "w-6 h-6 rounded-full border inline-flex items-center justify-center flex-shrink-0",
161
+ switch option.disabled {
162
+ | Some(true) => "bg-gray-100 border-gray-200"
163
+ | _ => "bg-white border-gray-500"
164
+ },
165
+ ])}>
166
+ <div className="w-4 h-4 rounded-full bg-primary-700" />
167
+ </div>
168
+ : <div
169
+ className={cx([
170
+ "w-6 h-6 rounded-full border border-gray-500 bg-white flex-shrink-0",
171
+ switch option.disabled {
172
+ | Some(true) => "border-gray-200"
173
+ | _ => "bg-white border-gray-500"
174
+ },
175
+ ])}
176
+ />}
177
+ {option.label->React.string}
178
+ </div>
179
+ }}
180
+ </Listbox.Option>
181
+ })
182
+ ->React.array}
183
+ </Listbox.Options>
184
+ </Transition>
185
+ </>
186
+ }}
187
+ </Listbox>
188
+ </div>
189
+ }
@@ -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