@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.
- package/.yarn/cache/@headlessui-react-npm-1.7.14-bf2f6f6d3e-9122114d7a.zip +0 -0
- package/.yarn/cache/client-only-npm-0.0.1-07d3e9505c-0c16bf660d.zip +0 -0
- package/.yarn/install-state.gz +0 -0
- package/package.json +2 -1
- package/playground/PlaygroundComponents.res +1 -0
- package/playground/components/Playground_Listbox.res +61 -0
- package/src/ui/Toolkit__Ui.res +1 -0
- package/src/ui/Toolkit__Ui_Listbox.res +189 -0
- package/src/ui/Toolkit__Ui_Listbox.resi +24 -0
|
Binary file
|
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colisweb/rescript-toolkit",
|
|
3
|
-
"version": "3.
|
|
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
|
+
}
|
package/src/ui/Toolkit__Ui.res
CHANGED
|
@@ -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
|