@lets-events/react 12.0.0 → 12.1.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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +6 -0
- package/dist/index.d.mts +21 -9
- package/dist/index.d.ts +21 -9
- package/dist/index.js +327 -167
- package/dist/index.mjs +324 -164
- package/package.json +1 -1
- package/src/components/Button/styledComponents.ts +1 -0
- package/src/components/Calendar/index.tsx +14 -7
- package/src/components/Calendar/styledComponents.ts +247 -206
- package/src/components/Drawer/index.tsx +76 -2
- package/src/components/FormFields/CalendarFormField.tsx +4 -1
- package/src/components/FormFields/IdentityDocumentNumberFormField.tsx +4 -7
- package/src/components/FormFields/MultiSelectFormField.tsx +3 -0
- package/src/components/FormFields/TimePickerFormField.tsx +1 -1
- package/src/components/MultiSelect.tsx +100 -55
- package/src/components/RichEditor/QuillComponent.tsx +1 -3
- package/src/components/TimePicker.tsx +32 -8
- package/src/hooks/useOnClickOutside.tsx +25 -3
|
@@ -19,6 +19,7 @@ export type CalendarFormFieldProps = Omit<
|
|
|
19
19
|
RegisterOptions<FieldValues, string>,
|
|
20
20
|
"valueAsNumber" | "valueAsDate" | "setValueAs" | "disabled"
|
|
21
21
|
>;
|
|
22
|
+
allowPastDates?: boolean;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
export const CalendarFormField = ({
|
|
@@ -29,6 +30,7 @@ export const CalendarFormField = ({
|
|
|
29
30
|
validationErrorMessage = "Este campo é obrigatório.",
|
|
30
31
|
rules,
|
|
31
32
|
onChange,
|
|
33
|
+
allowPastDates,
|
|
32
34
|
...calendarProps
|
|
33
35
|
}: CalendarFormFieldProps) => {
|
|
34
36
|
const handleValidate = useCallback(
|
|
@@ -63,7 +65,7 @@ export const CalendarFormField = ({
|
|
|
63
65
|
};
|
|
64
66
|
|
|
65
67
|
return (
|
|
66
|
-
<Flex direction="column">
|
|
68
|
+
<Flex direction="column" style={{ flex: "1" }}>
|
|
67
69
|
{label && (
|
|
68
70
|
<FormLabel
|
|
69
71
|
name={name}
|
|
@@ -80,6 +82,7 @@ export const CalendarFormField = ({
|
|
|
80
82
|
handleCalendarChange(date);
|
|
81
83
|
}}
|
|
82
84
|
hasError={haveError}
|
|
85
|
+
allowPastDates={allowPastDates}
|
|
83
86
|
{...calendarProps}
|
|
84
87
|
/>
|
|
85
88
|
|
|
@@ -8,11 +8,6 @@ type IdentityDocumentNumberFormFieldProps = {
|
|
|
8
8
|
validationErrorMessage: string;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
const isValidRG = (rg: string): boolean => {
|
|
12
|
-
const cleaned = rg.replace(/[^\d]/g, "");
|
|
13
|
-
return /^\d{9}$/.test(cleaned);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
11
|
export const IdentityDocumentNumberFormField = ({
|
|
17
12
|
name,
|
|
18
13
|
label,
|
|
@@ -31,9 +26,11 @@ export const IdentityDocumentNumberFormField = ({
|
|
|
31
26
|
replacement: { _: /[0-9]/ },
|
|
32
27
|
}}
|
|
33
28
|
validate={(value: string) => {
|
|
34
|
-
const
|
|
29
|
+
const cleaned = value.replace(/[^\d]/g, "");
|
|
30
|
+
const isEmpty = cleaned.length === 0;
|
|
35
31
|
if (!required && isEmpty) return true;
|
|
36
|
-
|
|
32
|
+
if (cleaned.length >= 3) return true;
|
|
33
|
+
return false || validationErrorMessage;
|
|
37
34
|
}}
|
|
38
35
|
/>
|
|
39
36
|
);
|
|
@@ -10,6 +10,7 @@ export type MultiSelectFormFieldProps = MultiSelectProps & {
|
|
|
10
10
|
required?: boolean;
|
|
11
11
|
selectedOrientation?: "row" | "column";
|
|
12
12
|
zIndex?: string;
|
|
13
|
+
maxHeight?: string;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export const MultiSelectFormField = ({
|
|
@@ -18,6 +19,7 @@ export const MultiSelectFormField = ({
|
|
|
18
19
|
required,
|
|
19
20
|
selectedOrientation = "column",
|
|
20
21
|
zIndex,
|
|
22
|
+
maxHeight,
|
|
21
23
|
...rest
|
|
22
24
|
}: MultiSelectFormFieldProps) => {
|
|
23
25
|
const { field, fieldState } = useController({
|
|
@@ -53,6 +55,7 @@ export const MultiSelectFormField = ({
|
|
|
53
55
|
color={haveError ? "error" : "default"}
|
|
54
56
|
selectedOrientation={selectedOrientation}
|
|
55
57
|
zIndex={zIndex}
|
|
58
|
+
maxHeight={maxHeight}
|
|
56
59
|
{...rest}
|
|
57
60
|
/>
|
|
58
61
|
<ErrorFormMessage message={errorMsg} />
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React, { useCallback, useRef, useState } from "react";
|
|
1
2
|
import { DropdownMenu, Theme } from "@radix-ui/themes";
|
|
2
3
|
import { CheckboxGroup, CheckboxItem } from "./CheckboxGroup";
|
|
3
4
|
import { styled } from "../styles";
|
|
@@ -9,10 +10,9 @@ import {
|
|
|
9
10
|
faSquareXmark,
|
|
10
11
|
} from "@fortawesome/free-solid-svg-icons";
|
|
11
12
|
import { colors } from "@lets-events/tokens";
|
|
12
|
-
import { ComponentProps,
|
|
13
|
+
import { ComponentProps, useMemo } from "react";
|
|
13
14
|
import { Flex } from "./Flex";
|
|
14
15
|
import { CSS } from "@stitches/react";
|
|
15
|
-
import React from "react";
|
|
16
16
|
|
|
17
17
|
const StyledContent = styled(DropdownMenu.Content, {
|
|
18
18
|
backgroundColor: "$dark50",
|
|
@@ -21,6 +21,9 @@ const StyledContent = styled(DropdownMenu.Content, {
|
|
|
21
21
|
boxShadow: "0px 2px 4px 0px #23354329, 0px 4px 4px 0px #23354314",
|
|
22
22
|
boxSizing: "border-box",
|
|
23
23
|
border: "1px solid $dark300",
|
|
24
|
+
zIndex: 999999,
|
|
25
|
+
minWidth: "var(--radix-dropdown-menu-trigger-width)",
|
|
26
|
+
maxWidth: "var(--radix-dropdown-menu-trigger-width)",
|
|
24
27
|
});
|
|
25
28
|
|
|
26
29
|
const StyledTrigger = styled("div", {
|
|
@@ -33,6 +36,7 @@ const StyledTrigger = styled("div", {
|
|
|
33
36
|
padding: "$6 $14",
|
|
34
37
|
boxSizing: "border-box",
|
|
35
38
|
gap: "4px",
|
|
39
|
+
width: "100%",
|
|
36
40
|
|
|
37
41
|
variants: {
|
|
38
42
|
color: {
|
|
@@ -77,6 +81,40 @@ const BadgeCloseBtn = styled("div", {
|
|
|
77
81
|
cursor: "pointer",
|
|
78
82
|
});
|
|
79
83
|
|
|
84
|
+
const StyledFlexWithMaxHeight = styled(Flex, {
|
|
85
|
+
variants: {
|
|
86
|
+
hasMaxHeight: {
|
|
87
|
+
true: {
|
|
88
|
+
overflowY: "auto",
|
|
89
|
+
"&::-webkit-scrollbar": {
|
|
90
|
+
width: "4px",
|
|
91
|
+
},
|
|
92
|
+
"&::-webkit-scrollbar-track": {
|
|
93
|
+
backgroundColor: "$dark100",
|
|
94
|
+
borderRadius: "2px",
|
|
95
|
+
},
|
|
96
|
+
"&::-webkit-scrollbar-thumb": {
|
|
97
|
+
backgroundColor: "$dark300",
|
|
98
|
+
borderRadius: "2px",
|
|
99
|
+
"&:hover": {
|
|
100
|
+
backgroundColor: "$dark400",
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
defaultVariants: {
|
|
108
|
+
hasMaxHeight: false,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
const StyledText = styled(Text, {
|
|
112
|
+
flex: 1,
|
|
113
|
+
overflow: "hidden",
|
|
114
|
+
whiteSpace: "nowrap",
|
|
115
|
+
textOverflow: "ellipsis",
|
|
116
|
+
});
|
|
117
|
+
|
|
80
118
|
export type MultiSelectProps = ComponentProps<typeof StyledTrigger> & {
|
|
81
119
|
placeholder?: string;
|
|
82
120
|
value?: string[];
|
|
@@ -91,6 +129,7 @@ export type MultiSelectProps = ComponentProps<typeof StyledTrigger> & {
|
|
|
91
129
|
singleSelect?: boolean;
|
|
92
130
|
selectedOrientation?: "row" | "column";
|
|
93
131
|
disabled?: boolean;
|
|
132
|
+
maxHeight?: string;
|
|
94
133
|
};
|
|
95
134
|
|
|
96
135
|
export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
|
|
@@ -107,13 +146,13 @@ export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
|
|
|
107
146
|
singleSelect = false,
|
|
108
147
|
selectedOrientation = "column",
|
|
109
148
|
disabled = false,
|
|
149
|
+
maxHeight,
|
|
110
150
|
},
|
|
111
151
|
fowardedRef
|
|
112
152
|
) => {
|
|
113
153
|
const [isOpen, setIsOpen] = useState(false);
|
|
114
154
|
|
|
115
155
|
const triggerRef = useRef<HTMLDivElement>(null);
|
|
116
|
-
|
|
117
156
|
const labelByValue = useMemo(() => {
|
|
118
157
|
return options.reduce<{ [key: string]: string }>((prev, curr) => {
|
|
119
158
|
return {
|
|
@@ -131,8 +170,6 @@ export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
|
|
|
131
170
|
[selectedValues, onValueChange]
|
|
132
171
|
);
|
|
133
172
|
|
|
134
|
-
const menuWidth = triggerRef.current?.offsetWidth;
|
|
135
|
-
|
|
136
173
|
const text = useMemo(() => {
|
|
137
174
|
if (selectedValues.length > 0 && singleSelect) {
|
|
138
175
|
const value = selectedValues[0];
|
|
@@ -146,20 +183,21 @@ export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
|
|
|
146
183
|
onValueChange?.([v]);
|
|
147
184
|
setIsOpen(false);
|
|
148
185
|
};
|
|
186
|
+
const handleToggle = useCallback(
|
|
187
|
+
(e: React.MouseEvent) => {
|
|
188
|
+
e.preventDefault();
|
|
189
|
+
e.stopPropagation();
|
|
190
|
+
if (disabled) return;
|
|
191
|
+
setIsOpen((prev) => !prev);
|
|
192
|
+
},
|
|
193
|
+
[disabled]
|
|
194
|
+
);
|
|
149
195
|
|
|
150
196
|
return (
|
|
151
197
|
<Theme>
|
|
152
|
-
<DropdownMenu.Root
|
|
153
|
-
<DropdownMenu.Trigger
|
|
154
|
-
onClick={() => {
|
|
155
|
-
if (disabled) return;
|
|
156
|
-
setIsOpen(true);
|
|
157
|
-
}}
|
|
158
|
-
>
|
|
198
|
+
<DropdownMenu.Root>
|
|
199
|
+
<DropdownMenu.Trigger>
|
|
159
200
|
<StyledTrigger
|
|
160
|
-
css={{
|
|
161
|
-
width,
|
|
162
|
-
}}
|
|
163
201
|
ref={(r) => {
|
|
164
202
|
if (!r) return;
|
|
165
203
|
triggerRef.current = r;
|
|
@@ -172,19 +210,15 @@ export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
|
|
|
172
210
|
}}
|
|
173
211
|
color={color}
|
|
174
212
|
disabled={disabled}
|
|
213
|
+
style={width !== "100%" ? { width } : undefined}
|
|
214
|
+
onClick={handleToggle}
|
|
175
215
|
>
|
|
176
|
-
<
|
|
216
|
+
<StyledText
|
|
177
217
|
typography={"labelMedium"}
|
|
178
|
-
css={{
|
|
179
|
-
flex: 1,
|
|
180
|
-
overflow: "hidden",
|
|
181
|
-
whiteSpace: "nowrap",
|
|
182
|
-
textOverflow: "ellipsis",
|
|
183
|
-
}}
|
|
184
218
|
color={disabled ? "dark400" : undefined}
|
|
185
219
|
>
|
|
186
220
|
{text}
|
|
187
|
-
</
|
|
221
|
+
</StyledText>
|
|
188
222
|
<FontAwesomeIcon
|
|
189
223
|
icon={isOpen ? faChevronUp : faChevronDown}
|
|
190
224
|
size="sm"
|
|
@@ -194,8 +228,8 @@ export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
|
|
|
194
228
|
</DropdownMenu.Trigger>
|
|
195
229
|
<StyledContent
|
|
196
230
|
css={{
|
|
197
|
-
width:
|
|
198
|
-
zIndex,
|
|
231
|
+
width: "100%",
|
|
232
|
+
zIndex: zIndex === "auto" ? 999999 : zIndex,
|
|
199
233
|
}}
|
|
200
234
|
>
|
|
201
235
|
{!singleSelect ? (
|
|
@@ -205,22 +239,32 @@ export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
|
|
|
205
239
|
onValueChange?.(v);
|
|
206
240
|
}}
|
|
207
241
|
>
|
|
208
|
-
<
|
|
242
|
+
<StyledFlexWithMaxHeight
|
|
243
|
+
direction={"column"}
|
|
244
|
+
gap={8}
|
|
245
|
+
hasMaxHeight={!!maxHeight}
|
|
246
|
+
style={maxHeight ? { maxHeight } : undefined}
|
|
247
|
+
>
|
|
209
248
|
{options.map(({ value, label }, i) => (
|
|
210
249
|
<CheckboxItem value={value} css={itemStyle} key={i}>
|
|
211
250
|
<Text typography={"labelSmall"}>{label}</Text>
|
|
212
251
|
</CheckboxItem>
|
|
213
252
|
))}
|
|
214
|
-
</
|
|
253
|
+
</StyledFlexWithMaxHeight>
|
|
215
254
|
</CheckboxGroup>
|
|
216
255
|
) : (
|
|
217
|
-
<
|
|
256
|
+
<StyledFlexWithMaxHeight
|
|
257
|
+
direction={"column"}
|
|
258
|
+
gap={8}
|
|
259
|
+
hasMaxHeight={!!maxHeight}
|
|
260
|
+
style={maxHeight ? { maxHeight } : undefined}
|
|
261
|
+
>
|
|
218
262
|
{options.map(({ value, label }, i) => (
|
|
219
263
|
<StyledItem key={i} onClick={() => handleItemClick(value)}>
|
|
220
264
|
<Text typography={"labelSmall"}>{label}</Text>
|
|
221
265
|
</StyledItem>
|
|
222
266
|
))}
|
|
223
|
-
</
|
|
267
|
+
</StyledFlexWithMaxHeight>
|
|
224
268
|
)}
|
|
225
269
|
</StyledContent>
|
|
226
270
|
</DropdownMenu.Root>
|
|
@@ -229,34 +273,35 @@ export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
|
|
|
229
273
|
<Flex
|
|
230
274
|
direction={selectedOrientation}
|
|
231
275
|
gap={8}
|
|
232
|
-
align={"center"}
|
|
276
|
+
align={selectedOrientation === "column" ? "start" : "center"}
|
|
233
277
|
justify={"start"}
|
|
234
|
-
css={{
|
|
235
|
-
margin: "8px 0",
|
|
236
|
-
}}
|
|
278
|
+
css={{ margin: "8px 0" }}
|
|
237
279
|
>
|
|
238
|
-
{selectedValues.map((value) =>
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
280
|
+
{selectedValues.map((value) => (
|
|
281
|
+
<Flex
|
|
282
|
+
key={value}
|
|
283
|
+
gap={4}
|
|
284
|
+
align={"center"}
|
|
285
|
+
css={{ flexWrap: "wrap" }}
|
|
286
|
+
>
|
|
287
|
+
<BadgeCloseBtn
|
|
288
|
+
onClick={(e) => {
|
|
289
|
+
e.stopPropagation();
|
|
290
|
+
handleRemove(value);
|
|
291
|
+
}}
|
|
292
|
+
role="button"
|
|
293
|
+
>
|
|
294
|
+
<FontAwesomeIcon icon={faSquareXmark} size="sm" />
|
|
295
|
+
</BadgeCloseBtn>
|
|
296
|
+
<Text
|
|
297
|
+
typography={"captionMedium"}
|
|
298
|
+
fontWeight={"regular"}
|
|
299
|
+
color="dark600"
|
|
300
|
+
>
|
|
301
|
+
{labelByValue[value]}
|
|
302
|
+
</Text>
|
|
303
|
+
</Flex>
|
|
304
|
+
))}
|
|
260
305
|
</Flex>
|
|
261
306
|
</>
|
|
262
307
|
)}
|
|
@@ -152,10 +152,8 @@ const QuillComponent: React.FC<QuillComponentProps> = ({
|
|
|
152
152
|
const headerSelect = toolbarElement.querySelector(
|
|
153
153
|
"select[data-value]"
|
|
154
154
|
) as HTMLSelectElement;
|
|
155
|
-
console.log(headerSelect, "headerSelect");
|
|
156
155
|
if (headerSelect) {
|
|
157
156
|
const options = headerSelect.querySelectorAll("option");
|
|
158
|
-
console.log(options, "options");
|
|
159
157
|
options.forEach((option) => {
|
|
160
158
|
if (option.value === "1") {
|
|
161
159
|
option.textContent = "Título 1";
|
|
@@ -167,7 +165,7 @@ const QuillComponent: React.FC<QuillComponentProps> = ({
|
|
|
167
165
|
});
|
|
168
166
|
}
|
|
169
167
|
}
|
|
170
|
-
},
|
|
168
|
+
}, 2000);
|
|
171
169
|
}
|
|
172
170
|
}, [quill, onChange, handleImageUpload]);
|
|
173
171
|
|
|
@@ -12,19 +12,25 @@ export const TimePickerStyled = styled("div", {
|
|
|
12
12
|
fontFamily: "$default",
|
|
13
13
|
lineHeight: "$base",
|
|
14
14
|
fontSize: "$14",
|
|
15
|
-
maxWidth: "200px",
|
|
16
15
|
borderRadius: "$sm",
|
|
17
16
|
"> div > div": {
|
|
18
|
-
paddingLeft: "1rem",
|
|
19
17
|
input: {
|
|
20
18
|
textAlign: "right",
|
|
21
19
|
},
|
|
22
20
|
},
|
|
21
|
+
variants: {
|
|
22
|
+
expand: {
|
|
23
|
+
true: {
|
|
24
|
+
width: "100%",
|
|
25
|
+
flex: "1",
|
|
26
|
+
display: "flex",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
23
30
|
});
|
|
24
31
|
|
|
25
32
|
export const TimePickerDropdownStyled = styled("div", {
|
|
26
33
|
position: "absolute",
|
|
27
|
-
left: 0,
|
|
28
34
|
zIndex: 10,
|
|
29
35
|
width: "100%",
|
|
30
36
|
maxWidth: "8.875rem",
|
|
@@ -98,22 +104,30 @@ export const InputStyled = styled("input", {
|
|
|
98
104
|
export const TimePickerButtonStyled = styled("button", {
|
|
99
105
|
backgroundColor: "transparent",
|
|
100
106
|
border: "none",
|
|
101
|
-
maxWidth: "200px",
|
|
102
107
|
padding: "0",
|
|
103
108
|
cursor: "pointer",
|
|
104
109
|
"> div > div": {
|
|
105
|
-
paddingLeft: "1rem",
|
|
106
110
|
input: {
|
|
107
111
|
textAlign: "right",
|
|
108
112
|
},
|
|
109
113
|
},
|
|
114
|
+
variants: {
|
|
115
|
+
expand: {
|
|
116
|
+
true: {
|
|
117
|
+
flex: "1",
|
|
118
|
+
display: "flex",
|
|
119
|
+
maxWidth: "100%",
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
110
123
|
});
|
|
111
124
|
|
|
112
125
|
export type TimePickerProps = {
|
|
113
126
|
selected: string | undefined;
|
|
114
127
|
setSelected: React.Dispatch<React.SetStateAction<string | undefined>>;
|
|
115
|
-
position?: "bottom" | "top";
|
|
128
|
+
position?: "bottom" | "top" | "top-right" | "bottom-right";
|
|
116
129
|
hasError?: boolean;
|
|
130
|
+
expand?: boolean;
|
|
117
131
|
};
|
|
118
132
|
const pad = (num: number) => String(num).padStart(2, "0");
|
|
119
133
|
|
|
@@ -122,6 +136,7 @@ export function TimePicker({
|
|
|
122
136
|
setSelected,
|
|
123
137
|
position = "bottom",
|
|
124
138
|
hasError,
|
|
139
|
+
expand = false,
|
|
125
140
|
}: TimePickerProps) {
|
|
126
141
|
const [hours, setHours] = useState("00");
|
|
127
142
|
const [minutes, setMinutes] = useState("00");
|
|
@@ -162,10 +177,11 @@ export function TimePicker({
|
|
|
162
177
|
);
|
|
163
178
|
|
|
164
179
|
return (
|
|
165
|
-
<TimePickerStyled ref={dropdownRef}>
|
|
180
|
+
<TimePickerStyled ref={dropdownRef} expand={expand}>
|
|
166
181
|
<TimePickerButtonStyled
|
|
167
182
|
type="button"
|
|
168
183
|
onClick={() => setIsOpen((prev) => !prev)}
|
|
184
|
+
expand={expand}
|
|
169
185
|
>
|
|
170
186
|
<TextField
|
|
171
187
|
value={selected}
|
|
@@ -184,7 +200,15 @@ export function TimePicker({
|
|
|
184
200
|
|
|
185
201
|
{isOpen && (
|
|
186
202
|
<TimePickerDropdownStyled
|
|
187
|
-
style={
|
|
203
|
+
style={
|
|
204
|
+
position === "top"
|
|
205
|
+
? { bottom: "110%", left: "0" }
|
|
206
|
+
: position === "top-right"
|
|
207
|
+
? { bottom: "110%", right: "0" }
|
|
208
|
+
: position === "bottom-right"
|
|
209
|
+
? { top: "110%", right: "0" }
|
|
210
|
+
: { top: "110%", left: "0" }
|
|
211
|
+
}
|
|
188
212
|
>
|
|
189
213
|
<TimerPickerContentStyled>
|
|
190
214
|
{["hours", "minutes"].map((unit) => (
|
|
@@ -1,12 +1,34 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
2
|
|
|
3
|
-
export function useOnClickOutside(
|
|
3
|
+
export function useOnClickOutside(
|
|
4
|
+
ref: any,
|
|
5
|
+
handler: (event?: MouseEvent | TouchEvent) => void
|
|
6
|
+
) {
|
|
4
7
|
useEffect(() => {
|
|
5
8
|
const listener = (event: MouseEvent | TouchEvent) => {
|
|
6
|
-
if (!ref
|
|
9
|
+
if (!ref?.current || !event.target) {
|
|
7
10
|
return;
|
|
8
11
|
}
|
|
9
|
-
|
|
12
|
+
|
|
13
|
+
const target = event.target as Element;
|
|
14
|
+
const currentTarget = event.currentTarget as Element;
|
|
15
|
+
|
|
16
|
+
if (ref.current.contains(target) || ref.current.contains(currentTarget)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (target.tagName === "HTML" || target.tagName === "BODY") {
|
|
21
|
+
const elementAtPoint = document.elementFromPoint(
|
|
22
|
+
(event as MouseEvent).clientX,
|
|
23
|
+
(event as MouseEvent).clientY
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (elementAtPoint && ref.current.contains(elementAtPoint)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
handler(event);
|
|
10
32
|
};
|
|
11
33
|
|
|
12
34
|
document.addEventListener("mousedown", listener);
|