@dmsi/wedgekit-react 0.0.550 → 0.0.552

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 (180) hide show
  1. package/dist/{chunk-U3QGZAVS.js → chunk-JADOJNBI.js} +4 -4
  2. package/dist/{chunk-N2KPADIL.js → chunk-WNGFRQ4Y.js} +7 -7
  3. package/dist/{chunk-ZVY3TLXL.js → chunk-ZIPJMN2E.js} +4 -4
  4. package/dist/components/Alert.js +2 -2
  5. package/dist/components/CalendarRange.js +10 -10
  6. package/dist/components/DataGrid/ColumnSelectorHeaderCell/ColumnSelectorMenuOption.js +10 -10
  7. package/dist/components/DataGrid/ColumnSelectorHeaderCell/index.js +10 -10
  8. package/dist/components/DataGrid/PinnedColumns.js +10 -10
  9. package/dist/components/DataGrid/TableBody/LoadingCell.js +10 -10
  10. package/dist/components/DataGrid/TableBody/TableBodyRow.js +10 -10
  11. package/dist/components/DataGrid/TableBody/index.js +10 -10
  12. package/dist/components/DataGrid/index.js +10 -10
  13. package/dist/components/DataGrid/utils.js +10 -10
  14. package/dist/components/DateInput.js +10 -10
  15. package/dist/components/DateRangeInput.js +10 -10
  16. package/dist/components/FilterGroup.js +5 -5
  17. package/dist/components/MobileDataGrid/ColumnSelector/index.js +10 -10
  18. package/dist/components/MobileDataGrid/MobileDataGridHeader.js +10 -10
  19. package/dist/components/MobileDataGrid/RowDetailModalProvider/index.js +5 -5
  20. package/dist/components/MobileDataGrid/index.js +10 -10
  21. package/dist/components/Modal.js +4 -4
  22. package/dist/components/ModalButtons.js +2 -2
  23. package/dist/components/ModalHeader.js +2 -2
  24. package/dist/components/NavigationTab.js +2 -2
  25. package/dist/components/NavigationTabs.js +2 -2
  26. package/dist/components/NestedMenu.js +3 -3
  27. package/dist/components/Notification.js +3 -3
  28. package/dist/components/OptionPill.js +2 -2
  29. package/dist/components/PDFViewer/DownloadIcon.js +2 -2
  30. package/dist/components/PDFViewer/PDFNavigation.js +2 -2
  31. package/dist/components/PDFViewer/index.js +6 -6
  32. package/dist/components/ProductImagePreview/index.js +1 -1
  33. package/dist/components/Stepper.js +3 -3
  34. package/dist/components/Toast.js +3 -3
  35. package/dist/components/Upload.js +3 -3
  36. package/dist/components/index.js +16 -16
  37. package/package.json +8 -9
  38. package/src/brand.css +0 -125
  39. package/src/classNames.ts +0 -174
  40. package/src/components/AccessChangerTabItem.tsx +0 -71
  41. package/src/components/Accordion.tsx +0 -108
  42. package/src/components/Alert.tsx +0 -81
  43. package/src/components/Breadcrumbs.tsx +0 -142
  44. package/src/components/Button.tsx +0 -216
  45. package/src/components/CalendarRange.tsx +0 -628
  46. package/src/components/Caption.tsx +0 -144
  47. package/src/components/Card.tsx +0 -88
  48. package/src/components/Checkbox.tsx +0 -206
  49. package/src/components/CompactImagesPreview.tsx +0 -135
  50. package/src/components/ContentTab.tsx +0 -84
  51. package/src/components/ContentTabs.tsx +0 -136
  52. package/src/components/DMSiLogo.tsx +0 -33
  53. package/src/components/DataGrid/ColumnSelectorHeaderCell/ColumnSelectorMenuOption.tsx +0 -35
  54. package/src/components/DataGrid/ColumnSelectorHeaderCell/index.tsx +0 -74
  55. package/src/components/DataGrid/PinnedColumns.tsx +0 -183
  56. package/src/components/DataGrid/TableBody/LoadingCell.tsx +0 -44
  57. package/src/components/DataGrid/TableBody/TableBodyRow.tsx +0 -157
  58. package/src/components/DataGrid/TableBody/index.tsx +0 -185
  59. package/src/components/DataGrid/index.tsx +0 -756
  60. package/src/components/DataGrid/types.ts +0 -98
  61. package/src/components/DataGrid/utils.tsx +0 -15
  62. package/src/components/DataGridCell.tsx +0 -526
  63. package/src/components/DataTable.tsx +0 -881
  64. package/src/components/DateInput.tsx +0 -306
  65. package/src/components/DateRangeInput.tsx +0 -758
  66. package/src/components/DebugJson.tsx +0 -28
  67. package/src/components/Display.tsx +0 -66
  68. package/src/components/EditingContext.tsx +0 -43
  69. package/src/components/EmptyCartIcon.tsx +0 -18
  70. package/src/components/FilterGroup.tsx +0 -264
  71. package/src/components/FullViewportBox.tsx +0 -19
  72. package/src/components/Grid.tsx +0 -97
  73. package/src/components/Heading.tsx +0 -72
  74. package/src/components/HorizontalDivider.tsx +0 -22
  75. package/src/components/Icon.tsx +0 -39
  76. package/src/components/ImagePlaceholder.tsx +0 -22
  77. package/src/components/Input.tsx +0 -609
  78. package/src/components/InputGroup.tsx +0 -59
  79. package/src/components/Label.tsx +0 -46
  80. package/src/components/Link.tsx +0 -117
  81. package/src/components/List.tsx +0 -18
  82. package/src/components/ListGroup.tsx +0 -82
  83. package/src/components/LiveChatComponent.tsx +0 -56
  84. package/src/components/LoadingScrim.tsx +0 -33
  85. package/src/components/LogoAgilityTopBar.tsx +0 -54
  86. package/src/components/LogoDMSiTopBar.tsx +0 -33
  87. package/src/components/LogoMillworkTopBar.tsx +0 -119
  88. package/src/components/MainBar.tsx +0 -91
  89. package/src/components/MaxViewportBox.tsx +0 -19
  90. package/src/components/Menu.tsx +0 -316
  91. package/src/components/MenuOption.tsx +0 -330
  92. package/src/components/MobileDataGrid/ColumnList.tsx +0 -66
  93. package/src/components/MobileDataGrid/ColumnSelector/index.tsx +0 -97
  94. package/src/components/MobileDataGrid/GridContextProvider/GridContext.tsx +0 -25
  95. package/src/components/MobileDataGrid/GridContextProvider/index.tsx +0 -132
  96. package/src/components/MobileDataGrid/GridContextProvider/useGridContext.ts +0 -10
  97. package/src/components/MobileDataGrid/MobileDataGridCard/MobileDataGridColumn.tsx +0 -27
  98. package/src/components/MobileDataGrid/MobileDataGridCard/index.tsx +0 -138
  99. package/src/components/MobileDataGrid/MobileDataGridHeader.tsx +0 -81
  100. package/src/components/MobileDataGrid/RowDetailModalProvider/ModalContent.tsx +0 -42
  101. package/src/components/MobileDataGrid/RowDetailModalProvider/index.tsx +0 -68
  102. package/src/components/MobileDataGrid/dataGridReducer.ts +0 -55
  103. package/src/components/MobileDataGrid/index.tsx +0 -92
  104. package/src/components/MobileDataGrid/types.ts +0 -4
  105. package/src/components/Modal.tsx +0 -312
  106. package/src/components/ModalButtons.tsx +0 -62
  107. package/src/components/ModalContent.tsx +0 -31
  108. package/src/components/ModalHeader.tsx +0 -78
  109. package/src/components/ModalScrim.tsx +0 -42
  110. package/src/components/NavigationTab.tsx +0 -95
  111. package/src/components/NavigationTabs.tsx +0 -70
  112. package/src/components/NestedMenu.tsx +0 -131
  113. package/src/components/Notification.tsx +0 -128
  114. package/src/components/OptionPill.tsx +0 -139
  115. package/src/components/OrderCheckIcon.tsx +0 -19
  116. package/src/components/PDFViewer/DownloadIcon.tsx +0 -25
  117. package/src/components/PDFViewer/PDFElement.tsx +0 -90
  118. package/src/components/PDFViewer/PDFNavigation.tsx +0 -68
  119. package/src/components/PDFViewer/PDFPage.tsx +0 -34
  120. package/src/components/PDFViewer/index.tsx +0 -128
  121. package/src/components/Pagination.tsx +0 -182
  122. package/src/components/Paragraph.tsx +0 -55
  123. package/src/components/Password.tsx +0 -62
  124. package/src/components/ProductImagePreview/CarouselPagination.tsx +0 -54
  125. package/src/components/ProductImagePreview/MobileImageCarousel.tsx +0 -226
  126. package/src/components/ProductImagePreview/ProductPrimaryImage.tsx +0 -219
  127. package/src/components/ProductImagePreview/Thumbnail.tsx +0 -55
  128. package/src/components/ProductImagePreview/ZoomWindow.tsx +0 -136
  129. package/src/components/ProductImagePreview/index.tsx +0 -182
  130. package/src/components/ProductImagePreview/useProductImagePreview.ts +0 -211
  131. package/src/components/ProjectBar.tsx +0 -82
  132. package/src/components/Radio.tsx +0 -146
  133. package/src/components/Search.tsx +0 -152
  134. package/src/components/SearchResultImage/index.tsx +0 -39
  135. package/src/components/Select.tsx +0 -114
  136. package/src/components/SideMenu.tsx +0 -30
  137. package/src/components/SideMenuGroup.tsx +0 -95
  138. package/src/components/SideMenuItem.tsx +0 -109
  139. package/src/components/SimpleTable.tsx +0 -77
  140. package/src/components/SkeletonParagraph.tsx +0 -31
  141. package/src/components/Spinner.tsx +0 -32
  142. package/src/components/Stack.tsx +0 -347
  143. package/src/components/StatusPill.tsx +0 -59
  144. package/src/components/Stepper.tsx +0 -128
  145. package/src/components/Subheader.tsx +0 -50
  146. package/src/components/Surface.tsx +0 -37
  147. package/src/components/Swatch.tsx +0 -1341
  148. package/src/components/Textarea.tsx +0 -102
  149. package/src/components/Theme.tsx +0 -27
  150. package/src/components/Time.tsx +0 -460
  151. package/src/components/Toast.tsx +0 -268
  152. package/src/components/Tooltip.tsx +0 -159
  153. package/src/components/TopBar.tsx +0 -139
  154. package/src/components/Upload.tsx +0 -107
  155. package/src/components/WorldpayIframe.tsx +0 -7
  156. package/src/components/index.ts +0 -34
  157. package/src/components/useMenuSystem.tsx +0 -456
  158. package/src/components/useMounted.tsx +0 -14
  159. package/src/darkmode.css +0 -278
  160. package/src/fonts.css +0 -23
  161. package/src/hooks/index.ts +0 -4
  162. package/src/hooks/useInfiniteScroll.tsx +0 -40
  163. package/src/hooks/useKeydown.ts +0 -42
  164. package/src/hooks/useMatchesMedia.ts +0 -18
  165. package/src/hooks/useTableLayout.ts +0 -106
  166. package/src/index.css +0 -800
  167. package/src/index.tsx +0 -5
  168. package/src/types.ts +0 -150
  169. package/src/utils/date.ts +0 -236
  170. package/src/utils/formatting.tsx +0 -81
  171. package/src/utils/index.ts +0 -4
  172. package/src/utils/mergeObjectArrays.ts +0 -18
  173. package/src/utils.ts +0 -24
  174. package/dist/{chunk-7FQ7PGUF.js → chunk-7COWXCPA.js} +3 -3
  175. package/dist/{chunk-NKCFYM7A.js → chunk-7SFFUICM.js} +3 -3
  176. package/dist/{chunk-25RZP3VR.js → chunk-AKJUBFJK.js} +3 -3
  177. package/dist/{chunk-TAPYQBQU.js → chunk-CMMQTIVM.js} +3 -3
  178. package/dist/{chunk-GYEXSNFP.js → chunk-FWCVZWE6.js} +3 -3
  179. package/dist/{chunk-MV6W7OMC.js → chunk-QMMPHXVE.js} +3 -3
  180. package/dist/{chunk-GG5OZTI5.js → chunk-XRE52QTN.js} +3 -3
