@lets-events/react 12.11.1 → 12.11.3

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 (98) hide show
  1. package/.eslintrc.json +2 -2
  2. package/.turbo/turbo-build.log +24 -21
  3. package/CHANGELOG.md +12 -0
  4. package/dist/index.d.mts +5 -3
  5. package/dist/index.d.ts +5 -3
  6. package/dist/index.js +177 -142
  7. package/dist/index.mjs +177 -142
  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 +132 -132
  12. package/src/components/Box.tsx +3 -3
  13. package/src/components/Button/index.tsx +85 -85
  14. package/src/components/Button/styledComponents.ts +361 -361
  15. package/src/components/ButtonGroup.tsx +484 -484
  16. package/src/components/Calendar/index.tsx +172 -168
  17. package/src/components/Calendar/styledComponents.ts +508 -480
  18. package/src/components/Card.tsx +74 -74
  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 +208 -204
  23. package/src/components/Drawer/index.tsx +113 -113
  24. package/src/components/Drawer/styledComponents.ts +97 -97
  25. package/src/components/Dropdown.tsx +302 -302
  26. package/src/components/Filter.tsx +164 -164
  27. package/src/components/Flex.tsx +130 -130
  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 +88 -88
  46. package/src/components/FormFields/RichEditorFormField.tsx +128 -128
  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 +135 -131
  60. package/src/components/MultiSelect/index.tsx +418 -417
  61. package/src/components/MultiSelect/styledComponents.ts +176 -176
  62. package/src/components/RadioGroup.tsx +210 -210
  63. package/src/components/RichEditor/QuillComponent.tsx +419 -419
  64. package/src/components/RichEditor/RichEditor.tsx +53 -53
  65. package/src/components/RichEditor/RichTextPresenter.tsx +18 -18
  66. package/src/components/RichEditor/editorConfig.ts +149 -149
  67. package/src/components/RichEditor/index.ts +3 -3
  68. package/src/components/RichEditor/styledComponents.ts +1175 -1175
  69. package/src/components/RichEditor/types.ts +12 -12
  70. package/src/components/Section.tsx +33 -33
  71. package/src/components/Step.tsx +164 -164
  72. package/src/components/Switch.tsx +108 -108
  73. package/src/components/Text.tsx +54 -54
  74. package/src/components/TextField.tsx +423 -423
  75. package/src/components/TextareaField.tsx +116 -116
  76. package/src/components/TimePicker.tsx +357 -357
  77. package/src/components/Toast/components/ToastItem.tsx +41 -41
  78. package/src/components/Toast/components/ToastProvider.tsx +63 -63
  79. package/src/components/Toast/hooks/useToast.ts +12 -12
  80. package/src/components/Toast/index.tsx +5 -5
  81. package/src/components/Toast/styles/index.ts +135 -135
  82. package/src/components/Toast/types/index.ts +46 -46
  83. package/src/components/ToggleElement/index.tsx +58 -58
  84. package/src/components/Tooltip/index.tsx +126 -126
  85. package/src/components/Tooltip/styles.ts +77 -77
  86. package/src/hooks/useCountries.ts +41 -41
  87. package/src/hooks/useHasHover.ts +21 -21
  88. package/src/hooks/useImageUpload.ts +139 -139
  89. package/src/hooks/useMediaQuery.ts +19 -19
  90. package/src/hooks/useOnClickOutside.tsx +42 -42
  91. package/src/index.tsx +72 -72
  92. package/src/styles/index.ts +41 -41
  93. package/src/types/typographyValues.ts +178 -178
  94. package/src/utils/getNestedValue.ts +3 -3
  95. package/src/utils/states.ts +29 -29
  96. package/src/utils/uploadService.ts +180 -180
  97. package/tsconfig.json +3 -3
  98. package/tsup.config.ts +38 -38
