@altruist03/ui 0.1.0 → 0.2.1
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,123 @@
|
|
|
1
|
+
export type CheckboxSize = 'sm' | 'md' | 'lg';
|
|
2
|
+
|
|
3
|
+
export interface CheckboxProps {
|
|
4
|
+
/**
|
|
5
|
+
* The label text displayed next to the checkbox
|
|
6
|
+
*/
|
|
7
|
+
label: string;
|
|
8
|
+
/**
|
|
9
|
+
* Position of the label: "end" = right of checkbox (default), "start" = left of checkbox
|
|
10
|
+
*/
|
|
11
|
+
labelPlacement?: 'start' | 'end';
|
|
12
|
+
/**
|
|
13
|
+
* Size variant: sm, md, or lg
|
|
14
|
+
*/
|
|
15
|
+
size?: CheckboxSize;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the checkbox is checked
|
|
18
|
+
*/
|
|
19
|
+
checked?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Default checked state (for uncontrolled usage)
|
|
22
|
+
*/
|
|
23
|
+
defaultChecked?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Whether the checkbox is disabled
|
|
26
|
+
*/
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Whether the checkbox is indeterminate (shows a dash instead of checkmark)
|
|
30
|
+
*/
|
|
31
|
+
indeterminate?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The name attribute for form grouping
|
|
34
|
+
*/
|
|
35
|
+
name?: string;
|
|
36
|
+
/**
|
|
37
|
+
* HTML id attribute
|
|
38
|
+
*/
|
|
39
|
+
id?: string;
|
|
40
|
+
/**
|
|
41
|
+
* The value attribute for form submission
|
|
42
|
+
*/
|
|
43
|
+
value?: string;
|
|
44
|
+
/**
|
|
45
|
+
* onChange handler
|
|
46
|
+
*/
|
|
47
|
+
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
48
|
+
/**
|
|
49
|
+
* onBlur handler
|
|
50
|
+
*/
|
|
51
|
+
onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void;
|
|
52
|
+
/**
|
|
53
|
+
* onFocus handler
|
|
54
|
+
*/
|
|
55
|
+
onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Helper text displayed below the checkbox (e.g. description or validation message)
|
|
58
|
+
*/
|
|
59
|
+
helperText?: React.ReactNode;
|
|
60
|
+
/**
|
|
61
|
+
* When true, shows error styling for the helper text (and can be used for validation state)
|
|
62
|
+
*/
|
|
63
|
+
error?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface CheckboxGroupProps {
|
|
67
|
+
/**
|
|
68
|
+
* The label/heading displayed above the checkbox group
|
|
69
|
+
*/
|
|
70
|
+
label?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Array of checkbox options
|
|
73
|
+
*/
|
|
74
|
+
options: Array<{
|
|
75
|
+
label: string;
|
|
76
|
+
value: string;
|
|
77
|
+
disabled?: boolean;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Selected values (for controlled usage)
|
|
81
|
+
*/
|
|
82
|
+
value?: string[];
|
|
83
|
+
/**
|
|
84
|
+
* Default selected values (for uncontrolled usage)
|
|
85
|
+
*/
|
|
86
|
+
defaultValue?: string[];
|
|
87
|
+
/**
|
|
88
|
+
* The name attribute for form grouping
|
|
89
|
+
*/
|
|
90
|
+
name?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Whether the group is disabled
|
|
93
|
+
*/
|
|
94
|
+
disabled?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Layout direction: 'horizontal' or 'vertical'
|
|
97
|
+
*/
|
|
98
|
+
direction?: 'horizontal' | 'vertical';
|
|
99
|
+
/**
|
|
100
|
+
* Number of columns for a grid layout (overrides direction when > 1)
|
|
101
|
+
*/
|
|
102
|
+
columns?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Optional class name for the root element
|
|
105
|
+
*/
|
|
106
|
+
className?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Size variant: sm, md, or lg
|
|
109
|
+
*/
|
|
110
|
+
size?: CheckboxSize;
|
|
111
|
+
/**
|
|
112
|
+
* onChange handler - receives the array of selected values
|
|
113
|
+
*/
|
|
114
|
+
onChange?: (values: string[]) => void;
|
|
115
|
+
/**
|
|
116
|
+
* Helper text displayed below the checkbox group
|
|
117
|
+
*/
|
|
118
|
+
helperText?: React.ReactNode;
|
|
119
|
+
/**
|
|
120
|
+
* When true, shows error styling for the helper text
|
|
121
|
+
*/
|
|
122
|
+
error?: boolean;
|
|
123
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { CloseButton } from "./CloseButton";
|
|
3
|
+
import type { CloseButtonProps } from "./CloseButton.types";
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof CloseButton> = {
|
|
6
|
+
title: "Design System/CloseButton",
|
|
7
|
+
component: CloseButton,
|
|
8
|
+
tags: [],
|
|
9
|
+
decorators: [
|
|
10
|
+
(Story) => (
|
|
11
|
+
<div style={{ padding: "24px" }}>
|
|
12
|
+
<Story />
|
|
13
|
+
</div>
|
|
14
|
+
),
|
|
15
|
+
],
|
|
16
|
+
args: {
|
|
17
|
+
size: "md",
|
|
18
|
+
variant: "filled",
|
|
19
|
+
disabled: false,
|
|
20
|
+
"aria-label": "Close",
|
|
21
|
+
color: "grey",
|
|
22
|
+
} as CloseButtonProps,
|
|
23
|
+
argTypes: {
|
|
24
|
+
color: {
|
|
25
|
+
control: { type: "radio" },
|
|
26
|
+
options: ["grey", "white"],
|
|
27
|
+
},
|
|
28
|
+
size: {
|
|
29
|
+
control: { type: "radio" },
|
|
30
|
+
options: ["xs", "sm", "md", "lg"],
|
|
31
|
+
},
|
|
32
|
+
variant: {
|
|
33
|
+
control: { type: "radio" },
|
|
34
|
+
options: ["filled", "outline"],
|
|
35
|
+
},
|
|
36
|
+
disabled: {
|
|
37
|
+
control: { type: "boolean" },
|
|
38
|
+
},
|
|
39
|
+
"aria-label": {
|
|
40
|
+
control: { type: "text" },
|
|
41
|
+
},
|
|
42
|
+
onClick: { action: "clicked" },
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default meta;
|
|
47
|
+
|
|
48
|
+
type Story = StoryObj<typeof CloseButton>;
|
|
49
|
+
|
|
50
|
+
export const Playground: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
size: "md",
|
|
53
|
+
variant: "filled",
|
|
54
|
+
disabled: false,
|
|
55
|
+
"aria-label": "Close",
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const Showcase: Story = {
|
|
60
|
+
render: () => (
|
|
61
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
|
|
62
|
+
{/* Filled – all sizes */}
|
|
63
|
+
<div style={{ display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" }}>
|
|
64
|
+
<CloseButton size="xs" variant="filled" />
|
|
65
|
+
<CloseButton size="sm" variant="filled" />
|
|
66
|
+
<CloseButton size="md" variant="filled" />
|
|
67
|
+
<CloseButton size="lg" variant="filled" />
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
{/* Outline – all sizes */}
|
|
71
|
+
<div style={{ display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" }}>
|
|
72
|
+
<CloseButton size="xs" variant="outline" />
|
|
73
|
+
<CloseButton size="sm" variant="outline" />
|
|
74
|
+
<CloseButton size="md" variant="outline" />
|
|
75
|
+
<CloseButton size="lg" variant="outline" />
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
{/* Disabled – filled */}
|
|
79
|
+
<div style={{ display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" }}>
|
|
80
|
+
<CloseButton size="xs" variant="filled" disabled />
|
|
81
|
+
<CloseButton size="sm" variant="filled" disabled />
|
|
82
|
+
<CloseButton size="md" variant="filled" disabled />
|
|
83
|
+
<CloseButton size="lg" variant="filled" disabled />
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
{/* Disabled – outline */}
|
|
87
|
+
<div style={{ display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" }}>
|
|
88
|
+
<CloseButton size="xs" variant="outline" disabled />
|
|
89
|
+
<CloseButton size="sm" variant="outline" disabled />
|
|
90
|
+
<CloseButton size="md" variant="outline" disabled />
|
|
91
|
+
<CloseButton size="lg" variant="outline" disabled />
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{/* Color: white (filled) */}
|
|
95
|
+
<div style={{ display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" }}>
|
|
96
|
+
<CloseButton size="md" variant="filled" color="white" />
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
),
|
|
100
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React, { useState, useCallback } from 'react';
|
|
2
|
+
// import { Icon } from "firebird-icon-lib";
|
|
3
|
+
import type { CloseButtonSize } from '../../tokens';
|
|
4
|
+
import type { CloseButtonProps } from './CloseButton.types';
|
|
5
|
+
import { getCloseButtonTokensFromResolved } from '../../tokens';
|
|
6
|
+
import { useTokens } from '../../ThemeProvider/ThemeContext';
|
|
7
|
+
import CloseIcon from '@mui/icons-material/Close';
|
|
8
|
+
|
|
9
|
+
export const CloseButton = ({
|
|
10
|
+
size = 'md',
|
|
11
|
+
variant = 'filled',
|
|
12
|
+
color = 'grey',
|
|
13
|
+
disabled = false,
|
|
14
|
+
'aria-label': ariaLabel = 'Close',
|
|
15
|
+
onMouseEnter,
|
|
16
|
+
onMouseLeave,
|
|
17
|
+
style,
|
|
18
|
+
...rest
|
|
19
|
+
}: CloseButtonProps) => {
|
|
20
|
+
const [hovered, setHovered] = useState(false);
|
|
21
|
+
const isHover = hovered && !disabled;
|
|
22
|
+
const resolvedTokens = useTokens();
|
|
23
|
+
const t = getCloseButtonTokensFromResolved(resolvedTokens);
|
|
24
|
+
|
|
25
|
+
const sizeKey = size as CloseButtonSize;
|
|
26
|
+
const sizeVal = t[
|
|
27
|
+
`size${sizeKey.charAt(0).toUpperCase()}${sizeKey.slice(1)}` as keyof typeof t
|
|
28
|
+
] as string;
|
|
29
|
+
const paddingVal = t[
|
|
30
|
+
`padding${sizeKey.charAt(0).toUpperCase()}${sizeKey.slice(1)}` as keyof typeof t
|
|
31
|
+
] as string;
|
|
32
|
+
const borderRadiusVal = t[
|
|
33
|
+
`borderRadius${sizeKey.charAt(0).toUpperCase()}${sizeKey.slice(1)}` as keyof typeof t
|
|
34
|
+
] as string;
|
|
35
|
+
|
|
36
|
+
const filledBackground = color === 'white' ? t.filledBackgroundWhite : t.filledBackground;
|
|
37
|
+
const filledHoverBackground =
|
|
38
|
+
color === 'white' ? t.filledHoverBackgroundWhite : t.filledHoverBackground;
|
|
39
|
+
|
|
40
|
+
const backgroundColor =
|
|
41
|
+
variant === 'filled' ?
|
|
42
|
+
disabled ? filledBackground
|
|
43
|
+
: isHover ? filledHoverBackground
|
|
44
|
+
: filledBackground
|
|
45
|
+
: t.outlineBackground;
|
|
46
|
+
|
|
47
|
+
const iconColor =
|
|
48
|
+
variant === 'filled' ?
|
|
49
|
+
disabled ? t.filledColor
|
|
50
|
+
: isHover ? t.filledHoverColor
|
|
51
|
+
: t.filledColor
|
|
52
|
+
: disabled ? t.outlineColor
|
|
53
|
+
: isHover ? t.outlineHoverColor
|
|
54
|
+
: t.outlineColor;
|
|
55
|
+
|
|
56
|
+
const border =
|
|
57
|
+
variant === 'outline' ?
|
|
58
|
+
isHover ? `1px solid ${t.outlineHoverBorder}`
|
|
59
|
+
: `1px solid ${t.outlineBorder}`
|
|
60
|
+
: t.filledBorder !== 'none' ? `1px solid ${t.filledBorder}`
|
|
61
|
+
: 'none';
|
|
62
|
+
|
|
63
|
+
const handleMouseEnter = useCallback(
|
|
64
|
+
(e: React.MouseEvent<HTMLButtonElement>) => {
|
|
65
|
+
setHovered(true);
|
|
66
|
+
onMouseEnter?.(e);
|
|
67
|
+
},
|
|
68
|
+
[onMouseEnter]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const handleMouseLeave = useCallback(
|
|
72
|
+
(e: React.MouseEvent<HTMLButtonElement>) => {
|
|
73
|
+
setHovered(false);
|
|
74
|
+
onMouseLeave?.(e);
|
|
75
|
+
},
|
|
76
|
+
[onMouseLeave]
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const buttonStyle: React.CSSProperties = {
|
|
80
|
+
width: sizeVal,
|
|
81
|
+
height: sizeVal,
|
|
82
|
+
minWidth: sizeVal,
|
|
83
|
+
minHeight: sizeVal,
|
|
84
|
+
padding: paddingVal,
|
|
85
|
+
margin: 0,
|
|
86
|
+
borderRadius: borderRadiusVal,
|
|
87
|
+
border,
|
|
88
|
+
backgroundColor,
|
|
89
|
+
color: iconColor,
|
|
90
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
91
|
+
display: 'inline-flex',
|
|
92
|
+
alignItems: 'center',
|
|
93
|
+
justifyContent: 'center',
|
|
94
|
+
outline: 'none',
|
|
95
|
+
boxSizing: 'border-box',
|
|
96
|
+
opacity: disabled ? parseFloat(t.disabledOpacity) : 1,
|
|
97
|
+
transition: 'background-color 0.15s ease, border-color 0.15s ease',
|
|
98
|
+
...style,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// const iconSize = parseInt(String(iconSizeVal).replace(/px$/, '') || '16', 10);
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<button
|
|
105
|
+
type="button"
|
|
106
|
+
aria-label={ariaLabel}
|
|
107
|
+
disabled={disabled}
|
|
108
|
+
style={buttonStyle}
|
|
109
|
+
onMouseEnter={handleMouseEnter}
|
|
110
|
+
onMouseLeave={handleMouseLeave}
|
|
111
|
+
{...rest}
|
|
112
|
+
>
|
|
113
|
+
{/* <Icon name="close" size={iconSize} color={iconColor} showLabel={false} /> */}
|
|
114
|
+
<CloseIcon fontSize={size as 'small' | 'medium' | 'large'} />
|
|
115
|
+
</button>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type CloseButtonSize = "xs" | "sm" | "md" | "lg";
|
|
2
|
+
|
|
3
|
+
export type CloseButtonVariant = "filled" | "outline";
|
|
4
|
+
|
|
5
|
+
export interface CloseButtonProps
|
|
6
|
+
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "color"> {
|
|
7
|
+
/** Size of the circular button */
|
|
8
|
+
size?: CloseButtonSize;
|
|
9
|
+
/** Visual variant: filled (default) or outline. Uses design tokens from components/closebutton.json */
|
|
10
|
+
variant?: CloseButtonVariant;
|
|
11
|
+
/** Background color variant for filled buttons */
|
|
12
|
+
color?: "grey" | "white";
|
|
13
|
+
/** Accessible label for the close action */
|
|
14
|
+
"aria-label"?: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { useRef, type CSSProperties } from 'react';
|
|
2
|
+
// import CloseIcon from '@mui/icons-material/Close';
|
|
3
|
+
import SearchIcon from '@mui/icons-material/Search';
|
|
4
|
+
// import { Button } from '../Button/Button';
|
|
5
|
+
import { TextField } from '../TextField/TextField';
|
|
6
|
+
|
|
7
|
+
export type CollapsibleSearchSize = 'sm' | 'md' | 'lg';
|
|
8
|
+
|
|
9
|
+
export interface CollapsibleSearchProps {
|
|
10
|
+
/** Current search text (controlled). */
|
|
11
|
+
value: string;
|
|
12
|
+
/** Fires on every keystroke; parent decides whether to debounce. */
|
|
13
|
+
onChange: (value: string) => void;
|
|
14
|
+
/** Placeholder shown inside the input when open. */
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
/** Width of the input when expanded. Defaults to 240. */
|
|
17
|
+
width?: number;
|
|
18
|
+
/** Size of the underlying TextField + Button. Defaults to "sm". */
|
|
19
|
+
size?: CollapsibleSearchSize;
|
|
20
|
+
/** Disable the control entirely. */
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
/** Optional className on the outer wrapper. */
|
|
23
|
+
className?: string;
|
|
24
|
+
/** Optional className on the toggle (search / close) icon button. */
|
|
25
|
+
toggleClassName?: string;
|
|
26
|
+
/** Optional inline style on the outer wrapper. */
|
|
27
|
+
style?: CSSProperties;
|
|
28
|
+
/**
|
|
29
|
+
* Optional callback fired when the search panel toggles open or closed.
|
|
30
|
+
* Useful if the parent wants to clear filters / refetch on close.
|
|
31
|
+
*/
|
|
32
|
+
onToggle?: (open: boolean) => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* CollapsibleSearch
|
|
37
|
+
*
|
|
38
|
+
* Compact search affordance for crowded toolbars (e.g. the Summary Report and
|
|
39
|
+
* Details Report tables on the fuel page). Renders as a single icon button
|
|
40
|
+
* by default; on click the input slides in next to the icon (which becomes
|
|
41
|
+
* a close button). Closing the panel clears the search value.
|
|
42
|
+
*/
|
|
43
|
+
export function CollapsibleSearch({
|
|
44
|
+
value,
|
|
45
|
+
onChange,
|
|
46
|
+
placeholder = 'Search',
|
|
47
|
+
// width = 240,
|
|
48
|
+
size = 'sm',
|
|
49
|
+
disabled,
|
|
50
|
+
// className,
|
|
51
|
+
// toggleClassName,
|
|
52
|
+
// style,
|
|
53
|
+
// onToggle,
|
|
54
|
+
}: CollapsibleSearchProps) {
|
|
55
|
+
// const [open, setOpen] = useState(false);
|
|
56
|
+
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
57
|
+
|
|
58
|
+
// useEffect(() => {
|
|
59
|
+
// if (open) {
|
|
60
|
+
// const id = window.requestAnimationFrame(() => inputRef.current?.focus());
|
|
61
|
+
// return () => window.cancelAnimationFrame(id);
|
|
62
|
+
// }
|
|
63
|
+
// return undefined;
|
|
64
|
+
// }, [open]);
|
|
65
|
+
|
|
66
|
+
// const handleToggle = useCallback(() => {
|
|
67
|
+
// setOpen((prev) => {
|
|
68
|
+
// const next = !prev;
|
|
69
|
+
// if (!next && value) onChange('');
|
|
70
|
+
// onToggle?.(next);
|
|
71
|
+
// return next;
|
|
72
|
+
// });
|
|
73
|
+
// }, [value, onChange, onToggle]);
|
|
74
|
+
|
|
75
|
+
// const wrapperStyle: CSSProperties = {
|
|
76
|
+
// display: 'inline-flex',
|
|
77
|
+
// alignItems: 'center',
|
|
78
|
+
// gap: 6,
|
|
79
|
+
// ...style,
|
|
80
|
+
// };
|
|
81
|
+
|
|
82
|
+
// const inputWrapperStyle: CSSProperties = {
|
|
83
|
+
// overflow: 'hidden',
|
|
84
|
+
// transition: 'width 220ms ease, opacity 220ms ease',
|
|
85
|
+
// width: open ? width : 0,
|
|
86
|
+
// opacity: open ? 1 : 0,
|
|
87
|
+
// pointerEvents: open ? 'auto' : 'none',
|
|
88
|
+
// };
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
// <div className={className} style={wrapperStyle}>
|
|
92
|
+
// <div style={inputWrapperStyle}>
|
|
93
|
+
<TextField
|
|
94
|
+
inputRef={inputRef as React.Ref<HTMLInputElement>}
|
|
95
|
+
value={value}
|
|
96
|
+
onChange={(e) => onChange(e.target.value)}
|
|
97
|
+
placeholder={placeholder}
|
|
98
|
+
size={size}
|
|
99
|
+
disabled={disabled}
|
|
100
|
+
fullWidth
|
|
101
|
+
startIcon={<SearchIcon sx={{ fontSize: 20 }} />}
|
|
102
|
+
/>
|
|
103
|
+
// </div>
|
|
104
|
+
// <Button
|
|
105
|
+
// variant="grey"
|
|
106
|
+
// size={size}
|
|
107
|
+
// iconOnly
|
|
108
|
+
// className={toggleClassName}
|
|
109
|
+
// aria-label={open ? 'Close search' : 'Open search'}
|
|
110
|
+
// aria-expanded={open}
|
|
111
|
+
// disabled={disabled}
|
|
112
|
+
// onClick={handleToggle}
|
|
113
|
+
// >
|
|
114
|
+
// {open ?
|
|
115
|
+
// <CloseIcon sx={{ fontSize: 18 }} />
|
|
116
|
+
// : <SearchIcon sx={{ fontSize: 18 }} />}
|
|
117
|
+
// </Button>
|
|
118
|
+
// </div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { DataTable } from './DataTable';
|
|
4
|
+
import { useTokens } from '../../ThemeProvider/ThemeContext';
|
|
5
|
+
import { getDataTableTokensFromResolved } from '../../tokens';
|
|
6
|
+
import { useTable, useSortBy } from 'react-table';
|
|
7
|
+
// import type { DataTableProps } from './DataTable.types';
|
|
8
|
+
interface SampleRow {
|
|
9
|
+
id: number;
|
|
10
|
+
name: string;
|
|
11
|
+
email: string;
|
|
12
|
+
status: string;
|
|
13
|
+
role: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const sampleColumns = [
|
|
17
|
+
{ accessor: 'id', Header: 'ID' },
|
|
18
|
+
{ accessor: 'name', Header: 'Name' },
|
|
19
|
+
{ accessor: 'email', Header: 'Email' },
|
|
20
|
+
{
|
|
21
|
+
accessor: 'status',
|
|
22
|
+
Header: 'Status',
|
|
23
|
+
render: (value: string) => (
|
|
24
|
+
<span
|
|
25
|
+
style={{
|
|
26
|
+
padding: '2px 10px',
|
|
27
|
+
borderRadius: '12px',
|
|
28
|
+
fontSize: '12px',
|
|
29
|
+
fontWeight: 500,
|
|
30
|
+
background:
|
|
31
|
+
value === 'Active' ? '#DEF7EC'
|
|
32
|
+
: value === 'Pending' ? '#FEF3C7'
|
|
33
|
+
: '#FEE2E2',
|
|
34
|
+
color:
|
|
35
|
+
value === 'Active' ? '#03543F'
|
|
36
|
+
: value === 'Pending' ? '#92400E'
|
|
37
|
+
: '#991B1B',
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
{value}
|
|
41
|
+
</span>
|
|
42
|
+
),
|
|
43
|
+
},
|
|
44
|
+
{ accessor: 'role', Header: 'Role' },
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const sampleData: SampleRow[] = [
|
|
48
|
+
{
|
|
49
|
+
id: 1,
|
|
50
|
+
name: 'Alice Johnson',
|
|
51
|
+
email: 'alice@example.com',
|
|
52
|
+
status: 'Active',
|
|
53
|
+
role: 'Admin',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 2,
|
|
57
|
+
name: 'Bob Smith',
|
|
58
|
+
email: 'bob@example.com',
|
|
59
|
+
status: 'Pending',
|
|
60
|
+
role: 'Editor',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 3,
|
|
64
|
+
name: 'Carol White',
|
|
65
|
+
email: 'carol@example.com',
|
|
66
|
+
status: 'Inactive',
|
|
67
|
+
role: 'Viewer',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 4,
|
|
71
|
+
name: 'David Lee',
|
|
72
|
+
email: 'david@example.com',
|
|
73
|
+
status: 'Active',
|
|
74
|
+
role: 'Editor',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: 5,
|
|
78
|
+
name: 'Eve Brown',
|
|
79
|
+
email: 'eve@example.com',
|
|
80
|
+
status: 'Active',
|
|
81
|
+
role: 'Admin',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 6,
|
|
85
|
+
name: 'Frank Davis',
|
|
86
|
+
email: 'frank@example.com',
|
|
87
|
+
status: 'Pending',
|
|
88
|
+
role: 'Viewer',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 7,
|
|
92
|
+
name: 'Grace Kim',
|
|
93
|
+
email: 'grace@example.com',
|
|
94
|
+
status: 'Active',
|
|
95
|
+
role: 'Editor',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: 8,
|
|
99
|
+
name: 'Hank Miller',
|
|
100
|
+
email: 'hank@example.com',
|
|
101
|
+
status: 'Inactive',
|
|
102
|
+
role: 'Viewer',
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
/* Theme-aware card wrapper using design tokens */
|
|
107
|
+
const Card = ({ title, children }: { title: string; children: React.ReactNode }) => {
|
|
108
|
+
const resolved = useTokens();
|
|
109
|
+
const tokens = getDataTableTokensFromResolved(resolved);
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<div
|
|
113
|
+
style={{
|
|
114
|
+
background: tokens.headerBackground,
|
|
115
|
+
borderRadius: '12px',
|
|
116
|
+
border: `1px solid ${tokens.cellBorderBottom}`,
|
|
117
|
+
overflow: 'hidden',
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
<div
|
|
121
|
+
style={{
|
|
122
|
+
padding: '16px 20px',
|
|
123
|
+
borderBottom: `1px solid ${tokens.cellBorderBottom}`,
|
|
124
|
+
fontSize: '14px',
|
|
125
|
+
fontWeight: 600,
|
|
126
|
+
color: tokens.headerColor,
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
{title}
|
|
130
|
+
</div>
|
|
131
|
+
<div>{children}</div>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const DataTableWrapper = ({ columns, data, ...props }: any) => {
|
|
137
|
+
const tableInstance = useTable({ columns, data }, useSortBy);
|
|
138
|
+
|
|
139
|
+
return <DataTable {...tableInstance} {...props} />;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const meta: Meta<typeof DataTableWrapper> = {
|
|
143
|
+
title: 'Design System/DataTable',
|
|
144
|
+
component: DataTableWrapper,
|
|
145
|
+
tags: [],
|
|
146
|
+
decorators: [
|
|
147
|
+
(Story) => (
|
|
148
|
+
<div style={{ padding: '24px' }}>
|
|
149
|
+
<Story />
|
|
150
|
+
</div>
|
|
151
|
+
),
|
|
152
|
+
],
|
|
153
|
+
args: {
|
|
154
|
+
columns: sampleColumns as any,
|
|
155
|
+
data: sampleData,
|
|
156
|
+
loading: false,
|
|
157
|
+
emptyMessage: 'No Record Found',
|
|
158
|
+
stickyHeader: true,
|
|
159
|
+
skeletonRows: 5,
|
|
160
|
+
},
|
|
161
|
+
argTypes: {
|
|
162
|
+
loading: {
|
|
163
|
+
control: { type: 'boolean' },
|
|
164
|
+
description: 'Show loading skeleton',
|
|
165
|
+
table: { defaultValue: { summary: 'false' } },
|
|
166
|
+
},
|
|
167
|
+
emptyMessage: {
|
|
168
|
+
control: { type: 'text' },
|
|
169
|
+
description: 'Message when data is empty',
|
|
170
|
+
table: { defaultValue: { summary: 'No Record Found' } },
|
|
171
|
+
},
|
|
172
|
+
stickyHeader: {
|
|
173
|
+
control: { type: 'boolean' },
|
|
174
|
+
description: 'Stick the header to the top on scroll',
|
|
175
|
+
table: { defaultValue: { summary: 'true' } },
|
|
176
|
+
},
|
|
177
|
+
skeletonRows: {
|
|
178
|
+
control: { type: 'number' },
|
|
179
|
+
description: 'Number of skeleton rows when loading',
|
|
180
|
+
table: { defaultValue: { summary: '5' } },
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
export default meta;
|
|
186
|
+
|
|
187
|
+
type Story = StoryObj<typeof DataTableWrapper>;
|
|
188
|
+
|
|
189
|
+
export const Playground: Story = {
|
|
190
|
+
args: {
|
|
191
|
+
columns: sampleColumns as any,
|
|
192
|
+
data: sampleData,
|
|
193
|
+
loading: false,
|
|
194
|
+
emptyMessage: 'No Record Found',
|
|
195
|
+
stickyHeader: true,
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export const Showcase: Story = {
|
|
200
|
+
render: () => {
|
|
201
|
+
return (
|
|
202
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '32px' }}>
|
|
203
|
+
{/* With Data + Sorting */}
|
|
204
|
+
<Card title="Sortable Table (click ID, Name, or Role headers)">
|
|
205
|
+
<DataTableWrapper columns={sampleColumns} data={sampleData} />
|
|
206
|
+
</Card>
|
|
207
|
+
|
|
208
|
+
{/* Loading State */}
|
|
209
|
+
<Card title="Loading State">
|
|
210
|
+
<DataTableWrapper columns={sampleColumns} data={[]} loading skeletonRows={4} />
|
|
211
|
+
</Card>
|
|
212
|
+
|
|
213
|
+
{/* Empty State */}
|
|
214
|
+
<Card title="Empty State">
|
|
215
|
+
<DataTableWrapper
|
|
216
|
+
columns={sampleColumns}
|
|
217
|
+
data={[]}
|
|
218
|
+
emptyMessage="No records found. Try adjusting your filters."
|
|
219
|
+
/>
|
|
220
|
+
</Card>
|
|
221
|
+
|
|
222
|
+
{/* Row Click */}
|
|
223
|
+
<Card title="Styling Overrides (Center Status)">
|
|
224
|
+
<DataTableWrapper
|
|
225
|
+
columns={sampleColumns}
|
|
226
|
+
data={sampleData.slice(0, 3)}
|
|
227
|
+
className_td_center={['Status', 'ID']}
|
|
228
|
+
/>
|
|
229
|
+
</Card>
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
},
|
|
233
|
+
};
|