mautourco-components 0.2.11 → 0.2.13
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/atoms/Icon/Icon.d.ts +1 -1
- package/dist/components/atoms/Icon/Icon.js +1 -1
- package/dist/components/atoms/Icon/icons/AccomIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/AccomIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/ArrowDownOutlineIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/ArrowDownOutlineIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/ArrowRightOutlineIcon.js +1 -1
- package/dist/components/atoms/Icon/icons/BusIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/BusIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/Calendar2Icon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/Calendar2Icon.js +36 -0
- package/dist/components/atoms/Icon/icons/MapIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/MapIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/MicroIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/MicroIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/MoreVerticalIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/MoreVerticalIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/NightIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/NightIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/RowExcursion.d.ts +16 -0
- package/dist/components/atoms/Icon/icons/RowExcursion.js +28 -0
- package/dist/components/atoms/Icon/icons/StopWatchIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/StopWatchIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/Utensils.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/Utensils.js +36 -0
- package/dist/components/atoms/Icon/icons/WalletIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/WalletIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/registry.d.ts +11 -0
- package/dist/components/atoms/Icon/icons/registry.js +49 -27
- package/dist/components/atoms/Typography/Typography.d.ts +3 -1
- package/dist/components/atoms/Typography/Typography.js +3 -15
- package/dist/components/molecules/ActionDropdown/ActionDropdown.css +2119 -0
- package/dist/components/molecules/ActionDropdown/ActionDropdown.d.ts +21 -0
- package/dist/components/molecules/ActionDropdown/ActionDropdown.js +34 -0
- package/dist/components/molecules/DateDisplay/DateDisplay.d.ts +14 -0
- package/dist/components/molecules/DateDisplay/DateDisplay.js +39 -0
- package/dist/components/molecules/FromTo/FromTo.d.ts +8 -0
- package/dist/components/molecules/FromTo/FromTo.js +24 -0
- package/dist/components/molecules/TableServiceItem/DetailsCol.d.ts +12 -0
- package/dist/components/molecules/TableServiceItem/DetailsCol.js +17 -0
- package/dist/components/molecules/TableServiceItem/ItemCol.d.ts +13 -0
- package/dist/components/molecules/TableServiceItem/ItemCol.js +24 -0
- package/dist/components/molecules/TableServiceItem/RowAccommodation.d.ts +16 -0
- package/dist/components/molecules/TableServiceItem/RowAccommodation.js +37 -0
- package/dist/components/molecules/TableServiceItem/RowExcursion.d.ts +16 -0
- package/dist/components/molecules/TableServiceItem/RowExcursion.js +22 -0
- package/dist/components/molecules/TableServiceItem/RowOtherServices.d.ts +9 -0
- package/dist/components/molecules/TableServiceItem/RowOtherServices.js +34 -0
- package/dist/components/molecules/TableServiceItem/RowTransfer.d.ts +15 -0
- package/dist/components/molecules/TableServiceItem/RowTransfer.js +37 -0
- package/dist/components/molecules/TableServiceItem/index.d.ts +17 -0
- package/dist/components/molecules/TableServiceItem/index.js +15 -0
- package/dist/components/molecules/TextWithIcon/TextWithIcon.d.ts +30 -0
- package/dist/components/molecules/TextWithIcon/TextWithIcon.js +31 -0
- package/dist/components/molecules/TooltipDisplay/TooltipDisplay.d.ts +13 -0
- package/dist/components/molecules/TooltipDisplay/TooltipDisplay.js +18 -0
- package/dist/components/organisms/DateTimePicker/DateTimePicker.d.ts +2 -0
- package/dist/components/organisms/DateTimePicker/DateTimePicker.js +31 -3
- package/dist/components/organisms/RoundTrip/RoundTrip.js +1 -1
- package/dist/components/organisms/Table/Table.css +2280 -0
- package/dist/components/organisms/Table/Table.d.ts +50 -0
- package/dist/components/organisms/Table/Table.js +95 -0
- package/dist/components/organisms/Table/TableCell.d.ts +15 -0
- package/dist/components/organisms/Table/TableCell.js +16 -0
- package/dist/components/organisms/Table/columns/booking-columns.d.ts +7 -0
- package/dist/components/organisms/Table/columns/booking-columns.js +83 -0
- package/dist/components/organisms/Table/columns/detail-resume-columns.d.ts +3 -0
- package/dist/components/organisms/Table/columns/detail-resume-columns.js +178 -0
- package/dist/components/organisms/Table/columns/index.d.ts +12 -0
- package/dist/components/organisms/Table/columns/index.js +9 -0
- package/dist/components/organisms/Table/columns/quotation-columns.d.ts +7 -0
- package/dist/components/organisms/Table/columns/quotation-columns.js +91 -0
- package/dist/components/organisms/Table/constant.d.ts +6 -0
- package/dist/components/organisms/Table/constant.js +24 -0
- package/dist/components/organisms/Table/index.d.ts +2 -0
- package/dist/components/organisms/Table/index.js +2 -0
- package/dist/components/organisms/TransferLine/TransferLine.js +1 -1
- package/dist/components/ui/popover.d.ts +3 -3
- package/dist/components/ui/popover.js +5 -5
- package/dist/components/ui/tooltip.d.ts +7 -0
- package/dist/components/ui/tooltip.js +42 -0
- package/dist/index.d.ts +41 -33
- package/dist/index.js +26 -20
- package/dist/styles/components/typography.css +1 -0
- package/dist/types/table/action-dropdown-type.types.d.ts +5 -0
- package/dist/types/table/action-dropdown-type.types.js +6 -0
- package/dist/types/table/booking.types.d.ts +16 -0
- package/dist/types/table/booking.types.js +1 -0
- package/dist/types/table/detail-resume.types.d.ts +155 -0
- package/dist/types/table/detail-resume.types.js +7 -0
- package/dist/types/table/index.d.ts +3 -0
- package/dist/types/table/index.js +3 -0
- package/dist/types/table/quotation.types.d.ts +23 -0
- package/dist/types/table/quotation.types.js +1 -0
- package/package.json +6 -1
- package/src/components/atoms/Icon/Icon.tsx +2 -8
- package/src/components/atoms/Icon/icons/AccomIcon.tsx +45 -0
- package/src/components/atoms/Icon/icons/ArrowDownOutlineIcon.tsx +41 -0
- package/src/components/atoms/Icon/icons/ArrowRightOutlineIcon.tsx +2 -7
- package/src/components/atoms/Icon/icons/BusIcon.tsx +52 -0
- package/src/components/atoms/Icon/icons/Calendar2Icon.tsx +54 -0
- package/src/components/atoms/Icon/icons/MapIcon.tsx +48 -0
- package/src/components/atoms/Icon/icons/MicroIcon.tsx +45 -0
- package/src/components/atoms/Icon/icons/MoreVerticalIcon.tsx +53 -0
- package/src/components/atoms/Icon/icons/NightIcon.tsx +45 -0
- package/src/components/atoms/Icon/icons/RowExcursion.tsx +54 -0
- package/src/components/atoms/Icon/icons/StopWatchIcon.tsx +45 -0
- package/src/components/atoms/Icon/icons/Utensils.tsx +45 -0
- package/src/components/atoms/Icon/icons/WalletIcon.tsx +45 -0
- package/src/components/atoms/Icon/icons/registry.tsx +50 -28
- package/src/components/atoms/Typography/Typography.tsx +22 -30
- package/src/components/molecules/ActionDropdown/ActionDropdown.css +23 -0
- package/src/components/molecules/ActionDropdown/ActionDropdown.tsx +53 -0
- package/src/components/molecules/DateDisplay/DateDisplay.tsx +47 -0
- package/src/components/molecules/FromTo/FromTo.tsx +31 -0
- package/src/components/molecules/TableServiceItem/DetailsCol.tsx +25 -0
- package/src/components/molecules/TableServiceItem/ItemCol.tsx +68 -0
- package/src/components/molecules/TableServiceItem/RowAccommodation.tsx +56 -0
- package/src/components/molecules/TableServiceItem/RowExcursion.tsx +40 -0
- package/src/components/molecules/TableServiceItem/RowOtherServices.tsx +50 -0
- package/src/components/molecules/TableServiceItem/RowTransfer.tsx +60 -0
- package/src/components/molecules/TableServiceItem/index.ts +24 -0
- package/src/components/molecules/TextWithIcon/TextWithIcon.tsx +62 -0
- package/src/components/molecules/TooltipDisplay/TooltipDisplay.tsx +32 -0
- package/src/components/organisms/CarBookingCard/index.ts +2 -0
- package/src/components/organisms/DateTimePicker/DateTimePicker.tsx +33 -2
- package/src/components/organisms/RoundTrip/RoundTrip.tsx +1 -0
- package/src/components/organisms/SearchBarTransfer/index.ts +1 -0
- package/src/components/organisms/Table/Table.css +185 -0
- package/src/components/organisms/Table/Table.tsx +273 -0
- package/src/components/organisms/Table/TableCell.tsx +40 -0
- package/src/components/organisms/Table/columns/booking-columns.tsx +118 -0
- package/src/components/organisms/Table/columns/detail-resume-columns.tsx +226 -0
- package/src/components/organisms/Table/columns/index.ts +11 -0
- package/src/components/organisms/Table/columns/quotation-columns.tsx +150 -0
- package/src/components/organisms/Table/constant.ts +31 -0
- package/src/components/organisms/Table/index.ts +2 -0
- package/src/components/organisms/TransferLine/TransferLine.tsx +1 -0
- package/src/components/ui/popover.tsx +10 -10
- package/src/components/ui/tooltip.tsx +45 -0
- package/src/styles/components/typography.css +4 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { DetailsCol, type DetailsColProps } from './DetailsCol';
|
|
2
|
+
import { ItemCol, type ItemColProps } from './ItemCol';
|
|
3
|
+
import { RowAccommodation, type RowAccommodationProps } from './RowAccommodation';
|
|
4
|
+
import { RowExcursion, type RowExcursionProps } from './RowExcursion';
|
|
5
|
+
import { RowOtherServices } from './RowOtherServices';
|
|
6
|
+
import { RowTransfer, type RowTransferProps } from './RowTransfer';
|
|
7
|
+
|
|
8
|
+
const TableServiceItem = {
|
|
9
|
+
DetailsCol,
|
|
10
|
+
ItemCol,
|
|
11
|
+
RowAccommodation,
|
|
12
|
+
RowExcursion,
|
|
13
|
+
RowOtherServices,
|
|
14
|
+
RowTransfer,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type {
|
|
18
|
+
DetailsColProps,
|
|
19
|
+
ItemColProps,
|
|
20
|
+
RowAccommodationProps,
|
|
21
|
+
RowExcursionProps,
|
|
22
|
+
RowTransferProps,
|
|
23
|
+
};
|
|
24
|
+
export default TableServiceItem;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { cn } from '@/src/lib/utils';
|
|
2
|
+
import Icon, { IconName } from '../../atoms/Icon/Icon';
|
|
3
|
+
import { Text, TextColor, TextLeading, TextVariant } from '../../atoms/Typography/Typography';
|
|
4
|
+
|
|
5
|
+
export interface TextWithIconProps {
|
|
6
|
+
/** Icon to display */
|
|
7
|
+
icon: IconName;
|
|
8
|
+
|
|
9
|
+
/** Icon size */
|
|
10
|
+
iconSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
11
|
+
|
|
12
|
+
/** Children to display */
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
|
|
15
|
+
/** Color of the text */
|
|
16
|
+
color?: TextColor;
|
|
17
|
+
|
|
18
|
+
/** Leading of the text */
|
|
19
|
+
textLeading?: TextLeading;
|
|
20
|
+
|
|
21
|
+
/** Variant of the text */
|
|
22
|
+
textVariant?: TextVariant;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A component that displays a text with an icon.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* <TextWithIcon icon="calendar" color="yellow">
|
|
30
|
+
* 20/12/2025
|
|
31
|
+
* </TextWithIcon>
|
|
32
|
+
*
|
|
33
|
+
* @param TextWithIconProps
|
|
34
|
+
* @returns
|
|
35
|
+
*/
|
|
36
|
+
const TextWithIcon: React.FC<TextWithIconProps> = (props) => {
|
|
37
|
+
const { icon, children, iconSize = 'sm', color = 'default', textLeading = '5', textVariant = 'medium' } = props;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
className={cn(
|
|
42
|
+
'flex items-center gap-x-2',
|
|
43
|
+
color === 'yellow' && 'text-[var(--color-yellow-600)]',
|
|
44
|
+
color === 'accent' && 'text-[var(--color-text-accent)]'
|
|
45
|
+
)}>
|
|
46
|
+
<span>
|
|
47
|
+
<Icon name={icon} size={iconSize} />
|
|
48
|
+
</span>
|
|
49
|
+
<Text
|
|
50
|
+
variant={textVariant}
|
|
51
|
+
size={iconSize}
|
|
52
|
+
className="flex items-center gap-x-2"
|
|
53
|
+
color={color}
|
|
54
|
+
leading={textLeading}
|
|
55
|
+
as="div">
|
|
56
|
+
{children}
|
|
57
|
+
</Text>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default TextWithIcon;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { TooltipContentProps } from '@radix-ui/react-tooltip';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Text } from '../../atoms/Typography/Typography';
|
|
4
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '../../ui/tooltip';
|
|
5
|
+
|
|
6
|
+
export interface TooltipDisplayProps {
|
|
7
|
+
/** Trigger element */
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
|
|
10
|
+
/** Tooltip content */
|
|
11
|
+
content: string;
|
|
12
|
+
|
|
13
|
+
/** Side of the tooltip */
|
|
14
|
+
side?: TooltipContentProps['side'];
|
|
15
|
+
|
|
16
|
+
/** Maximum width of the tooltip */
|
|
17
|
+
maxWidth?: `${number}px`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const TooltipDisplay: React.FC<TooltipDisplayProps> = (props) => {
|
|
21
|
+
const { children, content, side = 'right', maxWidth = '300px' } = props;
|
|
22
|
+
return (
|
|
23
|
+
<Tooltip>
|
|
24
|
+
<TooltipTrigger className="text-[var(--color-icon-branded)]">{children}</TooltipTrigger>
|
|
25
|
+
<TooltipContent className={`max-w-[${maxWidth}]`} side={side}>
|
|
26
|
+
<Text variant="medium" size="sm" className="!text-white">
|
|
27
|
+
{content}
|
|
28
|
+
</Text>
|
|
29
|
+
</TooltipContent>
|
|
30
|
+
</Tooltip>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -9,6 +9,8 @@ export interface DateTimePickerProps extends Partial<DateTimeProps> {
|
|
|
9
9
|
placeholder?: string;
|
|
10
10
|
disabled?: boolean;
|
|
11
11
|
onValueChange?: (value: string | string[]) => void;
|
|
12
|
+
/** Default value for the date picker (format: "yyyy-MM-dd" for single, ["yyyy-MM-dd", "yyyy-MM-dd"] for range) */
|
|
13
|
+
defaultValue?: string | string[];
|
|
12
14
|
/** Whether the calendar icon has full bg*/
|
|
13
15
|
iconBGFull?: boolean;
|
|
14
16
|
/** Position of the calendar icon: left or right */
|
|
@@ -35,12 +37,41 @@ const DateTimePicker: React.FC<DateTimePickerProps> = ({
|
|
|
35
37
|
disableBeforeToday = true,
|
|
36
38
|
disableToday = false,
|
|
37
39
|
onValueChange,
|
|
40
|
+
defaultValue,
|
|
38
41
|
iconBGFull = true,
|
|
39
42
|
iconPosition = "right",
|
|
40
43
|
showChevron = false,
|
|
41
44
|
}) => {
|
|
42
|
-
|
|
43
|
-
const
|
|
45
|
+
// Parse default value and set initial state
|
|
46
|
+
const parseDefaultValue = () => {
|
|
47
|
+
if (!defaultValue) return { value: "", dateRange: undefined };
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
if (selectionMode === "range" && Array.isArray(defaultValue)) {
|
|
51
|
+
// Handle range: ["yyyy-MM-dd", "yyyy-MM-dd"]
|
|
52
|
+
const [fromStr, toStr] = defaultValue;
|
|
53
|
+
const from = new Date(fromStr);
|
|
54
|
+
const to = toStr ? new Date(toStr) : from;
|
|
55
|
+
const dateRange = { from, to };
|
|
56
|
+
const displayValue = formatDateRange(dateRange);
|
|
57
|
+
return { value: displayValue, dateRange };
|
|
58
|
+
} else if (selectionMode === "single" && typeof defaultValue === "string") {
|
|
59
|
+
// Handle single: "yyyy-MM-dd"
|
|
60
|
+
const date = new Date(defaultValue);
|
|
61
|
+
const dateRange = { from: date, to: date };
|
|
62
|
+
const displayValue = format(date, "dd/MM/yyyy");
|
|
63
|
+
return { value: displayValue, dateRange };
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error("Error parsing default date value:", error);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { value: "", dateRange: undefined };
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const initialState = parseDefaultValue();
|
|
73
|
+
const [value, setValue] = useState<string>(initialState.value);
|
|
74
|
+
const [selectedDateRange, setSelectedDateRange] = useState<any>(initialState.dateRange);
|
|
44
75
|
const [selectedTime, setSelectedTime] = useState<{ hour: string; minute: string; meridiem: "AM" | "PM" } | undefined>(undefined);
|
|
45
76
|
const [isOpen, setIsOpen] = useState(false);
|
|
46
77
|
|
|
@@ -298,6 +298,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
298
298
|
showChevron={true}
|
|
299
299
|
onValueChange={handleDateRangeChange}
|
|
300
300
|
selectionMode="range"
|
|
301
|
+
defaultValue={arrivalDate && departureDate ? [arrivalDate, departureDate] : undefined}
|
|
301
302
|
/>
|
|
302
303
|
</div>
|
|
303
304
|
<div className="round-trip__field round-trip__field--pickup-dropoff">
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
.table-container {
|
|
2
|
+
overflow-y: hidden;
|
|
3
|
+
overflow-x: auto;
|
|
4
|
+
max-width: 1680px;
|
|
5
|
+
&.table-container--no-total {
|
|
6
|
+
padding-bottom: var(--spacing-padding-px-4);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.table {
|
|
11
|
+
width: 100%;
|
|
12
|
+
border-collapse: collapse;
|
|
13
|
+
border-spacing: 0;
|
|
14
|
+
th,
|
|
15
|
+
td {
|
|
16
|
+
padding-inline: var(--spacing-padding-px-4);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
.table__header {
|
|
20
|
+
th {
|
|
21
|
+
@apply h-11 text-left;
|
|
22
|
+
background-color: var(--color-elevation-level-2);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
.table__body {
|
|
26
|
+
tr {
|
|
27
|
+
@apply transition-colors duration-200;
|
|
28
|
+
border-top: solid 1px var(--color-surface-300);
|
|
29
|
+
&:hover:not(.table__no-hover) {
|
|
30
|
+
background-color: var(--color-elevation-state-hover-subtle);
|
|
31
|
+
}
|
|
32
|
+
&:first-child {
|
|
33
|
+
border-top: none;
|
|
34
|
+
}
|
|
35
|
+
&.table__row-yellow {
|
|
36
|
+
background-color: var(--color-yellow-50);
|
|
37
|
+
border: 1px solid transparent;
|
|
38
|
+
position: relative;
|
|
39
|
+
&::after {
|
|
40
|
+
content: '';
|
|
41
|
+
position: absolute;
|
|
42
|
+
inset: -1px;
|
|
43
|
+
pointer-events: none;
|
|
44
|
+
background-image:
|
|
45
|
+
repeating-linear-gradient(
|
|
46
|
+
to right,
|
|
47
|
+
var(--color-yellow-600) 0,
|
|
48
|
+
var(--color-yellow-600) 8px,
|
|
49
|
+
transparent 8px,
|
|
50
|
+
transparent 16px
|
|
51
|
+
),
|
|
52
|
+
repeating-linear-gradient(
|
|
53
|
+
to right,
|
|
54
|
+
var(--color-yellow-600) 0,
|
|
55
|
+
var(--color-yellow-600) 8px,
|
|
56
|
+
transparent 8px,
|
|
57
|
+
transparent 16px
|
|
58
|
+
),
|
|
59
|
+
repeating-linear-gradient(
|
|
60
|
+
to bottom,
|
|
61
|
+
var(--color-yellow-600) 0,
|
|
62
|
+
var(--color-yellow-600) 8px,
|
|
63
|
+
transparent 8px,
|
|
64
|
+
transparent 16px
|
|
65
|
+
),
|
|
66
|
+
repeating-linear-gradient(
|
|
67
|
+
to bottom,
|
|
68
|
+
var(--color-yellow-600) 0,
|
|
69
|
+
var(--color-yellow-600) 8px,
|
|
70
|
+
transparent 8px,
|
|
71
|
+
transparent 16px
|
|
72
|
+
);
|
|
73
|
+
background-size:
|
|
74
|
+
100% 1px,
|
|
75
|
+
100% 1px,
|
|
76
|
+
1px 100%,
|
|
77
|
+
1px 100%;
|
|
78
|
+
background-position: top, bottom, left, right;
|
|
79
|
+
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
|
|
80
|
+
}
|
|
81
|
+
&:hover {
|
|
82
|
+
background-color: var(--color-yellow-100);
|
|
83
|
+
}
|
|
84
|
+
& + tr {
|
|
85
|
+
border-top: none;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
&.table__row-border-0 {
|
|
89
|
+
border-top: none;
|
|
90
|
+
&:not(:nth-of-type(1)) {
|
|
91
|
+
td {
|
|
92
|
+
vertical-align: top;
|
|
93
|
+
padding-top: 0;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
td {
|
|
99
|
+
padding-block: var(--spacing-padding-px-4);
|
|
100
|
+
&.table__cell-nested {
|
|
101
|
+
padding: 0;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
tr:last-child {
|
|
104
|
+
border-bottom: none;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
.table__nested-wrapper {
|
|
109
|
+
overflow: hidden;
|
|
110
|
+
display: block;
|
|
111
|
+
}
|
|
112
|
+
.button__icon {
|
|
113
|
+
@apply transition-transform duration-200;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.table__row-nested {
|
|
118
|
+
border-left: solid 4px var(--color-primary-brand);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.table__button-expanded {
|
|
122
|
+
.button__icon {
|
|
123
|
+
@apply rotate-180;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.table__row-clickable {
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.table__button {
|
|
132
|
+
width: 136px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.table__row-grouped {
|
|
136
|
+
> td {
|
|
137
|
+
padding: 0;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.table__total-container {
|
|
142
|
+
max-width: 1680px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.table__total {
|
|
146
|
+
tr {
|
|
147
|
+
border: 1px solid transparent;
|
|
148
|
+
position: relative;
|
|
149
|
+
&::after {
|
|
150
|
+
content: '';
|
|
151
|
+
position: absolute;
|
|
152
|
+
inset: -1px;
|
|
153
|
+
pointer-events: none;
|
|
154
|
+
background-image:
|
|
155
|
+
repeating-linear-gradient(
|
|
156
|
+
to right,
|
|
157
|
+
var(--divider-color-default) 0,
|
|
158
|
+
var(--divider-color-default) 12px,
|
|
159
|
+
transparent 12px,
|
|
160
|
+
transparent 24px
|
|
161
|
+
),
|
|
162
|
+
repeating-linear-gradient(
|
|
163
|
+
to right,
|
|
164
|
+
var(--divider-color-default) 0,
|
|
165
|
+
var(--divider-color-default) 12px,
|
|
166
|
+
transparent 12px,
|
|
167
|
+
transparent 24px
|
|
168
|
+
);
|
|
169
|
+
background-size:
|
|
170
|
+
100% 1px,
|
|
171
|
+
100% 1px;
|
|
172
|
+
background-position: top, bottom;
|
|
173
|
+
background-repeat: repeat-x, repeat-x;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
td {
|
|
177
|
+
padding-block: var(--spacing-padding-px-4);
|
|
178
|
+
&:last-child {
|
|
179
|
+
width: 160px;
|
|
180
|
+
@media (min-width: 1680px) {
|
|
181
|
+
width: var(--last-column-width);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { cn } from '@/src/lib/utils';
|
|
2
|
+
import { AnimatePresence, domAnimation, LazyMotion } from 'motion/react';
|
|
3
|
+
import * as motion from 'motion/react-m';
|
|
4
|
+
import { Fragment, useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { Text } from '../../atoms/Typography/Typography';
|
|
6
|
+
import Pagination, { PaginationProps } from '../../molecules/Pagination/Pagination';
|
|
7
|
+
import './Table.css';
|
|
8
|
+
import { ColumnType, TableCell } from './TableCell';
|
|
9
|
+
|
|
10
|
+
export type TableRowData<T = any> = {
|
|
11
|
+
/** Unique identifier for the row */
|
|
12
|
+
id?: string;
|
|
13
|
+
/** Whether the row is visible */
|
|
14
|
+
visible?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Class name for the row
|
|
17
|
+
*
|
|
18
|
+
* Available classes:
|
|
19
|
+
* - table__row-yellow: For yellow rows
|
|
20
|
+
* - table__row-border-0: For no border
|
|
21
|
+
*/
|
|
22
|
+
className?: string;
|
|
23
|
+
|
|
24
|
+
/** Children rows for the row */
|
|
25
|
+
children?: T[];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export interface TableProps<T extends TableRowData<T>> {
|
|
29
|
+
/** Columns definitions for the table */
|
|
30
|
+
columns: ColumnType<T>[];
|
|
31
|
+
|
|
32
|
+
/** Data for the table */
|
|
33
|
+
data: T[];
|
|
34
|
+
|
|
35
|
+
/** Callback function to be called when a row is clicked */
|
|
36
|
+
onClickRow?: (e: React.MouseEvent<HTMLTableRowElement>, row: T) => void;
|
|
37
|
+
|
|
38
|
+
/** Pagination configuration for the table */
|
|
39
|
+
pagination?: PaginationProps;
|
|
40
|
+
|
|
41
|
+
/** Total rows in the table */
|
|
42
|
+
totalRows?: Record<string, string | number>;
|
|
43
|
+
|
|
44
|
+
/** Whether the child rows are visible */
|
|
45
|
+
isGrouped?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A component for displaying nested content in a table row.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* <NestedContent
|
|
53
|
+
* rowIndex={rowIndex}
|
|
54
|
+
* columns={columns}
|
|
55
|
+
* children={children}
|
|
56
|
+
* onClickRow={onClickRow}
|
|
57
|
+
* />
|
|
58
|
+
* @param NestedContentProps<T>
|
|
59
|
+
* @returns
|
|
60
|
+
*/
|
|
61
|
+
const NestedContent = <T extends TableRowData<T>>({
|
|
62
|
+
rowIndex,
|
|
63
|
+
columns,
|
|
64
|
+
children,
|
|
65
|
+
isGrouped,
|
|
66
|
+
onClickRow,
|
|
67
|
+
}: {
|
|
68
|
+
rowIndex: number;
|
|
69
|
+
columns: ColumnType<T>[];
|
|
70
|
+
children: T[];
|
|
71
|
+
isGrouped?: boolean;
|
|
72
|
+
onClickRow?: (e: React.MouseEvent<HTMLTableRowElement>, row: T) => void;
|
|
73
|
+
}) => {
|
|
74
|
+
const contentRef = useRef<HTMLDivElement>(null);
|
|
75
|
+
const [height, setHeight] = useState<number | 'auto'>(0);
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (contentRef.current) {
|
|
79
|
+
const measuredHeight = contentRef.current.scrollHeight;
|
|
80
|
+
setHeight(measuredHeight);
|
|
81
|
+
}
|
|
82
|
+
}, [children]);
|
|
83
|
+
|
|
84
|
+
const Tag = isGrouped ? 'div' : motion.div;
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<Tag
|
|
88
|
+
ref={contentRef}
|
|
89
|
+
initial={{ height: 0, opacity: 0 }}
|
|
90
|
+
animate={{ height, opacity: 1 }}
|
|
91
|
+
exit={{ height: 0, opacity: 0 }}
|
|
92
|
+
transition={{
|
|
93
|
+
height: { duration: 0.2, ease: 'easeInOut' },
|
|
94
|
+
opacity: { duration: 0.15, ease: 'easeInOut' },
|
|
95
|
+
}}
|
|
96
|
+
className="table__nested-wrapper">
|
|
97
|
+
<table className="table">
|
|
98
|
+
<tbody>
|
|
99
|
+
{children.map((child, childIndex) => (
|
|
100
|
+
<tr
|
|
101
|
+
key={`ch-${rowIndex}-${childIndex}`}
|
|
102
|
+
className={cn(child.className, {
|
|
103
|
+
'table__row-clickable': onClickRow,
|
|
104
|
+
})}
|
|
105
|
+
onClick={(e) => onClickRow?.(e, child as T)}>
|
|
106
|
+
<TableCell<T> columns={columns} row={child as T} rowIndex={childIndex} />
|
|
107
|
+
</tr>
|
|
108
|
+
))}
|
|
109
|
+
</tbody>
|
|
110
|
+
</table>
|
|
111
|
+
</Tag>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* A table component for displaying structured data in rows and columns. Supports customizable column definitions and data rows.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* <Table
|
|
120
|
+
* columns={columns}
|
|
121
|
+
* data={data}
|
|
122
|
+
* pagination={pagination}
|
|
123
|
+
* onClickRow={onClickRow}
|
|
124
|
+
* />
|
|
125
|
+
*
|
|
126
|
+
* @param props TableProps<T>
|
|
127
|
+
* @returns React.ReactNode
|
|
128
|
+
*
|
|
129
|
+
*/
|
|
130
|
+
export const Table = <T extends TableRowData<T>>(props: TableProps<T>) => {
|
|
131
|
+
const { columns, data, pagination, isGrouped, totalRows = {}, onClickRow } = props;
|
|
132
|
+
|
|
133
|
+
const normalizeLastColumnWidth = () => {
|
|
134
|
+
const width = columns[columns.length - 1].width;
|
|
135
|
+
if (typeof width === 'number') {
|
|
136
|
+
return `${width - 10}px`;
|
|
137
|
+
}
|
|
138
|
+
return width;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const hasTotal = Object.keys(totalRows).length > 0;
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<LazyMotion features={domAnimation}>
|
|
145
|
+
<div>
|
|
146
|
+
<div
|
|
147
|
+
className={cn('table-container', { 'table-container--no-total': !hasTotal })}>
|
|
148
|
+
<table className="table">
|
|
149
|
+
<thead className="table__header">
|
|
150
|
+
<tr>
|
|
151
|
+
{columns.map((column, columnIndex) => (
|
|
152
|
+
<th
|
|
153
|
+
key={`hd-${columnIndex}`}
|
|
154
|
+
className={column.className}
|
|
155
|
+
style={
|
|
156
|
+
column.width
|
|
157
|
+
? { minWidth: column.width, width: column.width }
|
|
158
|
+
: undefined
|
|
159
|
+
}>
|
|
160
|
+
<Text variant="bold" size="sm">
|
|
161
|
+
{column.header}
|
|
162
|
+
</Text>
|
|
163
|
+
</th>
|
|
164
|
+
))}
|
|
165
|
+
</tr>
|
|
166
|
+
</thead>
|
|
167
|
+
<tbody className="table__body">
|
|
168
|
+
{data.map((row, rowIndex) => {
|
|
169
|
+
const hasVisibleChildren = row.children?.some((child) => child.visible);
|
|
170
|
+
|
|
171
|
+
const defaultTable = (
|
|
172
|
+
<tr
|
|
173
|
+
className={cn(row.className, {
|
|
174
|
+
'table__row-nested': row.children?.length,
|
|
175
|
+
'table__row-clickable': onClickRow,
|
|
176
|
+
})}
|
|
177
|
+
onClick={(e) => onClickRow?.(e, row)}>
|
|
178
|
+
<TableCell<T> columns={columns} row={row} rowIndex={rowIndex} />
|
|
179
|
+
</tr>
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<Fragment key={`rw-${rowIndex}`}>
|
|
184
|
+
{isGrouped ? (
|
|
185
|
+
row.children && row.children.length > 0 ? (
|
|
186
|
+
<tr className="table__row-grouped">
|
|
187
|
+
<td colSpan={columns.length}>
|
|
188
|
+
<NestedContent<T>
|
|
189
|
+
isGrouped={isGrouped}
|
|
190
|
+
rowIndex={rowIndex}
|
|
191
|
+
columns={columns}
|
|
192
|
+
children={row.children || []}
|
|
193
|
+
onClickRow={onClickRow}
|
|
194
|
+
/>
|
|
195
|
+
</td>
|
|
196
|
+
</tr>
|
|
197
|
+
) : (
|
|
198
|
+
defaultTable
|
|
199
|
+
)
|
|
200
|
+
) : (
|
|
201
|
+
<>
|
|
202
|
+
{defaultTable}
|
|
203
|
+
<AnimatePresence initial={false}>
|
|
204
|
+
{hasVisibleChildren && (
|
|
205
|
+
<tr
|
|
206
|
+
key={`nested-${rowIndex}`}
|
|
207
|
+
className={cn('table__no-hover', {
|
|
208
|
+
'table__row-nested':
|
|
209
|
+
row.children && row.children.length > 0,
|
|
210
|
+
})}>
|
|
211
|
+
<td colSpan={columns.length} className="table__cell-nested">
|
|
212
|
+
<NestedContent<T>
|
|
213
|
+
rowIndex={rowIndex}
|
|
214
|
+
columns={columns}
|
|
215
|
+
children={row.children || []}
|
|
216
|
+
onClickRow={onClickRow}
|
|
217
|
+
/>
|
|
218
|
+
</td>
|
|
219
|
+
</tr>
|
|
220
|
+
)}
|
|
221
|
+
</AnimatePresence>
|
|
222
|
+
</>
|
|
223
|
+
)}
|
|
224
|
+
</Fragment>
|
|
225
|
+
);
|
|
226
|
+
})}
|
|
227
|
+
</tbody>
|
|
228
|
+
</table>
|
|
229
|
+
</div>
|
|
230
|
+
{hasTotal && (
|
|
231
|
+
<div className="table__total-container">
|
|
232
|
+
<table className="table">
|
|
233
|
+
<tbody className="table__total">
|
|
234
|
+
<tr>
|
|
235
|
+
<td colSpan={columns.length - 1}></td>
|
|
236
|
+
<td
|
|
237
|
+
style={
|
|
238
|
+
{
|
|
239
|
+
'--last-column-width': normalizeLastColumnWidth(),
|
|
240
|
+
} as React.CSSProperties
|
|
241
|
+
}>
|
|
242
|
+
<div className="relative">
|
|
243
|
+
<Text
|
|
244
|
+
size="md"
|
|
245
|
+
variant="bold"
|
|
246
|
+
className="absolute top-0 -left-3 -translate-x-full">
|
|
247
|
+
Total :{' '}
|
|
248
|
+
</Text>
|
|
249
|
+
<div>
|
|
250
|
+
{Object.entries(totalRows).map(([currency, total]) => (
|
|
251
|
+
<div key={currency}>
|
|
252
|
+
<Text size="md" variant="bold">
|
|
253
|
+
{currency} {total}
|
|
254
|
+
</Text>
|
|
255
|
+
</div>
|
|
256
|
+
))}
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
</td>
|
|
260
|
+
</tr>
|
|
261
|
+
</tbody>
|
|
262
|
+
</table>
|
|
263
|
+
</div>
|
|
264
|
+
)}
|
|
265
|
+
{pagination && (
|
|
266
|
+
<div className="flex justify-end mt-4">
|
|
267
|
+
<Pagination {...pagination} />
|
|
268
|
+
</div>
|
|
269
|
+
)}
|
|
270
|
+
</div>
|
|
271
|
+
</LazyMotion>
|
|
272
|
+
);
|
|
273
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableRowData } from './Table';
|
|
3
|
+
|
|
4
|
+
export type ColumnType<T = TableRowData> = {
|
|
5
|
+
header: string;
|
|
6
|
+
key: Extract<keyof T, string> | 'actions';
|
|
7
|
+
className?: string;
|
|
8
|
+
width?: number | string;
|
|
9
|
+
cell: (
|
|
10
|
+
value: T[Extract<keyof T, string>],
|
|
11
|
+
rawData: T,
|
|
12
|
+
index?: number
|
|
13
|
+
) => React.ReactNode;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export interface TableCellProps<T = TableRowData> {
|
|
17
|
+
columns: ColumnType<T>[];
|
|
18
|
+
row: T;
|
|
19
|
+
rowIndex: number;
|
|
20
|
+
}
|
|
21
|
+
export const TableCell = <T extends TableRowData>(props: TableCellProps<T>) => {
|
|
22
|
+
const { columns, row, rowIndex } = props;
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
{columns.map((column, columnIndex) => (
|
|
26
|
+
<td
|
|
27
|
+
key={`cl-${rowIndex}-${columnIndex}`}
|
|
28
|
+
style={
|
|
29
|
+
column.width ? { minWidth: column.width, width: column.width } : undefined
|
|
30
|
+
}>
|
|
31
|
+
{column.key === 'actions' ? (
|
|
32
|
+
<div>{column.cell({} as T[Extract<keyof T, string>], row, rowIndex)}</div>
|
|
33
|
+
) : (
|
|
34
|
+
column.cell(row[column.key], row, rowIndex)
|
|
35
|
+
)}
|
|
36
|
+
</td>
|
|
37
|
+
))}
|
|
38
|
+
</>
|
|
39
|
+
);
|
|
40
|
+
};
|