@colisweb/rescript-toolkit 2.24.0 → 2.25.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colisweb/rescript-toolkit",
3
- "version": "2.24.0",
3
+ "version": "2.25.0",
4
4
  "scripts": {
5
5
  "clean": "rescript clean",
6
6
  "build": "rescript build",
@@ -25,6 +25,7 @@ module Reference = Toolkit__Ui_Reference
25
25
  module RichText = Toolkit__Ui_RichText
26
26
  module ProgressBar = Toolkit__Ui_ProgressBar
27
27
  module Dropdown = Toolkit__Ui_Dropdown
28
+ module DropdownList = Toolkit__Ui_DropdownList
28
29
  module Layout = Toolkit__Ui_Layout
29
30
  module SpinnerFullScreen = Toolkit__Ui_SpinnerFullScreen
30
31
  module MultiSelect = Toolkit__Ui_MultiSelect
@@ -0,0 +1,164 @@
1
+ type position = [
2
+ | #bottom
3
+ | #top
4
+ ]
5
+
6
+ type item = {
7
+ icon: React.element,
8
+ label: React.element,
9
+ onClick: unit => unit,
10
+ }
11
+
12
+ @react.component
13
+ let make = (
14
+ ~label: React.element,
15
+ ~dropdownClassName="",
16
+ ~buttonClassName="",
17
+ ~containerClassName="",
18
+ ~defaultIsOpen=false,
19
+ ~buttonColor: Toolkit__Ui_Button.color=#white,
20
+ ~buttonSize: Toolkit__Ui_Button.size=#md,
21
+ ~buttonVariant: Toolkit__Ui_Button.variant=#default,
22
+ ~position=#bottom,
23
+ ~items: array<item>,
24
+ ) => {
25
+ let dropdownRef = React.useRef(Js.Nullable.null)
26
+ let buttonRef = React.useRef(Js.Nullable.null)
27
+ let (position, _setPosition) = React.useState(() => position)
28
+ let {isOpen, hide, toggle} = Toolkit__Hooks.useDisclosure(~defaultIsOpen, ())
29
+ let {isXs} = Toolkit__Hooks.useMediaQuery()
30
+
31
+ Toolkit__Hooks.useOnClickOutside(dropdownRef, _ => {
32
+ hide()
33
+ })
34
+ let (adjustmentStyle, setAdjustmentStyle) = React.useState(() => None)
35
+
36
+ React.useEffect1(() => {
37
+ if isOpen && !isXs {
38
+ Js.Global.setTimeout(() => {
39
+ buttonRef.current
40
+ ->Js.Nullable.toOption
41
+ ->Option.forEach(dom => {
42
+ let buttonRect = dom->Browser.DomElement.getBoundingClientRect
43
+ let dropdownRect =
44
+ dropdownRef.current
45
+ ->Js.Nullable.toOption
46
+ ->Option.map(Browser.DomElement.getBoundingClientRect)
47
+
48
+ let calculatedTop = switch position {
49
+ | #bottom => buttonRect.top +. buttonRect.height +. 10.
50
+ | #top => {
51
+ let base = buttonRect.top -. 10.
52
+ switch dropdownRect {
53
+ | None => base
54
+ | Some({height}) => {
55
+ let newBase = base -. height /. 2.
56
+ newBase < 0. ? buttonRect.top +. buttonRect.height +. 10. : newBase
57
+ }
58
+ }
59
+ }
60
+ }
61
+
62
+ let calculatedLeft = {
63
+ let baseContainerCenter = buttonRect.left +. buttonRect.width /. 2.
64
+
65
+ switch dropdownRect {
66
+ | None => baseContainerCenter
67
+ | Some({width}) => {
68
+ let baseCalculated = baseContainerCenter -. width /. 2.
69
+ let hasOverflowLeft = baseCalculated < 0.
70
+ let hasOverflowRight =
71
+ baseContainerCenter +. width /. 2. > Browser.innerWidth->Int.toFloat
72
+
73
+ if hasOverflowLeft {
74
+ 0.
75
+ } else if hasOverflowRight {
76
+ let tmp = baseContainerCenter +. width /. 2.
77
+
78
+ baseCalculated -. (tmp -. Browser.innerWidth->Int.toFloat)
79
+ } else {
80
+ baseCalculated
81
+ }
82
+ }
83
+ }
84
+ }
85
+
86
+ setAdjustmentStyle(_ => Some(
87
+ ReactDOM.Style.make(
88
+ ~top=`${calculatedTop->Js.Float.toString}px`,
89
+ ~left=`${calculatedLeft->Js.Float.toString}px`,
90
+ ~opacity="1",
91
+ (),
92
+ ),
93
+ ))
94
+ })
95
+ }, 16)->ignore
96
+ } else {
97
+ setAdjustmentStyle(_ => None)
98
+ }
99
+ None
100
+ }, [isOpen, isXs])
101
+
102
+ <div className={cx(["relative", containerClassName])}>
103
+ <Toolkit__Ui_Button
104
+ variant=buttonVariant
105
+ buttonRef={ReactDOM.Ref.domRef(buttonRef)}
106
+ size=buttonSize
107
+ type_="button"
108
+ color=buttonColor
109
+ onClick={event => {
110
+ switch dropdownRef.current->Js.Nullable.toOption {
111
+ | None => toggle()
112
+ | Some(domRef) => {
113
+ let isInDropdown = ReactEvent.Mouse.currentTarget(event)["contains"](. domRef)
114
+ if !isInDropdown {
115
+ toggle()
116
+ }
117
+ }
118
+ }
119
+ }}
120
+ className={cx([buttonClassName, "dropdown-button"])}>
121
+ label
122
+ {isOpen
123
+ ? <ReachUi.Portal>
124
+ <div
125
+ ref={ReactDOM.Ref.domRef(dropdownRef)}
126
+ className={cx([
127
+ "dropdown",
128
+ "top-0 left-0 p-2 transform transition-opacity duration-150 ease-in-out shadow rounded text-base font-normal text-neutral-700",
129
+ isXs ? "fixed !w-full !h-full z-40" : "absolute z-20 bg-white w-60 opacity-0",
130
+ dropdownClassName,
131
+ ])}
132
+ style={adjustmentStyle->Option.getWithDefault(ReactDOM.Style.make())}>
133
+ {isXs
134
+ ? <div
135
+ className="bg-neutral-500 absolute left-0 top-0 w-full h-full opacity-50 z-30"
136
+ />
137
+ : React.null}
138
+ <div className={cx([isXs ? "z-40 absolute left-0 bottom-0 w-full" : ""])}>
139
+ <div
140
+ className={cx([
141
+ "flex flex-col",
142
+ isXs ? "bg-white p-2 mx-2 shadow rounded-t-lg" : "",
143
+ ])}>
144
+ {items
145
+ ->Array.mapWithIndex((i, {icon, label, onClick}) => {
146
+ <div
147
+ onClick={_ => onClick()}
148
+ className={cx([
149
+ "flex flex-row gap-4 items-center py-2 hover:bg-neutral-100 focus:bg-neutral-100 cursor-pointer",
150
+ i == 0 ? "" : "border-t",
151
+ ])}
152
+ key={i->Int.toString}>
153
+ {icon} {label}
154
+ </div>
155
+ })
156
+ ->React.array}
157
+ </div>
158
+ </div>
159
+ </div>
160
+ </ReachUi.Portal>
161
+ : React.null}
162
+ </Toolkit__Ui_Button>
163
+ </div>
164
+ }
@@ -0,0 +1,24 @@
1
+ type position = [
2
+ | #bottom
3
+ | #top
4
+ ]
5
+
6
+ type item = {
7
+ icon: React.element,
8
+ label: React.element,
9
+ onClick: unit => unit,
10
+ }
11
+
12
+ @react.component
13
+ let make: (
14
+ ~label: React.element,
15
+ ~dropdownClassName: string=?,
16
+ ~buttonClassName: string=?,
17
+ ~containerClassName: string=?,
18
+ ~defaultIsOpen: bool=?,
19
+ ~buttonColor: Toolkit__Ui_Button.color=?,
20
+ ~buttonSize: Toolkit__Ui_Button.size=?,
21
+ ~buttonVariant: Toolkit__Ui_Button.variant=?,
22
+ ~position: position=?,
23
+ ~items: array<item>,
24
+ ) => React.element