@altruist03/ui 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/images/noData.webp +0 -0
- package/dist/index.js +15237 -650
- package/dist/index.js.map +1 -1
- package/dist/noData-XPRHKMFR.webp +0 -0
- package/package.json +21 -7
- package/src/ThemeProvider/ThemeContext.tsx +75 -0
- package/src/ThemeProvider/index.ts +7 -0
- package/src/assets/images/noData.webp +0 -0
- package/src/assets.d.ts +10 -0
- package/src/components/Accordion/Accordion.stories.tsx +64 -0
- package/src/components/Accordion/Accordion.tsx +219 -0
- package/src/components/Accordion/Accordion.types.ts +16 -0
- package/src/components/Avatar/Avatar.stories.tsx +304 -0
- package/src/components/Avatar/Avatar.tsx +211 -0
- package/src/components/Avatar/Avatar.types.ts +33 -0
- package/src/components/Badge/Badge.stories.tsx +143 -0
- package/src/components/Badge/Badge.tsx +138 -0
- package/src/components/Badge/Badge.types.ts +24 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +114 -0
- package/src/components/Breadcrumb/Breadcrumb.tsx +120 -0
- package/src/components/Breadcrumb/Breadcrumb.types.ts +22 -0
- package/src/components/Button/Button.stories.tsx +457 -0
- package/src/components/Button/Button.tsx +202 -0
- package/src/components/Button/Button.types.ts +18 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +254 -0
- package/src/components/Checkbox/Checkbox.tsx +352 -0
- package/src/components/Checkbox/Checkbox.types.ts +123 -0
- package/src/components/CloseButton/CloseButton.stories.tsx +100 -0
- package/src/components/CloseButton/CloseButton.tsx +117 -0
- package/src/components/CloseButton/CloseButton.types.ts +15 -0
- package/src/components/CollapsibleSearch/CollapsibleSearch.tsx +120 -0
- package/src/components/DataTable/DataTable.stories.tsx +233 -0
- package/src/components/DataTable/DataTable.tsx +968 -0
- package/src/components/DataTable/DataTable.types.ts +49 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +341 -0
- package/src/components/DatePicker/DatePicker.tsx +669 -0
- package/src/components/DatePicker/DatePicker.types.ts +105 -0
- package/src/components/DatePicker/DateTimePicker.tsx +35 -0
- package/src/components/DateRangePicker/DateRangePicker.tsx +179 -0
- package/src/components/DateRangePicker/DateRangePicker.types.ts +34 -0
- package/src/components/Drawer/Drawer.stories.tsx +243 -0
- package/src/components/Drawer/Drawer.tsx +196 -0
- package/src/components/Drawer/Drawer.types.ts +60 -0
- package/src/components/FileUpload/FileUpload.stories.tsx +162 -0
- package/src/components/FileUpload/FileUpload.tsx +216 -0
- package/src/components/FileUpload/FileUpload.types.ts +80 -0
- package/src/components/FilterPopover/FilterPopover.stories.tsx +173 -0
- package/src/components/FilterPopover/FilterPopover.tsx +310 -0
- package/src/components/FilterPopover/FilterPopover.types.ts +26 -0
- package/src/components/ImageViewer/ImageViewerToolbar.jsx +81 -0
- package/src/components/ImageViewer/useImagePanRotate.js +102 -0
- package/src/components/IpWhitelistField/IpWhitelistField.stories.tsx +138 -0
- package/src/components/IpWhitelistField/IpWhitelistField.tsx +164 -0
- package/src/components/IpWhitelistField/IpWhitelistField.types.ts +42 -0
- package/src/components/Loader/Loader.stories.tsx +95 -0
- package/src/components/Loader/Loader.tsx +132 -0
- package/src/components/Loader/Loader.types.ts +6 -0
- package/src/components/Menu/Menu.tsx +143 -0
- package/src/components/Menu/Menu.types.ts +28 -0
- package/src/components/MenuButton/MenuButton.stories.tsx +140 -0
- package/src/components/MenuButton/MenuButton.tsx +45 -0
- package/src/components/MenuButton/MenuButton.types.ts +21 -0
- package/src/components/Modal/Modal.stories.tsx +266 -0
- package/src/components/Modal/Modal.tsx +399 -0
- package/src/components/Modal/index.ts +2 -0
- package/src/components/Modal/types.ts +126 -0
- package/src/components/Pagination/Pagination.stories.tsx +167 -0
- package/src/components/Pagination/Pagination.tsx +266 -0
- package/src/components/Pagination/Pagination.types.ts +20 -0
- package/src/components/PeriodSelector/PeriodSelector.stories.tsx +50 -0
- package/src/components/PeriodSelector/PeriodSelector.tsx +47 -0
- package/src/components/PeriodSelector/PeriodSelector.types.ts +10 -0
- package/src/components/PhoneField/PhoneField.stories.tsx +141 -0
- package/src/components/PhoneField/PhoneField.tsx +284 -0
- package/src/components/PhoneField/PhoneField.types.ts +89 -0
- package/src/components/PhoneField/countryCodes.ts +236 -0
- package/src/components/Progress/Progress.stories.tsx +83 -0
- package/src/components/Progress/Progress.tsx +91 -0
- package/src/components/Progress/Progress.types.ts +22 -0
- package/src/components/RadioButton/RadioButton.stories.tsx +332 -0
- package/src/components/RadioButton/RadioButton.tsx +427 -0
- package/src/components/RadioButton/RadioButton.types.ts +117 -0
- package/src/components/ReportCard/ReportCard.tsx +183 -0
- package/src/components/ReportCard/ReportCard.types.ts +17 -0
- package/src/components/SectionIcon/SectionIcon.tsx +87 -0
- package/src/components/SectionIcon/SectionIcon.types.ts +23 -0
- package/src/components/SegmentedInputField/SegmentedInputField.stories.tsx +165 -0
- package/src/components/SegmentedInputField/SegmentedInputField.tsx +174 -0
- package/src/components/SegmentedInputField/SegmentedInputField.types.ts +51 -0
- package/src/components/SelectScroll/SelectScroll.stories.tsx +336 -0
- package/src/components/SelectScroll/SelectScroll.tsx +1119 -0
- package/src/components/SelectScroll/SelectScroll.types.ts +60 -0
- package/src/components/Selector/Selector.stories.tsx +382 -0
- package/src/components/Selector/Selector.tsx +1310 -0
- package/src/components/Selector/Selector.types.ts +71 -0
- package/src/components/Skeleton/Skeleton.stories.tsx +133 -0
- package/src/components/Skeleton/Skeleton.tsx +20 -0
- package/src/components/Skeleton/Skeleton.types.ts +3 -0
- package/src/components/Spinner/Spinner.stories.tsx +84 -0
- package/src/components/Spinner/Spinner.tsx +79 -0
- package/src/components/Spinner/Spinner.types.ts +8 -0
- package/src/components/StatCard/StatCard.stories.tsx +125 -0
- package/src/components/StatCard/StatCard.tsx +167 -0
- package/src/components/StatCard/StatCard.types.ts +20 -0
- package/src/components/StatusBadge/StatusBadge.stories.tsx +179 -0
- package/src/components/StatusBadge/StatusBadge.tsx +74 -0
- package/src/components/StatusBadge/StatusBadge.types.ts +23 -0
- package/src/components/Stepper/Stepper.stories.tsx +85 -0
- package/src/components/Stepper/Stepper.tsx +138 -0
- package/src/components/Stepper/Stepper.types.ts +16 -0
- package/src/components/SubTabs/SubTabs.stories.tsx +128 -0
- package/src/components/SubTabs/SubTabs.tsx +279 -0
- package/src/components/SubTabs/SubTabs.types.ts +44 -0
- package/src/components/SummaryCard/SummaryCard.stories.tsx +100 -0
- package/src/components/SummaryCard/SummaryCard.tsx +141 -0
- package/src/components/SummaryCard/SummaryCard.types.ts +22 -0
- package/src/components/Switch/Switch.stories.tsx +59 -0
- package/src/components/Switch/Switch.tsx +217 -0
- package/src/components/Switch/Switch.types.ts +22 -0
- package/src/components/Tabs/Tabs.stories.tsx +178 -0
- package/src/components/Tabs/Tabs.tsx +197 -0
- package/src/components/Tabs/Tabs.types.ts +34 -0
- package/src/components/TextField/TextField.stories.tsx +249 -0
- package/src/components/TextField/TextField.tsx +462 -0
- package/src/components/TextField/TextField.types.ts +141 -0
- package/src/components/Toast/Toast.stories.tsx +237 -0
- package/src/components/Toast/Toast.tsx +246 -0
- package/src/components/Toast/Toast.types.ts +31 -0
- package/src/components/ToggleButton/ToggleButton.stories.tsx +105 -0
- package/src/components/ToggleButton/ToggleButton.tsx +267 -0
- package/src/components/ToggleButton/ToggleButton.types.ts +19 -0
- package/src/components/UploadDropzone/UploadDropzone.jsx +78 -0
- package/src/components/UploadDropzone2/UploadDropzone.stories.tsx +94 -0
- package/src/components/UploadDropzone2/UploadDropzone.tsx +222 -0
- package/src/components/UploadDropzone2/UploadDropzone.types.ts +54 -0
- package/src/components/ViewEditToggle/ViewEditToggle.stories.tsx +40 -0
- package/src/components/ViewEditToggle/ViewEditToggle.tsx +239 -0
- package/src/components/ViewEditToggle/ViewEditToggle.types.ts +27 -0
- package/src/components/index.ts +157 -0
- package/src/icons/ReportDollarIcon.tsx +71 -0
- package/src/icons/index.ts +27 -0
- package/src/index.ts +214 -0
- package/src/storybook/preview.tsx +64 -0
- package/src/theme/index.ts +4 -0
- package/src/theme/types.d.ts +1 -0
- package/src/themes/cpc.ts +4 -0
- package/src/themes/firebird.ts +4 -0
- package/src/tokens/brands/cpc/themes/dark.json +82 -0
- package/src/tokens/brands/cpc/themes/light.json +1 -0
- package/src/tokens/brands/default/brand.json +20 -0
- package/src/tokens/brands/firebird/themes/dark.json +28 -0
- package/src/tokens/brands/firebird/themes/light.json +20 -0
- package/src/tokens/button.ts +24 -0
- package/src/tokens/components/accordion.json +52 -0
- package/src/tokens/components/avatar.json +40 -0
- package/src/tokens/components/badge.json +41 -0
- package/src/tokens/components/breadcrumb.json +13 -0
- package/src/tokens/components/button.json +67 -0
- package/src/tokens/components/card.json +39 -0
- package/src/tokens/components/checkbox.json +64 -0
- package/src/tokens/components/closebutton.json +55 -0
- package/src/tokens/components/datatable.json +40 -0
- package/src/tokens/components/datepicker.json +99 -0
- package/src/tokens/components/drawer.json +23 -0
- package/src/tokens/components/field.json +29 -0
- package/src/tokens/components/fileupload.json +57 -0
- package/src/tokens/components/filterpopover.json +29 -0
- package/src/tokens/components/input.json +31 -0
- package/src/tokens/components/ipwhitelistfield.json +16 -0
- package/src/tokens/components/loader.json +15 -0
- package/src/tokens/components/menu.json +21 -0
- package/src/tokens/components/modal.json +25 -0
- package/src/tokens/components/pagination.json +45 -0
- package/src/tokens/components/phonefield.json +41 -0
- package/src/tokens/components/progress.json +12 -0
- package/src/tokens/components/radio.json +87 -0
- package/src/tokens/components/reportcard.json +17 -0
- package/src/tokens/components/selector.json +87 -0
- package/src/tokens/components/selectscroll.json +65 -0
- package/src/tokens/components/skeleton.json +6 -0
- package/src/tokens/components/stepper.json +38 -0
- package/src/tokens/components/subtabs.json +45 -0
- package/src/tokens/components/switch.json +55 -0
- package/src/tokens/components/tabs.json +38 -0
- package/src/tokens/components/textfield.json +59 -0
- package/src/tokens/components/togglebutton.json +48 -0
- package/src/tokens/components/uploaddropzone.json +61 -0
- package/src/tokens/drawer.ts +37 -0
- package/src/tokens/foundation/breakpoints.json +10 -0
- package/src/tokens/foundation/colors.json +122 -0
- package/src/tokens/foundation/opacity.json +16 -0
- package/src/tokens/foundation/radius.json +14 -0
- package/src/tokens/foundation/size.json +38 -0
- package/src/tokens/foundation/spacing.json +19 -0
- package/src/tokens/foundation/typography.json +43 -0
- package/src/tokens/index.ts +3665 -0
- package/src/tokens/modal.ts +42 -0
- package/src/tokens/semantic/color.json +148 -0
- package/src/tokens/semantic/field.json +28 -0
- package/src/tokens/semantic/opacity.json +5 -0
- package/src/tokens/semantic/size.json +722 -0
- package/src/tokens/semantic/spacing.json +27 -0
- package/src/tokens/semantic/typography.json +87 -0
- package/src/utils/scrollLock.ts +44 -0
- package/dist/index.css +0 -514
- package/dist/index.css.map +0 -1
- package/dist/index.d.ts +0 -289
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export type DatePickerSize = "sm" | "md" | "lg";
|
|
2
|
+
|
|
3
|
+
export type DatePickerIconPosition = "start" | "end";
|
|
4
|
+
|
|
5
|
+
export interface DatePickerProps {
|
|
6
|
+
/**
|
|
7
|
+
* Field label shown above the input
|
|
8
|
+
*/
|
|
9
|
+
label: string;
|
|
10
|
+
/**
|
|
11
|
+
* Current value (for controlled usage)
|
|
12
|
+
*/
|
|
13
|
+
value?: Date | null;
|
|
14
|
+
/**
|
|
15
|
+
* Default value (for uncontrolled usage)
|
|
16
|
+
*/
|
|
17
|
+
defaultValue?: Date | null;
|
|
18
|
+
/**
|
|
19
|
+
* Placeholder text inside the input
|
|
20
|
+
*/
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Helper or error text displayed below the field
|
|
24
|
+
*/
|
|
25
|
+
helperText?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Marks the field as required and appends "*" to the label
|
|
28
|
+
*/
|
|
29
|
+
required?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Shows error state and styles
|
|
32
|
+
*/
|
|
33
|
+
error?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Disables the field
|
|
36
|
+
*/
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Makes the field stretch to full container width
|
|
40
|
+
*/
|
|
41
|
+
fullWidth?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Size of the date picker field
|
|
44
|
+
*/
|
|
45
|
+
size?: DatePickerSize;
|
|
46
|
+
/**
|
|
47
|
+
* Icon element to render inside the input
|
|
48
|
+
*
|
|
49
|
+
* Example:
|
|
50
|
+
* import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
|
|
51
|
+
* <DatePicker icon={<CalendarTodayIcon />} />
|
|
52
|
+
*
|
|
53
|
+
* If you prefer naming convention like `calendar_icon`, you can wrap it:
|
|
54
|
+
* const calendar_icon = <CalendarTodayIcon />;
|
|
55
|
+
* <DatePicker icon={calendar_icon} />
|
|
56
|
+
*/
|
|
57
|
+
icon?: React.ReactNode;
|
|
58
|
+
/**
|
|
59
|
+
* Position of the icon inside the input
|
|
60
|
+
*/
|
|
61
|
+
iconPosition?: DatePickerIconPosition;
|
|
62
|
+
/**
|
|
63
|
+
* Input name attribute
|
|
64
|
+
*/
|
|
65
|
+
name?: string;
|
|
66
|
+
/**
|
|
67
|
+
* HTML id attribute (used to link label and input)
|
|
68
|
+
*/
|
|
69
|
+
id?: string;
|
|
70
|
+
/**
|
|
71
|
+
* onChange handler
|
|
72
|
+
*/
|
|
73
|
+
onChange?: (value: Date | null) => void;
|
|
74
|
+
/**
|
|
75
|
+
* onBlur handler
|
|
76
|
+
*/
|
|
77
|
+
onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void;
|
|
78
|
+
/**
|
|
79
|
+
* onFocus handler
|
|
80
|
+
*/
|
|
81
|
+
onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
|
|
82
|
+
/**
|
|
83
|
+
* Minimum selectable date
|
|
84
|
+
*/
|
|
85
|
+
minDate?: Date;
|
|
86
|
+
/**
|
|
87
|
+
* Maximum selectable date
|
|
88
|
+
*/
|
|
89
|
+
maxDate?: Date;
|
|
90
|
+
/**
|
|
91
|
+
* Format string for displaying the date
|
|
92
|
+
*/
|
|
93
|
+
format?: string;
|
|
94
|
+
/**
|
|
95
|
+
* Format string for input parsing (if different from display format)
|
|
96
|
+
* If not provided, will use the `format` prop value
|
|
97
|
+
*/
|
|
98
|
+
inputFormat?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Allow users to type the date directly in the input field
|
|
101
|
+
* If false, users can only select dates from the calendar picker
|
|
102
|
+
* @default true
|
|
103
|
+
*/
|
|
104
|
+
allowKeyboardInput?: boolean;
|
|
105
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { DatePicker } from './DatePicker';
|
|
2
|
+
import type { DatePickerWrapperProps } from './DatePicker';
|
|
3
|
+
|
|
4
|
+
export type DateTimePickerProps = DatePickerWrapperProps & {
|
|
5
|
+
/** Display format for date and time (default: yyyy/MM/dd HH:mm) */
|
|
6
|
+
dateFormat?: string;
|
|
7
|
+
/** Minute step in the time list (default: 1) */
|
|
8
|
+
timeIntervals?: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Date and time picker built on the design-system DatePicker (24-hour format).
|
|
13
|
+
*/
|
|
14
|
+
export function DateTimePicker({
|
|
15
|
+
dateFormat = 'yyyy/MM/dd HH:mm',
|
|
16
|
+
timeFormat = 'HH:mm',
|
|
17
|
+
timeIntervals = 1,
|
|
18
|
+
timeCaption = 'Time',
|
|
19
|
+
placeholderText = 'Select date and time',
|
|
20
|
+
...props
|
|
21
|
+
}: DateTimePickerProps) {
|
|
22
|
+
return (
|
|
23
|
+
<DatePicker
|
|
24
|
+
{...props}
|
|
25
|
+
showTimeSelect
|
|
26
|
+
timeFormat={timeFormat}
|
|
27
|
+
timeIntervals={timeIntervals}
|
|
28
|
+
timeCaption={timeCaption}
|
|
29
|
+
dateFormat={dateFormat}
|
|
30
|
+
placeholderText={placeholderText}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default DateTimePicker;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { useCallback, type CSSProperties, forwardRef } from 'react';
|
|
2
|
+
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
|
|
3
|
+
import { DatePicker, ExampleCustomInput } from '../DatePicker/DatePicker';
|
|
4
|
+
import type { DateRangePickerProps } from './DateRangePicker.types';
|
|
5
|
+
|
|
6
|
+
const FIELD_HEIGHT: Record<NonNullable<DateRangePickerProps['size']>, number> = {
|
|
7
|
+
sm: 32,
|
|
8
|
+
md: 40,
|
|
9
|
+
lg: 48,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const RangeInput = forwardRef<HTMLDivElement, any>((props, ref) => {
|
|
13
|
+
const {
|
|
14
|
+
startLabel,
|
|
15
|
+
endLabel,
|
|
16
|
+
startPlaceholder,
|
|
17
|
+
endPlaceholder,
|
|
18
|
+
disabled,
|
|
19
|
+
wrapperStyle,
|
|
20
|
+
fieldGroupStyle,
|
|
21
|
+
inlineLabelStyle,
|
|
22
|
+
fieldStyle,
|
|
23
|
+
startDate,
|
|
24
|
+
endDate,
|
|
25
|
+
onClick,
|
|
26
|
+
isOpen,
|
|
27
|
+
onToggleOpen,
|
|
28
|
+
onToggleClose,
|
|
29
|
+
mouseDownOnFieldRef,
|
|
30
|
+
className,
|
|
31
|
+
} = props;
|
|
32
|
+
const size = (props.size || 'sm') as NonNullable<DateRangePickerProps['size']>;
|
|
33
|
+
|
|
34
|
+
// If date-fns format is used, we can just do a very simple slice for now or use toLocaleDateString
|
|
35
|
+
const valStart = startDate ? startDate.toLocaleDateString() : '';
|
|
36
|
+
const valEnd = endDate ? endDate.toLocaleDateString() : '';
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className={className} style={wrapperStyle} ref={ref}>
|
|
40
|
+
<div style={fieldGroupStyle}>
|
|
41
|
+
<span style={inlineLabelStyle}>{startLabel}</span>
|
|
42
|
+
<div style={fieldStyle}>
|
|
43
|
+
<ExampleCustomInput
|
|
44
|
+
value={valStart}
|
|
45
|
+
placeholder={startPlaceholder}
|
|
46
|
+
disabled={disabled}
|
|
47
|
+
size={size}
|
|
48
|
+
iconName="calendar"
|
|
49
|
+
onClick={onClick}
|
|
50
|
+
isOpen={isOpen}
|
|
51
|
+
onToggleOpen={onToggleOpen}
|
|
52
|
+
onToggleClose={onToggleClose}
|
|
53
|
+
mouseDownOnFieldRef={mouseDownOnFieldRef}
|
|
54
|
+
/>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<span
|
|
59
|
+
aria-hidden
|
|
60
|
+
style={{
|
|
61
|
+
display: 'inline-flex',
|
|
62
|
+
alignItems: 'center',
|
|
63
|
+
color: '#6B7280',
|
|
64
|
+
height: FIELD_HEIGHT[size],
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
<ArrowForwardIcon sx={{ fontSize: 18 }} />
|
|
68
|
+
</span>
|
|
69
|
+
|
|
70
|
+
<div style={fieldGroupStyle}>
|
|
71
|
+
<span style={inlineLabelStyle}>{endLabel}</span>
|
|
72
|
+
<div style={fieldStyle}>
|
|
73
|
+
<ExampleCustomInput
|
|
74
|
+
value={valEnd}
|
|
75
|
+
placeholder={endPlaceholder}
|
|
76
|
+
disabled={disabled}
|
|
77
|
+
size={size}
|
|
78
|
+
iconName="calendar"
|
|
79
|
+
onClick={onClick}
|
|
80
|
+
isOpen={isOpen}
|
|
81
|
+
onToggleOpen={onToggleOpen}
|
|
82
|
+
onToggleClose={onToggleClose}
|
|
83
|
+
mouseDownOnFieldRef={mouseDownOnFieldRef}
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
export function DateRangePicker({
|
|
92
|
+
startDate,
|
|
93
|
+
endDate,
|
|
94
|
+
onChange,
|
|
95
|
+
startLabel = 'From',
|
|
96
|
+
endLabel = 'To',
|
|
97
|
+
dateFormat = 'MMM dd, yyyy',
|
|
98
|
+
startPlaceholder = 'From',
|
|
99
|
+
endPlaceholder = 'To',
|
|
100
|
+
size = 'sm',
|
|
101
|
+
minDate,
|
|
102
|
+
maxDate,
|
|
103
|
+
disabled,
|
|
104
|
+
className,
|
|
105
|
+
style,
|
|
106
|
+
}: DateRangePickerProps) {
|
|
107
|
+
const handleRangeChange = useCallback(
|
|
108
|
+
(dates: any) => {
|
|
109
|
+
if (Array.isArray(dates)) {
|
|
110
|
+
const [nextStart, nextEnd] = dates;
|
|
111
|
+
onChange({ startDate: nextStart, endDate: nextEnd });
|
|
112
|
+
} else {
|
|
113
|
+
onChange({ startDate: dates, endDate: null });
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
[onChange]
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const wrapperStyle: CSSProperties = {
|
|
120
|
+
display: 'inline-flex',
|
|
121
|
+
alignItems: 'center',
|
|
122
|
+
gap: 12,
|
|
123
|
+
...style,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const fieldGroupStyle: CSSProperties = {
|
|
127
|
+
display: 'inline-flex',
|
|
128
|
+
alignItems: 'center',
|
|
129
|
+
gap: 8,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const inlineLabelStyle: CSSProperties = {
|
|
133
|
+
fontSize: size === 'lg' ? 14 : 13,
|
|
134
|
+
fontWeight: 500,
|
|
135
|
+
color: disabled ? '#9CA3AF' : '#374151',
|
|
136
|
+
whiteSpace: 'nowrap',
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const fieldWidth =
|
|
140
|
+
size === 'lg' ? 220
|
|
141
|
+
: size === 'md' ? 200
|
|
142
|
+
: 188;
|
|
143
|
+
const fieldStyle: CSSProperties = {
|
|
144
|
+
width: fieldWidth,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const DatePickerAny = DatePicker as any;
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<div className={className}>
|
|
151
|
+
<DatePickerAny
|
|
152
|
+
selectsRange={true}
|
|
153
|
+
startDate={startDate}
|
|
154
|
+
endDate={endDate}
|
|
155
|
+
onChange={handleRangeChange}
|
|
156
|
+
dateFormat={dateFormat}
|
|
157
|
+
minDate={minDate}
|
|
158
|
+
maxDate={maxDate}
|
|
159
|
+
disabled={disabled}
|
|
160
|
+
customInput={
|
|
161
|
+
<RangeInput
|
|
162
|
+
startLabel={startLabel}
|
|
163
|
+
endLabel={endLabel}
|
|
164
|
+
startPlaceholder={startPlaceholder}
|
|
165
|
+
endPlaceholder={endPlaceholder}
|
|
166
|
+
size={size}
|
|
167
|
+
disabled={disabled}
|
|
168
|
+
wrapperStyle={wrapperStyle}
|
|
169
|
+
fieldGroupStyle={fieldGroupStyle}
|
|
170
|
+
inlineLabelStyle={inlineLabelStyle}
|
|
171
|
+
fieldStyle={fieldStyle}
|
|
172
|
+
startDate={startDate}
|
|
173
|
+
endDate={endDate}
|
|
174
|
+
/>
|
|
175
|
+
}
|
|
176
|
+
/>
|
|
177
|
+
</div>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
|
|
3
|
+
export type DateRangePickerSize = 'sm' | 'md' | 'lg';
|
|
4
|
+
|
|
5
|
+
export interface DateRangePickerProps {
|
|
6
|
+
/** Currently selected start date. */
|
|
7
|
+
startDate: Date | null;
|
|
8
|
+
/** Currently selected end date. */
|
|
9
|
+
endDate: Date | null;
|
|
10
|
+
/** Fired whenever either date changes. */
|
|
11
|
+
onChange: (range: { startDate: Date | null; endDate: Date | null }) => void;
|
|
12
|
+
/** Label rendered above the start-date picker. Defaults to "Start date". */
|
|
13
|
+
startLabel?: string;
|
|
14
|
+
/** Label rendered above the end-date picker. Defaults to "End date". */
|
|
15
|
+
endLabel?: string;
|
|
16
|
+
/** Display format passed through to the underlying DatePickers. */
|
|
17
|
+
dateFormat?: string;
|
|
18
|
+
/** Placeholder shown in the start input when empty. */
|
|
19
|
+
startPlaceholder?: string;
|
|
20
|
+
/** Placeholder shown in the end input when empty. */
|
|
21
|
+
endPlaceholder?: string;
|
|
22
|
+
/** Size of each underlying DatePicker. */
|
|
23
|
+
size?: DateRangePickerSize;
|
|
24
|
+
/** Minimum selectable date for the start picker. */
|
|
25
|
+
minDate?: Date;
|
|
26
|
+
/** Maximum selectable date for the end picker. */
|
|
27
|
+
maxDate?: Date;
|
|
28
|
+
/** Disable both fields. */
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
/** Optional className applied to the outer wrapper. */
|
|
31
|
+
className?: string;
|
|
32
|
+
/** Optional inline style applied to the outer wrapper. */
|
|
33
|
+
style?: CSSProperties;
|
|
34
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { Drawer } from './Drawer';
|
|
4
|
+
import type { DrawerProps } from './Drawer.types';
|
|
5
|
+
import { Button } from '../Button/Button';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Drawer> = {
|
|
8
|
+
title: 'Design System/Drawer',
|
|
9
|
+
component: Drawer,
|
|
10
|
+
tags: [],
|
|
11
|
+
decorators: [
|
|
12
|
+
(Story) => (
|
|
13
|
+
<div style={{ padding: '24px', fontFamily: 'Inter, sans-serif' }}>
|
|
14
|
+
<Story />
|
|
15
|
+
</div>
|
|
16
|
+
),
|
|
17
|
+
],
|
|
18
|
+
args: {
|
|
19
|
+
anchor: 'right',
|
|
20
|
+
size: 'lg',
|
|
21
|
+
disableBackdropClose: false,
|
|
22
|
+
transitionDuration: 300,
|
|
23
|
+
} as DrawerProps,
|
|
24
|
+
argTypes: {
|
|
25
|
+
anchor: {
|
|
26
|
+
control: { type: 'radio' },
|
|
27
|
+
options: ['left', 'right', 'top', 'bottom'],
|
|
28
|
+
description: 'Side from which the drawer slides in',
|
|
29
|
+
},
|
|
30
|
+
size: {
|
|
31
|
+
control: { type: 'radio' },
|
|
32
|
+
options: ['sm', 'md', 'lg'],
|
|
33
|
+
description: 'Size preset for drawer width (left/right) or height (top/bottom)',
|
|
34
|
+
},
|
|
35
|
+
width: {
|
|
36
|
+
control: { type: 'number' },
|
|
37
|
+
description: 'Custom width/height in pixels (overrides size when set)',
|
|
38
|
+
},
|
|
39
|
+
disableBackdropClose: {
|
|
40
|
+
control: { type: 'boolean' },
|
|
41
|
+
description: 'Prevent closing when clicking the backdrop',
|
|
42
|
+
},
|
|
43
|
+
transitionDuration: {
|
|
44
|
+
control: { type: 'number' },
|
|
45
|
+
description: 'Animation duration in milliseconds',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default meta;
|
|
51
|
+
|
|
52
|
+
type Story = StoryObj<typeof Drawer>;
|
|
53
|
+
|
|
54
|
+
const DrawerContent = ({ title, description }: { title: string; description: string }) => (
|
|
55
|
+
<div style={{ padding: '24px' }}>
|
|
56
|
+
<h3 style={{ margin: '0 0 16px' }}>{title}</h3>
|
|
57
|
+
<p style={{ margin: 0 }}>{description}</p>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export const Playground: Story = {
|
|
62
|
+
args: {
|
|
63
|
+
anchor: 'right',
|
|
64
|
+
size: 'lg',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const PlaygroundComponent = (args: DrawerProps) => {
|
|
69
|
+
const [open, setOpen] = useState(false);
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
<Button onClick={() => setOpen(true)}>Open Drawer</Button>
|
|
73
|
+
<Drawer {...args} open={open} onClose={() => setOpen(false)}>
|
|
74
|
+
<DrawerContent
|
|
75
|
+
title="Drawer Content"
|
|
76
|
+
description="Adjust anchor, size, and other properties through the Storybook controls."
|
|
77
|
+
/>
|
|
78
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
79
|
+
<Button variant="grey" onClick={() => setOpen(false)}>
|
|
80
|
+
Close
|
|
81
|
+
</Button>
|
|
82
|
+
</div>
|
|
83
|
+
</Drawer>
|
|
84
|
+
</>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
Playground.render = (args) => <PlaygroundComponent {...args} />;
|
|
89
|
+
|
|
90
|
+
const ShowcaseComponent = () => {
|
|
91
|
+
const [openRight, setOpenRight] = useState(false);
|
|
92
|
+
const [openLeft, setOpenLeft] = useState(false);
|
|
93
|
+
const [openTop, setOpenTop] = useState(false);
|
|
94
|
+
const [openBottom, setOpenBottom] = useState(false);
|
|
95
|
+
const [openSm, setOpenSm] = useState(false);
|
|
96
|
+
const [openMd, setOpenMd] = useState(false);
|
|
97
|
+
const [openLg, setOpenLg] = useState(false);
|
|
98
|
+
const [openCustom, setOpenCustom] = useState(false);
|
|
99
|
+
const [openNoBackdrop, setOpenNoBackdrop] = useState(false);
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
|
|
103
|
+
{/* Right anchor (default) */}
|
|
104
|
+
<div>
|
|
105
|
+
<Button onClick={() => setOpenRight(true)}>Open Right Drawer</Button>
|
|
106
|
+
<Drawer anchor="right" size="lg" open={openRight} onClose={() => setOpenRight(false)}>
|
|
107
|
+
<DrawerContent
|
|
108
|
+
title="Right Drawer"
|
|
109
|
+
description="Drawer slides in from the right (default)."
|
|
110
|
+
/>
|
|
111
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
112
|
+
<Button variant="grey" onClick={() => setOpenRight(false)}>
|
|
113
|
+
Close
|
|
114
|
+
</Button>
|
|
115
|
+
</div>
|
|
116
|
+
</Drawer>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
{/* Left anchor */}
|
|
120
|
+
<div>
|
|
121
|
+
<Button onClick={() => setOpenLeft(true)}>Open Left Drawer</Button>
|
|
122
|
+
<Drawer anchor="left" size="md" open={openLeft} onClose={() => setOpenLeft(false)}>
|
|
123
|
+
<DrawerContent
|
|
124
|
+
title="Left Drawer"
|
|
125
|
+
description="Drawer slides in from the left (useful for RTL layouts)."
|
|
126
|
+
/>
|
|
127
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
128
|
+
<Button variant="grey" onClick={() => setOpenLeft(false)}>
|
|
129
|
+
Close
|
|
130
|
+
</Button>
|
|
131
|
+
</div>
|
|
132
|
+
</Drawer>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
{/* Top anchor */}
|
|
136
|
+
<div>
|
|
137
|
+
<Button onClick={() => setOpenTop(true)}>Open Top Drawer</Button>
|
|
138
|
+
<Drawer anchor="top" size="md" open={openTop} onClose={() => setOpenTop(false)}>
|
|
139
|
+
<DrawerContent title="Top Drawer" description="Drawer slides in from the top." />
|
|
140
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
141
|
+
<Button variant="grey" onClick={() => setOpenTop(false)}>
|
|
142
|
+
Close
|
|
143
|
+
</Button>
|
|
144
|
+
</div>
|
|
145
|
+
</Drawer>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
{/* Bottom anchor */}
|
|
149
|
+
<div>
|
|
150
|
+
<Button onClick={() => setOpenBottom(true)}>Open Bottom Drawer</Button>
|
|
151
|
+
<Drawer anchor="bottom" size="md" open={openBottom} onClose={() => setOpenBottom(false)}>
|
|
152
|
+
<DrawerContent title="Bottom Drawer" description="Drawer slides in from the bottom." />
|
|
153
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
154
|
+
<Button variant="grey" onClick={() => setOpenBottom(false)}>
|
|
155
|
+
Close
|
|
156
|
+
</Button>
|
|
157
|
+
</div>
|
|
158
|
+
</Drawer>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
{/* Small size */}
|
|
162
|
+
<div>
|
|
163
|
+
<Button onClick={() => setOpenSm(true)}>Open Small (550px)</Button>
|
|
164
|
+
<Drawer anchor="right" size="sm" open={openSm} onClose={() => setOpenSm(false)}>
|
|
165
|
+
<DrawerContent title="Small Drawer" description="Size preset: sm (550px width)." />
|
|
166
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
167
|
+
<Button variant="grey" onClick={() => setOpenSm(false)}>
|
|
168
|
+
Close
|
|
169
|
+
</Button>
|
|
170
|
+
</div>
|
|
171
|
+
</Drawer>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
{/* Medium size */}
|
|
175
|
+
<div>
|
|
176
|
+
<Button onClick={() => setOpenMd(true)}>Open Medium (800px)</Button>
|
|
177
|
+
<Drawer anchor="right" size="md" open={openMd} onClose={() => setOpenMd(false)}>
|
|
178
|
+
<DrawerContent title="Medium Drawer" description="Size preset: md (800px width)." />
|
|
179
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
180
|
+
<Button variant="grey" onClick={() => setOpenMd(false)}>
|
|
181
|
+
Close
|
|
182
|
+
</Button>
|
|
183
|
+
</div>
|
|
184
|
+
</Drawer>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
{/* Large size */}
|
|
188
|
+
<div>
|
|
189
|
+
<Button onClick={() => setOpenLg(true)}>Open Large (1200px)</Button>
|
|
190
|
+
<Drawer anchor="right" size="lg" open={openLg} onClose={() => setOpenLg(false)}>
|
|
191
|
+
<DrawerContent title="Large Drawer" description="Size preset: lg (1200px width)." />
|
|
192
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
193
|
+
<Button variant="grey" onClick={() => setOpenLg(false)}>
|
|
194
|
+
Close
|
|
195
|
+
</Button>
|
|
196
|
+
</div>
|
|
197
|
+
</Drawer>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
{/* Custom width */}
|
|
201
|
+
<div>
|
|
202
|
+
<Button onClick={() => setOpenCustom(true)}>Open Custom (1200px)</Button>
|
|
203
|
+
<Drawer anchor="right" width={1200} open={openCustom} onClose={() => setOpenCustom(false)}>
|
|
204
|
+
<DrawerContent
|
|
205
|
+
title="Custom Width Drawer"
|
|
206
|
+
description="Fixed width of 1200px via the width prop."
|
|
207
|
+
/>
|
|
208
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
209
|
+
<Button variant="grey" onClick={() => setOpenCustom(false)}>
|
|
210
|
+
Close
|
|
211
|
+
</Button>
|
|
212
|
+
</div>
|
|
213
|
+
</Drawer>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
{/* Disable backdrop close */}
|
|
217
|
+
<div>
|
|
218
|
+
<Button onClick={() => setOpenNoBackdrop(true)}>Open (Backdrop Click Disabled)</Button>
|
|
219
|
+
<Drawer
|
|
220
|
+
anchor="right"
|
|
221
|
+
size="md"
|
|
222
|
+
open={openNoBackdrop}
|
|
223
|
+
onClose={() => setOpenNoBackdrop(false)}
|
|
224
|
+
disableBackdropClose
|
|
225
|
+
>
|
|
226
|
+
<DrawerContent
|
|
227
|
+
title="No Backdrop Close"
|
|
228
|
+
description="Clicking the backdrop will not close this drawer. Use the Close button or Escape key."
|
|
229
|
+
/>
|
|
230
|
+
<div style={{ padding: '0 24px 24px' }}>
|
|
231
|
+
<Button variant="grey" onClick={() => setOpenNoBackdrop(false)}>
|
|
232
|
+
Close
|
|
233
|
+
</Button>
|
|
234
|
+
</div>
|
|
235
|
+
</Drawer>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export const Showcase: Story = {
|
|
242
|
+
render: () => <ShowcaseComponent />,
|
|
243
|
+
};
|