@bigmath-ui-library/core 2.0.4

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 (229) hide show
  1. package/LICENSE +7 -0
  2. package/LICENSE.md +1 -0
  3. package/README.md +42 -0
  4. package/dist/cjs/index.css +11 -0
  5. package/dist/cjs/index.js +134365 -0
  6. package/dist/esm/index.css +11 -0
  7. package/dist/esm/index.js +134258 -0
  8. package/package.json +58 -0
  9. package/rollup.config.js +73 -0
  10. package/src/BMClassnameSetup.ts +3 -0
  11. package/src/assets/icons/Calendar.svg +6 -0
  12. package/src/assets/icons/Close.svg +40 -0
  13. package/src/assets/icons/Default-Loading-Circles.svg +31 -0
  14. package/src/assets/icons/alert.svg +6 -0
  15. package/src/assets/icons/aws.svg +19 -0
  16. package/src/assets/icons/caret-down.svg +3 -0
  17. package/src/assets/icons/check.svg +6 -0
  18. package/src/assets/icons/circle-check-solid.svg +7 -0
  19. package/src/assets/icons/circle-check.svg +6 -0
  20. package/src/assets/icons/circle-selected.svg +3 -0
  21. package/src/assets/icons/circle-unselected.svg +3 -0
  22. package/src/assets/icons/close-basic.svg +3 -0
  23. package/src/assets/icons/close_collapse.svg +3 -0
  24. package/src/assets/icons/copy.svg +3 -0
  25. package/src/assets/icons/drag.svg +3 -0
  26. package/src/assets/icons/expand-more.svg +3 -0
  27. package/src/assets/icons/failed-solid.svg +7 -0
  28. package/src/assets/icons/globe.svg +3 -0
  29. package/src/assets/icons/google-cloud.svg +6 -0
  30. package/src/assets/icons/in-active.svg +4 -0
  31. package/src/assets/icons/info-solid.svg +6 -0
  32. package/src/assets/icons/info.svg +6 -0
  33. package/src/assets/icons/k8s.svg +4 -0
  34. package/src/assets/icons/lock-locked.svg +5 -0
  35. package/src/assets/icons/microsoft-azure.svg +9 -0
  36. package/src/assets/icons/onprem.svg +3 -0
  37. package/src/assets/icons/pencil.svg +3 -0
  38. package/src/assets/icons/search.svg +6 -0
  39. package/src/assets/icons/shield.svg +4 -0
  40. package/src/assets/icons/star.svg +3 -0
  41. package/src/assets/icons/success-tick.svg +3 -0
  42. package/src/assets/icons/timer.svg +3 -0
  43. package/src/assets/icons/visibility-off.svg +6 -0
  44. package/src/assets/icons/visibility.svg +6 -0
  45. package/src/assets/icons/warning.svg +6 -0
  46. package/src/bma/components/BMButton/BMButton.tsx +34 -0
  47. package/src/bma/components/BMButton/index.ts +1 -0
  48. package/src/bma/components/BMInput/BMInput.tsx +13 -0
  49. package/src/bma/components/BMInput/BMInputField.tsx +7 -0
  50. package/src/bma/components/BMInput/BMSearch.tsx +6 -0
  51. package/src/bma/components/BMInput/index.ts +3 -0
  52. package/src/bma/index.ts +3 -0
  53. package/src/bma/package.json +4 -0
  54. package/src/bma/theme/BMAutocomplete.ts +12 -0
  55. package/src/bma/theme/BMInput.ts +46 -0
  56. package/src/bma/theme/theme.ts +15 -0
  57. package/src/bma/theme/themeUtils.ts +10 -0
  58. package/src/components/BMAccordion/BMAccordion.tsx +150 -0
  59. package/src/components/BMAccordion/index.ts +1 -0
  60. package/src/components/BMAddSection/BMAddSection.tsx +38 -0
  61. package/src/components/BMAddSection/index.ts +1 -0
  62. package/src/components/BMAlert/BMAlert.tsx +168 -0
  63. package/src/components/BMAlert/index.ts +1 -0
  64. package/src/components/BMAutoComplete/BMAutoComplete.tsx +86 -0
  65. package/src/components/BMAutoComplete/index.ts +1 -0
  66. package/src/components/BMAvatar/BMAvatar.tsx +45 -0
  67. package/src/components/BMAvatar/index.ts +1 -0
  68. package/src/components/BMButton/BMButton.tsx +46 -0
  69. package/src/components/BMButton/BMButtonGroup.tsx +46 -0
  70. package/src/components/BMButton/BMSplitButton.tsx +72 -0
  71. package/src/components/BMButton/index.ts +3 -0
  72. package/src/components/BMCheckbox/BMCheckbox.tsx +44 -0
  73. package/src/components/BMCheckbox/BMCheckboxField.tsx +41 -0
  74. package/src/components/BMCheckbox/index.ts +2 -0
  75. package/src/components/BMCloudSelect/BMCloudList.tsx +43 -0
  76. package/src/components/BMCloudSelect/BMCloudSelect.tsx +109 -0
  77. package/src/components/BMCloudSelect/BMCloudSelectField.tsx +46 -0
  78. package/src/components/BMCloudSelect/index.ts +3 -0
  79. package/src/components/BMCodeBlock/BMCodeBlock.tsx +233 -0
  80. package/src/components/BMCodeBlock/index.ts +1 -0
  81. package/src/components/BMDatePicker/BMDatePicker.tsx +187 -0
  82. package/src/components/BMDatePicker/index.ts +1 -0
  83. package/src/components/BMDropdown/BMDropdown.tsx +107 -0
  84. package/src/components/BMDropdown/index.ts +1 -0
  85. package/src/components/BMForm/BMFormControlLabel.tsx +23 -0
  86. package/src/components/BMForm/BMLabel.tsx +24 -0
  87. package/src/components/BMForm/index.ts +2 -0
  88. package/src/components/BMHelloBanner/BMHelloBanner.tsx +68 -0
  89. package/src/components/BMHelloBanner/index.ts +1 -0
  90. package/src/components/BMInput/BMInput.tsx +31 -0
  91. package/src/components/BMInput/BMInputEditableCode.tsx +120 -0
  92. package/src/components/BMInput/BMInputField.tsx +37 -0
  93. package/src/components/BMInput/BMSearch.tsx +17 -0
  94. package/src/components/BMInput/BMStripeInput.tsx +24 -0
  95. package/src/components/BMInput/index.ts +5 -0
  96. package/src/components/BMLoadingBox/BMLoadingBox.tsx +45 -0
  97. package/src/components/BMLoadingBox/index.ts +1 -0
  98. package/src/components/BMMaps/BMMapMarker.css +12 -0
  99. package/src/components/BMMaps/BMMapMarker.tsx +68 -0
  100. package/src/components/BMMaps/BMMaps.tsx +129 -0
  101. package/src/components/BMMaps/MapIcons.tsx +83 -0
  102. package/src/components/BMMaps/icons/GeoPartition.svg +19 -0
  103. package/src/components/BMMaps/icons/GeoPartitionHover.svg +20 -0
  104. package/src/components/BMMaps/icons/MasterPreferred.svg +19 -0
  105. package/src/components/BMMaps/icons/MasterPreferredHover.svg +20 -0
  106. package/src/components/BMMaps/icons/ReadReplica.svg +18 -0
  107. package/src/components/BMMaps/icons/ReadReplicaHover.svg +19 -0
  108. package/src/components/BMMaps/icons/RegionNotSelected.svg +18 -0
  109. package/src/components/BMMaps/icons/RegionNotSelectedHover.svg +19 -0
  110. package/src/components/BMMaps/icons/RegionPreferred.svg +18 -0
  111. package/src/components/BMMaps/icons/RegionPreferredHover.svg +19 -0
  112. package/src/components/BMMaps/icons/RegionSelected.svg +18 -0
  113. package/src/components/BMMaps/icons/RegionSelectedHover.svg +19 -0
  114. package/src/components/BMMaps/index.ts +5 -0
  115. package/src/components/BMMaps/legend/MapLegend.tsx +80 -0
  116. package/src/components/BMMaps/markerTypes.ts +8 -0
  117. package/src/components/BMModal/BMModal.tsx +313 -0
  118. package/src/components/BMModal/index.ts +1 -0
  119. package/src/components/BMMultiEntry/BMMultiEntry.tsx +328 -0
  120. package/src/components/BMMultiEntry/BMMultiEntryField.tsx +47 -0
  121. package/src/components/BMMultiEntry/index.ts +2 -0
  122. package/src/components/BMMultiLevelStepper/BMMultiLevelStepper.tsx +191 -0
  123. package/src/components/BMMultiLevelStepper/index.ts +1 -0
  124. package/src/components/BMPagination/BMPagination.tsx +64 -0
  125. package/src/components/BMPagination/index.ts +1 -0
  126. package/src/components/BMPassword/BMPassword.tsx +37 -0
  127. package/src/components/BMPassword/BMPasswordField.tsx +50 -0
  128. package/src/components/BMPassword/index.ts +2 -0
  129. package/src/components/BMProgress/BMProgress.tsx +43 -0
  130. package/src/components/BMProgress/index.ts +1 -0
  131. package/src/components/BMRadio/BMRadio.tsx +162 -0
  132. package/src/components/BMRadio/BMRadioGroupField.tsx +40 -0
  133. package/src/components/BMRadio/index.ts +2 -0
  134. package/src/components/BMSelect/BMSelect.tsx +70 -0
  135. package/src/components/BMSelect/BMSelectField.tsx +47 -0
  136. package/src/components/BMSelect/index.ts +2 -0
  137. package/src/components/BMSlider/BMSlider.tsx +16 -0
  138. package/src/components/BMSlider/index.ts +1 -0
  139. package/src/components/BMSmartStatus/BMSmartStatus.tsx +185 -0
  140. package/src/components/BMSmartStatus/index.tsx +1 -0
  141. package/src/components/BMStatus/BMStatus.tsx +98 -0
  142. package/src/components/BMStatus/index.ts +1 -0
  143. package/src/components/BMTable/BMTable.tsx +131 -0
  144. package/src/components/BMTable/index.ts +1 -0
  145. package/src/components/BMTabs/BMTabs.tsx +50 -0
  146. package/src/components/BMTabs/index.ts +1 -0
  147. package/src/components/BMTag/BMTag.tsx +47 -0
  148. package/src/components/BMTag/index.ts +1 -0
  149. package/src/components/BMTagv2/BMTagv2.tsx +250 -0
  150. package/src/components/BMTagv2/index.ts +1 -0
  151. package/src/components/BMToggle/BMMultiToggleButton.tsx +99 -0
  152. package/src/components/BMToggle/BMToggle.tsx +35 -0
  153. package/src/components/BMToggle/BMToggleField.tsx +28 -0
  154. package/src/components/BMToggle/index.ts +3 -0
  155. package/src/components/BMTooltip/BMTooltip.tsx +52 -0
  156. package/src/components/BMTooltip/index.ts +1 -0
  157. package/src/components/BMWarning/BMWarning.tsx +39 -0
  158. package/src/components/BMWarning/index.ts +1 -0
  159. package/src/components/GenericFailure/GenericFailure.tsx +28 -0
  160. package/src/components/GenericFailure/index.ts +1 -0
  161. package/src/components/NoAccess/NoAccess.tsx +40 -0
  162. package/src/components/NoAccess/NoAccessActionTooltip.tsx +53 -0
  163. package/src/components/NoAccess/NoPermissionModal.tsx +55 -0
  164. package/src/components/NoAccess/index.ts +3 -0
  165. package/src/components/index.ts +34 -0
  166. package/src/index.ts +9 -0
  167. package/src/theme/BMAutoComplete.ts +152 -0
  168. package/src/theme/BMAvatar.ts +5 -0
  169. package/src/theme/BMButton.ts +132 -0
  170. package/src/theme/BMButtonGroup.ts +49 -0
  171. package/src/theme/BMCheckbox.ts +16 -0
  172. package/src/theme/BMFormHelperText.ts +19 -0
  173. package/src/theme/BMInput.ts +120 -0
  174. package/src/theme/BMMaps.ts +9 -0
  175. package/src/theme/BMRadio.ts +10 -0
  176. package/src/theme/BMTabs.ts +79 -0
  177. package/src/theme/BMTag.ts +28 -0
  178. package/src/theme/BMToggle.ts +50 -0
  179. package/src/theme/BMTooltip.ts +34 -0
  180. package/src/theme/theme.ts +326 -0
  181. package/src/theme/variables.ts +152 -0
  182. package/src/types/custom.d.ts +9 -0
  183. package/src/types/svg.d.ts +5 -0
  184. package/stories/BMAButton.stories.tsx +67 -0
  185. package/stories/BMAccordion.stories.tsx +55 -0
  186. package/stories/BMAddSection.stories.tsx +40 -0
  187. package/stories/BMAlert.stories.tsx +33 -0
  188. package/stories/BMAutoComplete.stories.tsx +65 -0
  189. package/stories/BMAvatar.stories.tsx +76 -0
  190. package/stories/BMButton.stories.tsx +57 -0
  191. package/stories/BMButton2.stories.tsx +131 -0
  192. package/stories/BMCheckbox.stories.tsx +23 -0
  193. package/stories/BMCloudSelectField.stories.tsx +40 -0
  194. package/stories/BMCodeBlock.stories.tsx +57 -0
  195. package/stories/BMDatePicker.stories.tsx +88 -0
  196. package/stories/BMDropdown.stories.tsx +84 -0
  197. package/stories/BMGroupButton.stories.tsx +53 -0
  198. package/stories/BMHelloBanner.stories.tsx +33 -0
  199. package/stories/BMInput.stories.tsx +184 -0
  200. package/stories/BMInputEditableCode.stories.tsx +86 -0
  201. package/stories/BMInputField.stories.tsx +50 -0
  202. package/stories/BMLoadingBox.stories.tsx +45 -0
  203. package/stories/BMMaps.stories.tsx +29 -0
  204. package/stories/BMModal.stories.tsx +218 -0
  205. package/stories/BMMultiEntry.stories.tsx +93 -0
  206. package/stories/BMMultiLevelStepper.stories.tsx +87 -0
  207. package/stories/BMPagination.stories.tsx +41 -0
  208. package/stories/BMPassword.stories.tsx +133 -0
  209. package/stories/BMProgress.stories.tsx +60 -0
  210. package/stories/BMRadio.stories.tsx +71 -0
  211. package/stories/BMSelect.stories.tsx +160 -0
  212. package/stories/BMSlider.stories.tsx +74 -0
  213. package/stories/BMSmartStatus.stories.tsx +98 -0
  214. package/stories/BMSplitButton.stories.tsx +32 -0
  215. package/stories/BMStatus.stories.tsx +29 -0
  216. package/stories/BMTable.stories.tsx +350 -0
  217. package/stories/BMTabs.stories.tsx +25 -0
  218. package/stories/BMTag.stories.tsx +63 -0
  219. package/stories/BMTagv2.stories.tsx +288 -0
  220. package/stories/BMToggle.stories.tsx +123 -0
  221. package/stories/BMTooltip.stories.tsx +59 -0
  222. package/stories/BMTypography.stories.tsx +79 -0
  223. package/stories/BMWarning.stories.tsx +55 -0
  224. package/stories/GenericFailure.stories.tsx +47 -0
  225. package/stories/NoAccess.stories.tsx +19 -0
  226. package/stories/NoAccessActionTooltip.stories.tsx +50 -0
  227. package/stories/NoPermissionModal.stories.tsx +46 -0
  228. package/tsconfig.base.json +21 -0
  229. package/tsconfig.build.json +23 -0
