@greatapps/common 1.1.218 → 1.1.221
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/dist/components/account/ConfigurationsMyAccountModal.mjs +6 -6
- package/dist/components/account/ConfigurationsMyAccountModal.mjs.map +1 -1
- package/dist/components/account/ConfirmDeleteAccountModal.mjs +2 -2
- package/dist/components/account/ConfirmDeleteAccountModal.mjs.map +1 -1
- package/dist/components/account/ConfirmGlobalPreferencesModal.mjs +2 -2
- package/dist/components/account/ConfirmGlobalPreferencesModal.mjs.map +1 -1
- package/dist/components/account/DeleteAccountModal.mjs +3 -3
- package/dist/components/account/DeleteAccountModal.mjs.map +1 -1
- package/dist/components/account/DisableTwoFactorAuthModal.mjs +2 -2
- package/dist/components/account/DisableTwoFactorAuthModal.mjs.map +1 -1
- package/dist/components/account/IsntPossibleDeleteAccountModal.mjs +2 -2
- package/dist/components/account/IsntPossibleDeleteAccountModal.mjs.map +1 -1
- package/dist/components/account/TwoFactorAuthModal.mjs +6 -6
- package/dist/components/account/TwoFactorAuthModal.mjs.map +1 -1
- package/dist/components/account/sections/ChangeEmailModal.mjs +6 -6
- package/dist/components/account/sections/ChangeEmailModal.mjs.map +1 -1
- package/dist/components/account/sections/ChangePasswordSection.mjs +4 -4
- package/dist/components/account/sections/ChangePasswordSection.mjs.map +1 -1
- package/dist/components/account/sections/ChangePhoneModal.mjs +5 -5
- package/dist/components/account/sections/ChangePhoneModal.mjs.map +1 -1
- package/dist/components/account/sections/MyProfileSection.mjs +3 -3
- package/dist/components/account/sections/MyProfileSection.mjs.map +1 -1
- package/dist/components/account/sections/PreferencesSection.mjs +6 -6
- package/dist/components/account/sections/PreferencesSection.mjs.map +1 -1
- package/dist/components/account/sections/SecuritySection.mjs +3 -3
- package/dist/components/account/sections/SecuritySection.mjs.map +1 -1
- package/dist/components/layouts/AppMobileNavBar.mjs +0 -1
- package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -1
- package/dist/components/layouts/MdSideBarNavigation.mjs +2 -2
- package/dist/components/layouts/MdSideBarNavigation.mjs.map +1 -1
- package/dist/components/layouts/NavBar.mjs +2 -2
- package/dist/components/layouts/NavBar.mjs.map +1 -1
- package/dist/components/layouts/NotificationsPopover.mjs +4 -4
- package/dist/components/layouts/NotificationsPopover.mjs.map +1 -1
- package/dist/components/layouts/ProfilePopover.mjs +7 -10
- package/dist/components/layouts/ProfilePopover.mjs.map +1 -1
- package/dist/components/layouts/UsersSelectorPopover.mjs +5 -5
- package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
- package/dist/components/navigation/ProjectSelectorPopover.mjs +6 -6
- package/dist/components/navigation/ProjectSelectorPopover.mjs.map +1 -1
- package/dist/components/navigation/subcomponents/ProjectSelector.mjs +5 -5
- package/dist/components/navigation/subcomponents/ProjectSelector.mjs.map +1 -1
- package/dist/components/pages/notifications/Notifications.mjs +4 -4
- package/dist/components/pages/notifications/Notifications.mjs.map +1 -1
- package/dist/components/ui/buttons/CopyButton.mjs +2 -2
- package/dist/components/ui/buttons/CopyButton.mjs.map +1 -1
- package/dist/components/ui/data-display/Accordion.mjs +2 -2
- package/dist/components/ui/data-display/Accordion.mjs.map +1 -1
- package/dist/components/ui/data-display/Pagination.mjs +7 -7
- package/dist/components/ui/data-display/Pagination.mjs.map +1 -1
- package/dist/components/ui/feedback/Toast.mjs +7 -7
- package/dist/components/ui/feedback/Toast.mjs.map +1 -1
- package/dist/components/ui/form/Calendar.mjs +7 -7
- package/dist/components/ui/form/Calendar.mjs.map +1 -1
- package/dist/components/ui/form/Checkbox.mjs +2 -2
- package/dist/components/ui/form/Checkbox.mjs.map +1 -1
- package/dist/components/ui/form/ComboboxField.mjs +4 -4
- package/dist/components/ui/form/ComboboxField.mjs.map +1 -1
- package/dist/components/ui/form/DateRangePicker.mjs +2 -2
- package/dist/components/ui/form/DateRangePicker.mjs.map +1 -1
- package/dist/components/ui/form/FormField.mjs +3 -3
- package/dist/components/ui/form/FormField.mjs.map +1 -1
- package/dist/components/ui/form/InputOtp.mjs +2 -2
- package/dist/components/ui/form/InputOtp.mjs.map +1 -1
- package/dist/components/ui/form/RadioGroup.mjs +2 -2
- package/dist/components/ui/form/RadioGroup.mjs.map +1 -1
- package/dist/components/ui/form/Select.mjs +5 -5
- package/dist/components/ui/form/Select.mjs.map +1 -1
- package/dist/components/ui/form/SwitchOptionFieldWithIcon.mjs.map +1 -1
- package/dist/components/ui/overlay/Command.mjs +2 -2
- package/dist/components/ui/overlay/Command.mjs.map +1 -1
- package/dist/components/ui/overlay/Dialog.mjs +2 -2
- package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
- package/dist/components/ui/overlay/Sheet.mjs +2 -2
- package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
- package/dist/components/widgets/notifications/NotificationCard.mjs +2 -2
- package/dist/components/widgets/notifications/NotificationCard.mjs.map +1 -1
- package/package.json +1 -2
- package/src/components/account/ConfigurationsMyAccountModal.tsx +150 -150
- package/src/components/account/ConfirmDeleteAccountModal.tsx +2 -2
- package/src/components/account/ConfirmGlobalPreferencesModal.tsx +66 -66
- package/src/components/account/DeleteAccountModal.tsx +3 -3
- package/src/components/account/DisableTwoFactorAuthModal.tsx +86 -86
- package/src/components/account/IsntPossibleDeleteAccountModal.tsx +2 -2
- package/src/components/account/TwoFactorAuthModal.tsx +223 -223
- package/src/components/account/sections/ChangeEmailModal.tsx +225 -225
- package/src/components/account/sections/ChangePasswordSection.tsx +64 -64
- package/src/components/account/sections/ChangePhoneModal.tsx +5 -5
- package/src/components/account/sections/MyProfileSection.tsx +327 -327
- package/src/components/account/sections/PreferencesSection.tsx +273 -273
- package/src/components/account/sections/SecuritySection.tsx +160 -160
- package/src/components/layouts/AppMobileNavBar.tsx +0 -1
- package/src/components/layouts/MdSideBarNavigation.tsx +54 -54
- package/src/components/layouts/NavBar.tsx +2 -2
- package/src/components/layouts/NotificationsPopover.tsx +115 -115
- package/src/components/layouts/ProfilePopover.tsx +179 -184
- package/src/components/layouts/UsersSelectorPopover.tsx +5 -5
- package/src/components/navigation/ProjectSelectorPopover.tsx +151 -151
- package/src/components/navigation/subcomponents/ProjectSelector.tsx +149 -149
- package/src/components/pages/notifications/Notifications.tsx +4 -4
- package/src/components/ui/buttons/CopyButton.tsx +2 -2
- package/src/components/ui/data-display/Accordion.tsx +2 -2
- package/src/components/ui/data-display/Pagination.tsx +7 -7
- package/src/components/ui/feedback/Toast.tsx +7 -7
- package/src/components/ui/form/Calendar.tsx +7 -7
- package/src/components/ui/form/Checkbox.tsx +2 -2
- package/src/components/ui/form/ComboboxField.tsx +154 -154
- package/src/components/ui/form/DateRangePicker.tsx +2 -2
- package/src/components/ui/form/FormField.tsx +131 -130
- package/src/components/ui/form/InputOtp.tsx +2 -2
- package/src/components/ui/form/RadioGroup.tsx +2 -2
- package/src/components/ui/form/Select.tsx +5 -5
- package/src/components/ui/form/SwitchOptionFieldWithIcon.tsx +2 -2
- package/src/components/ui/overlay/Command.tsx +2 -2
- package/src/components/ui/overlay/Dialog.tsx +2 -2
- package/src/components/ui/overlay/Sheet.tsx +2 -2
- package/src/components/widgets/notifications/NotificationCard.tsx +68 -68
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as React from "react"
|
|
6
6
|
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
|
7
|
-
import {
|
|
7
|
+
import { IconChevronDown } from '@tabler/icons-react'
|
|
8
8
|
import { cn } from "../../../infra/utils/clsx"
|
|
9
9
|
|
|
10
10
|
function Accordion({
|
|
@@ -56,7 +56,7 @@ function AccordionTrigger({
|
|
|
56
56
|
{...props}
|
|
57
57
|
>
|
|
58
58
|
{children}
|
|
59
|
-
<
|
|
59
|
+
<IconChevronDown className="size-5! text-gray-950 pointer-events-none shrink-0 translate-y-0.5 transition-transform duration-200" />
|
|
60
60
|
</AccordionPrimitive.Trigger>
|
|
61
61
|
</AccordionPrimitive.Header>
|
|
62
62
|
)
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react"
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "
|
|
5
|
+
IconChevronLeft,
|
|
6
|
+
IconChevronRight,
|
|
7
|
+
IconDots,
|
|
8
|
+
} from "@tabler/icons-react"
|
|
9
9
|
import { cn } from "../../../infra/utils/clsx"
|
|
10
10
|
import { Button, buttonVariants } from "../buttons/Button"
|
|
11
11
|
|
|
@@ -77,7 +77,7 @@ function PaginationPrevious({
|
|
|
77
77
|
className={cn("gap-1 size-8 sm:pl-2.5", className)}
|
|
78
78
|
{...props}
|
|
79
79
|
>
|
|
80
|
-
<
|
|
80
|
+
<IconChevronLeft />
|
|
81
81
|
</PaginationLink>
|
|
82
82
|
)
|
|
83
83
|
}
|
|
@@ -93,7 +93,7 @@ function PaginationNext({
|
|
|
93
93
|
className={cn("gap-1 size-8 sm:pr-2.5", className)}
|
|
94
94
|
{...props}
|
|
95
95
|
>
|
|
96
|
-
<
|
|
96
|
+
<IconChevronRight />
|
|
97
97
|
</PaginationLink>
|
|
98
98
|
)
|
|
99
99
|
}
|
|
@@ -109,7 +109,7 @@ function PaginationEllipsis({
|
|
|
109
109
|
className={cn("flex size-9 items-center justify-center", className)}
|
|
110
110
|
{...props}
|
|
111
111
|
>
|
|
112
|
-
<
|
|
112
|
+
<IconDots className="size-4 mt-1.5" />
|
|
113
113
|
<span className="sr-only">More pages</span>
|
|
114
114
|
</span>
|
|
115
115
|
)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as React from "react"
|
|
6
6
|
import { cva, type VariantProps } from "class-variance-authority"
|
|
7
|
-
import {
|
|
7
|
+
import { IconCircleCheck, IconCircleX, IconAlertCircle, IconInfoCircle, IconCircle, IconX } from "@tabler/icons-react"
|
|
8
8
|
import { toast } from "sonner"
|
|
9
9
|
import { cn } from "../../../infra/utils/clsx"
|
|
10
10
|
import { Button } from "../buttons/Button"
|
|
@@ -46,11 +46,11 @@ const toastIconContainerVariants = cva(
|
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
const TOAST_ICONS = {
|
|
49
|
-
success:
|
|
50
|
-
error:
|
|
51
|
-
warning:
|
|
52
|
-
info:
|
|
53
|
-
default:
|
|
49
|
+
success: IconCircleCheck,
|
|
50
|
+
error: IconCircleX,
|
|
51
|
+
warning: IconAlertCircle,
|
|
52
|
+
info: IconInfoCircle,
|
|
53
|
+
default: IconCircle,
|
|
54
54
|
} as const
|
|
55
55
|
|
|
56
56
|
interface ToastProps extends VariantProps<typeof toastIconContainerVariants> {
|
|
@@ -89,7 +89,7 @@ function Toast({
|
|
|
89
89
|
className="size-8 rounded-full"
|
|
90
90
|
onClick={() => toastId && toast.dismiss(toastId)}
|
|
91
91
|
>
|
|
92
|
-
<
|
|
92
|
+
<IconX size={18} />
|
|
93
93
|
</Button>
|
|
94
94
|
</div>
|
|
95
95
|
)}
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
import * as React from "react"
|
|
6
6
|
import { ptBR } from "date-fns/locale"
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from "
|
|
8
|
+
IconChevronDown,
|
|
9
|
+
IconChevronLeft,
|
|
10
|
+
IconChevronRight,
|
|
11
|
+
} from "@tabler/icons-react"
|
|
12
12
|
import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
|
|
13
13
|
import { Button, buttonVariants } from "../buttons/Button"
|
|
14
14
|
import { cn } from "../../../infra/utils/clsx"
|
|
@@ -153,13 +153,13 @@ function Calendar({
|
|
|
153
153
|
Chevron: ({ className, orientation, ...props }) => {
|
|
154
154
|
if (orientation === "left") {
|
|
155
155
|
return (
|
|
156
|
-
<
|
|
156
|
+
<IconChevronLeft className={cn("size-4", className)} {...props} />
|
|
157
157
|
)
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
if (orientation === "right") {
|
|
161
161
|
return (
|
|
162
|
-
<
|
|
162
|
+
<IconChevronRight
|
|
163
163
|
className={cn("size-4", className)}
|
|
164
164
|
{...props}
|
|
165
165
|
/>
|
|
@@ -167,7 +167,7 @@ function Calendar({
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
return (
|
|
170
|
-
<
|
|
170
|
+
<IconChevronDown className={cn("size-4", className)} {...props} />
|
|
171
171
|
)
|
|
172
172
|
},
|
|
173
173
|
DayButton: CalendarDayButton,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
5
|
-
import {
|
|
5
|
+
import { IconCheck } from '@tabler/icons-react';
|
|
6
6
|
import { cn } from "../../../infra/utils/clsx";
|
|
7
7
|
|
|
8
8
|
function Checkbox({
|
|
@@ -22,7 +22,7 @@ function Checkbox({
|
|
|
22
22
|
data-slot="checkbox-indicator"
|
|
23
23
|
className="grid place-content-center text-current transition-none"
|
|
24
24
|
>
|
|
25
|
-
<
|
|
25
|
+
<IconCheck className="size-3 text-current" />
|
|
26
26
|
</CheckboxPrimitive.Indicator>
|
|
27
27
|
</CheckboxPrimitive.Root>
|
|
28
28
|
);
|
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useState, useMemo } from 'react';
|
|
4
|
-
import {
|
|
5
|
-
import { Popover, PopoverContent, PopoverTrigger } from '../overlay/Popover';
|
|
6
|
-
import { cn } from '../../../infra/utils/clsx';
|
|
7
|
-
|
|
8
|
-
export type ComboboxOption = {
|
|
9
|
-
value: string;
|
|
10
|
-
label: string;
|
|
11
|
-
displayValue?: string;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
interface ComboboxFieldProps {
|
|
15
|
-
options: ComboboxOption[];
|
|
16
|
-
label?: string;
|
|
17
|
-
placeholder?: string;
|
|
18
|
-
searchPlaceholder?: string;
|
|
19
|
-
emptyMessage?: string;
|
|
20
|
-
value?: string;
|
|
21
|
-
onChange?: (value: string) => void;
|
|
22
|
-
disabled?: boolean;
|
|
23
|
-
icon?: React.ReactNode;
|
|
24
|
-
className?: string;
|
|
25
|
-
containerClassName?: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function ComboboxField({
|
|
29
|
-
options,
|
|
30
|
-
label,
|
|
31
|
-
placeholder = 'Selecione uma opção',
|
|
32
|
-
searchPlaceholder = 'Buscar...',
|
|
33
|
-
emptyMessage = 'Nenhuma opção encontrada.',
|
|
34
|
-
value,
|
|
35
|
-
onChange,
|
|
36
|
-
disabled = false,
|
|
37
|
-
icon,
|
|
38
|
-
className,
|
|
39
|
-
containerClassName,
|
|
40
|
-
}: ComboboxFieldProps) {
|
|
41
|
-
const [open, setOpen] = useState(false);
|
|
42
|
-
const [search, setSearch] = useState('');
|
|
43
|
-
|
|
44
|
-
const selectedOption = useMemo(
|
|
45
|
-
() => options.find((o) => o.value === value),
|
|
46
|
-
[options, value]
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
const filteredOptions = useMemo(() => {
|
|
50
|
-
const q = search.trim().toLowerCase();
|
|
51
|
-
if (!q) return options;
|
|
52
|
-
return options.filter((o) => o.label.toLowerCase().includes(q));
|
|
53
|
-
}, [options, search]);
|
|
54
|
-
|
|
55
|
-
const handleSelect = (optionValue: string) => {
|
|
56
|
-
onChange?.(optionValue);
|
|
57
|
-
setOpen(false);
|
|
58
|
-
setSearch('');
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<div className={cn('flex flex-col gap-1.5', containerClassName)}>
|
|
63
|
-
{label && (
|
|
64
|
-
<div className="flex items-center gap-1 paragraph-xsmall-semibold">
|
|
65
|
-
<span className="text-gray-600">{label}</span>
|
|
66
|
-
</div>
|
|
67
|
-
)}
|
|
68
|
-
|
|
69
|
-
<Popover
|
|
70
|
-
open={open}
|
|
71
|
-
onOpenChange={(v) => {
|
|
72
|
-
if (!disabled) {
|
|
73
|
-
setOpen(v);
|
|
74
|
-
if (!v) setSearch('');
|
|
75
|
-
}
|
|
76
|
-
}}
|
|
77
|
-
>
|
|
78
|
-
<PopoverTrigger asChild>
|
|
79
|
-
<button
|
|
80
|
-
type="button"
|
|
81
|
-
disabled={disabled}
|
|
82
|
-
className={cn(
|
|
83
|
-
'paragraph-small-medium w-full h-10 text-gray-950 px-4 transition-colors',
|
|
84
|
-
'flex items-center justify-between gap-2 rounded-md border bg-transparent',
|
|
85
|
-
'border-gray-200 hover:border-gray-400 focus:border-gray-950 focus:outline-none',
|
|
86
|
-
disabled && 'cursor-not-allowed opacity-50',
|
|
87
|
-
className
|
|
88
|
-
)}
|
|
89
|
-
>
|
|
90
|
-
<span className={cn('truncate text-left', !selectedOption && 'text-gray-400')}>
|
|
91
|
-
{selectedOption
|
|
92
|
-
? (selectedOption.displayValue ?? selectedOption.label)
|
|
93
|
-
: placeholder}
|
|
94
|
-
</span>
|
|
95
|
-
{icon ?? (
|
|
96
|
-
<
|
|
97
|
-
className={cn(
|
|
98
|
-
'size-4 opacity-50 shrink-0 transition-all duration-200',
|
|
99
|
-
open && 'rotate-180 opacity-100 text-gray-950'
|
|
100
|
-
)}
|
|
101
|
-
/>
|
|
102
|
-
)}
|
|
103
|
-
</button>
|
|
104
|
-
</PopoverTrigger>
|
|
105
|
-
|
|
106
|
-
<PopoverContent
|
|
107
|
-
className="p-0 overflow-hidden rounded-md border shadow-md"
|
|
108
|
-
align="start"
|
|
109
|
-
sideOffset={4}
|
|
110
|
-
style={{ width: 'var(--radix-popover-trigger-width)' }}
|
|
111
|
-
onWheel={(e) => e.stopPropagation()}
|
|
112
|
-
>
|
|
113
|
-
<div className="flex items-center gap-2 border-b border-gray-100 px-3 h-9">
|
|
114
|
-
<
|
|
115
|
-
<input
|
|
116
|
-
autoFocus
|
|
117
|
-
placeholder={searchPlaceholder}
|
|
118
|
-
value={search}
|
|
119
|
-
onChange={(e) => setSearch(e.target.value)}
|
|
120
|
-
className="flex h-full w-full bg-transparent text-sm outline-none placeholder:text-gray-400 paragraph-small-medium text-gray-950"
|
|
121
|
-
/>
|
|
122
|
-
</div>
|
|
123
|
-
|
|
124
|
-
<div className="overflow-y-auto max-h-[280px] p-1">
|
|
125
|
-
{filteredOptions.length === 0 ? (
|
|
126
|
-
<p className="py-6 text-center paragraph-small-medium text-gray-500">{emptyMessage}</p>
|
|
127
|
-
) : (
|
|
128
|
-
filteredOptions.map((option) => {
|
|
129
|
-
const isSelected = value === option.value;
|
|
130
|
-
return (
|
|
131
|
-
<div
|
|
132
|
-
key={option.value}
|
|
133
|
-
className={cn(
|
|
134
|
-
'flex items-center gap-2 rounded-sm px-2 h-9 cursor-pointer select-none',
|
|
135
|
-
'paragraph-small-medium text-gray-950',
|
|
136
|
-
'hover:bg-gray-100',
|
|
137
|
-
isSelected && 'bg-gray-50'
|
|
138
|
-
)}
|
|
139
|
-
onClick={() => handleSelect(option.value)}
|
|
140
|
-
>
|
|
141
|
-
<span className="flex-1 truncate">{option.label}</span>
|
|
142
|
-
{isSelected && <
|
|
143
|
-
</div>
|
|
144
|
-
);
|
|
145
|
-
})
|
|
146
|
-
)}
|
|
147
|
-
</div>
|
|
148
|
-
</PopoverContent>
|
|
149
|
-
</Popover>
|
|
150
|
-
</div>
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export default ComboboxField;
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useMemo } from 'react';
|
|
4
|
+
import { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-react';
|
|
5
|
+
import { Popover, PopoverContent, PopoverTrigger } from '../overlay/Popover';
|
|
6
|
+
import { cn } from '../../../infra/utils/clsx';
|
|
7
|
+
|
|
8
|
+
export type ComboboxOption = {
|
|
9
|
+
value: string;
|
|
10
|
+
label: string;
|
|
11
|
+
displayValue?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
interface ComboboxFieldProps {
|
|
15
|
+
options: ComboboxOption[];
|
|
16
|
+
label?: string;
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
searchPlaceholder?: string;
|
|
19
|
+
emptyMessage?: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
onChange?: (value: string) => void;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
icon?: React.ReactNode;
|
|
24
|
+
className?: string;
|
|
25
|
+
containerClassName?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function ComboboxField({
|
|
29
|
+
options,
|
|
30
|
+
label,
|
|
31
|
+
placeholder = 'Selecione uma opção',
|
|
32
|
+
searchPlaceholder = 'Buscar...',
|
|
33
|
+
emptyMessage = 'Nenhuma opção encontrada.',
|
|
34
|
+
value,
|
|
35
|
+
onChange,
|
|
36
|
+
disabled = false,
|
|
37
|
+
icon,
|
|
38
|
+
className,
|
|
39
|
+
containerClassName,
|
|
40
|
+
}: ComboboxFieldProps) {
|
|
41
|
+
const [open, setOpen] = useState(false);
|
|
42
|
+
const [search, setSearch] = useState('');
|
|
43
|
+
|
|
44
|
+
const selectedOption = useMemo(
|
|
45
|
+
() => options.find((o) => o.value === value),
|
|
46
|
+
[options, value]
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const filteredOptions = useMemo(() => {
|
|
50
|
+
const q = search.trim().toLowerCase();
|
|
51
|
+
if (!q) return options;
|
|
52
|
+
return options.filter((o) => o.label.toLowerCase().includes(q));
|
|
53
|
+
}, [options, search]);
|
|
54
|
+
|
|
55
|
+
const handleSelect = (optionValue: string) => {
|
|
56
|
+
onChange?.(optionValue);
|
|
57
|
+
setOpen(false);
|
|
58
|
+
setSearch('');
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className={cn('flex flex-col gap-1.5', containerClassName)}>
|
|
63
|
+
{label && (
|
|
64
|
+
<div className="flex items-center gap-1 paragraph-xsmall-semibold">
|
|
65
|
+
<span className="text-gray-600">{label}</span>
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
|
|
69
|
+
<Popover
|
|
70
|
+
open={open}
|
|
71
|
+
onOpenChange={(v) => {
|
|
72
|
+
if (!disabled) {
|
|
73
|
+
setOpen(v);
|
|
74
|
+
if (!v) setSearch('');
|
|
75
|
+
}
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
<PopoverTrigger asChild>
|
|
79
|
+
<button
|
|
80
|
+
type="button"
|
|
81
|
+
disabled={disabled}
|
|
82
|
+
className={cn(
|
|
83
|
+
'paragraph-small-medium w-full h-10 text-gray-950 px-4 transition-colors',
|
|
84
|
+
'flex items-center justify-between gap-2 rounded-md border bg-transparent',
|
|
85
|
+
'border-gray-200 hover:border-gray-400 focus:border-gray-950 focus:outline-none',
|
|
86
|
+
disabled && 'cursor-not-allowed opacity-50',
|
|
87
|
+
className
|
|
88
|
+
)}
|
|
89
|
+
>
|
|
90
|
+
<span className={cn('truncate text-left', !selectedOption && 'text-gray-400')}>
|
|
91
|
+
{selectedOption
|
|
92
|
+
? (selectedOption.displayValue ?? selectedOption.label)
|
|
93
|
+
: placeholder}
|
|
94
|
+
</span>
|
|
95
|
+
{icon ?? (
|
|
96
|
+
<IconChevronDown
|
|
97
|
+
className={cn(
|
|
98
|
+
'size-4 opacity-50 shrink-0 transition-all duration-200',
|
|
99
|
+
open && 'rotate-180 opacity-100 text-gray-950'
|
|
100
|
+
)}
|
|
101
|
+
/>
|
|
102
|
+
)}
|
|
103
|
+
</button>
|
|
104
|
+
</PopoverTrigger>
|
|
105
|
+
|
|
106
|
+
<PopoverContent
|
|
107
|
+
className="p-0 overflow-hidden rounded-md border shadow-md"
|
|
108
|
+
align="start"
|
|
109
|
+
sideOffset={4}
|
|
110
|
+
style={{ width: 'var(--radix-popover-trigger-width)' }}
|
|
111
|
+
onWheel={(e) => e.stopPropagation()}
|
|
112
|
+
>
|
|
113
|
+
<div className="flex items-center gap-2 border-b border-gray-100 px-3 h-9">
|
|
114
|
+
<IconSearch className="size-4 shrink-0 opacity-50 text-gray-500" />
|
|
115
|
+
<input
|
|
116
|
+
autoFocus
|
|
117
|
+
placeholder={searchPlaceholder}
|
|
118
|
+
value={search}
|
|
119
|
+
onChange={(e) => setSearch(e.target.value)}
|
|
120
|
+
className="flex h-full w-full bg-transparent text-sm outline-none placeholder:text-gray-400 paragraph-small-medium text-gray-950"
|
|
121
|
+
/>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div className="overflow-y-auto max-h-[280px] p-1">
|
|
125
|
+
{filteredOptions.length === 0 ? (
|
|
126
|
+
<p className="py-6 text-center paragraph-small-medium text-gray-500">{emptyMessage}</p>
|
|
127
|
+
) : (
|
|
128
|
+
filteredOptions.map((option) => {
|
|
129
|
+
const isSelected = value === option.value;
|
|
130
|
+
return (
|
|
131
|
+
<div
|
|
132
|
+
key={option.value}
|
|
133
|
+
className={cn(
|
|
134
|
+
'flex items-center gap-2 rounded-sm px-2 h-9 cursor-pointer select-none',
|
|
135
|
+
'paragraph-small-medium text-gray-950',
|
|
136
|
+
'hover:bg-gray-100',
|
|
137
|
+
isSelected && 'bg-gray-50'
|
|
138
|
+
)}
|
|
139
|
+
onClick={() => handleSelect(option.value)}
|
|
140
|
+
>
|
|
141
|
+
<span className="flex-1 truncate">{option.label}</span>
|
|
142
|
+
{isSelected && <IconCheck className="size-4 shrink-0 text-pages-600" />}
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
})
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
</PopoverContent>
|
|
149
|
+
</Popover>
|
|
150
|
+
</div>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export default ComboboxField;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useState, forwardRef, useEffect } from "react";
|
|
4
4
|
import { format } from "date-fns";
|
|
5
|
-
import {
|
|
5
|
+
import { IconCalendar } from '@tabler/icons-react';
|
|
6
6
|
import { DateRange } from "react-day-picker";
|
|
7
7
|
import { Calendar } from "./Calendar";
|
|
8
8
|
import { Popover, PopoverContent, PopoverTrigger } from "../overlay/Popover";
|
|
@@ -77,7 +77,7 @@ export const DateRangePicker = forwardRef<HTMLButtonElement, DateRangePickerProp
|
|
|
77
77
|
className
|
|
78
78
|
)}
|
|
79
79
|
>
|
|
80
|
-
<
|
|
80
|
+
<IconCalendar size={20} className="text-gray-400" />
|
|
81
81
|
<span className={cn(
|
|
82
82
|
"paragraph-small-medium",
|
|
83
83
|
range?.from && range?.to ? "text-gray-950" : "text-gray-500"
|