mautourco-components 0.2.4 → 0.2.7
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/README.md +190 -190
- package/dist/components/atoms/Avatar/Avatar.d.ts +14 -14
- package/dist/components/atoms/Avatar/Avatar.js +31 -31
- package/dist/components/atoms/Button/Button.css +320 -320
- package/dist/components/atoms/Button/Button.d.ts +27 -27
- package/dist/components/atoms/Button/Button.js +35 -35
- package/dist/components/atoms/Checkbox/Checkbox.d.ts +13 -13
- package/dist/components/atoms/Checkbox/Checkbox.js +39 -39
- package/dist/components/atoms/Icon/Icon.d.ts +10 -10
- package/dist/components/atoms/Icon/Icon.js +123 -123
- package/dist/components/atoms/Icon/icons/ArrivalIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/ArrivalIcon.js +31 -31
- package/dist/components/atoms/Icon/icons/BuildingIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/BuildingIcon.js +36 -36
- package/dist/components/atoms/Icon/icons/CalendarIcon.d.ts +12 -12
- package/dist/components/atoms/Icon/icons/CalendarIcon.js +41 -41
- package/dist/components/atoms/Icon/icons/CalendarOutlineIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/CalendarOutlineIcon.js +36 -36
- package/dist/components/atoms/Icon/icons/CarIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/CarIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/Check.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/Check.js +30 -30
- package/dist/components/atoms/Icon/icons/CheckCircleIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/CheckCircleIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/Chevron.d.ts +9 -9
- package/dist/components/atoms/Icon/icons/Chevron.js +54 -54
- package/dist/components/atoms/Icon/icons/ChevronDownIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/ChevronDownIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/Close.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/Close.js +30 -30
- package/dist/components/atoms/Icon/icons/DeleteIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/DeleteIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/DepartureIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/DepartureIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/EyeIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/EyeIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/FacebookIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/FacebookIcon.js +36 -36
- package/dist/components/atoms/Icon/icons/HomeIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/HomeIcon.js +25 -25
- package/dist/components/atoms/Icon/icons/InfoIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/InfoIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/LinkedInIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/LinkedInIcon.js +36 -36
- package/dist/components/atoms/Icon/icons/MapPinIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/MapPinIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/MautoucoLogo.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/MautoucoLogo.js +37 -37
- package/dist/components/atoms/Icon/icons/MenuIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/MenuIcon.js +37 -37
- package/dist/components/atoms/Icon/icons/MinusIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/MinusIcon.js +25 -25
- package/dist/components/atoms/Icon/icons/MoreIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/MoreIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/PlaneIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/PlaneIcon.js +36 -36
- package/dist/components/atoms/Icon/icons/PlusIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/PlusIcon.js +25 -25
- package/dist/components/atoms/Icon/icons/Search.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/Search.js +30 -30
- package/dist/components/atoms/Icon/icons/Settings.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/Settings.js +30 -30
- package/dist/components/atoms/Icon/icons/ShipIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/ShipIcon.js +36 -36
- package/dist/components/atoms/Icon/icons/StrollerIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/StrollerIcon.js +30 -30
- package/dist/components/atoms/Icon/icons/TwitterIcon.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/TwitterIcon.js +36 -36
- package/dist/components/atoms/Icon/icons/User.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/User.js +30 -30
- package/dist/components/atoms/Icon/icons/UserIcon.d.ts +12 -12
- package/dist/components/atoms/Icon/icons/UserIcon.js +41 -41
- package/dist/components/atoms/Icon/icons/Youtube.d.ts +8 -8
- package/dist/components/atoms/Icon/icons/Youtube.js +36 -36
- package/dist/components/atoms/Illustration/Illustration.d.ts +14 -14
- package/dist/components/atoms/Illustration/Illustration.js +33 -33
- package/dist/components/atoms/Illustration/illustrations.d.ts +51 -51
- package/dist/components/atoms/Illustration/illustrations.js +97 -97
- package/dist/components/atoms/Inputs/DropdownInput/DropdownInput.d.ts +12 -12
- package/dist/components/atoms/Inputs/DropdownInput/DropdownInput.js +53 -53
- package/dist/components/atoms/Inputs/Input/Input.d.ts +15 -15
- package/dist/components/atoms/Inputs/Input/Input.js +27 -27
- package/dist/components/atoms/Inputs/Textarea/Textarea.d.ts +14 -14
- package/dist/components/atoms/Inputs/Textarea/Textarea.js +15 -15
- package/dist/components/atoms/Link/Link.d.ts +44 -44
- package/dist/components/atoms/Link/Link.js +76 -76
- package/dist/components/atoms/RatingStar/RatingStar.d.ts +40 -40
- package/dist/components/atoms/RatingStar/RatingStar.js +54 -54
- package/dist/components/atoms/SegmentedButton/SegmentedButton.d.ts +27 -27
- package/dist/components/atoms/SegmentedButton/SegmentedButton.js +49 -49
- package/dist/components/atoms/SelectedValue/SelectedValue.d.ts +11 -11
- package/dist/components/atoms/SelectedValue/SelectedValue.js +29 -29
- package/dist/components/atoms/Slider/Slider.d.ts +52 -52
- package/dist/components/atoms/Slider/Slider.js +30 -30
- package/dist/components/atoms/Spinner/Spinner.d.ts +9 -9
- package/dist/components/atoms/Spinner/Spinner.js +38 -38
- package/dist/components/atoms/Spinner/variants/ButtonSpinner.d.ts +8 -8
- package/dist/components/atoms/Spinner/variants/ButtonSpinner.js +19 -19
- package/dist/components/atoms/Spinner/variants/LoadingSpinner.d.ts +7 -7
- package/dist/components/atoms/Spinner/variants/LoadingSpinner.js +7 -7
- package/dist/components/atoms/Tab/Tab.css +266 -266
- package/dist/components/atoms/Tab/Tab.d.ts +22 -22
- package/dist/components/atoms/Tab/Tab.js +54 -54
- package/dist/components/atoms/Typography/Typography.d.ts +24 -24
- package/dist/components/atoms/Typography/Typography.js +100 -100
- package/dist/components/molecules/Calendar/CalendarInput.d.ts +34 -34
- package/dist/components/molecules/Calendar/CalendarInput.js +49 -49
- package/dist/components/molecules/Calendar/DateTime.d.ts +25 -25
- package/dist/components/molecules/Calendar/DateTime.js +106 -106
- package/dist/components/molecules/Calendar/TimePicker.d.ts +16 -16
- package/dist/components/molecules/Calendar/TimePicker.js +91 -91
- package/dist/components/molecules/LocationDropdown/LocationDropdown.d.ts +34 -34
- package/dist/components/molecules/LocationDropdown/LocationDropdown.js +120 -120
- package/dist/components/molecules/LocationDropdown/index.d.ts +2 -2
- package/dist/components/molecules/LocationDropdown/index.js +1 -1
- package/dist/components/molecules/MultiSelectDropdown/MultiSelectDropdown.d.ts +29 -29
- package/dist/components/molecules/MultiSelectDropdown/MultiSelectDropdown.js +106 -106
- package/dist/components/molecules/RatingTab/RatingTab.d.ts +39 -39
- package/dist/components/molecules/RatingTab/RatingTab.js +41 -41
- package/dist/components/molecules/TabGroup/TabGroup.d.ts +17 -17
- package/dist/components/molecules/TabGroup/TabGroup.js +30 -30
- package/dist/components/molecules/UserCard/UserCard.d.ts +20 -20
- package/dist/components/molecules/UserCard/UserCard.js +57 -57
- package/dist/components/organisms/CardContainer/CardContainer.d.ts +37 -37
- package/dist/components/organisms/CardContainer/CardContainer.js +27 -27
- package/dist/components/organisms/DateTimePicker/DateTimePicker.d.ts +15 -15
- package/dist/components/organisms/DateTimePicker/DateTimePicker.js +66 -66
- package/dist/components/organisms/Dialog/Dialog.d.ts +103 -103
- package/dist/components/organisms/Dialog/Dialog.js +162 -162
- package/dist/components/organisms/Footer/Footer.d.ts +38 -38
- package/dist/components/organisms/Footer/Footer.js +74 -74
- package/dist/components/organisms/PaxSelector/PaxSelector.d.ts +63 -63
- package/dist/components/organisms/PaxSelector/PaxSelector.js +402 -402
- package/dist/components/organisms/RoundTrip/RoundTrip.d.ts +54 -54
- package/dist/components/organisms/RoundTrip/RoundTrip.js +179 -179
- package/dist/components/organisms/RoundTrip/index.d.ts +2 -2
- package/dist/components/organisms/RoundTrip/index.js +1 -1
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.d.ts +35 -35
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.js +192 -192
- package/dist/components/organisms/SearchBarTransfer/index.d.ts +2 -2
- package/dist/components/organisms/SearchBarTransfer/index.js +1 -1
- package/dist/components/organisms/TopNavigation/DesktopNav.d.ts +33 -33
- package/dist/components/organisms/TopNavigation/DesktopNav.js +32 -26
- package/dist/components/organisms/TopNavigation/MobileNav.d.ts +32 -32
- package/dist/components/organisms/TopNavigation/MobileNav.js +45 -45
- package/dist/components/organisms/TopNavigation/TopNavigation.d.ts +33 -33
- package/dist/components/organisms/TopNavigation/TopNavigation.js +20 -20
- package/dist/components/organisms/TransferLine/TransferLine.d.ts +53 -53
- package/dist/components/organisms/TransferLine/TransferLine.js +179 -179
- package/dist/components/ui/button.d.ts +10 -10
- package/dist/components/ui/button.js +56 -56
- package/dist/components/ui/calendar.d.ts +8 -8
- package/dist/components/ui/calendar.js +87 -87
- package/dist/components/ui/popover.d.ts +7 -7
- package/dist/components/ui/popover.js +42 -42
- package/dist/hooks/useMobile.d.ts +5 -5
- package/dist/hooks/useMobile.js +26 -26
- package/dist/index.d.ts +49 -49
- package/dist/index.js +46 -46
- package/dist/lib/utils.d.ts +7 -7
- package/dist/lib/utils.js +13 -13
- package/dist/styles/components/avatar.css +122 -122
- package/dist/styles/components/calendar.css +140 -140
- package/dist/styles/components/checkbox.css +206 -206
- package/dist/styles/components/dropdown.css +269 -269
- package/dist/styles/components/forms.css +209 -209
- package/dist/styles/components/illustration.css +123 -123
- package/dist/styles/components/molecule/calendarInput.css +133 -133
- package/dist/styles/components/molecule/dateTime.css +126 -126
- package/dist/styles/components/molecule/location-dropdown.css +132 -132
- package/dist/styles/components/molecule/timePicker.css +122 -122
- package/dist/styles/components/multiselect-dropdown.css +286 -286
- package/dist/styles/components/organism/card-container.css +148 -148
- package/dist/styles/components/organism/dialog.css +168 -168
- package/dist/styles/components/organism/footer.css +119 -119
- package/dist/styles/components/organism/pax-selector.css +617 -617
- package/dist/styles/components/organism/round-trip.css +139 -139
- package/dist/styles/components/organism/search-bar-transfer.css +158 -161
- package/dist/styles/components/organism/topnavigation.css +143 -143
- package/dist/styles/components/organism/transfer-line.css +138 -138
- package/dist/styles/components/rating-star.css +145 -145
- package/dist/styles/components/rating-tab.css +179 -179
- package/dist/styles/components/scrollbar.css +155 -155
- package/dist/styles/components/segmented-button.css +214 -214
- package/dist/styles/components/selected-value.css +175 -175
- package/dist/styles/components/slider.css +182 -182
- package/dist/styles/components/typography.css +245 -245
- package/dist/styles/tokens/tokens.css +119 -119
- package/dist/styles/tokens/tokens.d.ts +3108 -3108
- package/dist/styles/tokens/tokens.js +2652 -2652
- package/package.json +103 -103
- package/src/components/atoms/Avatar/Avatar.tsx +60 -60
- package/src/components/atoms/Button/Button.css +200 -200
- package/src/components/atoms/Button/Button.tsx +82 -82
- package/src/components/atoms/Checkbox/Checkbox.tsx +83 -83
- package/src/components/atoms/Icon/Icon.tsx +163 -163
- package/src/components/atoms/Icon/icons/ArrivalIcon.tsx +52 -52
- package/src/components/atoms/Icon/icons/BuildingIcon.tsx +50 -50
- package/src/components/atoms/Icon/icons/CalendarIcon.tsx +63 -63
- package/src/components/atoms/Icon/icons/CalendarOutlineIcon.tsx +50 -50
- package/src/components/atoms/Icon/icons/CarIcon.tsx +44 -44
- package/src/components/atoms/Icon/icons/Check.tsx +36 -36
- package/src/components/atoms/Icon/icons/CheckCircleIcon.tsx +48 -48
- package/src/components/atoms/Icon/icons/Chevron.tsx +73 -73
- package/src/components/atoms/Icon/icons/ChevronDownIcon.tsx +46 -46
- package/src/components/atoms/Icon/icons/Close.tsx +39 -39
- package/src/components/atoms/Icon/icons/DeleteIcon.tsx +44 -44
- package/src/components/atoms/Icon/icons/DepartureIcon.tsx +50 -50
- package/src/components/atoms/Icon/icons/EyeIcon.tsx +44 -44
- package/src/components/atoms/Icon/icons/FacebookIcon.tsx +50 -50
- package/src/components/atoms/Icon/icons/HomeIcon.tsx +52 -52
- package/src/components/atoms/Icon/icons/InfoIcon.tsx +44 -44
- package/src/components/atoms/Icon/icons/LinkedInIcon.tsx +50 -50
- package/src/components/atoms/Icon/icons/MapPinIcon.tsx +44 -44
- package/src/components/atoms/Icon/icons/MautoucoLogo.tsx +93 -93
- package/src/components/atoms/Icon/icons/MenuIcon.tsx +49 -49
- package/src/components/atoms/Icon/icons/MinusIcon.tsx +45 -45
- package/src/components/atoms/Icon/icons/MoreIcon.tsx +44 -44
- package/src/components/atoms/Icon/icons/PlaneIcon.tsx +50 -50
- package/src/components/atoms/Icon/icons/PlusIcon.tsx +45 -45
- package/src/components/atoms/Icon/icons/Search.tsx +37 -37
- package/src/components/atoms/Icon/icons/Settings.tsx +38 -38
- package/src/components/atoms/Icon/icons/ShipIcon.tsx +50 -50
- package/src/components/atoms/Icon/icons/StrollerIcon.tsx +44 -44
- package/src/components/atoms/Icon/icons/TwitterIcon.tsx +50 -50
- package/src/components/atoms/Icon/icons/User.tsx +37 -37
- package/src/components/atoms/Icon/icons/UserIcon.tsx +63 -63
- package/src/components/atoms/Icon/icons/Youtube.tsx +50 -50
- package/src/components/atoms/Illustration/Illustration.tsx +28 -28
- package/src/components/atoms/Illustration/illustrations.ts +116 -116
- package/src/components/atoms/Inputs/DropdownInput/DropdownInput.tsx +96 -96
- package/src/components/atoms/Inputs/Textarea/Textarea.tsx +51 -51
- package/src/components/atoms/Link/Link.tsx +168 -168
- package/src/components/atoms/RatingStar/RatingStar.tsx +114 -114
- package/src/components/atoms/SegmentedButton/SegmentedButton.tsx +94 -94
- package/src/components/atoms/SelectedValue/SelectedValue.tsx +59 -59
- package/src/components/atoms/Slider/Slider.tsx +95 -95
- package/src/components/atoms/Spinner/Spinner.tsx +56 -56
- package/src/components/atoms/Spinner/variants/ButtonSpinner.tsx +37 -37
- package/src/components/atoms/Spinner/variants/LoadingSpinner.tsx +22 -22
- package/src/components/atoms/Tab/Tab.css +147 -147
- package/src/components/atoms/Tab/Tab.tsx +96 -96
- package/src/components/atoms/Typography/Typography.tsx +153 -153
- package/src/components/molecules/Calendar/CalendarInput.tsx +135 -135
- package/src/components/molecules/Calendar/DateTime.tsx +172 -172
- package/src/components/molecules/Calendar/TimePicker.tsx +174 -174
- package/src/components/molecules/LocationDropdown/LocationDropdown.tsx +234 -234
- package/src/components/molecules/LocationDropdown/index.ts +2 -2
- package/src/components/molecules/RatingTab/RatingTab.tsx +96 -96
- package/src/components/molecules/TabGroup/TabGroup.tsx +60 -60
- package/src/components/molecules/UserCard/UserCard.stories.tsx +36 -36
- package/src/components/molecules/UserCard/UserCard.tsx +173 -173
- package/src/components/organisms/CardContainer/CardContainer.tsx +66 -66
- package/src/components/organisms/DateTimePicker/DateTimePicker.tsx +110 -110
- package/src/components/organisms/Dialog/Dialog.tsx +352 -352
- package/src/components/organisms/Footer/Footer.tsx +290 -290
- package/src/components/organisms/PaxSelector/PaxSelector.tsx +979 -979
- package/src/components/organisms/RoundTrip/RoundTrip.tsx +335 -335
- package/src/components/organisms/RoundTrip/index.ts +2 -2
- package/src/components/organisms/SearchBarTransfer/SearchBarTransfer.tsx +388 -388
- package/src/components/organisms/SearchBarTransfer/index.ts +2 -2
- package/src/components/organisms/TopNavigation/DesktopNav.tsx +133 -122
- package/src/components/organisms/TopNavigation/MobileNav.tsx +212 -212
- package/src/components/organisms/TopNavigation/TopNavigation.tsx +45 -45
- package/src/components/organisms/TransferLine/TransferLine.tsx +369 -369
- package/src/components/ui/button.tsx +60 -60
- package/src/components/ui/calendar.tsx +246 -246
- package/src/components/ui/popover.tsx +46 -46
- package/src/styles/components/avatar.css +58 -58
- package/src/styles/components/calendar.css +85 -85
- package/src/styles/components/checkbox.css +130 -130
- package/src/styles/components/dropdown.css +214 -214
- package/src/styles/components/forms.css +147 -147
- package/src/styles/components/illustration.css +7 -7
- package/src/styles/components/molecule/calendarInput.css +156 -156
- package/src/styles/components/molecule/dateTime.css +14 -14
- package/src/styles/components/molecule/location-dropdown.css +204 -204
- package/src/styles/components/molecule/timePicker.css +78 -78
- package/src/styles/components/multiselect-dropdown.css +230 -230
- package/src/styles/components/organism/card-container.css +49 -49
- package/src/styles/components/organism/dialog.css +241 -241
- package/src/styles/components/organism/footer.css +113 -113
- package/src/styles/components/organism/pax-selector.css +702 -702
- package/src/styles/components/organism/round-trip.css +55 -55
- package/src/styles/components/organism/search-bar-transfer.css +128 -127
- package/src/styles/components/organism/topnavigation.css +161 -161
- package/src/styles/components/organism/transfer-line.css +86 -86
- package/src/styles/components/rating-star.css +39 -39
- package/src/styles/components/rating-tab.css +83 -83
- package/src/styles/components/scrollbar.css +63 -63
- package/src/styles/components/segmented-button.css +134 -134
- package/src/styles/components/selected-value.css +80 -80
- package/src/styles/components/slider.css +86 -86
- package/src/styles/components/typography.css +251 -251
- package/src/styles/fonts.css +50 -0
- package/src/styles/tokens/tokens.css +119 -119
- package/src/styles/tokens/tokens.js +12 -6
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import Tab, { TabProps } from '../../atoms/Tab/Tab';
|
|
3
|
-
|
|
4
|
-
export type TabItem<T = string> = {
|
|
5
|
-
label: string;
|
|
6
|
-
value: T;
|
|
7
|
-
disabled?: boolean;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export interface TabGroupProps<T = string> {
|
|
11
|
-
items: TabItem<T>[];
|
|
12
|
-
size?: TabProps['size'];
|
|
13
|
-
variant?: TabProps['variant'];
|
|
14
|
-
active?: T;
|
|
15
|
-
defaultActive?: T;
|
|
16
|
-
onChange?: (value: T) => void;
|
|
17
|
-
className?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function TabGroup<T = string>({
|
|
21
|
-
items,
|
|
22
|
-
size = 'lg',
|
|
23
|
-
variant = 'inline',
|
|
24
|
-
active,
|
|
25
|
-
defaultActive,
|
|
26
|
-
onChange,
|
|
27
|
-
className = '',
|
|
28
|
-
}: TabGroupProps<T>) {
|
|
29
|
-
const [internalActive, setInternalActive] = React.useState<T | undefined>(
|
|
30
|
-
defaultActive ?? items[0]?.value
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
const isControlled = active !== undefined;
|
|
34
|
-
const current = (isControlled ? active : internalActive) as T | undefined;
|
|
35
|
-
|
|
36
|
-
const handleClick = (item: TabItem<T>) => {
|
|
37
|
-
if (item.disabled) return;
|
|
38
|
-
if (!isControlled) setInternalActive(item.value);
|
|
39
|
-
onChange?.(item.value);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div className={`tab-group flex ${className}`} role="tablist">
|
|
44
|
-
{items.map((it) => (
|
|
45
|
-
<Tab
|
|
46
|
-
key={String(it.value)}
|
|
47
|
-
isActive={current === it.value}
|
|
48
|
-
size={size}
|
|
49
|
-
variant={variant}
|
|
50
|
-
disabled={it.disabled}
|
|
51
|
-
onClick={() => handleClick(it)}
|
|
52
|
-
>
|
|
53
|
-
{it.label}
|
|
54
|
-
</Tab>
|
|
55
|
-
))}
|
|
56
|
-
</div>
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export default TabGroup;
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Tab, { TabProps } from '../../atoms/Tab/Tab';
|
|
3
|
+
|
|
4
|
+
export type TabItem<T = string> = {
|
|
5
|
+
label: string;
|
|
6
|
+
value: T;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export interface TabGroupProps<T = string> {
|
|
11
|
+
items: TabItem<T>[];
|
|
12
|
+
size?: TabProps['size'];
|
|
13
|
+
variant?: TabProps['variant'];
|
|
14
|
+
active?: T;
|
|
15
|
+
defaultActive?: T;
|
|
16
|
+
onChange?: (value: T) => void;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function TabGroup<T = string>({
|
|
21
|
+
items,
|
|
22
|
+
size = 'lg',
|
|
23
|
+
variant = 'inline',
|
|
24
|
+
active,
|
|
25
|
+
defaultActive,
|
|
26
|
+
onChange,
|
|
27
|
+
className = '',
|
|
28
|
+
}: TabGroupProps<T>) {
|
|
29
|
+
const [internalActive, setInternalActive] = React.useState<T | undefined>(
|
|
30
|
+
defaultActive ?? items[0]?.value
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const isControlled = active !== undefined;
|
|
34
|
+
const current = (isControlled ? active : internalActive) as T | undefined;
|
|
35
|
+
|
|
36
|
+
const handleClick = (item: TabItem<T>) => {
|
|
37
|
+
if (item.disabled) return;
|
|
38
|
+
if (!isControlled) setInternalActive(item.value);
|
|
39
|
+
onChange?.(item.value);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className={`tab-group flex ${className}`} role="tablist">
|
|
44
|
+
{items.map((it) => (
|
|
45
|
+
<Tab
|
|
46
|
+
key={String(it.value)}
|
|
47
|
+
isActive={current === it.value}
|
|
48
|
+
size={size}
|
|
49
|
+
variant={variant}
|
|
50
|
+
disabled={it.disabled}
|
|
51
|
+
onClick={() => handleClick(it)}
|
|
52
|
+
>
|
|
53
|
+
{it.label}
|
|
54
|
+
</Tab>
|
|
55
|
+
))}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default TabGroup;
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
-
|
|
3
|
-
import { UserCard } from './UserCard';
|
|
4
|
-
|
|
5
|
-
const meta = {
|
|
6
|
-
title: 'Molecules/UserCard',
|
|
7
|
-
component: UserCard,
|
|
8
|
-
argTypes: {
|
|
9
|
-
onSelectAgency: { action: 'agency selected' },
|
|
10
|
-
}
|
|
11
|
-
} satisfies Meta<typeof UserCard>;
|
|
12
|
-
|
|
13
|
-
export default meta;
|
|
14
|
-
|
|
15
|
-
type Story = StoryObj<typeof meta>;
|
|
16
|
-
|
|
17
|
-
export const Default: Story = {
|
|
18
|
-
args:{
|
|
19
|
-
user: {
|
|
20
|
-
name: "John Doe",
|
|
21
|
-
agency: "Beachcomber SA",
|
|
22
|
-
isAdmin: true,
|
|
23
|
-
},
|
|
24
|
-
agencies: [
|
|
25
|
-
{ id: 1, name: "Beachcomber SA", localisation: "Mauritius" },
|
|
26
|
-
{ id: 2, name: "Sun Resorts", localisation: "Maldives" },
|
|
27
|
-
{ id: 3, name: "Tropical Escapes", localisation: "Seychelles" },
|
|
28
|
-
],
|
|
29
|
-
selectedAgency: { id: 1, name: "Beachcomber SA", localisation: "Mauritius" },
|
|
30
|
-
},
|
|
31
|
-
render: (args) => (
|
|
32
|
-
<div className='flex justify-center w-full'>
|
|
33
|
-
<UserCard {...args} />
|
|
34
|
-
</div>
|
|
35
|
-
),
|
|
36
|
-
};
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { UserCard } from './UserCard';
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: 'Molecules/UserCard',
|
|
7
|
+
component: UserCard,
|
|
8
|
+
argTypes: {
|
|
9
|
+
onSelectAgency: { action: 'agency selected' },
|
|
10
|
+
}
|
|
11
|
+
} satisfies Meta<typeof UserCard>;
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof meta>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
args:{
|
|
19
|
+
user: {
|
|
20
|
+
name: "John Doe",
|
|
21
|
+
agency: "Beachcomber SA",
|
|
22
|
+
isAdmin: true,
|
|
23
|
+
},
|
|
24
|
+
agencies: [
|
|
25
|
+
{ id: 1, name: "Beachcomber SA", localisation: "Mauritius" },
|
|
26
|
+
{ id: 2, name: "Sun Resorts", localisation: "Maldives" },
|
|
27
|
+
{ id: 3, name: "Tropical Escapes", localisation: "Seychelles" },
|
|
28
|
+
],
|
|
29
|
+
selectedAgency: { id: 1, name: "Beachcomber SA", localisation: "Mauritius" },
|
|
30
|
+
},
|
|
31
|
+
render: (args) => (
|
|
32
|
+
<div className='flex justify-center w-full'>
|
|
33
|
+
<UserCard {...args} />
|
|
34
|
+
</div>
|
|
35
|
+
),
|
|
36
|
+
};
|
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
-
import { Avatar } from "../../atoms/Avatar/Avatar";
|
|
3
|
-
|
|
4
|
-
type User = {
|
|
5
|
-
name: string;
|
|
6
|
-
agency: string;
|
|
7
|
-
isAdmin: boolean;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
type Agency = {
|
|
11
|
-
id: number;
|
|
12
|
-
name: string;
|
|
13
|
-
localisation: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export interface UserCardProps {
|
|
17
|
-
user: User;
|
|
18
|
-
agencies: Agency[];
|
|
19
|
-
onSelectAgency?: (agency: Agency) => void;
|
|
20
|
-
selectedAgency?: Agency; // ✅ keep type as Agency
|
|
21
|
-
className?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const UserCard: React.FC<UserCardProps> = ({
|
|
25
|
-
user,
|
|
26
|
-
agencies,
|
|
27
|
-
onSelectAgency,
|
|
28
|
-
selectedAgency,
|
|
29
|
-
className = "",
|
|
30
|
-
}) => {
|
|
31
|
-
const [open, setOpen] = useState(false);
|
|
32
|
-
const [query, setQuery] = useState("");
|
|
33
|
-
const rootRef = useRef<HTMLDivElement>(null);
|
|
34
|
-
const searchRef = useRef<HTMLInputElement>(null);
|
|
35
|
-
|
|
36
|
-
// Close dropdown on outside click
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
if (!user.isAdmin || !open) return;
|
|
39
|
-
const handleClickOutside = (e: MouseEvent) => {
|
|
40
|
-
if (!rootRef.current?.contains(e.target as Node)) setOpen(false);
|
|
41
|
-
};
|
|
42
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
43
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
44
|
-
}, [open, user.isAdmin]);
|
|
45
|
-
|
|
46
|
-
// Auto-focus search input when dropdown opens
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
if (user.isAdmin && open) setTimeout(() => searchRef.current?.focus(), 0);
|
|
49
|
-
}, [open, user.isAdmin]);
|
|
50
|
-
|
|
51
|
-
// Filter agencies based on query
|
|
52
|
-
const filteredAgencies = useMemo(() => {
|
|
53
|
-
const q = query.trim().toLowerCase();
|
|
54
|
-
if (!q) return agencies;
|
|
55
|
-
return agencies.filter(
|
|
56
|
-
(a) =>
|
|
57
|
-
a.name.toLowerCase().includes(q) ||
|
|
58
|
-
a.localisation.toLowerCase().includes(q)
|
|
59
|
-
);
|
|
60
|
-
}, [agencies, query]);
|
|
61
|
-
|
|
62
|
-
const handleSelect = (a: Agency) => {
|
|
63
|
-
onSelectAgency?.(a);
|
|
64
|
-
setOpen(false);
|
|
65
|
-
setQuery("");
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
return (
|
|
69
|
-
<div ref={rootRef} className={`relative inline-flex items-center gap-3 ${className} ${user.isAdmin ? "cursor-pointer rounded-[11px] border border-[#D9D9D9] bg-white px-[13px] py-2" : ""}`}>
|
|
70
|
-
{/* Greeting */}
|
|
71
|
-
<div className="flex items-center gap-3">
|
|
72
|
-
<Avatar name={user.name} size="md" shape="circle" />
|
|
73
|
-
<div className="flex flex-col leading-tight">
|
|
74
|
-
<div className="text-[13px] text-muted-foreground">
|
|
75
|
-
Welcome back,{" "}
|
|
76
|
-
<span className="font-medium text-foreground">{user.name}</span>{" "}
|
|
77
|
-
<span aria-hidden>👋</span>
|
|
78
|
-
</div>
|
|
79
|
-
<div className="text-[13px] font-semibold text-foreground">
|
|
80
|
-
{selectedAgency ? selectedAgency.name : user.agency}
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
</div>
|
|
84
|
-
|
|
85
|
-
{/* Admin-only: Dropdown selector */}
|
|
86
|
-
{user.isAdmin && (
|
|
87
|
-
<>
|
|
88
|
-
<button
|
|
89
|
-
type="button"
|
|
90
|
-
aria-expanded={open}
|
|
91
|
-
aria-haspopup="listbox"
|
|
92
|
-
onClick={() => setOpen((v) => !v)}
|
|
93
|
-
className="inline-flex h-8 w-8 items-center justify-center rounded-lg bg-teal-600 text-white shadow-[0_2px_6px_rgba(0,0,0,0.15)] outline-none focus-visible:ring-2 focus-visible:ring-teal-300"
|
|
94
|
-
title="Open agency selector"
|
|
95
|
-
>
|
|
96
|
-
<svg
|
|
97
|
-
width="18"
|
|
98
|
-
height="18"
|
|
99
|
-
viewBox="0 0 24 24"
|
|
100
|
-
aria-hidden="true"
|
|
101
|
-
className={`transition-transform ${open ? "rotate-180" : ""}`}
|
|
102
|
-
>
|
|
103
|
-
<path
|
|
104
|
-
d="M6 9l6 6 6-6"
|
|
105
|
-
fill="none"
|
|
106
|
-
stroke="currentColor"
|
|
107
|
-
strokeWidth="2"
|
|
108
|
-
strokeLinecap="round"
|
|
109
|
-
strokeLinejoin="round"
|
|
110
|
-
/>
|
|
111
|
-
</svg>
|
|
112
|
-
</button>
|
|
113
|
-
|
|
114
|
-
{open && (
|
|
115
|
-
<div className="absolute right-0 top-12 z-50 w-[340px] rounded-2xl border border-black/5 bg-white p-3 shadow-[0_12px_30px_rgba(0,0,0,0.15)]">
|
|
116
|
-
{/* Search */}
|
|
117
|
-
<div className="relative mb-3">
|
|
118
|
-
<input
|
|
119
|
-
ref={searchRef}
|
|
120
|
-
value={query}
|
|
121
|
-
onChange={(e) => setQuery(e.target.value)}
|
|
122
|
-
placeholder="Search"
|
|
123
|
-
className="w-full rounded-xl border border-black/10 bg-white px-10 py-2 text-sm outline-none focus:border-black/20 shadow-[inset_0_1px_2px_rgba(0,0,0,0.06)]"
|
|
124
|
-
/>
|
|
125
|
-
<div className="absolute -translate-y-1/2 pointer-events-none left-3 top-1/2">
|
|
126
|
-
<svg width="18" height="18" viewBox="0 0 24 24">
|
|
127
|
-
<path
|
|
128
|
-
d="M21 21l-4.3-4.3M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15z"
|
|
129
|
-
fill="none"
|
|
130
|
-
stroke="currentColor"
|
|
131
|
-
strokeWidth="1.6"
|
|
132
|
-
strokeLinecap="round"
|
|
133
|
-
/>
|
|
134
|
-
</svg>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
|
|
138
|
-
{/* Agency List */}
|
|
139
|
-
<ul role="listbox" className="pr-1 overflow-auto max-h-64">
|
|
140
|
-
{filteredAgencies.map((a) => {
|
|
141
|
-
const isActive = selectedAgency?.id === a.id;
|
|
142
|
-
return (
|
|
143
|
-
<li key={a.id}>
|
|
144
|
-
<button
|
|
145
|
-
type="button"
|
|
146
|
-
onClick={() => handleSelect(a)}
|
|
147
|
-
className={`flex w-full items-center justify-between gap-3 rounded-lg px-2 py-2 text-left hover:bg-black/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-teal-300 ${
|
|
148
|
-
isActive ? "bg-black/[0.04]" : ""
|
|
149
|
-
}`}
|
|
150
|
-
aria-selected={isActive}
|
|
151
|
-
role="option"
|
|
152
|
-
>
|
|
153
|
-
<span className="text-[14px]">{a.name}</span>
|
|
154
|
-
<span className="text-[13px] font-semibold">
|
|
155
|
-
{a.localisation}
|
|
156
|
-
</span>
|
|
157
|
-
</button>
|
|
158
|
-
</li>
|
|
159
|
-
);
|
|
160
|
-
})}
|
|
161
|
-
{filteredAgencies.length === 0 && (
|
|
162
|
-
<li className="px-2 py-6 text-sm text-center text-muted-foreground">
|
|
163
|
-
No results
|
|
164
|
-
</li>
|
|
165
|
-
)}
|
|
166
|
-
</ul>
|
|
167
|
-
</div>
|
|
168
|
-
)}
|
|
169
|
-
</>
|
|
170
|
-
)}
|
|
171
|
-
</div>
|
|
172
|
-
);
|
|
173
|
-
};
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { Avatar } from "../../atoms/Avatar/Avatar";
|
|
3
|
+
|
|
4
|
+
type User = {
|
|
5
|
+
name: string;
|
|
6
|
+
agency: string;
|
|
7
|
+
isAdmin: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type Agency = {
|
|
11
|
+
id: number;
|
|
12
|
+
name: string;
|
|
13
|
+
localisation: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export interface UserCardProps {
|
|
17
|
+
user: User;
|
|
18
|
+
agencies: Agency[];
|
|
19
|
+
onSelectAgency?: (agency: Agency) => void;
|
|
20
|
+
selectedAgency?: Agency; // ✅ keep type as Agency
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const UserCard: React.FC<UserCardProps> = ({
|
|
25
|
+
user,
|
|
26
|
+
agencies,
|
|
27
|
+
onSelectAgency,
|
|
28
|
+
selectedAgency,
|
|
29
|
+
className = "",
|
|
30
|
+
}) => {
|
|
31
|
+
const [open, setOpen] = useState(false);
|
|
32
|
+
const [query, setQuery] = useState("");
|
|
33
|
+
const rootRef = useRef<HTMLDivElement>(null);
|
|
34
|
+
const searchRef = useRef<HTMLInputElement>(null);
|
|
35
|
+
|
|
36
|
+
// Close dropdown on outside click
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!user.isAdmin || !open) return;
|
|
39
|
+
const handleClickOutside = (e: MouseEvent) => {
|
|
40
|
+
if (!rootRef.current?.contains(e.target as Node)) setOpen(false);
|
|
41
|
+
};
|
|
42
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
43
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
44
|
+
}, [open, user.isAdmin]);
|
|
45
|
+
|
|
46
|
+
// Auto-focus search input when dropdown opens
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (user.isAdmin && open) setTimeout(() => searchRef.current?.focus(), 0);
|
|
49
|
+
}, [open, user.isAdmin]);
|
|
50
|
+
|
|
51
|
+
// Filter agencies based on query
|
|
52
|
+
const filteredAgencies = useMemo(() => {
|
|
53
|
+
const q = query.trim().toLowerCase();
|
|
54
|
+
if (!q) return agencies;
|
|
55
|
+
return agencies.filter(
|
|
56
|
+
(a) =>
|
|
57
|
+
a.name.toLowerCase().includes(q) ||
|
|
58
|
+
a.localisation.toLowerCase().includes(q)
|
|
59
|
+
);
|
|
60
|
+
}, [agencies, query]);
|
|
61
|
+
|
|
62
|
+
const handleSelect = (a: Agency) => {
|
|
63
|
+
onSelectAgency?.(a);
|
|
64
|
+
setOpen(false);
|
|
65
|
+
setQuery("");
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div ref={rootRef} className={`relative inline-flex items-center gap-3 ${className} ${user.isAdmin ? "cursor-pointer rounded-[11px] border border-[#D9D9D9] bg-white px-[13px] py-2" : ""}`}>
|
|
70
|
+
{/* Greeting */}
|
|
71
|
+
<div className="flex items-center gap-3">
|
|
72
|
+
<Avatar name={user.name} size="md" shape="circle" />
|
|
73
|
+
<div className="flex flex-col leading-tight">
|
|
74
|
+
<div className="text-[13px] text-muted-foreground">
|
|
75
|
+
Welcome back,{" "}
|
|
76
|
+
<span className="font-medium text-foreground">{user.name}</span>{" "}
|
|
77
|
+
<span aria-hidden>👋</span>
|
|
78
|
+
</div>
|
|
79
|
+
<div className="text-[13px] font-semibold text-foreground">
|
|
80
|
+
{selectedAgency ? selectedAgency.name : user.agency}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
{/* Admin-only: Dropdown selector */}
|
|
86
|
+
{user.isAdmin && (
|
|
87
|
+
<>
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
aria-expanded={open}
|
|
91
|
+
aria-haspopup="listbox"
|
|
92
|
+
onClick={() => setOpen((v) => !v)}
|
|
93
|
+
className="inline-flex h-8 w-8 items-center justify-center rounded-lg bg-teal-600 text-white shadow-[0_2px_6px_rgba(0,0,0,0.15)] outline-none focus-visible:ring-2 focus-visible:ring-teal-300"
|
|
94
|
+
title="Open agency selector"
|
|
95
|
+
>
|
|
96
|
+
<svg
|
|
97
|
+
width="18"
|
|
98
|
+
height="18"
|
|
99
|
+
viewBox="0 0 24 24"
|
|
100
|
+
aria-hidden="true"
|
|
101
|
+
className={`transition-transform ${open ? "rotate-180" : ""}`}
|
|
102
|
+
>
|
|
103
|
+
<path
|
|
104
|
+
d="M6 9l6 6 6-6"
|
|
105
|
+
fill="none"
|
|
106
|
+
stroke="currentColor"
|
|
107
|
+
strokeWidth="2"
|
|
108
|
+
strokeLinecap="round"
|
|
109
|
+
strokeLinejoin="round"
|
|
110
|
+
/>
|
|
111
|
+
</svg>
|
|
112
|
+
</button>
|
|
113
|
+
|
|
114
|
+
{open && (
|
|
115
|
+
<div className="absolute right-0 top-12 z-50 w-[340px] rounded-2xl border border-black/5 bg-white p-3 shadow-[0_12px_30px_rgba(0,0,0,0.15)]">
|
|
116
|
+
{/* Search */}
|
|
117
|
+
<div className="relative mb-3">
|
|
118
|
+
<input
|
|
119
|
+
ref={searchRef}
|
|
120
|
+
value={query}
|
|
121
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
122
|
+
placeholder="Search"
|
|
123
|
+
className="w-full rounded-xl border border-black/10 bg-white px-10 py-2 text-sm outline-none focus:border-black/20 shadow-[inset_0_1px_2px_rgba(0,0,0,0.06)]"
|
|
124
|
+
/>
|
|
125
|
+
<div className="absolute -translate-y-1/2 pointer-events-none left-3 top-1/2">
|
|
126
|
+
<svg width="18" height="18" viewBox="0 0 24 24">
|
|
127
|
+
<path
|
|
128
|
+
d="M21 21l-4.3-4.3M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15z"
|
|
129
|
+
fill="none"
|
|
130
|
+
stroke="currentColor"
|
|
131
|
+
strokeWidth="1.6"
|
|
132
|
+
strokeLinecap="round"
|
|
133
|
+
/>
|
|
134
|
+
</svg>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
{/* Agency List */}
|
|
139
|
+
<ul role="listbox" className="pr-1 overflow-auto max-h-64">
|
|
140
|
+
{filteredAgencies.map((a) => {
|
|
141
|
+
const isActive = selectedAgency?.id === a.id;
|
|
142
|
+
return (
|
|
143
|
+
<li key={a.id}>
|
|
144
|
+
<button
|
|
145
|
+
type="button"
|
|
146
|
+
onClick={() => handleSelect(a)}
|
|
147
|
+
className={`flex w-full items-center justify-between gap-3 rounded-lg px-2 py-2 text-left hover:bg-black/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-teal-300 ${
|
|
148
|
+
isActive ? "bg-black/[0.04]" : ""
|
|
149
|
+
}`}
|
|
150
|
+
aria-selected={isActive}
|
|
151
|
+
role="option"
|
|
152
|
+
>
|
|
153
|
+
<span className="text-[14px]">{a.name}</span>
|
|
154
|
+
<span className="text-[13px] font-semibold">
|
|
155
|
+
{a.localisation}
|
|
156
|
+
</span>
|
|
157
|
+
</button>
|
|
158
|
+
</li>
|
|
159
|
+
);
|
|
160
|
+
})}
|
|
161
|
+
{filteredAgencies.length === 0 && (
|
|
162
|
+
<li className="px-2 py-6 text-sm text-center text-muted-foreground">
|
|
163
|
+
No results
|
|
164
|
+
</li>
|
|
165
|
+
)}
|
|
166
|
+
</ul>
|
|
167
|
+
</div>
|
|
168
|
+
)}
|
|
169
|
+
</>
|
|
170
|
+
)}
|
|
171
|
+
</div>
|
|
172
|
+
);
|
|
173
|
+
};
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
|
|
3
|
-
export type CardContainerSpacing = 'compact' | 'normal' | 'relaxed' | 'chill';
|
|
4
|
-
|
|
5
|
-
export interface CardContainerProps {
|
|
6
|
-
/**
|
|
7
|
-
* The content to be displayed inside the card container
|
|
8
|
-
*/
|
|
9
|
-
children: React.ReactNode;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Spacing variant for the card container padding
|
|
13
|
-
* - compact: 8px padding
|
|
14
|
-
* - normal: 12px padding
|
|
15
|
-
* - relaxed: 16px padding
|
|
16
|
-
* - chill: 24px padding
|
|
17
|
-
*/
|
|
18
|
-
spacing?: CardContainerSpacing;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Additional CSS classes to apply to the card container
|
|
22
|
-
*/
|
|
23
|
-
className?: string;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Optional click handler
|
|
27
|
-
*/
|
|
28
|
-
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Optional data attributes for testing or tracking
|
|
32
|
-
*/
|
|
33
|
-
'data-testid'?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* CardContainer is a versatile UI element that groups related content,
|
|
38
|
-
* such as text, images, buttons, or interactive elements.
|
|
39
|
-
*
|
|
40
|
-
* It supports different spacing variants to control the visual density
|
|
41
|
-
* and padding of the container.
|
|
42
|
-
*/
|
|
43
|
-
export const CardContainer: React.FC<CardContainerProps> = ({
|
|
44
|
-
children,
|
|
45
|
-
spacing = 'normal',
|
|
46
|
-
className = '',
|
|
47
|
-
onClick,
|
|
48
|
-
'data-testid': testId,
|
|
49
|
-
}) => {
|
|
50
|
-
const baseClass = 'card-container';
|
|
51
|
-
const spacingClass = `card-container--spacing-${spacing}`;
|
|
52
|
-
const classes = [baseClass, spacingClass, className].filter(Boolean).join(' ');
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<div
|
|
56
|
-
className={classes}
|
|
57
|
-
onClick={onClick}
|
|
58
|
-
data-testid={testId}
|
|
59
|
-
>
|
|
60
|
-
{children}
|
|
61
|
-
</div>
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export default CardContainer;
|
|
66
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export type CardContainerSpacing = 'compact' | 'normal' | 'relaxed' | 'chill';
|
|
4
|
+
|
|
5
|
+
export interface CardContainerProps {
|
|
6
|
+
/**
|
|
7
|
+
* The content to be displayed inside the card container
|
|
8
|
+
*/
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Spacing variant for the card container padding
|
|
13
|
+
* - compact: 8px padding
|
|
14
|
+
* - normal: 12px padding
|
|
15
|
+
* - relaxed: 16px padding
|
|
16
|
+
* - chill: 24px padding
|
|
17
|
+
*/
|
|
18
|
+
spacing?: CardContainerSpacing;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Additional CSS classes to apply to the card container
|
|
22
|
+
*/
|
|
23
|
+
className?: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Optional click handler
|
|
27
|
+
*/
|
|
28
|
+
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Optional data attributes for testing or tracking
|
|
32
|
+
*/
|
|
33
|
+
'data-testid'?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* CardContainer is a versatile UI element that groups related content,
|
|
38
|
+
* such as text, images, buttons, or interactive elements.
|
|
39
|
+
*
|
|
40
|
+
* It supports different spacing variants to control the visual density
|
|
41
|
+
* and padding of the container.
|
|
42
|
+
*/
|
|
43
|
+
export const CardContainer: React.FC<CardContainerProps> = ({
|
|
44
|
+
children,
|
|
45
|
+
spacing = 'normal',
|
|
46
|
+
className = '',
|
|
47
|
+
onClick,
|
|
48
|
+
'data-testid': testId,
|
|
49
|
+
}) => {
|
|
50
|
+
const baseClass = 'card-container';
|
|
51
|
+
const spacingClass = `card-container--spacing-${spacing}`;
|
|
52
|
+
const classes = [baseClass, spacingClass, className].filter(Boolean).join(' ');
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
className={classes}
|
|
57
|
+
onClick={onClick}
|
|
58
|
+
data-testid={testId}
|
|
59
|
+
>
|
|
60
|
+
{children}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default CardContainer;
|
|
66
|
+
|