@lets-events/react 12.9.3 → 12.10.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.
Files changed (94) hide show
  1. package/.eslintrc.json +2 -2
  2. package/.turbo/turbo-build.log +21 -19
  3. package/CHANGELOG.md +6 -0
  4. package/dist/index.d.mts +15 -2
  5. package/dist/index.d.ts +15 -2
  6. package/dist/index.js +296 -200
  7. package/dist/index.mjs +264 -169
  8. package/package.json +1 -1
  9. package/src/components/Alert.tsx +303 -303
  10. package/src/components/Avatar.tsx +55 -55
  11. package/src/components/Badge.tsx +123 -123
  12. package/src/components/Box.tsx +3 -3
  13. package/src/components/Button/index.tsx +74 -62
  14. package/src/components/Button/styledComponents.ts +361 -320
  15. package/src/components/ButtonGroup.tsx +484 -484
  16. package/src/components/Calendar/index.tsx +168 -168
  17. package/src/components/Calendar/styledComponents.ts +480 -480
  18. package/src/components/Card.tsx +67 -67
  19. package/src/components/CheckboxGroup.tsx +176 -176
  20. package/src/components/Container.tsx +39 -39
  21. package/src/components/Divider.tsx +7 -7
  22. package/src/components/DoubleCalendar/index.tsx +182 -182
  23. package/src/components/Drawer/index.tsx +100 -100
  24. package/src/components/Drawer/styledComponents.ts +103 -103
  25. package/src/components/Dropdown.tsx +302 -302
  26. package/src/components/Filter.tsx +164 -164
  27. package/src/components/Flex.tsx +118 -118
  28. package/src/components/FormFields/AddressFormFields/CityFormField.tsx +111 -111
  29. package/src/components/FormFields/AddressFormFields/CountryFormField.tsx +33 -33
  30. package/src/components/FormFields/AddressFormFields/PostalCodeFormField.tsx +39 -39
  31. package/src/components/FormFields/AddressFormFields/StateFormField.tsx +32 -32
  32. package/src/components/FormFields/AddressFormFields/index.tsx +141 -141
  33. package/src/components/FormFields/BirthDateFormField.tsx +84 -84
  34. package/src/components/FormFields/CNPJFormField.tsx +87 -87
  35. package/src/components/FormFields/CPFFormField.tsx +78 -78
  36. package/src/components/FormFields/CalendarFormField.tsx +98 -98
  37. package/src/components/FormFields/CheckboxGroupFormField.tsx +91 -91
  38. package/src/components/FormFields/DateAndTimeFormField.tsx +217 -217
  39. package/src/components/FormFields/DoubleCalendarFormField.tsx +96 -96
  40. package/src/components/FormFields/EmailFormField.tsx +27 -27
  41. package/src/components/FormFields/Form.tsx +39 -39
  42. package/src/components/FormFields/IdentityDocumentNumberFormField.tsx +32 -32
  43. package/src/components/FormFields/MultiSelectFormField.tsx +64 -64
  44. package/src/components/FormFields/PhoneFormField.tsx +40 -40
  45. package/src/components/FormFields/RadioGroupFormField.tsx +86 -86
  46. package/src/components/FormFields/RichEditorFormField.tsx +103 -103
  47. package/src/components/FormFields/SelectFormField.tsx +113 -113
  48. package/src/components/FormFields/SwitchFormField.tsx +46 -46
  49. package/src/components/FormFields/TextAreaFormField.tsx +61 -61
  50. package/src/components/FormFields/TextFormField.tsx +112 -112
  51. package/src/components/FormFields/TimePickerFormField.tsx +88 -88
  52. package/src/components/FormFields/subComponents/ErrorFormMessage.tsx +36 -36
  53. package/src/components/FormFields/subComponents/FormLabel.tsx +36 -36
  54. package/src/components/FormFields/utils/validation.ts +23 -23
  55. package/src/components/Grid.tsx +137 -137
  56. package/src/components/Icon.tsx +47 -47
  57. package/src/components/MenuDropdown/index.tsx +38 -38
  58. package/src/components/MenuDropdown/styledComponents.ts +31 -31
  59. package/src/components/Modal.tsx +110 -110
  60. package/src/components/MultiSelect/index.tsx +305 -305
  61. package/src/components/MultiSelect/styledComponents.ts +160 -160
  62. package/src/components/RadioGroup.tsx +210 -210
  63. package/src/components/RichEditor/QuillComponent.tsx +468 -468
  64. package/src/components/RichEditor/RichEditor.tsx +49 -49
  65. package/src/components/RichEditor/RichTextPresenter.tsx +18 -18
  66. package/src/components/RichEditor/index.ts +3 -3
  67. package/src/components/RichEditor/styledComponents.ts +1170 -1170
  68. package/src/components/Section.tsx +33 -33
  69. package/src/components/Step.tsx +164 -164
  70. package/src/components/Switch.tsx +108 -108
  71. package/src/components/Text.tsx +38 -38
  72. package/src/components/TextField.tsx +372 -372
  73. package/src/components/TextareaField.tsx +116 -116
  74. package/src/components/TimePicker.tsx +357 -357
  75. package/src/components/Toast/components/ToastItem.tsx +41 -41
  76. package/src/components/Toast/components/ToastProvider.tsx +63 -63
  77. package/src/components/Toast/hooks/useToast.ts +12 -12
  78. package/src/components/Toast/index.tsx +5 -5
  79. package/src/components/Toast/styles/index.ts +135 -135
  80. package/src/components/Toast/types/index.ts +46 -46
  81. package/src/components/ToggleElement/index.tsx +58 -0
  82. package/src/components/Tooltip/index.tsx +73 -73
  83. package/src/components/Tooltip/styles.ts +77 -77
  84. package/src/hooks/useCountries.ts +41 -41
  85. package/src/hooks/useImageUpload.ts +139 -139
  86. package/src/hooks/useOnClickOutside.tsx +42 -42
  87. package/src/index.tsx +72 -72
  88. package/src/styles/index.ts +41 -41
  89. package/src/types/typographyValues.ts +178 -178
  90. package/src/utils/getNestedValue.ts +3 -3
  91. package/src/utils/states.ts +29 -29
  92. package/src/utils/uploadService.ts +180 -180
  93. package/tsconfig.json +3 -3
  94. package/tsup.config.ts +38 -38