@@ -1,609 +0,0 @@
1
- "use client";
2
- import {
3
- ComponentProps,
4
- ReactNode,
5
- RefObject,
6
- useEffect,
7
- useRef,
8
- useState,
9
- } from "react";
10
-
11
- import clsx from "clsx";
12
- import {
13
- baseTransition,
14
- componentGap,
15
- componentPaddingMinusBorder,
16
- componentPaddingXUsingComponentGap,
17
- componentPaddingMinusBorderDesktop,
18
- typography,
19
- } from "../classNames";
20
- import { Label } from "./Label";
21
- import { Icon } from "./Icon";
22
- import {
23
- getDecimalPlaceholder,
24
- formatDecimalValue,
25
- formatCurrencyDisplay,
26
- } from "../utils/formatting";
27
- import { TextAlign } from "../types";
28
- import { Paragraph } from "./Paragraph";
29
-
30
- export type InputVariant =
31
- | "default"
32
- | "search"
33
- | "finder"
34
- | "currency"
35
- | "percentage"
36
- | "uom";
37
-
38
- export type InputFormatting = {
39
- variant?: InputVariant;
40
- decimals?: number;
41
- uom?: string;
42
- removeSearchIcon?: boolean;
43
- };
44
-
45
- export type InputBaseProps = {
46
- id?: string;
47
- testid?: string;
48
- after?: ReactNode;
49
- before?: ReactNode;
50
- rightAdornment?: ReactNode;
51
- label?: string;
52
- error?: boolean;
53
- align?: TextAlign;
54
- caption?: ReactNode;
55
- required?: boolean;
56
- selectOnFocus?: boolean;
57
- inputContainerRef?: RefObject<HTMLLabelElement | null>;
58
- removeRoundness?: boolean;
59
- removeBorder?: boolean;
60
- wrapperClassName?: string;
61
- focus?: boolean;
62
- secondaryIconColor?: boolean;
63
- fullWidth?: boolean; // If true, input takes full width of the container
64
- autocompletePadding?: boolean; // If true, applies padding suitable for autocomplete dropdowns
65
- wrapperRef?: RefObject<HTMLDivElement | null>;
66
- } & InputFormatting &
67
- Omit<ComponentProps<"input">, "align" | "id">;
68
-
69
- export const InputBase = ({
70
- id,
71
- testid,
72
- before,
73
- after,
74
- rightAdornment,
75
- type,
76
- label,
77
- error,
78
- className,
79
- align = "left",
80
- caption,
81
- required,
82
- selectOnFocus,
83
- removeRoundness,
84
- inputContainerRef,
85
- removeBorder,
86
- wrapperClassName,
87
- focus,
88
- secondaryIconColor,
89
- fullWidth = true,
90
- width,
91
- wrapperRef,
92
- autocompletePadding = false,
93
- ...props
94
- }: InputBaseProps) => {
95
- const attributes = {
96
- "data-error": (error && !focus) || null,
97
- "data-focus": focus || null,
98
- };
99
- const inputRef = useRef<HTMLInputElement | null>(null);
100
- const inputId = id ? `${id}-input` : undefined;
101
-
102
- useEffect(() => {
103
- const input = inputRef.current;
104
- const focusHandler = () => {
105
- input?.select();
106
- };
107
- if (selectOnFocus) {
108
- inputRef.current?.addEventListener("focus", focusHandler);
109
-
110
- return () => {
111
- input?.removeEventListener("focus", focusHandler);
112
- };
113
- }
114
- }, [selectOnFocus]);
115
-
116
- const inputBaseClass = clsx(
117
- fullWidth ? "w-full" : "w-fit",
118
- "flex flex-row items-center",
119
- "bg-background-action-secondary-normal caret-icon-on-action-secondary-normal",
120
- componentGap,
121
- baseTransition,
122
- "outline-transparent outline-2 -outline-offset-2",
123
- !autocompletePadding && componentPaddingMinusBorder,
124
- autocompletePadding && componentPaddingMinusBorderDesktop,
125
- !removeRoundness && "rounded-base",
126
- !removeBorder && "border border-border-primary-normal",
127
- "relative",
128
- );
129
-
130
- const inputFocusClass = clsx(
131
- "has-[[data-focus]]:border-transparent has-[[data-focus]]:outline-border-primary-focus focus-within:border-transparent focus-within:outline-border-primary-focus",
132
- );
133
-
134
- const inputDisabledClass = clsx(
135
- "has-disabled:bg-background-action-secondary-disabled",
136
- );
137
-
138
- const inputReadOnlyClass = clsx(
139
- "has-[input:not(:disabled):read-only]:outline-none has-[input:not(:disabled):read-only]:bg-transparent has-[input:not(:disabled):read-only]:border-transparent has-[input:not(:disabled):read-only]:pl-0",
140
- );
141
-
142
- const inputInvalidClass = clsx(
143
- "has-[[data-error]]:border-transparent has-[[data-error]]:not-focus-within:outline-border-primary-error has-[[data-error]]:not-focus-within:outline-1",
144
- );
145
-
146
- return (
147
- <label
148
- id={id}
149
- data-testid={testid}
150
- htmlFor={inputId}
151
- ref={inputContainerRef}
152
- className={clsx(
153
- "w-full flex flex-col",
154
- "block",
155
- "text-text-primary-normal has-disabled:text-text-primary-disabled",
156
- componentGap,
157
- )}
158
- style={{
159
- ...props.style,
160
- }}
161
- >
162
- {label && (
163
- <div className={clsx("flex items-center", componentGap)}>
164
- <Label
165
- id={id ? `${id}-label` : undefined}
166
- color={error ? "text-primary-error" : undefined}
167
- className={clsx(
168
- props.disabled || props.readOnly
169
- ? "cursor-default"
170
- : "cursor-pointer",
171
- )}
172
- >
173
- {label}
174
- </Label>
175
-
176
- {required && (
177
- <span
178
- className={clsx(typography.label, "text-text-critical-normal")}
179
- >
180
- *
181
- </span>
182
- )}
183
- </div>
184
- )}
185
-
186
- <div
187
- className={clsx(
188
- inputBaseClass,
189
- !props.disabled && inputInvalidClass,
190
- inputFocusClass,
191
- inputDisabledClass,
192
- inputReadOnlyClass,
193
- wrapperClassName,
194
- )}
195
- ref={(el) => {
196
- if (wrapperRef) {
197
- wrapperRef.current = el;
198
- }
199
- }}
200
- >
201
- {before}
202
-
203
- <input
204
- ref={(el) => {
205
- inputRef.current = el;
206
- }}
207
- type={type}
208
- required={required}
209
- {...props}
210
- {...attributes}
211
- id={inputId}
212
- data-testid={testid ? `${testid}-input` : undefined}
213
- className={clsx(
214
- "flex-1 outline-none w-full max-w-full min-h-6 min-w-0",
215
- "[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
216
- "placeholder:text-text-secondary-normal disabled:text-text-secondary-disabled",
217
- align === "right" && "text-right",
218
- align === "center" && "text-center",
219
- componentPaddingXUsingComponentGap,
220
- typography.paragraph,
221
- className,
222
- props.readOnly && !props.disabled && "!px-0",
223
- )}
224
- style={{ ...props.style, width }}
225
- />
226
-
227
- {secondaryIconColor ? (
228
- <span className="contents text-text-secondary-normal">{after}</span>
229
- ) : (
230
- after
231
- )}
232
- {rightAdornment}
233
- </div>
234
-
235
- {caption && (
236
- <div
237
- id={id ? `${id}-caption` : undefined}
238
- data-testid={testid ? `${testid}-caption` : undefined}
239
- >
240
- {caption}
241
- </div>
242
- )}
243
- </label>
244
- );
245
- };
246
-
247
- export const Input = ({
248
- variant = "default",
249
- decimals,
250
- uom,
251
- removeSearchIcon,
252
- value: propValue,
253
- onChange,
254
- onBlur,
255
- onClear,
256
- id,
257
- testid,
258
- rightAdornment,
259
- ...props
260
- }: Omit<ComponentProps<"input">, "onChange" | "align" | "children"> &
261
- InputBaseProps & {
262
- onChange?: React.ChangeEventHandler<HTMLInputElement>;
263
- onClear?: () => void;
264
- }) => {
265
- const [internalValue, setInternalValue] = useState("");
266
- const [displayValue, setDisplayValue] = useState("");
267
- useEffect(() => {
268
- const stringValue = propValue?.toString() ?? "";
269
- setInternalValue(stringValue);
270
- setDisplayValue(stringValue);
271
- }, [propValue]);
272
-
273
- useEffect(() => {
274
- if (variant !== "currency") {
275
- return;
276
- }
277
-
278
- const stringValue = propValue?.toString() ?? "";
279
-
280
- if (!stringValue) {
281
- return;
282
- }
283
-
284
- const formatted = formatDecimalValue(stringValue, decimals ?? 2);
285
-
286
- setInternalValue(formatted);
287
- setDisplayValue(formatCurrencyDisplay(formatted));
288
- // Intentionally not adding dependencies to avoid formatting on every change
289
- // eslint-disable-next-line react-hooks/exhaustive-deps
290
- }, []);
291
-
292
- const getInputProps = () => {
293
- const baseProps = {
294
- ...props,
295
- id,
296
- ...getDecimalPlaceholder(decimals),
297
- value: propValue,
298
- };
299
-
300
- switch (variant) {
301
- case "search":
302
- return {
303
- ...baseProps,
304
- placeholder: props.placeholder ?? "Search",
305
- className: "!mr-6",
306
- value: displayValue,
307
- };
308
-
309
- case "finder":
310
- return baseProps;
311
-
312
- case "currency":
313
- return {
314
- ...baseProps,
315
- align: "right" as const,
316
- type: "text" as const,
317
- value: displayValue,
318
- };
319
-
320
- case "percentage":
321
- case "uom":
322
- return {
323
- ...baseProps,
324
- type: "number" as const,
325
- align: "right" as const,
326
- };
327
-
328
- default:
329
- return baseProps;
330
- }
331
- };
332
-
333
- const getBeforeElement = () => {
334
- if (props.before) return props.before;
335
-
336
- switch (variant) {
337
- case "search":
338
- return !removeSearchIcon ? (
339
- <span className="text-icon-primary-normal contents">
340
- <Icon name="search" />
341
- </span>
342
- ) : null;
343
-
344
- case "currency":
345
- return (
346
- <span className="text-icon-primary-normal contents">
347
- <Icon name="attach_money" />
348
- </span>
349
- );
350
-
351
- default:
352
- return null;
353
- }
354
- };
355
-
356
- const getAfterElement = () => {
357
- if (props.after) return props.after;
358
-
359
- switch (variant) {
360
- case "search": {
361
- const hasValue = displayValue.length > 0;
362
- return hasValue && !props.readOnly ? (
363
- <Icon
364
- id={id ? `${id}-clear-button` : undefined}
365
- testid={testid ? `${testid}-clear-button` : undefined}
366
- name="close"
367
- onClick={handleSearchReset}
368
- className="cursor-pointer absolute right-2 bottom-2/4 translate-y-2/4"
369
- />
370
- ) : null;
371
- }
372
-
373
- case "finder":
374
- return <Icon name="search" />;
375
-
376
- case "uom":
377
- return uom ? (
378
- <Paragraph color="text-secondary-normal">
379
- {uom.toUpperCase()}
380
- </Paragraph>
381
- ) : null;
382
-
383
- case "percentage":
384
- return (
385
- <span className="text-icon-primary-normal contents">
386
- <Icon name="percent" />
387
- </span>
388
- );
389
-
390
- default:
391
- return null;
392
- }
393
- };
394
-
395
- const handleSearchReset = () => {
396
- setInternalValue("");
397
- setDisplayValue("");
398
-
399
- if (onChange) {
400
- const syntheticEvent = {
401
- target: { value: "" },
402
- } as React.ChangeEvent<HTMLInputElement>;
403
-
404
- if (typeof onChange === "function") {
405
- onChange(syntheticEvent);
406
- }
407
- }
408
-
409
- onClear?.();
410
- };
411
-
412
- const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
413
- const rawValue = e.target.value;
414
- const maxNumber =
415
- props.max != null
416
- ? Number(String(props.max).replace(/,/g, ""))
417
- : undefined;
418
-
419
- if (variant === "currency") {
420
- const raw = rawValue.replace(/,/g, ""); // Remove commas for processing
421
-
422
- if (raw === "") {
423
- setInternalValue("");
424
- setDisplayValue("");
425
- if (onChange) {
426
- const syntheticEvent = {
427
- ...e,
428
- target: { ...e.target, value: "" },
429
- } as React.ChangeEvent<HTMLInputElement>;
430
- onChange(syntheticEvent);
431
- }
432
- return;
433
- }
434
-
435
- const regex = /^\d*\.?\d*$/;
436
- if (!regex.test(raw)) return;
437
-
438
- const parts = raw.split(".");
439
- const currentDecimals = decimals ?? 2;
440
- if (parts.length === 2 && parts[1].length > currentDecimals) return;
441
-
442
- const asNumber = Number(raw);
443
- if (!isNaN(asNumber) && maxNumber != null && asNumber > maxNumber) {
444
- // Clamp to max
445
- const clamped = maxNumber;
446
- const formattedClamped = formatDecimalValue(
447
- clamped.toString(),
448
- currentDecimals,
449
- );
450
- setInternalValue(formattedClamped);
451
- setDisplayValue(formatCurrencyDisplay(formattedClamped));
452
- if (onChange) {
453
- const syntheticEvent = {
454
- ...e,
455
- target: { ...e.target, value: clamped.toString() },
456
- } as React.ChangeEvent<HTMLInputElement>;
457
- onChange(syntheticEvent);
458
- }
459
- return;
460
- }
461
-
462
- setInternalValue(raw);
463
- setDisplayValue(formatCurrencyDisplay(raw));
464
-
465
- if (!isNaN(asNumber) && onChange) {
466
- const syntheticEvent = {
467
- ...e,
468
- target: { ...e.target, value: asNumber.toString() },
469
- } as React.ChangeEvent<HTMLInputElement>;
470
- onChange(syntheticEvent);
471
- }
472
- return;
473
- }
474
-
475
- // Handle numeric variants (percentage / uom) wrt max prop
476
- if (
477
- (variant === "percentage" || variant === "uom") &&
478
- e.target.type === "number"
479
- ) {
480
- const numeric = Number(rawValue);
481
- if (!isNaN(numeric) && maxNumber != null && numeric > maxNumber) {
482
- const clamped = maxNumber;
483
- const formattedClamped = formatDecimalValue(
484
- clamped.toString(),
485
- decimals ?? 0,
486
- );
487
- setInternalValue(formattedClamped);
488
- setDisplayValue(formattedClamped);
489
-
490
- if (typeof onChange === "function") {
491
- const syntheticEvent = {
492
- ...e,
493
- target: { ...e.target, value: clamped.toString() },
494
- } as React.ChangeEvent<HTMLInputElement>;
495
- onChange(syntheticEvent);
496
- }
497
- return;
498
- }
499
-
500
- setInternalValue(rawValue);
501
- setDisplayValue(rawValue);
502
- if (typeof onChange === "function") {
503
- onChange(e);
504
- }
505
- return;
506
- }
507
-
508
- // Default behavior for other variants
509
- setInternalValue(rawValue);
510
- setDisplayValue(rawValue);
511
- if (typeof onChange === "function") {
512
- onChange(e);
513
- }
514
- };
515
-
516
- const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
517
- if (!internalValue) {
518
- onBlur?.(e);
519
- return;
520
- }
521
-
522
- if (variant === "currency") {
523
- const formatted = formatDecimalValue(internalValue, decimals ?? 2);
524
- setInternalValue(formatted);
525
- setDisplayValue(formatCurrencyDisplay(formatted));
526
-
527
- const asNumber = Number(formatted);
528
- if (!isNaN(asNumber) && onChange) {
529
- const syntheticEvent = {
530
- ...e,
531
- target: { ...e.target, value: asNumber.toString() },
532
- } as React.ChangeEvent<HTMLInputElement>;
533
- onChange(syntheticEvent);
534
- }
535
- } else if (variant === "uom" || variant === "percentage") {
536
- const formattedValue = formatDecimalValue(e.target.value, decimals);
537
- e.target.value = formattedValue;
538
- }
539
-
540
- onBlur?.(e);
541
- };
542
-
543
- const inputProps = getInputProps();
544
-
545
- return (
546
- <InputBase
547
- {...inputProps}
548
- before={getBeforeElement()}
549
- after={getAfterElement()}
550
- onChange={handleChange}
551
- onBlur={handleBlur}
552
- testid={testid}
553
- rightAdornment={rightAdornment}
554
- />
555
- );
556
- };
557
-
558
- Input.displayName = "Input";
559
-
560
- // Legacy component exports for backward compatibility
561
- export const Finder = (
562
- props: Omit<ComponentProps<"input">, "value" | "align" | "children" | "id"> &
563
- InputBaseProps & { value?: string | number },
564
- ) => <Input {...props} variant="finder" />;
565
-
566
- export const UOM = (
567
- props: Omit<ComponentProps<"input">, "value" | "align" | "children" | "id"> &
568
- InputBaseProps & {
569
- uom: string;
570
- value?: string | number;
571
- },
572
- ) => <Input {...props} variant="uom" />;
573
-
574
- export const Currency = (
575
- props: Omit<
576
- ComponentProps<"input">,
577
- "onChange" | "align" | "children" | "id"
578
- > &
579
- InputBaseProps & {
580
- onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
581
- },
582
- ) => {
583
- const handleCurrencyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
584
- // For currency, we want to pass the numeric value but maintain the string interface
585
- props.onChange?.(e);
586
- };
587
-
588
- return (
589
- <Input
590
- {...props}
591
- variant="currency"
592
- decimals={props.decimals ?? 2}
593
- onChange={handleCurrencyChange}
594
- />
595
- );
596
- };
597
-
598
- export const Percentage = (
599
- props: Omit<ComponentProps<"input">, "value" | "align" | "children" | "id"> &
600
- InputBaseProps & {
601
- value?: string | number;
602
- },
603
- ) => <Input {...props} variant="percentage" />;
604
-
605
- // Set display names for legacy components
606
- Finder.displayName = "Finder";
607
- UOM.displayName = "UOM";
608
- Currency.displayName = "Currency";
609
- Percentage.displayName = "Percentage";
@@ -1,59 +0,0 @@
1
- "use client";
2
- import { ComponentProps, ReactNode } from "react";
3
- import { Label } from "./Label";
4
- import clsx from "clsx";
5
- import { useId } from "react";
6
- import { componentGap, layoutGap } from "../classNames";
7
-
8
- type InputGroupProps = {
9
- id?: string;
10
- testid?: string;
11
- label: string;
12
- orientation?: "vertical" | "horizontal";
13
- error?: boolean;
14
- caption?: ReactNode;
15
- };
16
-
17
- export const InputGroup = ({
18
- id,
19
- testid,
20
- label,
21
- orientation = "horizontal",
22
- error = false,
23
- children,
24
- caption,
25
- ...props
26
- }: ComponentProps<"div"> & InputGroupProps) => {
27
- const internalId = useId();
28
- const labelId = id ? `${id}-label` : undefined;
29
- const labelTestId = testid ? `${testid}-label` : undefined;
30
-
31
- return (
32
- <div id={id} data-testid={testid} {...props} className={clsx("flex flex-col", componentGap)}>
33
- <Label
34
- id={labelId}
35
- testid={labelTestId}
36
- as="label"
37
- className={clsx({ "!text-text-primary-error": error })}
38
- htmlFor={internalId}
39
- >
40
- {label}
41
- </Label>
42
-
43
- <div
44
- className={clsx(
45
- "flex *:py-mobile-component-padding desktop:*:py-desktop-component-padding compact:*:py-desktop-compact-component-padding",
46
- orientation === "vertical"
47
- ? "flex-col"
48
- : clsx("items-center", layoutGap),
49
- )}
50
- >
51
- {children}
52
- </div>
53
-
54
- {caption && <div id={id ? `${id}-caption` : undefined} data-testid={testid ? `${testid}-caption` : undefined}>{caption}</div>}
55
- </div>
56
- );
57
- };
58
-
59
- InputGroup.displayName = "InputGroup";
@@ -1,46 +0,0 @@
1
- import clsx from "clsx";
2
- import { AsProps, TextAttributes, TypographyProps } from "../types";
3
- import { componentPaddingXUsingComponentGap, typography } from "../classNames";
4
- export type Tags = "span" | "label" | "p" | "a";
5
-
6
- type LabelProps = {
7
- as?: Tags;
8
- id?: string;
9
- testid?: string;
10
- } & AsProps<Tags> &
11
- TextAttributes &
12
- TypographyProps;
13
-
14
- export const Label = ({
15
- as = "span",
16
- padded,
17
- className,
18
- color,
19
- align,
20
- id,
21
- testid,
22
- ...props
23
- }: LabelProps) => {
24
- const Element = as;
25
- return (
26
- <Element
27
- id={id}
28
- data-testid={testid}
29
- className={clsx(
30
- typography.label,
31
- align === "left" && "text-left",
32
- align === "center" && "text-center",
33
- align === "right" && "text-right",
34
- className,
35
- padded && componentPaddingXUsingComponentGap,
36
- )}
37
- {...props}
38
- style={{
39
- ...props.style,
40
- color: color ? `var(--color-${color})` : undefined,
41
- }}
42
- />
43
- );
44
- };
45
-
46
- Label.displayName = "Label";