@@ -0,0 +1,328 @@
1
+ import {
2
+ FC,
3
+ useRef,
4
+ useState,
5
+ ReactElement,
6
+ KeyboardEvent,
7
+ FocusEvent,
8
+ } from "react";
9
+ import {
10
+ Box,
11
+ Chip,
12
+ FormHelperText,
13
+ InputBase,
14
+ Paper,
15
+ styled,
16
+ Typography,
17
+ } from "@mui/material";
18
+ import type { FieldError } from "react-hook-form";
19
+ import { throttle } from "lodash";
20
+ import { BMTooltip } from "../BMTooltip/BMTooltip";
21
+ import ErrorIcon from "@coreApp/assets/icons/failed-solid.svg";
22
+ import CloseIcon from "@coreApp/assets/icons/close-basic.svg";
23
+
24
+ export interface BMMultiEntryProps {
25
+ error?: boolean | FieldError;
26
+ disabled?: boolean;
27
+ tooltipFn?: (entry: string) => string | null;
28
+ label?: string;
29
+ helperText?: string;
30
+ onChange?: (value: string[]) => void;
31
+ chipIcon?: ReactElement | ((entry: string) => ReactElement | undefined);
32
+ placeholderText?: string;
33
+ value?: string[] | string;
34
+ overrideHeight?: string | number;
35
+ overrideWidth?: string | number;
36
+ dataTestId?: string;
37
+ checkWarning?: (entry: string) => boolean;
38
+ lowercaseEntry?: boolean;
39
+ subLabel?: ReactElement;
40
+ removeInvalidEntriesMsg?: ReactElement;
41
+ multiEntryHitEnterMsg?: ReactElement;
42
+ }
43
+
44
+ // Styled Components
45
+ const Label = styled(Typography)(({ theme }) => ({
46
+ fontSize: "13px",
47
+ fontWeight: 500,
48
+ color: theme.palette.grey[600],
49
+ marginBottom: theme.spacing(0.4),
50
+ marginTop: theme.spacing(0.4),
51
+ }));
52
+
53
+ const EntryWrapper = styled(Paper, {
54
+ shouldForwardProp: (prop) =>
55
+ prop !== "focus" && prop !== "overrideHeight" && prop !== "overrideWidth",
56
+ })<{
57
+ focus?: boolean;
58
+ overrideHeight?: string | number;
59
+ overrideWidth?: string | number;
60
+ }>(({ theme, overrideHeight, overrideWidth }) => ({
61
+ display: "flex",
62
+ flexWrap: "wrap",
63
+ alignItems: "flex-start",
64
+ alignContent: "flex-start",
65
+ gap: theme.spacing(0.5),
66
+ padding: theme.spacing(0.5, 0.5, 0, 0.875),
67
+ minHeight: 40,
68
+ height: overrideHeight ?? "auto",
69
+ width: overrideWidth ?? "100%",
70
+ overflowY: "auto",
71
+ overflowX: "hidden",
72
+ cursor: "text",
73
+ border: `1px solid ${theme.palette.grey[300]}`,
74
+ }));
75
+
76
+ const StyledChip = styled(Chip)(({ theme }) => ({
77
+ backgroundColor: theme.palette.primary[200],
78
+ borderRadius: 6,
79
+ height: theme.spacing(3),
80
+ marginRight: theme.spacing(0.5),
81
+ marginBottom: theme.spacing(0.5),
82
+ maxWidth: 250,
83
+ overflow: "hidden",
84
+ textOverflow: "ellipsis",
85
+ whiteSpace: "nowrap",
86
+ "&:hover": {
87
+ backgroundColor: theme.palette.primary[200],
88
+ },
89
+ "& .MuiChip-deleteIcon": {
90
+ width: theme.spacing(2),
91
+ height: theme.spacing(2),
92
+ },
93
+ fontSize: "11.5px",
94
+ fontWeight: 400,
95
+ }));
96
+
97
+ const WarningChip = styled(StyledChip)(({ theme }) => ({
98
+ backgroundColor: theme.palette.warning[100],
99
+ "& .MuiChip-icon": {
100
+ color: theme.palette.warning[700],
101
+ },
102
+ }));
103
+
104
+ const TextInput = styled(InputBase)(({ theme }) => ({
105
+ flexShrink: 0,
106
+ minWidth: 120,
107
+ height: "24px",
108
+ fontSize: "13px",
109
+ fontWeight: 400,
110
+ marginBottom: theme.spacing(0.5),
111
+ "& input": {
112
+ padding: 0,
113
+ width: "100%",
114
+ boxSizing: "border-box",
115
+ },
116
+ }));
117
+
118
+ const CloseIconStyled = styled(CloseIcon)(({ theme }) => ({
119
+ position: "relative",
120
+ top: "1px",
121
+ color: theme.palette.grey[600],
122
+ }));
123
+
124
+ const ErrorIconStyled = styled(ErrorIcon)(({ theme }) => ({
125
+ width: 16,
126
+ height: 16,
127
+ [`& g path:nth-of-type(2)`]: {
128
+ fill: theme.palette.error[500],
129
+ },
130
+ }));
131
+
132
+ export const BMMultiEntry: FC<BMMultiEntryProps> = ({
133
+ tooltipFn,
134
+ onChange,
135
+ checkWarning,
136
+ label,
137
+ placeholderText,
138
+ value,
139
+ error,
140
+ helperText,
141
+ chipIcon,
142
+ dataTestId,
143
+ disabled,
144
+ lowercaseEntry = false,
145
+ overrideHeight,
146
+ overrideWidth,
147
+ subLabel,
148
+ removeInvalidEntriesMsg,
149
+ multiEntryHitEnterMsg,
150
+ }) => {
151
+ const textInputRef = useRef<HTMLInputElement>(null);
152
+ const [fieldInFocus, setFieldInFocus] = useState(false);
153
+
154
+ const errorArr: FieldError[] = Array.isArray(error) ? error : [];
155
+ const entries = Array.isArray(value)
156
+ ? value.map((item) => (lowercaseEntry ? item.toLowerCase() : item))
157
+ : (value ?? "")
158
+ .split(/[ ,]+/)
159
+ .map((item) => (lowercaseEntry ? item.toLowerCase() : item));
160
+
161
+ const updateEntries = (items: string[]) => {
162
+ const updated = items.map((item) =>
163
+ lowercaseEntry ? item.toLowerCase() : item
164
+ );
165
+ onChange?.(updated);
166
+ };
167
+
168
+ const handleDelete = (entry: string) => {
169
+ updateEntries(entries.filter((e) => e !== entry));
170
+ };
171
+
172
+ const handleClick = (entry: string) => {
173
+ handleDelete(entry);
174
+ if (textInputRef.current) {
175
+ textInputRef.current.value = entry;
176
+ }
177
+ };
178
+
179
+ const handleBlur = (e: FocusEvent<HTMLInputElement>) => {
180
+ setFieldInFocus(false);
181
+ const input = e.target.value.trim();
182
+ if (input) {
183
+ const items = input.split(/[ ,]+/).filter(Boolean);
184
+ updateEntries(Array.from(new Set([...entries, ...items])));
185
+ e.target.value = "";
186
+ }
187
+ };
188
+
189
+ const handleKeyUp = throttle(
190
+ (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
191
+ const input = e.target as HTMLInputElement;
192
+ const value = input.value;
193
+ const lastChar = value[value.length - 1];
194
+ if (lastChar === "," || lastChar === " " || e.key === "Enter") {
195
+ const items = value.split(/[ ,]+/).filter(Boolean);
196
+ updateEntries(Array.from(new Set([...entries, ...items])));
197
+ input.value = "";
198
+ e.preventDefault();
199
+ }
200
+ },
201
+ 200
202
+ );
203
+
204
+ const handleBackspace = throttle(
205
+ (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
206
+ const input = e.target as HTMLInputElement;
207
+ if (input.value.length === 0 && entries.length > 0) {
208
+ updateEntries(entries.slice(0, -1));
209
+ }
210
+ },
211
+ 200
212
+ );
213
+
214
+ const getChipIcon = (
215
+ entry: string,
216
+ invalid: FieldError | undefined
217
+ ): ReactElement | undefined => {
218
+ if (invalid) return <ErrorIconStyled />;
219
+ if (chipIcon) {
220
+ return typeof chipIcon === "function" ? chipIcon(entry) : chipIcon;
221
+ }
222
+ return undefined;
223
+ };
224
+
225
+ return (
226
+ <>
227
+ {label && <Label>{label}</Label>}
228
+ <EntryWrapper
229
+ onClick={() => {
230
+ setFieldInFocus(true);
231
+ textInputRef.current?.focus();
232
+ }}
233
+ data-testid={dataTestId}
234
+ focus={fieldInFocus}
235
+ overrideHeight={overrideHeight}
236
+ overrideWidth={overrideWidth}
237
+ >
238
+ {entries.map((entry, index) => {
239
+ const invalid = errorArr[index];
240
+ const tooltip = invalid?.message ?? tooltipFn?.(entry) ?? undefined;
241
+ const warning = checkWarning?.(entry) ?? false;
242
+ const ChipComp = warning ? WarningChip : StyledChip;
243
+
244
+ return (
245
+ <BMTooltip title={tooltip ?? ""} key={`${entry}-tooltip`}>
246
+ <ChipComp
247
+ label={entry}
248
+ icon={getChipIcon(entry, invalid)}
249
+ deleteIcon={<CloseIconStyled />}
250
+ onDelete={() => handleDelete(entry)}
251
+ clickable
252
+ onClick={() => handleClick(entry)}
253
+ />
254
+ </BMTooltip>
255
+ );
256
+ })}
257
+ <TextInput
258
+ inputRef={textInputRef}
259
+ placeholder={placeholderText}
260
+ disabled={disabled}
261
+ onKeyDown={(e) => {
262
+ if (e.key === "Backspace") handleBackspace(e);
263
+ else if (e.key === "Enter")
264
+ handleBlur(e as unknown as FocusEvent<HTMLInputElement>);
265
+ }}
266
+ onKeyUp={handleKeyUp}
267
+ onBlur={handleBlur}
268
+ />
269
+ </EntryWrapper>
270
+
271
+ {subLabel && (
272
+ <Box
273
+ sx={{
274
+ mt: 1,
275
+ color: "grey.700",
276
+ fontSize: "11.5px",
277
+ fontWeight: 400,
278
+ }}
279
+ >
280
+ {subLabel}
281
+ </Box>
282
+ )}
283
+
284
+ {error &&
285
+ (textInputRef.current?.value?.length ?? 0) === 0 &&
286
+ helperText && (
287
+ <FormHelperText
288
+ error
289
+ sx={{
290
+ mt: 1,
291
+ fontSize: "11.5px",
292
+ fontWeight: 400,
293
+ }}
294
+ >
295
+ {helperText}
296
+ </FormHelperText>
297
+ )}
298
+
299
+ {Array.isArray(error) && error.length > 0 && removeInvalidEntriesMsg && (
300
+ <FormHelperText
301
+ sx={{
302
+ mt: 1,
303
+ fontSize: "11.5px",
304
+ fontWeight: 400,
305
+ }}
306
+ error
307
+ >
308
+ {removeInvalidEntriesMsg}
309
+ </FormHelperText>
310
+ )}
311
+
312
+ {error &&
313
+ (textInputRef.current?.value?.length ?? 0) > 0 &&
314
+ multiEntryHitEnterMsg && (
315
+ <FormHelperText
316
+ error
317
+ sx={{
318
+ mt: 1,
319
+ fontSize: "11.5px",
320
+ fontWeight: 400,
321
+ }}
322
+ >
323
+ {multiEntryHitEnterMsg}
324
+ </FormHelperText>
325
+ )}
326
+ </>
327
+ );
328
+ };
@@ -0,0 +1,47 @@
1
+ import { ReactElement } from "react";
2
+ import {
3
+ useController,
4
+ UseControllerProps,
5
+ type FieldValues,
6
+ } from "react-hook-form";
7
+ import { BMMultiEntry, BMMultiEntryProps } from "./BMMultiEntry";
8
+
9
+ type BMMultiEntryFieldProps<T extends FieldValues> = UseControllerProps<T> &
10
+ BMMultiEntryProps;
11
+
12
+ export const BMMultiEntryField = <T extends FieldValues>(
13
+ props: BMMultiEntryFieldProps<T>
14
+ ): ReactElement => {
15
+ const {
16
+ name,
17
+ rules,
18
+ defaultValue,
19
+ control,
20
+ shouldUnregister,
21
+ placeholderText,
22
+ chipIcon,
23
+ dataTestId,
24
+ ...restInputProps
25
+ } = props;
26
+ const { field, fieldState } = useController({
27
+ name,
28
+ rules,
29
+ defaultValue,
30
+ control,
31
+ shouldUnregister,
32
+ });
33
+
34
+ return (
35
+ <BMMultiEntry
36
+ {...restInputProps}
37
+ label={props?.label}
38
+ onChange={field.onChange}
39
+ value={field.value}
40
+ error={fieldState.error}
41
+ chipIcon={chipIcon}
42
+ helperText={fieldState.error?.message ?? ""}
43
+ placeholderText={placeholderText}
44
+ dataTestId={dataTestId}
45
+ />
46
+ );
47
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./BMMultiEntry";
2
+ export * from "./BMMultiEntryField";
@@ -0,0 +1,191 @@
1
+ import { FC, useState, useEffect } from "react";
2
+ import { Box, Typography, Avatar } from "@mui/material";
3
+ import SuccessTick from "../../assets/icons/success-tick.svg";
4
+
5
+ export type SubStep = {
6
+ //This objetc can be extended to add custom icons and other properties
7
+ title: string;
8
+ };
9
+
10
+ export type Step = {
11
+ groupTitle: String;
12
+ subSteps: SubStep[];
13
+ };
14
+
15
+ export interface BMStepperProps {
16
+ steps: Step[];
17
+ activeStep: number;
18
+ dataTestId: string;
19
+ }
20
+
21
+ export interface StepperProgressTracker {
22
+ activeStep: number;
23
+ totalSteps: number;
24
+ }
25
+
26
+ export const StepperProgressTracker: FC<StepperProgressTracker> = ({
27
+ activeStep,
28
+ totalSteps,
29
+ }) => {
30
+ return (
31
+ <Box display="flex" sx={{ width: "100%", mb: 3 }} flexDirection={"column"}>
32
+ <Box display="flex" flexDirection={"row"} sx={{ width: "100%" }}>
33
+ {Array.from({ length: totalSteps }, (value, index) => index + 1).map(
34
+ (stepNumber, arrayIndex) => {
35
+ return (
36
+ <Box
37
+ sx={{
38
+ height: "4px",
39
+ bgcolor: stepNumber > activeStep ? "#E9EEF2" : "#A5A6F6",
40
+ borderRight: "1px solid #FFFFFF",
41
+ borderTopLeftRadius: arrayIndex === 0 ? "8px" : "0px",
42
+ borderBottomLeftRadius: arrayIndex === 0 ? "8px" : "0px",
43
+ borderTopRightRadius:
44
+ stepNumber === totalSteps ? "8px" : "0px",
45
+ borderBottomRightRadius:
46
+ stepNumber === totalSteps ? "8px" : "0px",
47
+ }}
48
+ display={"flex"}
49
+ flexDirection={"row"}
50
+ flex={1}
51
+ data-testid={`step-${stepNumber}`}
52
+ ></Box>
53
+ );
54
+ }
55
+ )}
56
+ </Box>
57
+ <Box
58
+ display={"flex"}
59
+ flexDirection={"row"}
60
+ justifyContent={"flex-end"}
61
+ flex={1}
62
+ sx={{ pt: 1 }}
63
+ >
64
+ <Typography variant="subtitle2" sx={{ color: "#5D5FEF" }}>
65
+ {activeStep}
66
+ </Typography>
67
+ <Typography variant="subtitle2" sx={{ color: "#97A5B0" }}>
68
+ &nbsp;/&nbsp;{totalSteps}
69
+ </Typography>
70
+ </Box>
71
+ </Box>
72
+ );
73
+ };
74
+
75
+ export const BMMultiLevelStepper: FC<BMStepperProps> = ({
76
+ steps,
77
+ activeStep,
78
+ }) => {
79
+ const [visitedStep, setVisitedStep] = useState(activeStep);
80
+ let stepCount = 0;
81
+
82
+ useEffect(() => {
83
+ if (visitedStep <= activeStep) setVisitedStep(activeStep);
84
+ }, [activeStep]);
85
+
86
+ const totalSteps = steps.reduce(
87
+ (accumulator, currentValue) => accumulator + currentValue.subSteps.length,
88
+ 0
89
+ );
90
+
91
+ return (
92
+ <Box sx={{ width: "300px", p: 3 }}>
93
+ <StepperProgressTracker totalSteps={totalSteps} activeStep={activeStep} />
94
+ {steps.map(({ groupTitle, subSteps }, stepIndex) => {
95
+ const isMainStepInProgress =
96
+ stepCount + subSteps.length <= visitedStep ||
97
+ (stepCount < visitedStep &&
98
+ visitedStep < stepCount + subSteps.length);
99
+ return (
100
+ <Box key={`${stepIndex}${groupTitle}`}>
101
+ <Typography
102
+ sx={{
103
+ mt: 1,
104
+ mb: 1,
105
+ color: isMainStepInProgress ? "#0B1117" : "#97A5B0",
106
+ }}
107
+ variant="body1"
108
+ >
109
+ {groupTitle}
110
+ </Typography>
111
+ <Box
112
+ sx={{
113
+ ml: 2,
114
+ borderLeft: "1px solid #D7DEE4",
115
+ height: isMainStepInProgress
116
+ ? "24px"
117
+ : stepIndex !== steps.length - 1
118
+ ? "32px"
119
+ : "0px",
120
+ }}
121
+ ></Box>
122
+ {isMainStepInProgress &&
123
+ subSteps.map(({ title }, subStepIndex) => {
124
+ stepCount = stepCount + 1;
125
+ const isCurrentStepCompleted = stepCount < activeStep;
126
+ return (
127
+ <Box
128
+ key={subStepIndex + title}
129
+ display={"flex"}
130
+ flexDirection={"column"}
131
+ >
132
+ <Box
133
+ display="flex"
134
+ flexDirection={"row"}
135
+ alignItems={"center"}
136
+ sx={{ lineHeight: "16px" }}
137
+ >
138
+ <Avatar
139
+ sx={{
140
+ bgcolor: isCurrentStepCompleted
141
+ ? "#CDEFE1"
142
+ : stepCount === activeStep
143
+ ? "#735AF5"
144
+ : "#E9EEF2",
145
+ height: "32px",
146
+ width: "32px",
147
+ color:
148
+ stepCount === activeStep ? "#FFFFFF" : "#6D7C88",
149
+ }}
150
+ >
151
+ {isCurrentStepCompleted ? (
152
+ <SuccessTick />
153
+ ) : (
154
+ <Typography variant="body2">{stepCount}</Typography>
155
+ )}
156
+ </Avatar>
157
+ <Typography
158
+ sx={{
159
+ pl: 2,
160
+ color:
161
+ isCurrentStepCompleted || stepCount === activeStep
162
+ ? "#0B1117"
163
+ : "#6D7C88",
164
+ }}
165
+ variant="body2"
166
+ >
167
+ {title}
168
+ </Typography>
169
+ </Box>
170
+
171
+ {stepCount !== totalSteps && (
172
+ <Box
173
+ sx={{
174
+ ml: 2,
175
+ borderLeft: "1px solid #D7DEE4",
176
+ height:
177
+ subSteps.length - 1 === subStepIndex
178
+ ? "24px"
179
+ : "16px",
180
+ }}
181
+ ></Box>
182
+ )}
183
+ </Box>
184
+ );
185
+ })}
186
+ </Box>
187
+ );
188
+ })}
189
+ </Box>
190
+ );
191
+ };
@@ -0,0 +1 @@
1
+ export * from "./BMMultiLevelStepper";
@@ -0,0 +1,64 @@
1
+ import { FC, useEffect, useState } from "react";
2
+ import { Pagination, PaginationItem, Box } from "@mui/material";
3
+
4
+ interface PaginationProps {
5
+ onPageSelect: (pageNo: number) => void;
6
+ pageSize?: number;
7
+ currentPage?: number;
8
+ hasMore?: boolean;
9
+ dataTestId: string;
10
+ }
11
+
12
+ /**
13
+ * Pagination is 1-indexed
14
+ */
15
+ export const BMPagination: FC<PaginationProps> = ({
16
+ pageSize = 4,
17
+ onPageSelect,
18
+ currentPage,
19
+ hasMore,
20
+ dataTestId
21
+ }) => {
22
+ const [page, setPage] = useState(1);
23
+
24
+ useEffect(() => {
25
+ if (currentPage) {
26
+ setPage(currentPage);
27
+ }
28
+ }, [currentPage]);
29
+
30
+ return (
31
+ <Pagination
32
+ siblingCount={1}
33
+ page={page}
34
+ boundaryCount={1}
35
+ shape="rounded"
36
+ count={pageSize}
37
+ onChange={(_e, newPage) => {
38
+ setPage(newPage);
39
+ onPageSelect(newPage);
40
+ }}
41
+ data-testid={dataTestId}
42
+ renderItem={(params) => {
43
+ if (params?.type === "next" && hasMore) {
44
+ return (
45
+ <Box component="span" display="flex" alignItems="center">
46
+ <PaginationItem
47
+ {...params}
48
+ aria-label="Go to end-ellipsis page"
49
+ color="standard"
50
+ shape="rounded"
51
+ size="medium"
52
+ type="end-ellipsis"
53
+ variant="text"
54
+ sx={{ display: "inline-flex", minWidth: 16 }}
55
+ />
56
+ <PaginationItem {...params} />
57
+ </Box>
58
+ );
59
+ }
60
+ return <PaginationItem {...params} />;
61
+ }}
62
+ />
63
+ );
64
+ };
@@ -0,0 +1 @@
1
+ export * from "./BMPagination";
@@ -0,0 +1,37 @@
1
+ import { IconButton, InputAdornment } from "@mui/material";
2
+ import { type FC, useState } from "react";
3
+ import { BMInput, type BMInputProps } from "../BMInput";
4
+ import Visibility from '../../assets/icons/visibility.svg';
5
+ import VisibilityOff from '../../assets/icons/visibility-off.svg';
6
+
7
+ export const BMPassword: FC<BMInputProps & { hidePasswordButton?: boolean }> = (
8
+ props,
9
+ ) => {
10
+ const [showPassword, setShowPassword] = useState(false);
11
+
12
+ const handleClickShowPassword = () => {
13
+ setShowPassword(!showPassword);
14
+ };
15
+ let inputProps = {};
16
+ if (props.hidePasswordButton) {
17
+ inputProps = {};
18
+ } else {
19
+ inputProps = {
20
+ endAdornment: (
21
+ <InputAdornment position="end">
22
+ <IconButton onClick={handleClickShowPassword} tabIndex={-1} sx={{ padding: '12px' }}>
23
+ {showPassword ? <Visibility /> : <VisibilityOff />}
24
+ </IconButton>
25
+ </InputAdornment>
26
+ ),
27
+ };
28
+ }
29
+
30
+ return (
31
+ <BMInput
32
+ type={showPassword ? "text" : "password"}
33
+ {...props}
34
+ InputProps={inputProps}
35
+ />
36
+ );
37
+ };