@@ -1,357 +1,357 @@
1
- import React, { useCallback, useEffect, useRef, useState } from "react";
2
- import { Box } from "./Box";
3
- import { Button } from "./Button";
4
- import { TextField, TextFieldSlot } from "./TextField";
5
- import { Text } from "./Text";
6
- import Icon from "./Icon";
7
- import { styled } from "../styles";
8
- import { useOnClickOutside } from "../hooks/useOnClickOutside";
9
-
10
- export const TimePickerStyled = styled("div", {
11
- position: "relative",
12
- width: "fit-content",
13
- fontFamily: "$default",
14
- lineHeight: "$base",
15
- fontSize: "$14",
16
- borderRadius: "$sm",
17
- "> div > div": {
18
- input: {
19
- textAlign: "right",
20
- },
21
- },
22
- variants: {
23
- expand: {
24
- true: {
25
- width: "100%",
26
- flex: "1",
27
- display: "flex",
28
- },
29
- },
30
- },
31
- });
32
-
33
- export const TimePickerDropdownStyled = styled("div", {
34
- position: "absolute",
35
- zIndex: 10,
36
- width: "100%",
37
- maxWidth: "min-content",
38
- backgroundColor: "$neutral50",
39
- border: "1px solid $neutral300",
40
- borderRadius: "$sm",
41
- boxShadow: "0px 2px 8px 0px $shadow50",
42
- });
43
-
44
- export const TimePickerFooterStyled = styled("div", {
45
- borderTop: "2px solid $neutral100",
46
- padding: "$4 $16",
47
- display: "flex",
48
- justifyContent: "center",
49
- alignItems: "center",
50
- height: "3rem",
51
- });
52
-
53
- export const TimerPickerContentStyled = styled("div", {
54
- display: "flex",
55
- gap: "$16",
56
- alignItems: "center",
57
- padding: "$16 $16 $8 ",
58
- "& > div:nth-child(2)": {
59
- order: 2,
60
- },
61
- input: {
62
- padding: "0",
63
- textAlign: "center!important",
64
- },
65
- });
66
-
67
- export const InputStyled = styled("input", {
68
- height: "$40",
69
- fontFamily: "$default",
70
- borderRadius: "$sm",
71
- boxSizing: "border-box",
72
- color: "$dark500",
73
- border: "1px solid $dark300",
74
- position: "relative",
75
- display: "flex",
76
- width: "100%",
77
- alignItems: "center",
78
- padding: "0",
79
- outline: "none",
80
- margin: 0,
81
- textAlign: "center",
82
- "&:has(input:focus)": {
83
- border: "2px solid $brand300",
84
- },
85
- "&:has(input:disabled)": {
86
- backgroundColor: "$dark100",
87
- color: "$dark400",
88
- border: "1px solid $dark200",
89
- cursor: "not-allowed",
90
- },
91
- inputMode: "numeric",
92
- "&::-webkit-inner-spin-button": {
93
- WebkitAppearance: "none",
94
- margin: 0,
95
- },
96
- "&::-webkit-outer-spin-button": {
97
- WebkitAppearance: "none",
98
- margin: 0,
99
- },
100
- "&[type='number']": {
101
- MozAppearance: "textfield",
102
- },
103
- });
104
-
105
- export const TimePickerButtonStyled = styled("button", {
106
- backgroundColor: "transparent",
107
- border: "none",
108
- padding: "0",
109
- cursor: "pointer",
110
- "> div > div": {
111
- input: {
112
- textAlign: "right",
113
- },
114
- },
115
- variants: {
116
- expand: {
117
- true: {
118
- flex: "1",
119
- display: "flex",
120
- maxWidth: "100%",
121
- },
122
- },
123
- },
124
- });
125
- export const TimePickerIconButton = styled(Button, {
126
- padding: "0 !important",
127
- });
128
- export type TimePickerProps = {
129
- selected: string | undefined;
130
- setSelected: React.Dispatch<React.SetStateAction<string | undefined>>;
131
- position?: "bottom" | "top" | "top-right" | "bottom-right";
132
- hasError?: boolean;
133
- expand?: boolean;
134
- disabled?: boolean;
135
- };
136
- const pad = (num: number) => String(num).padStart(2, "0");
137
-
138
- const parseTime = (value?: string) => {
139
- if (!value) {
140
- return {
141
- parsedHours: "00",
142
- parsedMinutes: "00",
143
- };
144
- }
145
-
146
- const [hours, minutes] = value.split(":");
147
- const nextHours = Math.min(Math.max(parseInt(hours || "0", 10), 0), 23);
148
- const nextMinutes = Math.min(Math.max(parseInt(minutes || "0", 10), 0), 59);
149
-
150
- return {
151
- parsedHours: Number.isNaN(nextHours) ? "00" : pad(nextHours),
152
- parsedMinutes: Number.isNaN(nextMinutes) ? "00" : pad(nextMinutes),
153
- };
154
- };
155
-
156
- export function TimePicker({
157
- selected,
158
- setSelected,
159
- position = "bottom",
160
- hasError,
161
- expand = false,
162
- disabled = false,
163
- }: TimePickerProps) {
164
- const [hours, setHours] = useState("00");
165
- const [minutes, setMinutes] = useState("00");
166
- const [rawHours, setRawHours] = useState("00");
167
- const [rawMinutes, setRawMinutes] = useState("00");
168
- const [isOpen, setIsOpen] = useState(false);
169
- const dropdownRef = useRef(null);
170
-
171
- useOnClickOutside(dropdownRef, () => setIsOpen(false));
172
-
173
- useEffect(() => {
174
- const { parsedHours, parsedMinutes } = parseTime(selected);
175
- setHours(parsedHours);
176
- setMinutes(parsedMinutes);
177
- setRawHours(parsedHours);
178
- setRawMinutes(parsedMinutes);
179
- }, [selected]);
180
-
181
- const handleIncrement = useCallback(
182
- (type: "hours" | "minutes") => {
183
- if (type === "hours") {
184
- const next = (parseInt(hours) + 1) % 24;
185
- setHours(pad(next));
186
- setRawHours(pad(next));
187
- } else {
188
- const next = (parseInt(minutes) + 1) % 60;
189
- setMinutes(pad(next));
190
- setRawMinutes(pad(next));
191
- }
192
- },
193
- [hours, minutes]
194
- );
195
- const handleDecrement = useCallback(
196
- (type: "hours" | "minutes") => {
197
- if (type === "hours") {
198
- const prev = (parseInt(hours) - 1 + 24) % 24;
199
- setHours(pad(prev));
200
- setRawHours(pad(prev));
201
- } else {
202
- const prev = (parseInt(minutes) - 1 + 60) % 60;
203
- setMinutes(pad(prev));
204
- setRawMinutes(pad(prev));
205
- }
206
- },
207
- [hours, minutes]
208
- );
209
-
210
- return (
211
- <TimePickerStyled ref={dropdownRef} expand={expand}>
212
- <TimePickerButtonStyled
213
- type="button"
214
- onClick={() => setIsOpen((prev) => !prev)}
215
- expand={expand}
216
- >
217
- <TextField
218
- value={selected}
219
- readOnly
220
- type="text"
221
- placeholder="00:00"
222
- typography="labelSmall"
223
- fontWeight="regular"
224
- color={hasError ? "error" : "default"}
225
- disabled={disabled}
226
- >
227
- <TextFieldSlot>
228
- <Icon name="clock" size="xl" color="#4C4F54" />
229
- </TextFieldSlot>
230
- </TextField>
231
- </TimePickerButtonStyled>
232
-
233
- {isOpen && (
234
- <TimePickerDropdownStyled
235
- style={
236
- position === "top"
237
- ? { bottom: "110%", left: "0" }
238
- : position === "top-right"
239
- ? { bottom: "110%", right: "0" }
240
- : position === "bottom-right"
241
- ? { top: "110%", right: "0" }
242
- : { top: "110%", left: "0" }
243
- }
244
- >
245
- <TimerPickerContentStyled>
246
- {["hours", "minutes"].map((unit) => (
247
- <Box
248
- key={unit}
249
- style={{
250
- display: "flex",
251
- alignItems: "center",
252
- flexDirection: "column",
253
- }}
254
- >
255
- <TimePickerIconButton
256
- type="button"
257
- variant="text"
258
- onClick={() => handleIncrement(unit as "hours" | "minutes")}
259
- >
260
- <svg
261
- xmlns="http://www.w3.org/2000/svg"
262
- width="32"
263
- height="32"
264
- viewBox="0 0 32 32"
265
- fill="none"
266
- >
267
- <path
268
- d="M0 8C0 3.58172 3.58172 0 8 0H24C28.4183 0 32 3.58172 32 8V24C32 28.4183 28.4183 32 24 32H8C3.58172 32 0 28.4183 0 24V8Z"
269
- fill="white"
270
- />
271
- <path
272
- d="M16.7063 12.2937C16.3157 11.9031 15.6813 11.9031 15.2907 12.2937L10.2907 17.2937C9.9001 17.6843 9.9001 18.3187 10.2907 18.7093C10.6813 19.1 11.3157 19.1 11.7063 18.7093L16.0001 14.4156L20.2938 18.7062C20.6845 19.0968 21.3188 19.0968 21.7095 18.7062C22.1001 18.3156 22.1001 17.6812 21.7095 17.2906L16.7095 12.2906L16.7063 12.2937Z"
273
- fill="#808289"
274
- />
275
- </svg>
276
- </TimePickerIconButton>
277
- <InputStyled
278
- inputMode="numeric"
279
- pattern="[0-9]*"
280
- type="text"
281
- placeholder="00"
282
- value={unit === "hours" ? rawHours : rawMinutes}
283
- onChange={(e) => {
284
- const rawValue = e.target.value.replace(/\D/g, "");
285
- if (unit === "hours") {
286
- setRawHours(rawValue);
287
- } else {
288
- setRawMinutes(rawValue);
289
- }
290
- }}
291
- onBlur={() => {
292
- let num = 0;
293
- if (unit === "hours") {
294
- num = Math.min(parseInt(rawHours || "0", 10), 23);
295
- const padded = pad(num);
296
- setHours(padded);
297
- setRawHours(padded);
298
- } else {
299
- num = Math.min(parseInt(rawMinutes || "0", 10), 59);
300
- const padded = pad(num);
301
- setMinutes(padded);
302
- setRawMinutes(padded);
303
- }
304
- }}
305
- onPaste={(e) => {
306
- const paste = e.clipboardData.getData("Text");
307
- if (!/^\d{1,2}$/.test(paste)) {
308
- e.preventDefault();
309
- }
310
- }}
311
- />
312
- <TimePickerIconButton
313
- type="button"
314
- variant="text"
315
- onClick={() => handleDecrement(unit as "hours" | "minutes")}
316
- >
317
- <svg
318
- xmlns="http://www.w3.org/2000/svg"
319
- width="32"
320
- height="32"
321
- viewBox="0 0 32 32"
322
- fill="none"
323
- >
324
- <path
325
- d="M0 8C0 3.58172 3.58172 0 8 0H24C28.4183 0 32 3.58172 32 8V24C32 28.4183 28.4183 32 24 32H8C3.58172 32 0 28.4183 0 24V8Z"
326
- fill="white"
327
- />
328
- <path
329
- d="M15.2937 19.7063C15.6843 20.0969 16.3187 20.0969 16.7093 19.7063L21.7093 14.7063C22.0999 14.3157 22.0999 13.6813 21.7093 13.2907C21.3187 12.9 20.6843 12.9 20.2937 13.2907L15.9999 17.5844L11.7062 13.2938C11.3155 12.9032 10.6812 12.9032 10.2905 13.2938C9.8999 13.6844 9.8999 14.3188 10.2905 14.7094L15.2905 19.7094L15.2937 19.7063Z"
330
- fill="#808289"
331
- />
332
- </svg>
333
- </TimePickerIconButton>
334
- </Box>
335
- ))}
336
- <Text>:</Text>
337
- </TimerPickerContentStyled>
338
- <TimePickerFooterStyled>
339
- <Button
340
- type="button"
341
- variant="text"
342
- color="brand"
343
- onClick={() => {
344
- setSelected(`${hours}:${minutes}`);
345
- setIsOpen(false);
346
- }}
347
- size={"medium"}
348
- fontWeight="medium"
349
- >
350
- Aplicar
351
- </Button>
352
- </TimePickerFooterStyled>
353
- </TimePickerDropdownStyled>
354
- )}
355
- </TimePickerStyled>
356
- );
357
- }
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
+ import { Box } from "./Box";
3
+ import { Button } from "./Button";
4
+ import { TextField, TextFieldSlot } from "./TextField";
5
+ import { Text } from "./Text";
6
+ import Icon from "./Icon";
7
+ import { styled } from "../styles";
8
+ import { useOnClickOutside } from "../hooks/useOnClickOutside";
9
+
10
+ export const TimePickerStyled = styled("div", {
11
+ position: "relative",
12
+ width: "fit-content",
13
+ fontFamily: "$default",
14
+ lineHeight: "$base",
15
+ fontSize: "$14",
16
+ borderRadius: "$sm",
17
+ "> div > div": {
18
+ input: {
19
+ textAlign: "right",
20
+ },
21
+ },
22
+ variants: {
23
+ expand: {
24
+ true: {
25
+ width: "100%",
26
+ flex: "1",
27
+ display: "flex",
28
+ },
29
+ },
30
+ },
31
+ });
32
+
33
+ export const TimePickerDropdownStyled = styled("div", {
34
+ position: "absolute",
35
+ zIndex: 10,
36
+ width: "100%",
37
+ maxWidth: "min-content",
38
+ backgroundColor: "$neutral50",
39
+ border: "1px solid $neutral300",
40
+ borderRadius: "$sm",
41
+ boxShadow: "0px 2px 8px 0px $shadow50",
42
+ });
43
+
44
+ export const TimePickerFooterStyled = styled("div", {
45
+ borderTop: "2px solid $neutral100",
46
+ padding: "$4 $16",
47
+ display: "flex",
48
+ justifyContent: "center",
49
+ alignItems: "center",
50
+ height: "3rem",
51
+ });
52
+
53
+ export const TimerPickerContentStyled = styled("div", {
54
+ display: "flex",
55
+ gap: "$16",
56
+ alignItems: "center",
57
+ padding: "$16 $16 $8 ",
58
+ "& > div:nth-child(2)": {
59
+ order: 2,
60
+ },
61
+ input: {
62
+ padding: "0",
63
+ textAlign: "center!important",
64
+ },
65
+ });
66
+
67
+ export const InputStyled = styled("input", {
68
+ height: "$40",
69
+ fontFamily: "$default",
70
+ borderRadius: "$sm",
71
+ boxSizing: "border-box",
72
+ color: "$dark500",
73
+ border: "1px solid $dark300",
74
+ position: "relative",
75
+ display: "flex",
76
+ width: "100%",
77
+ alignItems: "center",
78
+ padding: "0",
79
+ outline: "none",
80
+ margin: 0,
81
+ textAlign: "center",
82
+ "&:has(input:focus)": {
83
+ border: "2px solid $brand300",
84
+ },
85
+ "&:has(input:disabled)": {
86
+ backgroundColor: "$dark100",
87
+ color: "$dark400",
88
+ border: "1px solid $dark200",
89
+ cursor: "not-allowed",
90
+ },
91
+ inputMode: "numeric",
92
+ "&::-webkit-inner-spin-button": {
93
+ WebkitAppearance: "none",
94
+ margin: 0,
95
+ },
96
+ "&::-webkit-outer-spin-button": {
97
+ WebkitAppearance: "none",
98
+ margin: 0,
99
+ },
100
+ "&[type='number']": {
101
+ MozAppearance: "textfield",
102
+ },
103
+ });
104
+
105
+ export const TimePickerButtonStyled = styled("button", {
106
+ backgroundColor: "transparent",
107
+ border: "none",
108
+ padding: "0",
109
+ cursor: "pointer",
110
+ "> div > div": {
111
+ input: {
112
+ textAlign: "right",
113
+ },
114
+ },
115
+ variants: {
116
+ expand: {
117
+ true: {
118
+ flex: "1",
119
+ display: "flex",
120
+ maxWidth: "100%",
121
+ },
122
+ },
123
+ },
124
+ });
125
+ export const TimePickerIconButton = styled(Button, {
126
+ padding: "0 !important",
127
+ });
128
+ export type TimePickerProps = {
129
+ selected: string | undefined;
130
+ setSelected: React.Dispatch<React.SetStateAction<string | undefined>>;
131
+ position?: "bottom" | "top" | "top-right" | "bottom-right";
132
+ hasError?: boolean;
133
+ expand?: boolean;
134
+ disabled?: boolean;
135
+ };
136
+ const pad = (num: number) => String(num).padStart(2, "0");
137
+
138
+ const parseTime = (value?: string) => {
139
+ if (!value) {
140
+ return {
141
+ parsedHours: "00",
142
+ parsedMinutes: "00",
143
+ };
144
+ }
145
+
146
+ const [hours, minutes] = value.split(":");
147
+ const nextHours = Math.min(Math.max(parseInt(hours || "0", 10), 0), 23);
148
+ const nextMinutes = Math.min(Math.max(parseInt(minutes || "0", 10), 0), 59);
149
+
150
+ return {
151
+ parsedHours: Number.isNaN(nextHours) ? "00" : pad(nextHours),
152
+ parsedMinutes: Number.isNaN(nextMinutes) ? "00" : pad(nextMinutes),
153
+ };
154
+ };
155
+
156
+ export function TimePicker({
157
+ selected,
158
+ setSelected,
159
+ position = "bottom",
160
+ hasError,
161
+ expand = false,
162
+ disabled = false,
163
+ }: TimePickerProps) {
164
+ const [hours, setHours] = useState("00");
165
+ const [minutes, setMinutes] = useState("00");
166
+ const [rawHours, setRawHours] = useState("00");
167
+ const [rawMinutes, setRawMinutes] = useState("00");
168
+ const [isOpen, setIsOpen] = useState(false);
169
+ const dropdownRef = useRef(null);
170
+
171
+ useOnClickOutside(dropdownRef, () => setIsOpen(false));
172
+
173
+ useEffect(() => {
174
+ const { parsedHours, parsedMinutes } = parseTime(selected);
175
+ setHours(parsedHours);
176
+ setMinutes(parsedMinutes);
177
+ setRawHours(parsedHours);
178
+ setRawMinutes(parsedMinutes);
179
+ }, [selected]);
180
+
181
+ const handleIncrement = useCallback(
182
+ (type: "hours" | "minutes") => {
183
+ if (type === "hours") {
184
+ const next = (parseInt(hours) + 1) % 24;
185
+ setHours(pad(next));
186
+ setRawHours(pad(next));
187
+ } else {
188
+ const next = (parseInt(minutes) + 1) % 60;
189
+ setMinutes(pad(next));
190
+ setRawMinutes(pad(next));
191
+ }
192
+ },
193
+ [hours, minutes]
194
+ );
195
+ const handleDecrement = useCallback(
196
+ (type: "hours" | "minutes") => {
197
+ if (type === "hours") {
198
+ const prev = (parseInt(hours) - 1 + 24) % 24;
199
+ setHours(pad(prev));
200
+ setRawHours(pad(prev));
201
+ } else {
202
+ const prev = (parseInt(minutes) - 1 + 60) % 60;
203
+ setMinutes(pad(prev));
204
+ setRawMinutes(pad(prev));
205
+ }
206
+ },
207
+ [hours, minutes]
208
+ );
209
+
210
+ return (
211
+ <TimePickerStyled ref={dropdownRef} expand={expand}>
212
+ <TimePickerButtonStyled
213
+ type="button"
214
+ onClick={() => setIsOpen((prev) => !prev)}
215
+ expand={expand}
216
+ >
217
+ <TextField
218
+ value={selected}
219
+ readOnly
220
+ type="text"
221
+ placeholder="00:00"
222
+ typography="labelSmall"
223
+ fontWeight="regular"
224
+ color={hasError ? "error" : "default"}
225
+ disabled={disabled}
226
+ >
227
+ <TextFieldSlot>
228
+ <Icon name="clock" size="xl" color="#4C4F54" />
229
+ </TextFieldSlot>
230
+ </TextField>
231
+ </TimePickerButtonStyled>
232
+
233
+ {isOpen && (
234
+ <TimePickerDropdownStyled
235
+ style={
236
+ position === "top"
237
+ ? { bottom: "110%", left: "0" }
238
+ : position === "top-right"
239
+ ? { bottom: "110%", right: "0" }
240
+ : position === "bottom-right"
241
+ ? { top: "110%", right: "0" }
242
+ : { top: "110%", left: "0" }
243
+ }
244
+ >
245
+ <TimerPickerContentStyled>
246
+ {["hours", "minutes"].map((unit) => (
247
+ <Box
248
+ key={unit}
249
+ style={{
250
+ display: "flex",
251
+ alignItems: "center",
252
+ flexDirection: "column",
253
+ }}
254
+ >
255
+ <TimePickerIconButton
256
+ type="button"
257
+ variant="text"
258
+ onClick={() => handleIncrement(unit as "hours" | "minutes")}
259
+ >
260
+ <svg
261
+ xmlns="http://www.w3.org/2000/svg"
262
+ width="32"
263
+ height="32"
264
+ viewBox="0 0 32 32"
265
+ fill="none"
266
+ >
267
+ <path
268
+ d="M0 8C0 3.58172 3.58172 0 8 0H24C28.4183 0 32 3.58172 32 8V24C32 28.4183 28.4183 32 24 32H8C3.58172 32 0 28.4183 0 24V8Z"
269
+ fill="white"
270
+ />
271
+ <path
272
+ d="M16.7063 12.2937C16.3157 11.9031 15.6813 11.9031 15.2907 12.2937L10.2907 17.2937C9.9001 17.6843 9.9001 18.3187 10.2907 18.7093C10.6813 19.1 11.3157 19.1 11.7063 18.7093L16.0001 14.4156L20.2938 18.7062C20.6845 19.0968 21.3188 19.0968 21.7095 18.7062C22.1001 18.3156 22.1001 17.6812 21.7095 17.2906L16.7095 12.2906L16.7063 12.2937Z"
273
+ fill="#808289"
274
+ />
275
+ </svg>
276
+ </TimePickerIconButton>
277
+ <InputStyled
278
+ inputMode="numeric"
279
+ pattern="[0-9]*"
280
+ type="text"
281
+ placeholder="00"
282
+ value={unit === "hours" ? rawHours : rawMinutes}
283
+ onChange={(e) => {
284
+ const rawValue = e.target.value.replace(/\D/g, "");
285
+ if (unit === "hours") {
286
+ setRawHours(rawValue);
287
+ } else {
288
+ setRawMinutes(rawValue);
289
+ }
290
+ }}
291
+ onBlur={() => {
292
+ let num = 0;
293
+ if (unit === "hours") {
294
+ num = Math.min(parseInt(rawHours || "0", 10), 23);
295
+ const padded = pad(num);
296
+ setHours(padded);
297
+ setRawHours(padded);
298
+ } else {
299
+ num = Math.min(parseInt(rawMinutes || "0", 10), 59);
300
+ const padded = pad(num);
301
+ setMinutes(padded);
302
+ setRawMinutes(padded);
303
+ }
304
+ }}
305
+ onPaste={(e) => {
306
+ const paste = e.clipboardData.getData("Text");
307
+ if (!/^\d{1,2}$/.test(paste)) {
308
+ e.preventDefault();
309
+ }
310
+ }}
311
+ />
312
+ <TimePickerIconButton
313
+ type="button"
314
+ variant="text"
315
+ onClick={() => handleDecrement(unit as "hours" | "minutes")}
316
+ >
317
+ <svg
318
+ xmlns="http://www.w3.org/2000/svg"
319
+ width="32"
320
+ height="32"
321
+ viewBox="0 0 32 32"
322
+ fill="none"
323
+ >
324
+ <path
325
+ d="M0 8C0 3.58172 3.58172 0 8 0H24C28.4183 0 32 3.58172 32 8V24C32 28.4183 28.4183 32 24 32H8C3.58172 32 0 28.4183 0 24V8Z"
326
+ fill="white"
327
+ />
328
+ <path
329
+ d="M15.2937 19.7063C15.6843 20.0969 16.3187 20.0969 16.7093 19.7063L21.7093 14.7063C22.0999 14.3157 22.0999 13.6813 21.7093 13.2907C21.3187 12.9 20.6843 12.9 20.2937 13.2907L15.9999 17.5844L11.7062 13.2938C11.3155 12.9032 10.6812 12.9032 10.2905 13.2938C9.8999 13.6844 9.8999 14.3188 10.2905 14.7094L15.2905 19.7094L15.2937 19.7063Z"
330
+ fill="#808289"
331
+ />
332
+ </svg>
333
+ </TimePickerIconButton>
334
+ </Box>
335
+ ))}
336
+ <Text>:</Text>
337
+ </TimerPickerContentStyled>
338
+ <TimePickerFooterStyled>
339
+ <Button
340
+ type="button"
341
+ variant="text"
342
+ color="brand"
343
+ onClick={() => {
344
+ setSelected(`${hours}:${minutes}`);
345
+ setIsOpen(false);
346
+ }}
347
+ size={"medium"}
348
+ fontWeight="medium"
349
+ >
350
+ Aplicar
351
+ </Button>
352
+ </TimePickerFooterStyled>
353
+ </TimePickerDropdownStyled>
354
+ )}
355
+ </TimePickerStyled>
356
+ );
357
+ }