@@ -1,417 +1,418 @@
1
- import React, { useCallback, useRef, useState } from "react";
2
- import { DropdownMenu, Theme } from "@radix-ui/themes";
3
- import { CheckboxGroup, CheckboxItem } from "../CheckboxGroup";
4
- import { Text } from "../Text";
5
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
6
- import {
7
- faChevronDown,
8
- faChevronUp,
9
- faSquareXmark,
10
- } from "@fortawesome/free-solid-svg-icons";
11
- import { colors } from "@lets-events/tokens";
12
- import { ComponentProps, useMemo } from "react";
13
- import { Flex } from "../Flex";
14
- import { Button } from "../Button";
15
- import { Modal } from "../Modal";
16
- import { useMediaQuery } from "../../hooks/useMediaQuery";
17
- import {
18
- CloseBtnStyled,
19
- ButtonSelectAllStyled,
20
- itemStyle,
21
- StyledContent,
22
- StyledFlexSelectedItems,
23
- StyledFlexWithMaxHeight,
24
- StyledItem,
25
- StyledModalOptionsWrapper,
26
- StyledSectionDivider,
27
- StyledSectionTitle,
28
- StyledText,
29
- StyledTrigger,
30
- } from "./styledComponents";
31
-
32
- const MOBILE_MODAL_MAX_HEIGHT = "90vh";
33
- const MOBILE_MODAL_HEADER_OFFSET = "65px";
34
-
35
- const MOBILE_BREAKPOINT = "(max-width: 840px)";
36
-
37
- export type MultiSelectOption = {
38
- label: string;
39
- value: string;
40
- };
41
-
42
- export type MultiSelectSection = {
43
- name: string;
44
- options: MultiSelectOption[];
45
- };
46
-
47
- export type MultiSelectProps = ComponentProps<typeof StyledTrigger> & {
48
- placeholder?: string;
49
- value?: string[];
50
- onValueChange?: (v: string[]) => void;
51
- options?: MultiSelectOption[];
52
- optionsBySection?: MultiSelectSection[];
53
- width?: string;
54
- zIndex?: string;
55
- showSelectedValues?: boolean;
56
- singleSelect?: boolean;
57
- selectedOrientation?: "row" | "column";
58
- disabled?: boolean;
59
- maxHeight?: string;
60
- selectedAllOptions?: boolean;
61
- selectedAllText?: string;
62
- selectedScroll?: boolean;
63
- showMoreButton?: boolean;
64
- showMoreButtonLabel?: string;
65
- showMoreButtonOnClick?: () => void;
66
- helperTextAfterField?: string;
67
- };
68
-
69
- export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
70
- (
71
- {
72
- placeholder,
73
- value: selectedValues = [],
74
- onValueChange,
75
- options = [],
76
- optionsBySection,
77
- color,
78
- width = "100%",
79
- zIndex = "auto",
80
- showSelectedValues = true,
81
- singleSelect = false,
82
- selectedOrientation = "column",
83
- disabled = false,
84
- maxHeight,
85
- selectedAllOptions = false,
86
- selectedAllText,
87
- selectedScroll = false,
88
- showMoreButton = false,
89
- showMoreButtonLabel = "Carregar mais",
90
- showMoreButtonOnClick,
91
- helperTextAfterField = "",
92
- },
93
- fowardedRef
94
- ) => {
95
- const [isOpen, setIsOpen] = useState(false);
96
- const triggerRef = useRef<HTMLDivElement>(null);
97
- const [allOptionsSelected, setAllOptionsSelected] = useState(false);
98
- const isMobile = useMediaQuery(MOBILE_BREAKPOINT);
99
- const hasSections = !!optionsBySection?.length;
100
-
101
- const resolvedOptions = useMemo((): MultiSelectOption[] => {
102
- if (hasSections) {
103
- return optionsBySection!.reduce<MultiSelectOption[]>(
104
- (acc, section) => acc.concat(section.options),
105
- []
106
- );
107
- }
108
- return options;
109
- }, [hasSections, options, optionsBySection]);
110
-
111
- const labelByValue = useMemo(() => {
112
- return resolvedOptions.reduce<{ [key: string]: string }>((prev, curr) => {
113
- return {
114
- ...prev,
115
- [curr.value]: curr.label,
116
- };
117
- }, {});
118
- }, [resolvedOptions]);
119
-
120
- const handleRemove = useCallback(
121
- (value: string) => {
122
- const newValue = selectedValues.filter((v) => v !== value);
123
- onValueChange?.(newValue);
124
- },
125
- [selectedValues, onValueChange]
126
- );
127
-
128
- const handleSelectAll = useCallback(
129
- (e: React.MouseEvent) => {
130
- e.preventDefault();
131
- e.stopPropagation();
132
- const allSelected = selectedValues.length === resolvedOptions.length;
133
- if (allSelected) {
134
- onValueChange?.([]);
135
- setAllOptionsSelected(false)
136
- } else {
137
- onValueChange?.(resolvedOptions.map((o) => o.value));
138
- setAllOptionsSelected(true)
139
- }
140
- },
141
- [selectedValues, resolvedOptions, onValueChange]
142
- );
143
-
144
- const text = useMemo(() => {
145
- if (selectedValues.length > 0 && singleSelect) {
146
- const value = selectedValues[0];
147
- return labelByValue[value];
148
- }
149
- return placeholder ?? "Selecione";
150
- }, [selectedValues, placeholder, singleSelect, labelByValue]);
151
-
152
- const handleItemClick = (v: string) => {
153
- onValueChange?.([v]);
154
- setIsOpen(false);
155
- };
156
-
157
- const handleToggle = useCallback(
158
- (e: React.MouseEvent) => {
159
- e.preventDefault();
160
- e.stopPropagation();
161
- if (disabled) return;
162
- setIsOpen((prev) => !prev);
163
- },
164
- [disabled]
165
- );
166
-
167
- const triggerElement = (
168
- <StyledTrigger
169
- ref={(r) => {
170
- if (!r) return;
171
- triggerRef.current = r;
172
- if (fowardedRef) {
173
- if (typeof fowardedRef === "function") fowardedRef(r);
174
- else fowardedRef.current = r;
175
- }
176
- }}
177
- color={color}
178
- disabled={disabled}
179
- style={width !== "100%" ? { width } : undefined}
180
- onClick={!isMobile ? handleToggle : undefined}
181
- >
182
- <StyledText
183
- typography={"labelMedium"}
184
- color={disabled ? "dark400" : undefined}
185
- >
186
- {text}
187
- </StyledText>
188
- <FontAwesomeIcon
189
- icon={isOpen ? faChevronUp : faChevronDown}
190
- size="sm"
191
- color={disabled ? colors.dark400 : colors.dark600}
192
- />
193
- </StyledTrigger>
194
- );
195
-
196
- const selectAllBlock = selectedAllOptions && (
197
- <>
198
- <ButtonSelectAllStyled
199
- css={itemStyle}
200
- onClick={(e) => {
201
- handleSelectAll(e);
202
- setIsOpen(false);
203
- }}
204
- type="button"
205
- >
206
- <div className={allOptionsSelected ? "checked" : ""}></div>
207
- <Text typography="labelSmall">
208
- {selectedAllText ? selectedAllText : "Selecionar Todos"}
209
- </Text>
210
- </ButtonSelectAllStyled>
211
- <StyledSectionDivider />
212
- </>
213
- );
214
-
215
- const showMoreButtonBlock = showMoreButton && showMoreButtonOnClick && (
216
- <Button
217
- variant="menuDropdownItem"
218
- color="brand"
219
- onClick={showMoreButtonOnClick}
220
- fontWeight="semibold"
221
- type="button"
222
- css={{
223
- justifyContent: "flex-start",
224
- color: "var(--colors-brand500)!important",
225
- }}
226
- >
227
- {showMoreButtonLabel}
228
- </Button>
229
- );
230
-
231
- const renderCheckboxOptions = () => {
232
- if (hasSections) {
233
- return optionsBySection!.map((section, sectionIndex) => (
234
- <React.Fragment key={section.name}>
235
- {sectionIndex > 0 && <StyledSectionDivider />}
236
- <StyledSectionTitle typography="labelSmall" fontWeight="semibold" color="dark600">
237
- {section.name}
238
- </StyledSectionTitle>
239
- {section.options.map(({ value, label }, i) => (
240
- <CheckboxItem value={value} css={itemStyle} key={`${section.name}-${i}`}>
241
- <Text typography={"labelSmall"}>{label}</Text>
242
- </CheckboxItem>
243
- ))}
244
- </React.Fragment>
245
- ));
246
- }
247
-
248
- return resolvedOptions.map(({ value, label }, i) => (
249
- <CheckboxItem value={value} css={itemStyle} key={i}>
250
- <Text typography={"labelSmall"}>{label}</Text>
251
- </CheckboxItem>
252
- ));
253
- };
254
-
255
- const renderSingleSelectOptions = () => {
256
- if (hasSections) {
257
- return optionsBySection!.map((section, sectionIndex) => (
258
- <React.Fragment key={section.name}>
259
- {sectionIndex > 0 && <StyledSectionDivider />}
260
- <StyledSectionTitle typography="labelSmall" fontWeight="semibold" color="dark600">
261
- {section.name}
262
- </StyledSectionTitle>
263
- {section.options.map(({ value, label }, i) => (
264
- <StyledItem key={`${section.name}-${i}`} onClick={() => handleItemClick(value)}>
265
- <Text typography={"labelSmall"}>{label}</Text>
266
- </StyledItem>
267
- ))}
268
- </React.Fragment>
269
- ));
270
- }
271
-
272
- return resolvedOptions.map(({ value, label }, i) => (
273
- <StyledItem key={i} onClick={() => handleItemClick(value)}>
274
- <Text typography={"labelSmall"}>{label}</Text>
275
- </StyledItem>
276
- ));
277
- };
278
-
279
- const optionsContent = !singleSelect ? (
280
- <CheckboxGroup
281
- value={selectedValues}
282
- onValueChange={(v) => {
283
- onValueChange?.(v);
284
- setAllOptionsSelected((v || []).length === resolvedOptions.length);
285
- }}
286
- >
287
- <StyledFlexWithMaxHeight
288
- direction={"column"}
289
- gap={8}
290
- hasMaxHeight={!!maxHeight && !isMobile}
291
- style={maxHeight && !isMobile ? { maxHeight } : undefined}
292
- >
293
- {selectAllBlock}
294
- {renderCheckboxOptions()}
295
- {showMoreButtonBlock}
296
- </StyledFlexWithMaxHeight>
297
- </CheckboxGroup>
298
- ) : (
299
- <StyledFlexWithMaxHeight
300
- direction={"column"}
301
- gap={8}
302
- hasMaxHeight={!!maxHeight && !isMobile}
303
- style={maxHeight && !isMobile ? { maxHeight } : undefined}
304
- >
305
- {renderSingleSelectOptions()}
306
- {showMoreButtonBlock}
307
- </StyledFlexWithMaxHeight>
308
- );
309
-
310
- const modalZIndex =
311
- zIndex === "auto" ? undefined : Number(zIndex);
312
-
313
- return (
314
- <Theme style={width !== "100%" ? { width } : undefined}>
315
- {isMobile ? (
316
- <Modal
317
- open={disabled ? false : isOpen}
318
- onOpenChange={(open) => !disabled && setIsOpen(open)}
319
- trigger={triggerElement}
320
- title={placeholder ?? "Selecione"}
321
- maxHeight={MOBILE_MODAL_MAX_HEIGHT}
322
- zIndex={modalZIndex}
323
- preventAutoFocus
324
- fitContent
325
- >
326
- <StyledModalOptionsWrapper
327
- css={{ maxHeight: `calc(${MOBILE_MODAL_MAX_HEIGHT} - ${MOBILE_MODAL_HEADER_OFFSET})` }}
328
- >
329
- {optionsContent}
330
- </StyledModalOptionsWrapper>
331
- </Modal>
332
- ) : (
333
- <DropdownMenu.Root open={isOpen} onOpenChange={setIsOpen}>
334
- <DropdownMenu.Trigger>{triggerElement}</DropdownMenu.Trigger>
335
- <StyledContent
336
- css={{
337
- width: "100%",
338
- zIndex: zIndex === "auto" ? 999999 : zIndex,
339
- }}
340
- >
341
- {optionsContent}
342
- </StyledContent>
343
- </DropdownMenu.Root>
344
- )}
345
- <div style={{ padding: '4px 8px 0 0' }}>
346
- {helperTextAfterField && (
347
- <Text typography="captionMedium" fontWeight="regular" color="dark600">
348
- {helperTextAfterField}
349
- </Text>
350
- )}
351
- {selectedValues.length > 0 && showSelectedValues && (
352
- <StyledFlexSelectedItems
353
- direction={selectedOrientation}
354
- gap={8}
355
- align={selectedOrientation === "column" ? "start" : "center"}
356
- justify={"start"}
357
- css={{ ...(selectedScroll && { maxHeight: maxHeight || "400px" }) }}
358
- >
359
- {allOptionsSelected ? (
360
- <Flex
361
- key="all-selected"
362
- gap={4}
363
- align={"center"}
364
- css={{ flexWrap: "wrap" }}
365
- >
366
- <CloseBtnStyled
367
- onClick={(e) => {
368
- e.stopPropagation();
369
- onValueChange?.([]);
370
- setAllOptionsSelected(false);
371
- }}
372
- type="button"
373
- >
374
- <FontAwesomeIcon icon={faSquareXmark} size="sm" />
375
- </CloseBtnStyled>
376
- <Text
377
- typography={"captionMedium"}
378
- fontWeight={"regular"}
379
- color="dark600"
380
- >
381
- {"Todos selecionados"}
382
- </Text>
383
- </Flex>
384
- ) : (
385
- selectedValues.map((value) => (
386
- <Flex
387
- key={value}
388
- gap={4}
389
- align={"center"}
390
- css={{ flexWrap: "wrap" }}
391
- >
392
- <CloseBtnStyled
393
- onClick={(e) => {
394
- e.stopPropagation();
395
- handleRemove(value);
396
- }}
397
- type="button"
398
- >
399
- <FontAwesomeIcon icon={faSquareXmark} size="sm" />
400
- </CloseBtnStyled>
401
- <Text
402
- typography={"captionMedium"}
403
- fontWeight={"regular"}
404
- color="dark600"
405
- >
406
- {labelByValue[value]}
407
- </Text>
408
- </Flex>
409
- ))
410
- )}
411
- </StyledFlexSelectedItems>
412
- )}
413
- </div>
414
- </Theme>
415
- );
416
- }
417
- );
1
+ import React, { useCallback, useRef, useState } from "react";
2
+ import { DropdownMenu, Theme } from "@radix-ui/themes";
3
+ import { CheckboxGroup, CheckboxItem } from "../CheckboxGroup";
4
+ import { Text } from "../Text";
5
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
6
+ import {
7
+ faChevronDown,
8
+ faChevronUp,
9
+ faSquareXmark,
10
+ } from "@fortawesome/free-solid-svg-icons";
11
+ import { colors } from "@lets-events/tokens";
12
+ import { ComponentProps, useMemo } from "react";
13
+ import { Flex } from "../Flex";
14
+ import { Button } from "../Button";
15
+ import { Modal } from "../Modal";
16
+ import { useMediaQuery } from "../../hooks/useMediaQuery";
17
+ import {
18
+ CloseBtnStyled,
19
+ ButtonSelectAllStyled,
20
+ itemStyle,
21
+ StyledContent,
22
+ StyledFlexSelectedItems,
23
+ StyledFlexWithMaxHeight,
24
+ StyledItem,
25
+ StyledModalOptionsWrapper,
26
+ StyledSectionDivider,
27
+ StyledSectionTitle,
28
+ StyledText,
29
+ StyledTrigger,
30
+ } from "./styledComponents";
31
+
32
+ const MOBILE_MODAL_MAX_HEIGHT = "90vh";
33
+ const MOBILE_MODAL_HEADER_OFFSET = "65px";
34
+
35
+ const MOBILE_BREAKPOINT = "(max-width: 840px)";
36
+
37
+ export type MultiSelectOption = {
38
+ label: string;
39
+ value: string;
40
+ };
41
+
42
+ export type MultiSelectSection = {
43
+ name: string;
44
+ options: MultiSelectOption[];
45
+ };
46
+
47
+ export type MultiSelectProps = ComponentProps<typeof StyledTrigger> & {
48
+ placeholder?: string;
49
+ value?: string[];
50
+ onValueChange?: (v: string[]) => void;
51
+ options?: MultiSelectOption[];
52
+ optionsBySection?: MultiSelectSection[];
53
+ width?: string;
54
+ zIndex?: string;
55
+ showSelectedValues?: boolean;
56
+ singleSelect?: boolean;
57
+ selectedOrientation?: "row" | "column";
58
+ disabled?: boolean;
59
+ maxHeight?: string;
60
+ selectedAllOptions?: boolean;
61
+ selectedAllText?: string;
62
+ selectedScroll?: boolean;
63
+ showMoreButton?: boolean;
64
+ showMoreButtonLabel?: string;
65
+ showMoreButtonOnClick?: () => void;
66
+ helperTextAfterField?: string;
67
+ };
68
+
69
+ export const MultiSelect = React.forwardRef<HTMLDivElement, MultiSelectProps>(
70
+ (
71
+ {
72
+ placeholder,
73
+ value: selectedValues = [],
74
+ onValueChange,
75
+ options = [],
76
+ optionsBySection,
77
+ color,
78
+ width = "100%",
79
+ zIndex = "auto",
80
+ showSelectedValues = true,
81
+ singleSelect = false,
82
+ selectedOrientation = "column",
83
+ disabled = false,
84
+ maxHeight,
85
+ selectedAllOptions = false,
86
+ selectedAllText,
87
+ selectedScroll = false,
88
+ showMoreButton = false,
89
+ showMoreButtonLabel = "Carregar mais",
90
+ showMoreButtonOnClick,
91
+ helperTextAfterField = "",
92
+ },
93
+ fowardedRef
94
+ ) => {
95
+ const [isOpen, setIsOpen] = useState(false);
96
+ const triggerRef = useRef<HTMLDivElement>(null);
97
+ const [allOptionsSelected, setAllOptionsSelected] = useState(false);
98
+ const isMobile = useMediaQuery(MOBILE_BREAKPOINT);
99
+ const hasSections = !!optionsBySection?.length;
100
+
101
+ const resolvedOptions = useMemo((): MultiSelectOption[] => {
102
+ if (hasSections) {
103
+ return optionsBySection!.reduce<MultiSelectOption[]>(
104
+ (acc, section) => acc.concat(section.options),
105
+ []
106
+ );
107
+ }
108
+ return options;
109
+ }, [hasSections, options, optionsBySection]);
110
+
111
+ const labelByValue = useMemo(() => {
112
+ return resolvedOptions.reduce<{ [key: string]: string }>((prev, curr) => {
113
+ return {
114
+ ...prev,
115
+ [curr.value]: curr.label,
116
+ };
117
+ }, {});
118
+ }, [resolvedOptions]);
119
+
120
+ const handleRemove = useCallback(
121
+ (value: string) => {
122
+ const newValue = selectedValues.filter((v) => v !== value);
123
+ onValueChange?.(newValue);
124
+ },
125
+ [selectedValues, onValueChange]
126
+ );
127
+
128
+ const handleSelectAll = useCallback(
129
+ (e: React.MouseEvent) => {
130
+ e.preventDefault();
131
+ e.stopPropagation();
132
+ const allSelected = selectedValues.length === resolvedOptions.length;
133
+ if (allSelected) {
134
+ onValueChange?.([]);
135
+ setAllOptionsSelected(false)
136
+ } else {
137
+ onValueChange?.(resolvedOptions.map((o) => o.value));
138
+ setAllOptionsSelected(true)
139
+ }
140
+ },
141
+ [selectedValues, resolvedOptions, onValueChange]
142
+ );
143
+
144
+ const text = useMemo(() => {
145
+ if (selectedValues.length > 0 && singleSelect) {
146
+ const value = selectedValues[0];
147
+ return labelByValue[value];
148
+ }
149
+ return placeholder ?? "Selecione";
150
+ }, [selectedValues, placeholder, singleSelect, labelByValue]);
151
+
152
+ const handleItemClick = (v: string) => {
153
+ onValueChange?.([v]);
154
+ setIsOpen(false);
155
+ };
156
+
157
+ const handleToggle = useCallback(
158
+ (e: React.MouseEvent) => {
159
+ e.preventDefault();
160
+ e.stopPropagation();
161
+ if (disabled) return;
162
+ setIsOpen((prev) => !prev);
163
+ },
164
+ [disabled]
165
+ );
166
+
167
+ const triggerElement = (
168
+ <StyledTrigger
169
+ ref={(r) => {
170
+ if (!r) return;
171
+ triggerRef.current = r;
172
+ if (fowardedRef) {
173
+ if (typeof fowardedRef === "function") fowardedRef(r);
174
+ else fowardedRef.current = r;
175
+ }
176
+ }}
177
+ color={color}
178
+ disabled={disabled}
179
+ style={width !== "100%" ? { width } : undefined}
180
+ onClick={!isMobile ? handleToggle : undefined}
181
+ >
182
+ <StyledText
183
+ typography={"labelMedium"}
184
+ color={disabled ? "dark400" : undefined}
185
+ >
186
+ {text}
187
+ </StyledText>
188
+ <FontAwesomeIcon
189
+ icon={isOpen ? faChevronUp : faChevronDown}
190
+ size="sm"
191
+ color={disabled ? colors.dark400 : colors.dark600}
192
+ />
193
+ </StyledTrigger>
194
+ );
195
+
196
+ const selectAllBlock = selectedAllOptions && (
197
+ <>
198
+ <ButtonSelectAllStyled
199
+ css={itemStyle}
200
+ onClick={(e) => {
201
+ handleSelectAll(e);
202
+ setIsOpen(false);
203
+ }}
204
+ type="button"
205
+ >
206
+ <div className={allOptionsSelected ? "checked" : ""}></div>
207
+ <Text typography="labelSmall">
208
+ {selectedAllText ? selectedAllText : "Selecionar Todos"}
209
+ </Text>
210
+ </ButtonSelectAllStyled>
211
+ <StyledSectionDivider />
212
+ </>
213
+ );
214
+
215
+ const showMoreButtonBlock = showMoreButton && showMoreButtonOnClick && (
216
+ <Button
217
+ variant="menuDropdownItem"
218
+ color="brand"
219
+ onClick={showMoreButtonOnClick}
220
+ fontWeight="semibold"
221
+ type="button"
222
+ css={{
223
+ justifyContent: "flex-start",
224
+ color: "var(--colors-brand500)!important",
225
+ }}
226
+ >
227
+ {showMoreButtonLabel}
228
+ </Button>
229
+ );
230
+
231
+ const renderCheckboxOptions = () => {
232
+ if (hasSections) {
233
+ return optionsBySection!.map((section, sectionIndex) => (
234
+ <React.Fragment key={section.name}>
235
+ {sectionIndex > 0 && <StyledSectionDivider />}
236
+ <StyledSectionTitle typography="labelSmall" fontWeight="semibold" color="dark600">
237
+ {section.name}
238
+ </StyledSectionTitle>
239
+ {section.options.map(({ value, label }, i) => (
240
+ <CheckboxItem value={value} css={itemStyle} key={`${section.name}-${i}`}>
241
+ <Text typography={"labelSmall"}>{label}</Text>
242
+ </CheckboxItem>
243
+ ))}
244
+ </React.Fragment>
245
+ ));
246
+ }
247
+
248
+ return resolvedOptions.map(({ value, label }, i) => (
249
+ <CheckboxItem value={value} css={itemStyle} key={i}>
250
+ <Text typography={"labelSmall"}>{label}</Text>
251
+ </CheckboxItem>
252
+ ));
253
+ };
254
+
255
+ const renderSingleSelectOptions = () => {
256
+ if (hasSections) {
257
+ return optionsBySection!.map((section, sectionIndex) => (
258
+ <React.Fragment key={section.name}>
259
+ {sectionIndex > 0 && <StyledSectionDivider />}
260
+ <StyledSectionTitle typography="labelSmall" fontWeight="semibold" color="dark600">
261
+ {section.name}
262
+ </StyledSectionTitle>
263
+ {section.options.map(({ value, label }, i) => (
264
+ <StyledItem key={`${section.name}-${i}`} onClick={() => handleItemClick(value)}>
265
+ <Text typography={"labelSmall"}>{label}</Text>
266
+ </StyledItem>
267
+ ))}
268
+ </React.Fragment>
269
+ ));
270
+ }
271
+
272
+ return resolvedOptions.map(({ value, label }, i) => (
273
+ <StyledItem key={i} onClick={() => handleItemClick(value)}>
274
+ <Text typography={"labelSmall"}>{label}</Text>
275
+ </StyledItem>
276
+ ));
277
+ };
278
+
279
+ const optionsContent = !singleSelect ? (
280
+ <CheckboxGroup
281
+ value={selectedValues}
282
+ onValueChange={(v) => {
283
+ onValueChange?.(v);
284
+ setAllOptionsSelected((v || []).length === resolvedOptions.length);
285
+ }}
286
+ >
287
+ <StyledFlexWithMaxHeight
288
+ direction={"column"}
289
+ gap={8}
290
+ hasMaxHeight={!!maxHeight && !isMobile}
291
+ style={maxHeight && !isMobile ? { maxHeight } : undefined}
292
+ >
293
+ {selectAllBlock}
294
+ {renderCheckboxOptions()}
295
+ {showMoreButtonBlock}
296
+ </StyledFlexWithMaxHeight>
297
+ </CheckboxGroup>
298
+ ) : (
299
+ <StyledFlexWithMaxHeight
300
+ direction={"column"}
301
+ gap={8}
302
+ hasMaxHeight={!!maxHeight && !isMobile}
303
+ style={maxHeight && !isMobile ? { maxHeight } : undefined}
304
+ >
305
+ {renderSingleSelectOptions()}
306
+ {showMoreButtonBlock}
307
+ </StyledFlexWithMaxHeight>
308
+ );
309
+
310
+ const modalZIndex =
311
+ zIndex === "auto" ? undefined : Number(zIndex);
312
+
313
+ return (
314
+ <Theme style={width !== "100%" ? { width } : undefined}>
315
+ {isMobile ? (
316
+ <Modal
317
+ open={disabled ? false : isOpen}
318
+ onOpenChange={(open) => !disabled && setIsOpen(open)}
319
+ trigger={triggerElement}
320
+ title={placeholder ?? "Selecione"}
321
+ maxHeight={MOBILE_MODAL_MAX_HEIGHT}
322
+ zIndex={modalZIndex}
323
+ preventAutoFocus
324
+ titleTypography="headline8"
325
+ fitContent
326
+ >
327
+ <StyledModalOptionsWrapper
328
+ css={{ maxHeight: `calc(${MOBILE_MODAL_MAX_HEIGHT} - ${MOBILE_MODAL_HEADER_OFFSET})` }}
329
+ >
330
+ {optionsContent}
331
+ </StyledModalOptionsWrapper>
332
+ </Modal>
333
+ ) : (
334
+ <DropdownMenu.Root open={isOpen} onOpenChange={setIsOpen}>
335
+ <DropdownMenu.Trigger>{triggerElement}</DropdownMenu.Trigger>
336
+ <StyledContent
337
+ css={{
338
+ width: "100%",
339
+ zIndex: zIndex === "auto" ? 999999 : zIndex,
340
+ }}
341
+ >
342
+ {optionsContent}
343
+ </StyledContent>
344
+ </DropdownMenu.Root>
345
+ )}
346
+ <div style={{ padding: '4px 8px 0 0' }}>
347
+ {helperTextAfterField && (
348
+ <Text typography="captionMedium" fontWeight="regular" color="dark600">
349
+ {helperTextAfterField}
350
+ </Text>
351
+ )}
352
+ {selectedValues.length > 0 && showSelectedValues && (
353
+ <StyledFlexSelectedItems
354
+ direction={selectedOrientation}
355
+ gap={8}
356
+ align={selectedOrientation === "column" ? "start" : "center"}
357
+ justify={"start"}
358
+ css={{ ...(selectedScroll && { maxHeight: maxHeight || "400px" }) }}
359
+ >
360
+ {allOptionsSelected ? (
361
+ <Flex
362
+ key="all-selected"
363
+ gap={4}
364
+ align={"center"}
365
+ css={{ flexWrap: "wrap" }}
366
+ >
367
+ <CloseBtnStyled
368
+ onClick={(e) => {
369
+ e.stopPropagation();
370
+ onValueChange?.([]);
371
+ setAllOptionsSelected(false);
372
+ }}
373
+ type="button"
374
+ >
375
+ <FontAwesomeIcon icon={faSquareXmark} size="sm" />
376
+ </CloseBtnStyled>
377
+ <Text
378
+ typography={"captionMedium"}
379
+ fontWeight={"regular"}
380
+ color="dark600"
381
+ >
382
+ {"Todos selecionados"}
383
+ </Text>
384
+ </Flex>
385
+ ) : (
386
+ selectedValues.map((value) => (
387
+ <Flex
388
+ key={value}
389
+ gap={4}
390
+ align={"center"}
391
+ css={{ flexWrap: "wrap" }}
392
+ >
393
+ <CloseBtnStyled
394
+ onClick={(e) => {
395
+ e.stopPropagation();
396
+ handleRemove(value);
397
+ }}
398
+ type="button"
399
+ >
400
+ <FontAwesomeIcon icon={faSquareXmark} size="sm" />
401
+ </CloseBtnStyled>
402
+ <Text
403
+ typography={"captionMedium"}
404
+ fontWeight={"regular"}
405
+ color="dark600"
406
+ >
407
+ {labelByValue[value]}
408
+ </Text>
409
+ </Flex>
410
+ ))
411
+ )}
412
+ </StyledFlexSelectedItems>
413
+ )}
414
+ </div>
415
+ </Theme>
416
+ );
417
+ }
418
+ );