@colisweb/rescript-toolkit 5.15.5 → 5.16.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/package.json +6 -1
- package/src/form/Reform.res +3 -1
- package/src/form/Toolkit__Form.res +7 -6
- package/src/hooks/Toolkit__Hooks.res +1 -1
- package/src/ui/Toolkit__Ui.res +3 -0
- package/src/ui/Toolkit__Ui_DropdownMenu.res +93 -0
- package/src/ui/Toolkit__Ui_Popover.res +57 -0
- package/src/ui/Toolkit__Ui_ScrollArea.res +14 -0
- package/src/ui/Toolkit__Ui_Snackbar.res +36 -38
- package/src/ui/Toolkit__Ui_Snackbar.resi +1 -1
- package/src/ui/Toolkit__Ui_Tag.res +9 -7
- package/src/ui/Toolkit__Ui_Tooltip.res +63 -84
- package/src/ui/radix.css +371 -0
- package/src/ui/styles.css +1 -0
- package/src/vendors/Radix.res +469 -0
- package/src/ui/Toolkit__Ui_Tooltip.resi +0 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colisweb/rescript-toolkit",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.16.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"clean": "rescript clean",
|
|
@@ -35,6 +35,11 @@
|
|
|
35
35
|
"@greenlabs/ppx-spice": "0.2.1",
|
|
36
36
|
"@headlessui/react": "1.7.18",
|
|
37
37
|
"@headlessui/tailwindcss": "0.2.0",
|
|
38
|
+
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
|
39
|
+
"@radix-ui/react-popover": "^1.1.1",
|
|
40
|
+
"@radix-ui/react-scroll-area": "^1.1.0",
|
|
41
|
+
"@radix-ui/react-toast": "^1.2.1",
|
|
42
|
+
"@radix-ui/react-tooltip": "1.1.2",
|
|
38
43
|
"@reach/auto-id": "0.18.0",
|
|
39
44
|
"@rescript/react": "0.12.0",
|
|
40
45
|
"autoprefixer": "10.4.17",
|
package/src/form/Reform.res
CHANGED
|
@@ -128,19 +128,20 @@ module Make = (StateLenses: Config) => {
|
|
|
128
128
|
switch type_ {
|
|
129
129
|
| "password" =>
|
|
130
130
|
<Toolkit__Ui_Tooltip
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
contentClassName={"min-w-[200px] text-center"}
|
|
132
|
+
tooltipContent={showPassword
|
|
133
133
|
? <ReactIntl.FormattedMessage defaultMessage="Masquer le mot de passe" />
|
|
134
|
-
: <ReactIntl.FormattedMessage defaultMessage="Afficher le mot de passe" />}
|
|
135
|
-
<button
|
|
134
|
+
: <ReactIntl.FormattedMessage defaultMessage="Afficher le mot de passe" />}
|
|
135
|
+
triggerContent={<button
|
|
136
136
|
type_="button"
|
|
137
137
|
className="p-1 bg-neutral-300 rounded-r border border-gray-300 text-neutral-800"
|
|
138
138
|
onClick={_ => setShowPassword(v => !v)}>
|
|
139
139
|
{showPassword
|
|
140
140
|
? <ReactIcons.AiFillEyeInvisible size={26} />
|
|
141
141
|
: <ReactIcons.AiFillEye size={26} />}
|
|
142
|
-
</button>
|
|
143
|
-
|
|
142
|
+
</button>}
|
|
143
|
+
/>
|
|
144
|
+
|
|
144
145
|
| _ => React.null
|
|
145
146
|
}
|
|
146
147
|
})}
|
|
@@ -163,7 +163,7 @@ let useClipboard = (~onCopyNotificationMessage: option<string>=?, value: string)
|
|
|
163
163
|
let (hasCopied, setHasCopied) = React.useState(() => false)
|
|
164
164
|
let onCopy = React.useCallback(() => {
|
|
165
165
|
onCopyNotificationMessage->Option.forEach(message =>
|
|
166
|
-
Toolkit__Ui_Snackbar.show(~title=message, ~variant
|
|
166
|
+
Toolkit__Ui_Snackbar.show(~title=message, ~variant=Success, ())->ignore
|
|
167
167
|
)
|
|
168
168
|
|
|
169
169
|
let didCopy = CopyToClipboard.copy(value)
|
package/src/ui/Toolkit__Ui.res
CHANGED
|
@@ -40,3 +40,6 @@ module WeekDateFilter = Toolkit__Ui_WeekDateFilter
|
|
|
40
40
|
module Coordinates = Toolkit__Ui_Coordinates
|
|
41
41
|
module Autocomplete = Toolkit__Ui_Autocomplete
|
|
42
42
|
module WeekdayNavigation = Toolkit__Ui_WeekdayNavigation
|
|
43
|
+
module Popover = Toolkit__Ui_Popover
|
|
44
|
+
module DropdownMenu = Toolkit__Ui_DropdownMenu
|
|
45
|
+
module ScrollArea = Toolkit__Ui_ScrollArea
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
open Radix
|
|
2
|
+
type item = {
|
|
3
|
+
label: React.element,
|
|
4
|
+
rightSlot?: React.element,
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
type itemContent = {
|
|
8
|
+
...DropdownMenu.Item.options,
|
|
9
|
+
...item,
|
|
10
|
+
}
|
|
11
|
+
type subTrigger = {...DropdownMenu.SubTrigger.options, ...item}
|
|
12
|
+
|
|
13
|
+
type content =
|
|
14
|
+
| Item(itemContent)
|
|
15
|
+
| Separator
|
|
16
|
+
| Label(React.element)
|
|
17
|
+
| SubItems(subTrigger, array<itemContent>)
|
|
18
|
+
|
|
19
|
+
%%private(let renderRightSlot = rightSlot => <div className="RightSlot"> rightSlot </div>)
|
|
20
|
+
|
|
21
|
+
@react.component
|
|
22
|
+
let make = (
|
|
23
|
+
~trigger,
|
|
24
|
+
~triggerOptions: option<DropdownMenu.Trigger.options>=?,
|
|
25
|
+
~rootOptions: option<DropdownMenu.Root.options>=?,
|
|
26
|
+
~contentOptions: option<DropdownMenu.Content.options>=?,
|
|
27
|
+
~content: array<content>,
|
|
28
|
+
) => {
|
|
29
|
+
<DropdownMenu.Root {...(rootOptions->Option.getWithDefault({})->Obj.magic)}>
|
|
30
|
+
<DropdownMenu.Trigger {...(triggerOptions->Option.getWithDefault({})->Obj.magic)}>
|
|
31
|
+
trigger
|
|
32
|
+
</DropdownMenu.Trigger>
|
|
33
|
+
<DropdownMenu.Portal>
|
|
34
|
+
<DropdownMenu.Content
|
|
35
|
+
{...(contentOptions->Option.getWithDefault({})->Obj.magic)}
|
|
36
|
+
className="DropdownMenuContent"
|
|
37
|
+
sideOffset={contentOptions
|
|
38
|
+
->Option.flatMap(v => v.sideOffset)
|
|
39
|
+
->Option.getWithDefault(5)}>
|
|
40
|
+
{content
|
|
41
|
+
->Array.mapWithIndex((i, content) => {
|
|
42
|
+
switch content {
|
|
43
|
+
| Label(element) =>
|
|
44
|
+
<DropdownMenu.Label
|
|
45
|
+
key={i->Int.toString ++ "dropdown-menu-item"} className="DropdownMenuLabel">
|
|
46
|
+
element
|
|
47
|
+
</DropdownMenu.Label>
|
|
48
|
+
| Separator =>
|
|
49
|
+
<DropdownMenu.Separator
|
|
50
|
+
key={i->Int.toString ++ "dropdown-menu-item"} className="DropdownMenuSeparator"
|
|
51
|
+
/>
|
|
52
|
+
| Item(item) =>
|
|
53
|
+
<DropdownMenu.Item
|
|
54
|
+
key={i->Int.toString ++ "dropdown-menu-item"}
|
|
55
|
+
className="DropdownMenuItem"
|
|
56
|
+
disabled=?{item.disabled}
|
|
57
|
+
onSelect=?{item.onSelect}>
|
|
58
|
+
{item.label}
|
|
59
|
+
{item.rightSlot->Option.mapWithDefault(React.null, renderRightSlot)}
|
|
60
|
+
</DropdownMenu.Item>
|
|
61
|
+
|
|
62
|
+
| SubItems(item, subContent) =>
|
|
63
|
+
<DropdownMenu.Sub key={i->Int.toString ++ "dropdown-menu-item"}>
|
|
64
|
+
<DropdownMenu.SubTrigger className="DropdownMenuSubTrigger" disabled=?{item.disabled}>
|
|
65
|
+
{item.label}
|
|
66
|
+
{item.rightSlot->Option.mapWithDefault(React.null, renderRightSlot)}
|
|
67
|
+
</DropdownMenu.SubTrigger>
|
|
68
|
+
<DropdownMenu.Portal>
|
|
69
|
+
<DropdownMenu.SubContent
|
|
70
|
+
className="DropdownMenuSubContent" sideOffset={2} alignOffset={-5}>
|
|
71
|
+
{subContent
|
|
72
|
+
->Array.mapWithIndex((j, item) => {
|
|
73
|
+
<DropdownMenu.Item
|
|
74
|
+
key={i->Int.toString ++ j->Int.toString ++ "dropdown-menu-item"}
|
|
75
|
+
disabled=?{item.disabled}
|
|
76
|
+
onSelect=?{item.onSelect}
|
|
77
|
+
className="DropdownMenuItem">
|
|
78
|
+
{item.label}
|
|
79
|
+
{item.rightSlot->Option.mapWithDefault(React.null, renderRightSlot)}
|
|
80
|
+
</DropdownMenu.Item>
|
|
81
|
+
})
|
|
82
|
+
->React.array}
|
|
83
|
+
</DropdownMenu.SubContent>
|
|
84
|
+
</DropdownMenu.Portal>
|
|
85
|
+
</DropdownMenu.Sub>
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
->React.array}
|
|
89
|
+
<DropdownMenu.Arrow className="DropdownMenuArrow" />
|
|
90
|
+
</DropdownMenu.Content>
|
|
91
|
+
</DropdownMenu.Portal>
|
|
92
|
+
</DropdownMenu.Root>
|
|
93
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
open Radix
|
|
2
|
+
|
|
3
|
+
type color =
|
|
4
|
+
| White
|
|
5
|
+
| Black
|
|
6
|
+
| Neutral
|
|
7
|
+
| Primary
|
|
8
|
+
|
|
9
|
+
@react.component
|
|
10
|
+
let make = (
|
|
11
|
+
~trigger,
|
|
12
|
+
~triggerAsChild=false,
|
|
13
|
+
~content,
|
|
14
|
+
~color=White,
|
|
15
|
+
~rootOptions: option<Popover.Root.options>=?,
|
|
16
|
+
~contentOptions: option<Popover.Content.options>=?,
|
|
17
|
+
) => {
|
|
18
|
+
let defaultContent: Popover.Content.props = {
|
|
19
|
+
children: <>
|
|
20
|
+
content
|
|
21
|
+
<Popover.Close
|
|
22
|
+
className="absolute w-6 h-6 right-2 top-2 inline-flex items-center justify-center rounded-full hover:bg-primary-500/25">
|
|
23
|
+
<ReactIcons.MdClose />
|
|
24
|
+
</Popover.Close>
|
|
25
|
+
<Popover.Arrow
|
|
26
|
+
className={switch color {
|
|
27
|
+
| White => "fill-white"
|
|
28
|
+
| Neutral => "fill-neutral-800"
|
|
29
|
+
| Black => "fill-neutral-900"
|
|
30
|
+
| Primary => "fill-primary-700"
|
|
31
|
+
}}
|
|
32
|
+
/>
|
|
33
|
+
</>,
|
|
34
|
+
}
|
|
35
|
+
<Popover.Root {...(rootOptions->Option.getWithDefault({})->Obj.magic)}>
|
|
36
|
+
<Popover.Trigger asChild=triggerAsChild> trigger </Popover.Trigger>
|
|
37
|
+
<Popover.Portal>
|
|
38
|
+
<Popover.Content
|
|
39
|
+
{...contentOptions->Option.mapWithDefault(defaultContent, options => {
|
|
40
|
+
...options->Obj.magic,
|
|
41
|
+
children: defaultContent.children,
|
|
42
|
+
})}
|
|
43
|
+
className={cx([
|
|
44
|
+
"rounded-lg w-72 p-4 shadow-lg z-50 cw-PopoverContent",
|
|
45
|
+
switch color {
|
|
46
|
+
| White => "bg-white text-neutral-800"
|
|
47
|
+
| Neutral => "bg-neutral-800 text-white"
|
|
48
|
+
| Black => "bg-neutral-900 text-white"
|
|
49
|
+
| Primary => "bg-primary-700 text-white"
|
|
50
|
+
},
|
|
51
|
+
contentOptions->Option.flatMap(v => v.className)->Option.getWithDefault(""),
|
|
52
|
+
])}
|
|
53
|
+
sideOffset={contentOptions->Option.flatMap(v => v.sideOffset)->Option.getWithDefault(5)}
|
|
54
|
+
/>
|
|
55
|
+
</Popover.Portal>
|
|
56
|
+
</Popover.Root>
|
|
57
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
open Radix
|
|
2
|
+
@react.component
|
|
3
|
+
let make = (~children, ~className="") => {
|
|
4
|
+
<ScrollArea.Root className={cx(["ScrollAreaRoot", className])}>
|
|
5
|
+
<ScrollArea.Viewport className="ScrollAreaViewport"> children </ScrollArea.Viewport>
|
|
6
|
+
<ScrollArea.Scrollbar className="ScrollAreaScrollbar" orientation=Vertical>
|
|
7
|
+
<ScrollArea.Thumb className="ScrollAreaThumb" />
|
|
8
|
+
</ScrollArea.Scrollbar>
|
|
9
|
+
<ScrollArea.Scrollbar className="ScrollAreaScrollbar" orientation=Horizontal>
|
|
10
|
+
<ScrollArea.Thumb className="ScrollAreaThumb" />
|
|
11
|
+
</ScrollArea.Scrollbar>
|
|
12
|
+
<ScrollArea.Corner className="ScrollAreaCorner" />
|
|
13
|
+
</ScrollArea.Root>
|
|
14
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
open Radix
|
|
2
|
+
|
|
1
3
|
type rec state = {list: array<options>}
|
|
2
4
|
and options = {
|
|
3
5
|
id: id,
|
|
@@ -9,7 +11,7 @@ and options = {
|
|
|
9
11
|
timeout: int,
|
|
10
12
|
}
|
|
11
13
|
and id
|
|
12
|
-
and variant =
|
|
14
|
+
and variant = Success | Warning | Danger
|
|
13
15
|
|
|
14
16
|
type action =
|
|
15
17
|
| Show(options)
|
|
@@ -60,41 +62,37 @@ module Item = {
|
|
|
60
62
|
let make = (~options) => {
|
|
61
63
|
let {id, isVisible, variant, title, content, closable, timeout} = options
|
|
62
64
|
|
|
63
|
-
let (mounted, setMounted) = React.useState(() => false)
|
|
64
|
-
|
|
65
65
|
React.useEffect(() => {
|
|
66
|
-
setMounted(_ => true)
|
|
67
|
-
|
|
68
66
|
let timeoutId = Js.Global.setTimeout(() => {
|
|
69
67
|
hide(id)
|
|
70
68
|
}, timeout)
|
|
71
69
|
Some(() => Js.Global.clearTimeout(timeoutId))
|
|
72
70
|
}, [])
|
|
73
71
|
|
|
74
|
-
<
|
|
75
|
-
|
|
72
|
+
<Toast.Root
|
|
73
|
+
open_={isVisible}
|
|
74
|
+
onOpenChange={v => v ? () : hide(id)}
|
|
76
75
|
className={cx([
|
|
77
|
-
"
|
|
78
|
-
mounted ? "-translate-y-14" : "!opacity-0",
|
|
79
|
-
isVisible ? "opacity-100" : "opacity-0 translate-x-[200px]",
|
|
76
|
+
"transition duration-500 ease-in-out mt-3 p-3 pl-3 pr-10 transform cw-snackbar ToastRoot",
|
|
80
77
|
{
|
|
81
78
|
switch variant {
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
|
79
|
+
| Success => "bg-success-100 cw-snackbar--success"
|
|
80
|
+
| Warning => "bg-warning-100 cw-snackbar--warning"
|
|
81
|
+
| Danger => "bg-danger-100 cw-snackbar--danger"
|
|
85
82
|
}
|
|
86
83
|
},
|
|
87
84
|
])}>
|
|
88
85
|
{closable
|
|
89
|
-
? <button className="absolute right-1" onClick={_ => hide(id)}>
|
|
86
|
+
? <button className="absolute top-2 right-1 " onClick={_ => hide(id)}>
|
|
90
87
|
<ReactIcons.MdClose
|
|
91
88
|
size={24}
|
|
92
89
|
className={cx([
|
|
90
|
+
"rounded-full",
|
|
93
91
|
{
|
|
94
92
|
switch variant {
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
93
|
+
| Success => "text-neutral-700 hover:bg-neutral-300"
|
|
94
|
+
| Warning => "text-warning-700 hover:bg-warning-300"
|
|
95
|
+
| Danger => "text-danger-700 hover:bg-danger-300"
|
|
98
96
|
}
|
|
99
97
|
},
|
|
100
98
|
])}
|
|
@@ -104,27 +102,29 @@ module Item = {
|
|
|
104
102
|
<div className="flex flex-row gap-3 relative">
|
|
105
103
|
<div>
|
|
106
104
|
{switch variant {
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
105
|
+
| Success => <ReactIcons.MdCheckCircle size=28 className="text-success-600" />
|
|
106
|
+
| Warning => <ReactIcons.MdWarning size=28 className="text-warning-600" />
|
|
107
|
+
| Danger => <ReactIcons.MdError size=28 className="text-danger-600" />
|
|
110
108
|
}}
|
|
111
109
|
</div>
|
|
112
|
-
<
|
|
110
|
+
<Toast.Title className={"ToastTitle"}>
|
|
113
111
|
<p
|
|
114
112
|
className={cx([
|
|
115
|
-
"text-lg cw-snackbar-title",
|
|
113
|
+
"text-lg cw-snackbar-title mb-1",
|
|
116
114
|
switch variant {
|
|
117
|
-
|
|
|
118
|
-
|
|
|
119
|
-
|
|
|
115
|
+
| Success => "text-neutral-700"
|
|
116
|
+
| Warning => "text-warning-700"
|
|
117
|
+
| Danger => "text-danger-700"
|
|
120
118
|
},
|
|
121
119
|
])}>
|
|
122
120
|
{title->React.string}
|
|
123
121
|
</p>
|
|
124
|
-
</
|
|
122
|
+
</Toast.Title>
|
|
125
123
|
</div>
|
|
126
|
-
{content->Option.
|
|
127
|
-
|
|
124
|
+
{content->Option.mapWithDefault(React.null, content => {
|
|
125
|
+
<Toast.Description className="ToastDescription"> content </Toast.Description>
|
|
126
|
+
})}
|
|
127
|
+
</Toast.Root>
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -133,15 +133,13 @@ module Provider = {
|
|
|
133
133
|
let make = () => {
|
|
134
134
|
let {list} = store.useStore()
|
|
135
135
|
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
{
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
</div>
|
|
145
|
-
</Toolkit__Ui_Portal>
|
|
136
|
+
<Radix.Toast.Provider swipeDirection={Right}>
|
|
137
|
+
{list
|
|
138
|
+
->Array.map(e => {
|
|
139
|
+
<Item key={e.id->Obj.magic} options=e />
|
|
140
|
+
})
|
|
141
|
+
->React.array}
|
|
142
|
+
<Toast.Viewport className="ToastViewport" />
|
|
143
|
+
</Radix.Toast.Provider>
|
|
146
144
|
}
|
|
147
145
|
}
|
|
@@ -23,6 +23,7 @@ let make = (
|
|
|
23
23
|
~tooltipClassName=?,
|
|
24
24
|
~children,
|
|
25
25
|
) => {
|
|
26
|
+
let disclosure = Toolkit__Hooks.useDisclosure()
|
|
26
27
|
let sizeStyle = x =>
|
|
27
28
|
switch x {
|
|
28
29
|
| #xs => "text-xs leading-4 px-1"
|
|
@@ -59,11 +60,12 @@ let make = (
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
<Toolkit__Ui_Tooltip
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
<Toolkit__Ui_Tooltip.Controlled
|
|
64
|
+
open_={disclosure.isOpen}
|
|
65
|
+
onOpenChange={_ => tooltipLabel->Option.isSome ? disclosure.toggle() : ()}
|
|
66
|
+
tooltipContent={tooltipLabel->Option.getWithDefault(React.null)}
|
|
67
|
+
contentClassName=?tooltipClassName
|
|
68
|
+
triggerContent={<div
|
|
67
69
|
className={cx([
|
|
68
70
|
className,
|
|
69
71
|
"inline-flex self-center rounded font-semibold max-w-xs",
|
|
@@ -71,6 +73,6 @@ let make = (
|
|
|
71
73
|
sizeStyle(size),
|
|
72
74
|
])}>
|
|
73
75
|
<span className="truncate"> children </span>
|
|
74
|
-
</div>
|
|
75
|
-
|
|
76
|
+
</div>}
|
|
77
|
+
/>
|
|
76
78
|
}
|
|
@@ -1,90 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
|
5
|
-
|
|
|
6
|
-
]
|
|
1
|
+
open Radix
|
|
2
|
+
|
|
3
|
+
type color =
|
|
4
|
+
| White
|
|
5
|
+
| Black
|
|
7
6
|
|
|
8
7
|
@react.component
|
|
9
8
|
let make = (
|
|
10
|
-
~
|
|
11
|
-
~
|
|
12
|
-
~
|
|
13
|
-
~
|
|
14
|
-
~
|
|
15
|
-
~
|
|
16
|
-
~
|
|
9
|
+
~triggerContent,
|
|
10
|
+
~tooltipContent,
|
|
11
|
+
~side: Tooltip.side=Top,
|
|
12
|
+
~sideOffset=5,
|
|
13
|
+
~contentClassName="",
|
|
14
|
+
~color=White,
|
|
15
|
+
~defaultOpen=?,
|
|
17
16
|
) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
ref.current
|
|
26
|
-
->Js.Nullable.toOption
|
|
27
|
-
->Option.forEach(dom => {
|
|
28
|
-
let {left, width, right, top} = dom->Browser.DomElement.getBoundingClientRect
|
|
29
|
-
|
|
30
|
-
let overflowFromRight = left +. width > Browser.innerWidth->Float.fromInt
|
|
31
|
-
let overflowFromLeft = left <= 0.
|
|
32
|
-
|
|
33
|
-
let overflowCorrection = {
|
|
34
|
-
if overflowFromRight {
|
|
35
|
-
Some(-.(width -. (Browser.innerWidth->Int.toFloat -. left)))
|
|
36
|
-
} else if overflowFromLeft {
|
|
37
|
-
Some(-.left)
|
|
38
|
-
} else {
|
|
39
|
-
None
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
switch position {
|
|
44
|
-
| #left if left < 0. => setPosition(_ => #right)
|
|
45
|
-
| #right if right < 0. => setPosition(_ => #left)
|
|
46
|
-
| #top if top < 0. => setPosition(_ => #bottom)
|
|
47
|
-
| _ => ()
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
setAdjustmentStyle(
|
|
51
|
-
_ => Some(
|
|
52
|
-
ReactDOM.Style.make(
|
|
53
|
-
~marginLeft=overflowCorrection->Option.mapWithDefault(
|
|
54
|
-
"",
|
|
55
|
-
correction => `${correction->Js.Float.toString}px`,
|
|
56
|
-
),
|
|
57
|
-
~opacity="1",
|
|
58
|
-
(),
|
|
59
|
-
),
|
|
60
|
-
),
|
|
61
|
-
)
|
|
62
|
-
})
|
|
63
|
-
} else {
|
|
64
|
-
setAdjustmentStyle(_ => None)
|
|
65
|
-
}
|
|
66
|
-
None
|
|
67
|
-
}, (isHover, ref))
|
|
68
|
-
|
|
69
|
-
<div className={cx(["relative", containerClassName])}>
|
|
70
|
-
children
|
|
71
|
-
{isHover && canBeShowed
|
|
72
|
-
? <div
|
|
73
|
-
ref={ReactDOM.Ref.domRef(ref)}
|
|
17
|
+
<Tooltip.Provider>
|
|
18
|
+
<Tooltip.Root ?defaultOpen delayDuration={0}>
|
|
19
|
+
<Tooltip.Trigger> {triggerContent} </Tooltip.Trigger>
|
|
20
|
+
<Tooltip.Portal>
|
|
21
|
+
<Tooltip.Content
|
|
22
|
+
side
|
|
23
|
+
sideOffset
|
|
74
24
|
className={cx([
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
25
|
+
"TooltipContent",
|
|
26
|
+
`TooltipContent--${(color :> string)}`,
|
|
27
|
+
contentClassName,
|
|
28
|
+
])}>
|
|
29
|
+
{tooltipContent}
|
|
30
|
+
<Tooltip.Arrow className="TooltipArrow" />
|
|
31
|
+
</Tooltip.Content>
|
|
32
|
+
</Tooltip.Portal>
|
|
33
|
+
</Tooltip.Root>
|
|
34
|
+
</Tooltip.Provider>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module Controlled = {
|
|
38
|
+
@react.component
|
|
39
|
+
let make = (
|
|
40
|
+
~triggerContent,
|
|
41
|
+
~tooltipContent,
|
|
42
|
+
~side: Tooltip.side=Top,
|
|
43
|
+
~sideOffset=5,
|
|
44
|
+
~contentClassName="",
|
|
45
|
+
~color=White,
|
|
46
|
+
~open_,
|
|
47
|
+
~onOpenChange,
|
|
48
|
+
~defaultOpen=?,
|
|
49
|
+
) => {
|
|
50
|
+
<Tooltip.Provider>
|
|
51
|
+
<Tooltip.Root ?defaultOpen delayDuration={0} open_ onOpenChange>
|
|
52
|
+
<Tooltip.Trigger> {triggerContent} </Tooltip.Trigger>
|
|
53
|
+
<Tooltip.Portal>
|
|
54
|
+
<Tooltip.Content
|
|
55
|
+
side
|
|
56
|
+
sideOffset
|
|
57
|
+
className={cx([
|
|
58
|
+
"TooltipContent",
|
|
59
|
+
`TooltipContent--${(color :> string)}`,
|
|
60
|
+
contentClassName,
|
|
61
|
+
])}>
|
|
62
|
+
{tooltipContent}
|
|
63
|
+
<Tooltip.Arrow className="TooltipArrow" />
|
|
64
|
+
</Tooltip.Content>
|
|
65
|
+
</Tooltip.Portal>
|
|
66
|
+
</Tooltip.Root>
|
|
67
|
+
</Tooltip.Provider>
|
|
68
|
+
}
|
|
90
69
|
}
|