@altruist03/ui 0.0.0-stage → 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.
Files changed (205) hide show
  1. package/assets/images/noData.webp +0 -0
  2. package/dist/index.js +15318 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/noData-XPRHKMFR.webp +0 -0
  5. package/package.json +51 -4
  6. package/src/ThemeProvider/ThemeContext.tsx +75 -0
  7. package/src/ThemeProvider/index.ts +7 -0
  8. package/src/assets/images/noData.webp +0 -0
  9. package/src/assets.d.ts +10 -0
  10. package/src/components/Accordion/Accordion.stories.tsx +64 -0
  11. package/src/components/Accordion/Accordion.tsx +219 -0
  12. package/src/components/Accordion/Accordion.types.ts +16 -0
  13. package/src/components/Avatar/Avatar.stories.tsx +304 -0
  14. package/src/components/Avatar/Avatar.tsx +211 -0
  15. package/src/components/Avatar/Avatar.types.ts +33 -0
  16. package/src/components/Badge/Badge.stories.tsx +143 -0
  17. package/src/components/Badge/Badge.tsx +138 -0
  18. package/src/components/Badge/Badge.types.ts +24 -0
  19. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +114 -0
  20. package/src/components/Breadcrumb/Breadcrumb.tsx +120 -0
  21. package/src/components/Breadcrumb/Breadcrumb.types.ts +22 -0
  22. package/src/components/Button/Button.stories.tsx +457 -0
  23. package/src/components/Button/Button.tsx +202 -0
  24. package/src/components/Button/Button.types.ts +18 -0
  25. package/src/components/Checkbox/Checkbox.stories.tsx +254 -0
  26. package/src/components/Checkbox/Checkbox.tsx +352 -0
  27. package/src/components/Checkbox/Checkbox.types.ts +123 -0
  28. package/src/components/CloseButton/CloseButton.stories.tsx +100 -0
  29. package/src/components/CloseButton/CloseButton.tsx +117 -0
  30. package/src/components/CloseButton/CloseButton.types.ts +15 -0
  31. package/src/components/CollapsibleSearch/CollapsibleSearch.tsx +120 -0
  32. package/src/components/DataTable/DataTable.stories.tsx +233 -0
  33. package/src/components/DataTable/DataTable.tsx +968 -0
  34. package/src/components/DataTable/DataTable.types.ts +49 -0
  35. package/src/components/DatePicker/DatePicker.stories.tsx +341 -0
  36. package/src/components/DatePicker/DatePicker.tsx +669 -0
  37. package/src/components/DatePicker/DatePicker.types.ts +105 -0
  38. package/src/components/DatePicker/DateTimePicker.tsx +35 -0
  39. package/src/components/DateRangePicker/DateRangePicker.tsx +179 -0
  40. package/src/components/DateRangePicker/DateRangePicker.types.ts +34 -0
  41. package/src/components/Drawer/Drawer.stories.tsx +243 -0
  42. package/src/components/Drawer/Drawer.tsx +196 -0
  43. package/src/components/Drawer/Drawer.types.ts +60 -0
  44. package/src/components/FileUpload/FileUpload.stories.tsx +162 -0
  45. package/src/components/FileUpload/FileUpload.tsx +216 -0
  46. package/src/components/FileUpload/FileUpload.types.ts +80 -0
  47. package/src/components/FilterPopover/FilterPopover.stories.tsx +173 -0
  48. package/src/components/FilterPopover/FilterPopover.tsx +310 -0
  49. package/src/components/FilterPopover/FilterPopover.types.ts +26 -0
  50. package/src/components/ImageViewer/ImageViewerToolbar.jsx +81 -0
  51. package/src/components/ImageViewer/useImagePanRotate.js +102 -0
  52. package/src/components/IpWhitelistField/IpWhitelistField.stories.tsx +138 -0
  53. package/src/components/IpWhitelistField/IpWhitelistField.tsx +164 -0
  54. package/src/components/IpWhitelistField/IpWhitelistField.types.ts +42 -0
  55. package/src/components/Loader/Loader.stories.tsx +95 -0
  56. package/src/components/Loader/Loader.tsx +132 -0
  57. package/src/components/Loader/Loader.types.ts +6 -0
  58. package/src/components/Menu/Menu.tsx +143 -0
  59. package/src/components/Menu/Menu.types.ts +28 -0
  60. package/src/components/MenuButton/MenuButton.stories.tsx +140 -0
  61. package/src/components/MenuButton/MenuButton.tsx +45 -0
  62. package/src/components/MenuButton/MenuButton.types.ts +21 -0
  63. package/src/components/Modal/Modal.stories.tsx +266 -0
  64. package/src/components/Modal/Modal.tsx +399 -0
  65. package/src/components/Modal/index.ts +2 -0
  66. package/src/components/Modal/types.ts +126 -0
  67. package/src/components/Pagination/Pagination.stories.tsx +167 -0
  68. package/src/components/Pagination/Pagination.tsx +266 -0
  69. package/src/components/Pagination/Pagination.types.ts +20 -0
  70. package/src/components/PeriodSelector/PeriodSelector.stories.tsx +50 -0
  71. package/src/components/PeriodSelector/PeriodSelector.tsx +47 -0
  72. package/src/components/PeriodSelector/PeriodSelector.types.ts +10 -0
  73. package/src/components/PhoneField/PhoneField.stories.tsx +141 -0
  74. package/src/components/PhoneField/PhoneField.tsx +284 -0
  75. package/src/components/PhoneField/PhoneField.types.ts +89 -0
  76. package/src/components/PhoneField/countryCodes.ts +236 -0
  77. package/src/components/Progress/Progress.stories.tsx +83 -0
  78. package/src/components/Progress/Progress.tsx +91 -0
  79. package/src/components/Progress/Progress.types.ts +22 -0
  80. package/src/components/RadioButton/RadioButton.stories.tsx +332 -0
  81. package/src/components/RadioButton/RadioButton.tsx +427 -0
  82. package/src/components/RadioButton/RadioButton.types.ts +117 -0
  83. package/src/components/ReportCard/ReportCard.tsx +183 -0
  84. package/src/components/ReportCard/ReportCard.types.ts +17 -0
  85. package/src/components/SectionIcon/SectionIcon.tsx +87 -0
  86. package/src/components/SectionIcon/SectionIcon.types.ts +23 -0
  87. package/src/components/SegmentedInputField/SegmentedInputField.stories.tsx +165 -0
  88. package/src/components/SegmentedInputField/SegmentedInputField.tsx +174 -0
  89. package/src/components/SegmentedInputField/SegmentedInputField.types.ts +51 -0
  90. package/src/components/SelectScroll/SelectScroll.stories.tsx +336 -0
  91. package/src/components/SelectScroll/SelectScroll.tsx +1119 -0
  92. package/src/components/SelectScroll/SelectScroll.types.ts +60 -0
  93. package/src/components/Selector/Selector.stories.tsx +382 -0
  94. package/src/components/Selector/Selector.tsx +1310 -0
  95. package/src/components/Selector/Selector.types.ts +71 -0
  96. package/src/components/Skeleton/Skeleton.stories.tsx +133 -0
  97. package/src/components/Skeleton/Skeleton.tsx +20 -0
  98. package/src/components/Skeleton/Skeleton.types.ts +3 -0
  99. package/src/components/Spinner/Spinner.stories.tsx +84 -0
  100. package/src/components/Spinner/Spinner.tsx +79 -0
  101. package/src/components/Spinner/Spinner.types.ts +8 -0
  102. package/src/components/StatCard/StatCard.stories.tsx +125 -0
  103. package/src/components/StatCard/StatCard.tsx +167 -0
  104. package/src/components/StatCard/StatCard.types.ts +20 -0
  105. package/src/components/StatusBadge/StatusBadge.stories.tsx +179 -0
  106. package/src/components/StatusBadge/StatusBadge.tsx +74 -0
  107. package/src/components/StatusBadge/StatusBadge.types.ts +23 -0
  108. package/src/components/Stepper/Stepper.stories.tsx +85 -0
  109. package/src/components/Stepper/Stepper.tsx +138 -0
  110. package/src/components/Stepper/Stepper.types.ts +16 -0
  111. package/src/components/SubTabs/SubTabs.stories.tsx +128 -0
  112. package/src/components/SubTabs/SubTabs.tsx +279 -0
  113. package/src/components/SubTabs/SubTabs.types.ts +44 -0
  114. package/src/components/SummaryCard/SummaryCard.stories.tsx +100 -0
  115. package/src/components/SummaryCard/SummaryCard.tsx +141 -0
  116. package/src/components/SummaryCard/SummaryCard.types.ts +22 -0
  117. package/src/components/Switch/Switch.stories.tsx +59 -0
  118. package/src/components/Switch/Switch.tsx +217 -0
  119. package/src/components/Switch/Switch.types.ts +22 -0
  120. package/src/components/Tabs/Tabs.stories.tsx +178 -0
  121. package/src/components/Tabs/Tabs.tsx +197 -0
  122. package/src/components/Tabs/Tabs.types.ts +34 -0
  123. package/src/components/TextField/TextField.stories.tsx +249 -0
  124. package/src/components/TextField/TextField.tsx +462 -0
  125. package/src/components/TextField/TextField.types.ts +141 -0
  126. package/src/components/Toast/Toast.stories.tsx +237 -0
  127. package/src/components/Toast/Toast.tsx +246 -0
  128. package/src/components/Toast/Toast.types.ts +31 -0
  129. package/src/components/ToggleButton/ToggleButton.stories.tsx +105 -0
  130. package/src/components/ToggleButton/ToggleButton.tsx +267 -0
  131. package/src/components/ToggleButton/ToggleButton.types.ts +19 -0
  132. package/src/components/UploadDropzone/UploadDropzone.jsx +78 -0
  133. package/src/components/UploadDropzone2/UploadDropzone.stories.tsx +94 -0
  134. package/src/components/UploadDropzone2/UploadDropzone.tsx +222 -0
  135. package/src/components/UploadDropzone2/UploadDropzone.types.ts +54 -0
  136. package/src/components/ViewEditToggle/ViewEditToggle.stories.tsx +40 -0
  137. package/src/components/ViewEditToggle/ViewEditToggle.tsx +239 -0
  138. package/src/components/ViewEditToggle/ViewEditToggle.types.ts +27 -0
  139. package/src/components/index.ts +157 -0
  140. package/src/icons/ReportDollarIcon.tsx +71 -0
  141. package/src/icons/index.ts +27 -0
  142. package/src/index.ts +214 -0
  143. package/src/storybook/preview.tsx +64 -0
  144. package/src/theme/index.ts +4 -0
  145. package/src/theme/types.d.ts +1 -0
  146. package/src/themes/cpc.ts +4 -0
  147. package/src/themes/firebird.ts +4 -0
  148. package/src/tokens/brands/cpc/themes/dark.json +82 -0
  149. package/src/tokens/brands/cpc/themes/light.json +1 -0
  150. package/src/tokens/brands/default/brand.json +20 -0
  151. package/src/tokens/brands/firebird/themes/dark.json +28 -0
  152. package/src/tokens/brands/firebird/themes/light.json +20 -0
  153. package/src/tokens/button.ts +24 -0
  154. package/src/tokens/components/accordion.json +52 -0
  155. package/src/tokens/components/avatar.json +40 -0
  156. package/src/tokens/components/badge.json +41 -0
  157. package/src/tokens/components/breadcrumb.json +13 -0
  158. package/src/tokens/components/button.json +67 -0
  159. package/src/tokens/components/card.json +39 -0
  160. package/src/tokens/components/checkbox.json +64 -0
  161. package/src/tokens/components/closebutton.json +55 -0
  162. package/src/tokens/components/datatable.json +40 -0
  163. package/src/tokens/components/datepicker.json +99 -0
  164. package/src/tokens/components/drawer.json +23 -0
  165. package/src/tokens/components/field.json +29 -0
  166. package/src/tokens/components/fileupload.json +57 -0
  167. package/src/tokens/components/filterpopover.json +29 -0
  168. package/src/tokens/components/input.json +31 -0
  169. package/src/tokens/components/ipwhitelistfield.json +16 -0
  170. package/src/tokens/components/loader.json +15 -0
  171. package/src/tokens/components/menu.json +21 -0
  172. package/src/tokens/components/modal.json +25 -0
  173. package/src/tokens/components/pagination.json +45 -0
  174. package/src/tokens/components/phonefield.json +41 -0
  175. package/src/tokens/components/progress.json +12 -0
  176. package/src/tokens/components/radio.json +87 -0
  177. package/src/tokens/components/reportcard.json +17 -0
  178. package/src/tokens/components/selector.json +87 -0
  179. package/src/tokens/components/selectscroll.json +65 -0
  180. package/src/tokens/components/skeleton.json +6 -0
  181. package/src/tokens/components/stepper.json +38 -0
  182. package/src/tokens/components/subtabs.json +45 -0
  183. package/src/tokens/components/switch.json +55 -0
  184. package/src/tokens/components/tabs.json +38 -0
  185. package/src/tokens/components/textfield.json +59 -0
  186. package/src/tokens/components/togglebutton.json +48 -0
  187. package/src/tokens/components/uploaddropzone.json +61 -0
  188. package/src/tokens/drawer.ts +37 -0
  189. package/src/tokens/foundation/breakpoints.json +10 -0
  190. package/src/tokens/foundation/colors.json +122 -0
  191. package/src/tokens/foundation/opacity.json +16 -0
  192. package/src/tokens/foundation/radius.json +14 -0
  193. package/src/tokens/foundation/size.json +38 -0
  194. package/src/tokens/foundation/spacing.json +19 -0
  195. package/src/tokens/foundation/typography.json +43 -0
  196. package/src/tokens/index.ts +3665 -0
  197. package/src/tokens/modal.ts +42 -0
  198. package/src/tokens/semantic/color.json +148 -0
  199. package/src/tokens/semantic/field.json +28 -0
  200. package/src/tokens/semantic/opacity.json +5 -0
  201. package/src/tokens/semantic/size.json +722 -0
  202. package/src/tokens/semantic/spacing.json +27 -0
  203. package/src/tokens/semantic/typography.json +87 -0
  204. package/src/utils/scrollLock.ts +44 -0
  205. package/README.md +0 -3
@@ -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
+ };