@trackunit/react-form-components 1.7.34 → 1.7.37

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 (35) hide show
  1. package/index.cjs.js +352 -362
  2. package/index.esm.js +348 -356
  3. package/package.json +8 -8
  4. package/src/components/BaseInput/BaseInput.d.ts +1 -1
  5. package/src/components/{DateInput/DateInput.d.ts → DateField/DateBaseInput/DateBaseInput.d.ts} +3 -6
  6. package/src/components/DateField/DateField.d.ts +2 -2
  7. package/src/components/{EmailInput/EmailInput.d.ts → EmailField/EmailBaseInput/EmailBaseInput.d.ts} +5 -8
  8. package/src/components/FormGroup/FormGroup.d.ts +1 -1
  9. package/src/components/NumberField/NumberBaseInput/NumberBaseInput.d.ts +11 -0
  10. package/src/components/NumberField/NumberField.d.ts +2 -2
  11. package/src/components/PasswordField/PasswordBaseInput/PasswordBaseInput.d.ts +12 -0
  12. package/src/components/PasswordField/PasswordField.d.ts +2 -2
  13. package/src/components/{PhoneInput/PhoneInput.d.ts → PhoneField/PhoneBaseInput/PhoneBaseInput.d.ts} +4 -7
  14. package/src/components/PhoneField/PhoneField.d.ts +2 -2
  15. package/src/components/Search/Search.d.ts +2 -2
  16. package/src/components/{TextArea/TextArea.d.ts → TextAreaField/TextArea/TextAreaBaseInput.d.ts} +2 -5
  17. package/src/components/{TextArea/TextArea.variants.d.ts → TextAreaField/TextArea/TextAreaBaseInput.variants.d.ts} +1 -1
  18. package/src/components/TextAreaField/TextAreaField.d.ts +2 -2
  19. package/src/components/TextField/TextBaseInput/TextBaseInput.d.ts +11 -0
  20. package/src/components/TextField/TextField.d.ts +2 -2
  21. package/src/components/{UrlInput/UrlInput.d.ts → UrlField/UrlBaseInput/UrlBaseInput.d.ts} +4 -7
  22. package/src/components/UrlField/UrlField.d.ts +2 -2
  23. package/src/index.d.ts +10 -12
  24. package/src/components/EmailInput/index.d.ts +0 -1
  25. package/src/components/NumberInput/NumberInput.d.ts +0 -14
  26. package/src/components/PasswordField/index.d.ts +0 -1
  27. package/src/components/PasswordInput/PasswordInput.d.ts +0 -15
  28. package/src/components/PhoneInput/index.d.ts +0 -1
  29. package/src/components/TextArea/index.d.ts +0 -1
  30. package/src/components/TextAreaField/index.d.ts +0 -1
  31. package/src/components/TextInput/TextInput.d.ts +0 -14
  32. /package/src/components/{PhoneInput → PhoneField/PhoneBaseInput}/CountryCodeSelect.d.ts +0 -0
  33. /package/src/components/{PhoneInput → PhoneField/PhoneBaseInput}/CountryCodes.d.ts +0 -0
  34. /package/src/components/{PhoneInput → PhoneField/PhoneBaseInput}/PhoneInputValidationUtils.d.ts +0 -0
  35. /package/src/components/{PhoneInput → PhoneField/PhoneBaseInput}/PhoneNumberUtilities.d.ts +0 -0
package/index.cjs.js CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var i18nLibraryTranslation = require('@trackunit/i18n-library-translation');
5
+ var polyfill = require('@js-temporal/polyfill');
5
6
  var reactComponents = require('@trackunit/react-components');
6
- var usehooksTs = require('usehooks-ts');
7
- var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
8
7
  var uiDesignTokens = require('@trackunit/ui-design-tokens');
9
8
  var react = require('react');
9
+ var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
10
10
  var stringTs = require('string-ts');
11
- var sharedUtils = require('@trackunit/shared-utils');
12
- var polyfill = require('@js-temporal/polyfill');
11
+ var usehooksTs = require('usehooks-ts');
13
12
  var parsePhoneNumberFromString = require('libphonenumber-js');
13
+ var sharedUtils = require('@trackunit/shared-utils');
14
14
  var reactHookForm = require('react-hook-form');
15
15
  var ReactSelect = require('react-select');
16
16
  var ReactAsyncCreatableSelect = require('react-select/async-creatable');
@@ -99,82 +99,6 @@ const setupLibraryTranslations = () => {
99
99
  i18nLibraryTranslation.registerTranslations(translations);
100
100
  };
101
101
 
102
- const cvaActionButton = cssClassVarianceUtilities.cvaMerge(["drop-shadow-none", "rounded-md"], {
103
- variants: {
104
- size: {
105
- small: ["w-6", "h-6", "min-h-0"],
106
- medium: ["w-6", "h-6", "min-h-0"],
107
- large: ["w-8", "h-8"],
108
- },
109
- },
110
- defaultVariants: {
111
- size: "medium",
112
- },
113
- });
114
- const cvaActionContainer = cssClassVarianceUtilities.cvaMerge(["flex", "items-center"], {
115
- variants: {
116
- size: {
117
- //I just measured manually the top/bottom spacing
118
- //when using the action button inside an input
119
- //might need tweaking in the future
120
- small: ["m-[1px]"],
121
- medium: ["m-[3px]"],
122
- large: ["m-[7px]"],
123
- },
124
- },
125
- defaultVariants: {
126
- size: "medium",
127
- },
128
- });
129
-
130
- /**
131
- * The ActionButton component is a wrapper over IconButton to perform an action when the onClick event is triggered.
132
- *
133
- * @param {ActionButtonProps} props - The props for the ActionButton component
134
- * @returns {ReactElement} ActionButton component
135
- */
136
- const ActionButton = ({ type, value, dataTestId, size, disabled, className, onClick }) => {
137
- const [, copyToClipboard] = usehooksTs.useCopyToClipboard();
138
- const getIconName = () => {
139
- switch (type) {
140
- case "PHONE_NUMBER":
141
- return "PhoneArrowUpRight";
142
- case "WEB_ADDRESS":
143
- return "ArrowTopRightOnSquare";
144
- case "EMAIL":
145
- return "Envelope";
146
- case "EDIT":
147
- return "Pencil";
148
- case "COPY":
149
- default:
150
- return "ClipboardDocument";
151
- }
152
- };
153
- const buttonAction = () => {
154
- switch (type) {
155
- case "EMAIL":
156
- return window.open(`mailto:${value}`);
157
- case "WEB_ADDRESS":
158
- if (value) {
159
- return window.open(value, "_blank", "noopener,noreferrer");
160
- }
161
- return null;
162
- case "PHONE_NUMBER":
163
- return window.open(`tel:${value}`);
164
- case "EDIT":
165
- return value?.current?.click();
166
- case "COPY":
167
- // Typescript seems to be unable to detect RefObject
168
- // as one of the members of the union RefObject | string | null which gives access to the `current` property
169
- return copyToClipboard(value?.current?.value ?? "");
170
- default:
171
- return null;
172
- }
173
- };
174
- const adjustedIconSize = size === "large" ? "medium" : size;
175
- return (jsxRuntime.jsx("div", { className: cvaActionContainer({ className, size }), children: jsxRuntime.jsx(reactComponents.IconButton, { className: cvaActionButton({ size: adjustedIconSize }), dataTestId: dataTestId || "testIconButtonId", disabled: disabled, icon: jsxRuntime.jsx(reactComponents.Icon, { name: getIconName(), size: adjustedIconSize }), onClick: buttonAction, size: "small", variant: "secondary" }) }));
176
- };
177
-
178
102
  const cvaInputBase = cssClassVarianceUtilities.cvaMerge([
179
103
  "component-baseInput-shadow",
180
104
  "component-baseInput-border",
@@ -344,6 +268,82 @@ const AddonRenderer = ({ addon, dataTestId, className, fieldSize, position }) =>
344
268
  return (jsxRuntime.jsx("div", { className: cvaInputAddon({ size: fieldSize, position, className }), "data-testid": dataTestId ? `${dataTestId}-addon${stringTs.titleCase(position)}` : null, children: addon }));
345
269
  };
346
270
 
271
+ const cvaActionButton = cssClassVarianceUtilities.cvaMerge(["drop-shadow-none", "rounded-md"], {
272
+ variants: {
273
+ size: {
274
+ small: ["w-6", "h-6", "min-h-0"],
275
+ medium: ["w-6", "h-6", "min-h-0"],
276
+ large: ["w-8", "h-8"],
277
+ },
278
+ },
279
+ defaultVariants: {
280
+ size: "medium",
281
+ },
282
+ });
283
+ const cvaActionContainer = cssClassVarianceUtilities.cvaMerge(["flex", "items-center"], {
284
+ variants: {
285
+ size: {
286
+ //I just measured manually the top/bottom spacing
287
+ //when using the action button inside an input
288
+ //might need tweaking in the future
289
+ small: ["m-[1px]"],
290
+ medium: ["m-[3px]"],
291
+ large: ["m-[7px]"],
292
+ },
293
+ },
294
+ defaultVariants: {
295
+ size: "medium",
296
+ },
297
+ });
298
+
299
+ /**
300
+ * The ActionButton component is a wrapper over IconButton to perform an action when the onClick event is triggered.
301
+ *
302
+ * @param {ActionButtonProps} props - The props for the ActionButton component
303
+ * @returns {ReactElement} ActionButton component
304
+ */
305
+ const ActionButton = ({ type, value, dataTestId, size, disabled, className, onClick }) => {
306
+ const [, copyToClipboard] = usehooksTs.useCopyToClipboard();
307
+ const getIconName = () => {
308
+ switch (type) {
309
+ case "PHONE_NUMBER":
310
+ return "PhoneArrowUpRight";
311
+ case "WEB_ADDRESS":
312
+ return "ArrowTopRightOnSquare";
313
+ case "EMAIL":
314
+ return "Envelope";
315
+ case "EDIT":
316
+ return "Pencil";
317
+ case "COPY":
318
+ default:
319
+ return "ClipboardDocument";
320
+ }
321
+ };
322
+ const buttonAction = () => {
323
+ switch (type) {
324
+ case "EMAIL":
325
+ return window.open(`mailto:${value}`);
326
+ case "WEB_ADDRESS":
327
+ if (value) {
328
+ return window.open(value, "_blank", "noopener,noreferrer");
329
+ }
330
+ return null;
331
+ case "PHONE_NUMBER":
332
+ return window.open(`tel:${value}`);
333
+ case "EDIT":
334
+ return value?.current?.click();
335
+ case "COPY":
336
+ // Typescript seems to be unable to detect RefObject
337
+ // as one of the members of the union RefObject | string | null which gives access to the `current` property
338
+ return copyToClipboard(value?.current?.value ?? "");
339
+ default:
340
+ return null;
341
+ }
342
+ };
343
+ const adjustedIconSize = size === "large" ? "medium" : size;
344
+ return (jsxRuntime.jsx("div", { className: cvaActionContainer({ className, size }), children: jsxRuntime.jsx(reactComponents.IconButton, { className: cvaActionButton({ size: adjustedIconSize }), dataTestId: dataTestId || "testIconButtonId", disabled: disabled, icon: jsxRuntime.jsx(reactComponents.Icon, { name: getIconName(), size: adjustedIconSize }), onClick: buttonAction, size: "small", variant: "secondary" }) }));
345
+ };
346
+
347
347
  const GenericActionsRenderer = ({ genericAction, disabled, fieldSize, innerRef, tooltipLabel, }) => {
348
348
  const [t] = useTranslation();
349
349
  if (!genericAction) {
@@ -413,41 +413,260 @@ const SuffixRenderer = ({ suffix, isInvalid, isWarning, dataTestId, disabled, })
413
413
  };
414
414
 
415
415
  /**
416
- * A base input component that can be used for text inputs, password inputs, etc.
417
- * A reference to the input element is provided as the `ref` prop.
418
- * Extends props from [React.InputHTMLAttributes](https://reactjs.org/docs/dom-elements.html#input)
416
+ * A base input component that can be used for text inputs, password inputs, etc.
417
+ * A reference to the input element is provided as the `ref` prop.
418
+ * Extends props from [React.InputHTMLAttributes](https://reactjs.org/docs/dom-elements.html#input)
419
+ *
420
+ * For specific input types make sure to use the corresponding input component.
421
+ * This is a base used by our other input components such as TextBaseInput, NumberBaseInput, PasswordBaseInput, etc.
422
+ */
423
+ const BaseInput = ({ className, isInvalid, dataTestId, prefix, suffix, addonBefore, addonAfter, actions, fieldSize = "medium", nonInteractive = false, inputClassName, placeholder, isWarning, type, genericAction, style, ref, ...rest }) => {
424
+ // Derive final flags
425
+ const renderAsDisabled = Boolean(rest.disabled);
426
+ const renderAsReadonly = Boolean(rest.readOnly);
427
+ const beforeContainerRef = react.useRef(null);
428
+ const { width: beforeContainerWidth } = reactComponents.useGeometry(beforeContainerRef);
429
+ const afterContainerRef = react.useRef(null);
430
+ const { width: afterContainerWidth } = reactComponents.useGeometry(afterContainerRef);
431
+ // Keep a reference to the input element
432
+ const innerRef = react.useRef(null);
433
+ react.useImperativeHandle(ref, () => innerRef.current, []);
434
+ return (jsxRuntime.jsxs("div", { className: cvaInput$1({
435
+ disabled: renderAsDisabled,
436
+ invalid: isInvalid,
437
+ isWarning,
438
+ size: fieldSize,
439
+ className,
440
+ }), "data-testid": dataTestId ? `${dataTestId}-container` : undefined, style: style, children: [jsxRuntime.jsxs("div", { className: cvaAccessoriesContainer({ className: cvaInputItemPlacementManager({ position: "before" }) }), "data-testid": dataTestId ? `${dataTestId}-before-container` : undefined, ref: beforeContainerRef, children: [jsxRuntime.jsx(AddonRenderer, { addon: addonBefore, dataTestId: dataTestId, fieldSize: fieldSize, position: "before" }), jsxRuntime.jsx(PrefixRenderer, { dataTestId: dataTestId, disabled: renderAsDisabled, prefix: prefix, type: type })] }), jsxRuntime.jsx("input", { "aria-required": rest.required, className: cvaInputField({
441
+ readOnly: renderAsReadonly,
442
+ size: fieldSize,
443
+ disabled: renderAsDisabled,
444
+ className: cvaInputItemPlacementManager({ position: "span", className: inputClassName }),
445
+ }), "data-testid": dataTestId, placeholder: renderAsDisabled ? undefined : placeholder, ref: innerRef, style: {
446
+ paddingLeft: beforeContainerWidth ? `calc(${beforeContainerWidth}px + ${uiDesignTokens.themeSpacing[2]})` : undefined,
447
+ paddingRight: afterContainerWidth ? `calc(${afterContainerWidth}px + ${uiDesignTokens.themeSpacing[2]})` : undefined,
448
+ }, type: type, ...rest, disabled: renderAsDisabled, readOnly: renderAsReadonly || nonInteractive }), jsxRuntime.jsxs("div", { className: cvaAccessoriesContainer({ className: cvaInputItemPlacementManager({ position: "after" }) }), "data-testid": dataTestId ? `${dataTestId}-after-container` : undefined, ref: afterContainerRef, children: [jsxRuntime.jsx(LockReasonRenderer, { dataTestId: dataTestId + "-disabled", lockReason: rest.disabled }), jsxRuntime.jsx(LockReasonRenderer, { dataTestId: dataTestId + "-readonly", lockReason: rest.readOnly && !rest.disabled ? rest.readOnly : undefined }), jsxRuntime.jsx(GenericActionsRenderer, { fieldSize: fieldSize, genericAction: genericAction, innerRef: innerRef }), jsxRuntime.jsx(SuffixRenderer, { dataTestId: dataTestId, disabled: renderAsDisabled, isInvalid: isInvalid, isWarning: isWarning, suffix: suffix }), actions, jsxRuntime.jsx(AddonRenderer, { addon: addonAfter, dataTestId: dataTestId, fieldSize: fieldSize, position: "after" })] })] }));
449
+ };
450
+ BaseInput.displayName = "BaseInput";
451
+
452
+ /**
453
+ * A wrapper around BaseInput with a pop-up day picker.
454
+ *
455
+ * The value is formatted to an ISO date string (YYYY-MM-DD)
456
+ *
457
+ * NOTE: If shown with a label, please use the `DateField` component instead.
458
+ */
459
+ const DateBaseInput = ({ min, max, defaultValue, value, ref, ...rest }) => {
460
+ const formatDateToInputString = (date) => date instanceof Date
461
+ ? polyfill.Temporal.PlainDateTime.from({
462
+ year: date.getFullYear(),
463
+ month: date.getMonth() + 1,
464
+ day: date.getDate(),
465
+ })
466
+ .toPlainDate()
467
+ .toString()
468
+ : date;
469
+ // Chrome and Firefox need their default icon to have datepicker functionality.
470
+ const showIcon = !/Chrome/.test(navigator.userAgent) && !/Firefox/.test(navigator.userAgent);
471
+ return (jsxRuntime.jsx(BaseInput, { defaultValue: formatDateToInputString(defaultValue), max: formatDateToInputString(max), min: formatDateToInputString(min), ref: ref, suffix: showIcon ? jsxRuntime.jsx(reactComponents.Icon, { dataTestId: "calendar", name: "Calendar", size: "medium", type: "solid" }) : null, type: "date", value: formatDateToInputString(value), ...rest }));
472
+ };
473
+
474
+ /**
475
+ * A thin wrapper around the `BaseInput` component for number input fields.
476
+ *
477
+ * NOTE: If shown with a label, please use the `NumberField` component instead.
478
+ */
479
+ const NumberBaseInput = ({ ref, ...rest }) => {
480
+ const inputElementRef = react.useRef(null);
481
+ const preventDefaultWheelEvent = react.useCallback((event) => {
482
+ const inputElement = inputElementRef.current;
483
+ const activeElement = document.activeElement;
484
+ if (inputElement && activeElement === inputElement) {
485
+ event.preventDefault();
486
+ }
487
+ }, []);
488
+ const forwardAndStoreInputRef = react.useCallback((node) => {
489
+ const previousNode = inputElementRef.current;
490
+ if (previousNode) {
491
+ previousNode.removeEventListener("wheel", preventDefaultWheelEvent);
492
+ }
493
+ inputElementRef.current = node;
494
+ if (node) {
495
+ // NOTE: Prevent the default browser behavior of changing the value via mouse wheel
496
+ node.addEventListener("wheel", preventDefaultWheelEvent, { passive: false });
497
+ }
498
+ if (typeof ref === "function") {
499
+ ref(node);
500
+ }
501
+ else if (ref && typeof ref === "object") {
502
+ ref.current = node;
503
+ }
504
+ }, [preventDefaultWheelEvent, ref]);
505
+ react.useEffect(() => {
506
+ return () => {
507
+ const element = inputElementRef.current;
508
+ if (element) {
509
+ element.removeEventListener("wheel", preventDefaultWheelEvent);
510
+ }
511
+ };
512
+ }, [preventDefaultWheelEvent]);
513
+ return jsxRuntime.jsx(BaseInput, { ref: forwardAndStoreInputRef, type: "number", ...rest, value: rest.value });
514
+ };
515
+
516
+ /**
517
+ * @param phoneNumber - a phone number as a string
518
+ * @returns {boolean} true if the phone number starts with a plus sign
519
+ * @example checkIfPhoneNumberHasPlus("123456789") // false
520
+ * checkIfPhoneNumberHasPlus("+123456789") // true
521
+ */
522
+ const checkIfPhoneNumberHasPlus = (phoneNumber) => {
523
+ return phoneNumber.startsWith("+");
524
+ };
525
+ /**
526
+ * @param phoneNumber - a phone number as a string
527
+ * @returns {string|number} the phone number with a plus sign in front of it
528
+ * @example getPhoneNumberWithPlus("123456789") // "+123456789"
529
+ */
530
+ const getPhoneNumberWithPlus = (phoneNumber) => {
531
+ const stringPhoneNumber = phoneNumber.toString();
532
+ return checkIfPhoneNumberHasPlus(stringPhoneNumber) ? stringPhoneNumber : `+${stringPhoneNumber}`;
533
+ };
534
+ /**
535
+ * Generates a flag emoji based on the given country code.
536
+ *
537
+ * @param {string} countryCode - The two-letter country code (ISO 3166-1 alpha-2).
538
+ * @returns {string} - The corresponding flag emoji for the given country code.
539
+ * @example getPhoneNumberWithPlus("DK") // "🇩🇰"
540
+ */
541
+ const countryCodeToFlagEmoji = (countryCode) => {
542
+ let code = countryCode;
543
+ if (countryCode.startsWith("+")) {
544
+ code = getCountryAbbreviation(countryCode.substring(1));
545
+ }
546
+ else if (!isNaN(Number(countryCode))) {
547
+ code = getCountryAbbreviation(countryCode);
548
+ }
549
+ return parsePhoneNumberFromString.isSupportedCountry(code.toUpperCase())
550
+ ? code.toUpperCase().replace(/./g, char => String.fromCodePoint(127397 + char.charCodeAt(0)))
551
+ : "";
552
+ };
553
+ /**
554
+ * Retrieves the ISO 3166-1 alpha-2 country code associated with a given international calling code.
555
+ *
556
+ * @param {string} callCode - The international calling code for a country.
557
+ * @returns {string} The abbreviation for a country or an empty string if no matching country is found.
558
+ * @example getCountryAbbreviation("45") // "DK"
559
+ * @example getCountryAbbreviation("+45") // "DK"
560
+ */
561
+ const getCountryAbbreviation = (callCode) => {
562
+ let code = callCode;
563
+ if (callCode.startsWith("+")) {
564
+ code = callCode.substring(1);
565
+ }
566
+ return parsePhoneNumberFromString.getCountries().find(c => parsePhoneNumberFromString.getCountryCallingCode(c) === code) || "";
567
+ };
568
+
569
+ const DEFAULT_COUNTRY_CODE = undefined;
570
+ /**
571
+ * A component for inputting phone numbers with an optional action button for initiating a phone call.
572
+ *
573
+ * @param {string} [dataTestId] - The data test ID for the component.
574
+ * @param {string|number} [value] - The value of the input field. The value should include the country code as well.
575
+ * @param {boolean} [disabled=false] - Whether the component is disabled or not.
576
+ * @param {string} [fieldSize="medium"] - The size of the input field.
577
+ * @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
578
+ */
579
+ const PhoneBaseInput = ({ dataTestId, isInvalid, disabled = false, value, defaultValue, fieldSize = "medium", disableAction = false, onChange, readOnly, onFocus, onBlur, name, ref, ...rest }) => {
580
+ const [innerValue, setInnerValue] = react.useState(() => {
581
+ return (value?.toString() || defaultValue?.toString()) ?? "";
582
+ });
583
+ const fieldIsFocused = react.useRef(false);
584
+ const [countryCode, setCountryCode] = react.useState(DEFAULT_COUNTRY_CODE);
585
+ const determineCountry = react.useCallback((newValue) => {
586
+ const asYouType = new parsePhoneNumberFromString.AsYouType();
587
+ asYouType.input(newValue);
588
+ setCountryCode(asYouType.getCountry());
589
+ }, []);
590
+ const handleChange = react.useCallback(event => {
591
+ const newValue = event.target.value;
592
+ event.target.value = parsePhoneNumberFromString.parseIncompletePhoneNumber(newValue);
593
+ onChange?.(event);
594
+ setInnerValue(newValue);
595
+ determineCountry(newValue);
596
+ }, [onChange, determineCountry]);
597
+ const makePretty = react.useCallback((newValue) => {
598
+ const asYouType = new parsePhoneNumberFromString.AsYouType();
599
+ const pretty = asYouType.input(newValue);
600
+ setInnerValue(pretty);
601
+ setCountryCode(asYouType.getCountry());
602
+ }, []);
603
+ react.useEffect(() => {
604
+ if (!fieldIsFocused.current) {
605
+ makePretty(typeof value === "string" ? value : "");
606
+ }
607
+ }, [makePretty, value]);
608
+ const handleBlur = react.useCallback(event => {
609
+ const newValue = event.target.value;
610
+ makePretty(newValue);
611
+ onBlur?.(event);
612
+ fieldIsFocused.current = false;
613
+ }, [makePretty, onBlur]);
614
+ const handleFocus = react.useCallback(event => {
615
+ const newValue = event.target.value;
616
+ const noneFormattedValue = parsePhoneNumberFromString.parseIncompletePhoneNumber(newValue);
617
+ setInnerValue(noneFormattedValue);
618
+ onFocus?.(event);
619
+ fieldIsFocused.current = true;
620
+ }, [onFocus]);
621
+ return (jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2", "data-testid": dataTestId ? `${dataTestId}-container` : null, children: jsxRuntime.jsx(BaseInput, { actions: !disableAction && innerValue && innerValue.length > 0 ? (jsxRuntime.jsx(ActionButton, { dataTestId: dataTestId ? `${dataTestId}-phoneIcon` : undefined, disabled: isInvalid, size: fieldSize ?? undefined, type: "PHONE_NUMBER", value: value?.toString() || "" })) : null, dataTestId: dataTestId ? `${dataTestId}-phoneNumberInput` : undefined, disabled: disabled, fieldSize: fieldSize, id: "phoneInput-number", isInvalid: isInvalid, name: name, onBlur: handleBlur, onChange: handleChange, onFocus: handleFocus, prefix: (countryCode && countryCodeToFlagEmoji(countryCode)) || undefined, readOnly: readOnly, ref: ref, type: "tel", value: innerValue, ...rest }) }));
622
+ };
623
+
624
+ const cvaTextAreaBaseInput = cssClassVarianceUtilities.cvaMerge([
625
+ cvaInputBase(),
626
+ "block",
627
+ "overflow-auto",
628
+ "appearance-none",
629
+ "px-3",
630
+ "py-2",
631
+ "text-base",
632
+ "text-slate-900",
633
+ "placeholder-slate-400",
634
+ "w-full",
635
+ "h-20",
636
+ "transition",
637
+ ], {
638
+ variants: {
639
+ disabled: {
640
+ true: cvaInputBaseDisabled(),
641
+ false: "",
642
+ },
643
+ invalid: {
644
+ true: cvaInputBaseInvalid(),
645
+ false: "",
646
+ },
647
+ resize: {
648
+ both: "resize",
649
+ vertical: "resize-y",
650
+ horizontal: "resize-x",
651
+ none: "resize-none",
652
+ },
653
+ },
654
+ });
655
+
656
+ /**
657
+ * The TextArea is a base component, and should not be used very often.
658
+ * For most cases the TextAreaField is the correct component.
659
+ */
660
+ const TextAreaBaseInput = ({ id, name, value, rows, disabled, placeholder, readOnly, tabIndex, onChange, onFocus, onBlur, maxLength, resize = "vertical", defaultValue, required, dataTestId, isInvalid, className, ref, ...rest }) => {
661
+ return (jsxRuntime.jsx("textarea", { className: cvaTextAreaBaseInput({ className, resize, invalid: isInvalid, disabled }), defaultValue: defaultValue, disabled: disabled, id: id, maxLength: maxLength, name: name, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, readOnly: readOnly, ref: ref, required: required, rows: rows, tabIndex: tabIndex, value: value, ...rest, "data-testid": dataTestId, onChange: onChange }));
662
+ };
663
+
664
+ /**
665
+ * A thin wrapper around the `BaseInput` component for text input fields.
419
666
  *
420
- * For specific input types make sure to use the corresponding input component.
421
- * This is a base used by our other input components such as TextInput, NumberInput, PasswordInput, etc.
667
+ * NOTE: If shown with a label, please use the `TextField` component instead.
422
668
  */
423
- const BaseInput = ({ className, isInvalid, dataTestId, prefix, suffix, addonBefore, addonAfter, actions, fieldSize = "medium", nonInteractive = false, inputClassName, placeholder, isWarning, type, genericAction, style, ref, ...rest }) => {
424
- // Derive final flags
425
- const renderAsDisabled = Boolean(rest.disabled);
426
- const renderAsReadonly = Boolean(rest.readOnly);
427
- const beforeContainerRef = react.useRef(null);
428
- const { width: beforeContainerWidth } = reactComponents.useGeometry(beforeContainerRef);
429
- const afterContainerRef = react.useRef(null);
430
- const { width: afterContainerWidth } = reactComponents.useGeometry(afterContainerRef);
431
- // Keep a reference to the input element
432
- const innerRef = react.useRef(null);
433
- react.useImperativeHandle(ref, () => innerRef.current, []);
434
- return (jsxRuntime.jsxs("div", { className: cvaInput$1({
435
- disabled: renderAsDisabled,
436
- invalid: isInvalid,
437
- isWarning,
438
- size: fieldSize,
439
- className,
440
- }), "data-testid": dataTestId ? `${dataTestId}-container` : undefined, style: style, children: [jsxRuntime.jsxs("div", { className: cvaAccessoriesContainer({ className: cvaInputItemPlacementManager({ position: "before" }) }), "data-testid": dataTestId ? `${dataTestId}-before-container` : undefined, ref: beforeContainerRef, children: [jsxRuntime.jsx(AddonRenderer, { addon: addonBefore, dataTestId: dataTestId, fieldSize: fieldSize, position: "before" }), jsxRuntime.jsx(PrefixRenderer, { dataTestId: dataTestId, disabled: renderAsDisabled, prefix: prefix, type: type })] }), jsxRuntime.jsx("input", { "aria-required": rest.required, className: cvaInputField({
441
- readOnly: renderAsReadonly,
442
- size: fieldSize,
443
- disabled: renderAsDisabled,
444
- className: cvaInputItemPlacementManager({ position: "span", className: inputClassName }),
445
- }), "data-testid": dataTestId, placeholder: renderAsDisabled ? undefined : placeholder, ref: innerRef, style: {
446
- paddingLeft: beforeContainerWidth ? `calc(${beforeContainerWidth}px + ${uiDesignTokens.themeSpacing[2]})` : undefined,
447
- paddingRight: afterContainerWidth ? `calc(${afterContainerWidth}px + ${uiDesignTokens.themeSpacing[2]})` : undefined,
448
- }, type: type, ...rest, disabled: renderAsDisabled, readOnly: renderAsReadonly || nonInteractive }), jsxRuntime.jsxs("div", { className: cvaAccessoriesContainer({ className: cvaInputItemPlacementManager({ position: "after" }) }), "data-testid": dataTestId ? `${dataTestId}-after-container` : undefined, ref: afterContainerRef, children: [jsxRuntime.jsx(LockReasonRenderer, { dataTestId: dataTestId + "-disabled", lockReason: rest.disabled }), jsxRuntime.jsx(LockReasonRenderer, { dataTestId: dataTestId + "-readonly", lockReason: rest.readOnly && !rest.disabled ? rest.readOnly : undefined }), jsxRuntime.jsx(GenericActionsRenderer, { fieldSize: fieldSize, genericAction: genericAction, innerRef: innerRef }), jsxRuntime.jsx(SuffixRenderer, { dataTestId: dataTestId, disabled: renderAsDisabled, isInvalid: isInvalid, isWarning: isWarning, suffix: suffix }), actions, jsxRuntime.jsx(AddonRenderer, { addon: addonAfter, dataTestId: dataTestId, fieldSize: fieldSize, position: "after" })] })] }));
449
- };
450
- BaseInput.displayName = "BaseInput";
669
+ const TextBaseInput = ({ ref, ...rest }) => jsxRuntime.jsx(BaseInput, { ref: ref, type: "text", ...rest });
451
670
 
452
671
  /**
453
672
  * Shared CVA for binary control items: Checkbox, RadioItem, ToggleSwitchOption
@@ -714,7 +933,7 @@ const FormGroup = ({ isInvalid, isWarning, helpText, helpAddon, tip, className,
714
933
  const color = isInvalid ? "danger" : isWarning ? "warning" : null;
715
934
  return color ? jsxRuntime.jsx(reactComponents.Icon, { color: color, name: "ExclamationTriangle", size: "small" }) : null;
716
935
  }, [isInvalid, isWarning]);
717
- return (jsxRuntime.jsxs("div", { className: cvaFormGroup({ className }), "data-testid": dataTestId, children: [jsxRuntime.jsxs("div", { className: cvaFormGroupContainerBefore(), children: [label ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Label, { className: "component-formGroup-font", dataTestId: dataTestId ? `${dataTestId}-label` : undefined, htmlFor: htmlFor, id: htmlFor + "-label", children: label }), required ? (jsxRuntime.jsx(reactComponents.Tooltip, { "data-testid": "required-asterisk", label: t("field.required.asterisk.tooltip"), children: "*" })) : null] })) : null, tip ? (jsxRuntime.jsx(reactComponents.Tooltip, { className: "ml-1", dataTestId: dataTestId ? `${dataTestId}-tooltip` : undefined, label: tip, placement: "bottom" })) : null] }), children, helpText || helpAddon ? (jsxRuntime.jsxs("div", { className: cvaFormGroupContainerAfter({ invalid: isInvalid, isWarning: isWarning }), children: [helpText ? (jsxRuntime.jsxs("div", { className: "flex gap-1", children: [validationStateIcon, jsxRuntime.jsx("span", { "data-testid": dataTestId ? `${dataTestId}-helpText` : undefined, children: helpText })] })) : undefined, helpAddon ? (jsxRuntime.jsx("span", { className: cvaHelpAddon(), "data-testid": dataTestId ? `${dataTestId}-helpAddon` : null, children: helpAddon })) : null] })) : null] }));
936
+ return (jsxRuntime.jsxs("div", { className: cvaFormGroup({ className }), "data-testid": dataTestId, children: [label ? (jsxRuntime.jsxs("div", { className: cvaFormGroupContainerBefore(), children: [jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Label, { className: "component-formGroup-font", dataTestId: dataTestId ? `${dataTestId}-label` : undefined, htmlFor: htmlFor, id: htmlFor + "-label", children: label }), required ? (jsxRuntime.jsx(reactComponents.Tooltip, { "data-testid": "required-asterisk", label: t("field.required.asterisk.tooltip"), children: "*" })) : null] }), tip ? (jsxRuntime.jsx(reactComponents.Tooltip, { className: "ml-1", dataTestId: dataTestId ? `${dataTestId}-tooltip` : undefined, label: tip, placement: "bottom" })) : null] })) : null, children, helpText || helpAddon ? (jsxRuntime.jsxs("div", { className: cvaFormGroupContainerAfter({ invalid: isInvalid, isWarning: isWarning }), children: [helpText ? (jsxRuntime.jsxs("div", { className: "flex gap-1", children: [validationStateIcon, jsxRuntime.jsx("span", { "data-testid": dataTestId ? `${dataTestId}-helpText` : undefined, children: helpText })] })) : undefined, helpAddon ? (jsxRuntime.jsx("span", { className: cvaHelpAddon(), "data-testid": dataTestId ? `${dataTestId}-helpAddon` : null, children: helpAddon })) : null] })) : null] }));
718
937
  };
719
938
 
720
939
  /**
@@ -840,29 +1059,6 @@ const ColorField = react.forwardRef(({ label, id, tip, helpText, errorMessage, h
840
1059
  });
841
1060
  ColorField.displayName = "ColorField";
842
1061
 
843
- /**
844
- * A wrapper around BaseInput with a pop-up day picker.
845
- *
846
- * The value is formatted to an ISO date string (YYYY-MM-DD)
847
- *
848
- * NOTE: If shown with a label, please use the `DateField` component instead.
849
- */
850
- const DateInput = ({ min, max, defaultValue, value, ref, ...rest }) => {
851
- const formatDateToInputString = (date) => date instanceof Date
852
- ? polyfill.Temporal.PlainDateTime.from({
853
- year: date.getFullYear(),
854
- month: date.getMonth() + 1,
855
- day: date.getDate(),
856
- })
857
- .toPlainDate()
858
- .toString()
859
- : date;
860
- // Chrome and Firefox need their default icon to have datepicker functionality.
861
- const showIcon = !/Chrome/.test(navigator.userAgent) && !/Firefox/.test(navigator.userAgent);
862
- return (jsxRuntime.jsx(BaseInput, { defaultValue: formatDateToInputString(defaultValue), max: formatDateToInputString(max), min: formatDateToInputString(min), ref: ref, suffix: showIcon ? jsxRuntime.jsx(reactComponents.Icon, { dataTestId: "calendar", name: "Calendar", size: "medium", type: "solid" }) : null, type: "date", value: formatDateToInputString(value), ...rest }));
863
- };
864
- DateInput.displayName = "DateInput";
865
-
866
1062
  /**
867
1063
  * The date field component is used for entering date values.
868
1064
  *
@@ -873,7 +1069,7 @@ DateInput.displayName = "DateInput";
873
1069
  const DateField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInvalid, className, defaultValue, dataTestId, ref, ...rest }) => {
874
1070
  const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
875
1071
  const htmlForId = id ? id : "dateField-" + sharedUtils.uuidv4();
876
- return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(DateInput, { "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, ref: ref, ...rest, className: className, dataTestId: dataTestId }) }));
1072
+ return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(DateBaseInput, { "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, ref: ref, ...rest, className: className, dataTestId: dataTestId }) }));
877
1073
  };
878
1074
  DateField.displayName = "DateField";
879
1075
 
@@ -1028,8 +1224,8 @@ const validateEmailId = (emailId, required) => {
1028
1224
  * A reference to the input element is provided as the `ref` prop.
1029
1225
  * For specific input types make sure to use the corresponding input component.
1030
1226
  */
1031
- const EmailInput = ({ fieldSize = "medium", disabled = false, dataTestId, isInvalid = false, onChange, disableAction = false, ref, ...rest }) => {
1032
- const [email, setEmail] = react.useState("");
1227
+ const EmailBaseInput = ({ fieldSize = "medium", disabled = false, dataTestId, isInvalid = false, onChange, disableAction = false, ref, ...rest }) => {
1228
+ const [email, setEmail] = react.useState(rest.value?.toString() || rest.defaultValue?.toString());
1033
1229
  const sendEmail = () => {
1034
1230
  return window.open(`mailto:${email}`);
1035
1231
  };
@@ -1041,7 +1237,6 @@ const EmailInput = ({ fieldSize = "medium", disabled = false, dataTestId, isInva
1041
1237
  const renderAsInvalid = (email && !validateEmailAddress(email)) || isInvalid;
1042
1238
  return (jsxRuntime.jsx(BaseInput, { actions: email && email.length > 0 ? (jsxRuntime.jsx(ActionButton, { dataTestId: dataTestId ? `${dataTestId}-emailIcon` : undefined, disabled: disableAction || isInvalid, onClick: sendEmail, size: fieldSize ?? undefined, type: "EMAIL", value: email })) : null, dataTestId: dataTestId, disabled: disabled, isInvalid: renderAsInvalid, onChange: handleChange, placeholder: rest.placeholder || "mail@example.com", ref: ref, type: "email", ...rest }));
1043
1239
  };
1044
- EmailInput.displayName = "EmailInput";
1045
1240
 
1046
1241
  /**
1047
1242
  * The EmailField component is used to enter email.
@@ -1069,7 +1264,7 @@ const EmailField = ({ label, id, tip, helpText, errorMessage, helpAddon, classNa
1069
1264
  onChange(event);
1070
1265
  }
1071
1266
  }, [onChange]);
1072
- return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(EmailInput, { "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, onBlur: handleBlur, onChange: handleChange, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
1267
+ return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(EmailBaseInput, { "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, onBlur: handleBlur, onChange: handleChange, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
1073
1268
  };
1074
1269
  EmailField.displayName = "EmailField";
1075
1270
 
@@ -1123,49 +1318,6 @@ const validateNumber = (number, required = false, min, max) => {
1123
1318
  return "INVALID_NUMBER";
1124
1319
  };
1125
1320
 
1126
- /**
1127
- * A thin wrapper around the `BaseInput` component for number input fields.
1128
- *
1129
- * NOTE: If shown with a label, please use the `NumberField` component instead.
1130
- */
1131
- const NumberInput = ({ ref, ...rest }) => {
1132
- const inputElementRef = react.useRef(null);
1133
- const preventDefaultWheelEvent = react.useCallback((event) => {
1134
- const inputElement = inputElementRef.current;
1135
- const activeElement = document.activeElement;
1136
- if (inputElement && activeElement === inputElement) {
1137
- event.preventDefault();
1138
- }
1139
- }, []);
1140
- const forwardAndStoreInputRef = react.useCallback((node) => {
1141
- const previousNode = inputElementRef.current;
1142
- if (previousNode) {
1143
- previousNode.removeEventListener("wheel", preventDefaultWheelEvent);
1144
- }
1145
- inputElementRef.current = node;
1146
- if (node) {
1147
- // NOTE: Prevent the default browser behavior of changing the value via mouse wheel
1148
- node.addEventListener("wheel", preventDefaultWheelEvent, { passive: false });
1149
- }
1150
- if (typeof ref === "function") {
1151
- ref(node);
1152
- }
1153
- else if (ref && typeof ref === "object") {
1154
- ref.current = node;
1155
- }
1156
- }, [preventDefaultWheelEvent, ref]);
1157
- react.useEffect(() => {
1158
- return () => {
1159
- const element = inputElementRef.current;
1160
- if (element) {
1161
- element.removeEventListener("wheel", preventDefaultWheelEvent);
1162
- }
1163
- };
1164
- }, [preventDefaultWheelEvent]);
1165
- return jsxRuntime.jsx(BaseInput, { ref: forwardAndStoreInputRef, type: "number", ...rest, value: rest.value });
1166
- };
1167
- NumberInput.displayName = "NumberInput";
1168
-
1169
1321
  /**
1170
1322
  * The number field component is used for entering numeric values and includes controls for incrementally increasing or decreasing the value.
1171
1323
  *
@@ -1215,7 +1367,7 @@ const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInva
1215
1367
  onChange(event);
1216
1368
  }
1217
1369
  }, [onChange]);
1218
- return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(NumberInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, onBlur: handleBlur, onChange: handleChange, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
1370
+ return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(NumberBaseInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, onBlur: handleBlur, onChange: handleChange, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
1219
1371
  };
1220
1372
  NumberField.displayName = "NumberField";
1221
1373
 
@@ -1329,11 +1481,10 @@ OptionCard.displayName = "OptionCard";
1329
1481
  *
1330
1482
  * NOTE: If shown with a label, please use the `PasswordField` component instead.
1331
1483
  */
1332
- const PasswordInput = ({ ref, fieldSize, ...rest }) => {
1484
+ const PasswordBaseInput = ({ ref, fieldSize, ...rest }) => {
1333
1485
  const [showPassword, setShowPassword] = react.useState(false);
1334
1486
  return (jsxRuntime.jsx(BaseInput, { ref: ref, ...rest, actions: jsxRuntime.jsx("div", { className: cvaActionContainer({ size: fieldSize }), children: jsxRuntime.jsx(reactComponents.IconButton, { className: cvaActionButton({ size: fieldSize }), icon: jsxRuntime.jsx(reactComponents.Icon, { name: showPassword ? "EyeSlash" : "Eye", size: "small" }), onClick: () => setShowPassword(prevState => !prevState), size: "small", variant: "secondary" }) }), type: showPassword ? "text" : "password" }));
1335
1487
  };
1336
- PasswordInput.displayName = "PasswordInput";
1337
1488
 
1338
1489
  /**
1339
1490
  * Password fields enter a password or other confidential information. Characters are masked as they are typed.
@@ -1348,119 +1499,10 @@ const PasswordField = ({ id, label, tip, helpText, helpAddon, errorMessage, isIn
1348
1499
  const handleChange = react.useCallback((event) => {
1349
1500
  onChange?.(event);
1350
1501
  }, [onChange]);
1351
- return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(PasswordInput, { ...rest, "aria-labelledby": htmlFor + "-label", className: className, dataTestId: dataTestId, disabled: rest.readOnly, id: htmlFor, isInvalid: renderAsInvalid, maxLength: maxLength, onChange: handleChange, ref: ref, value: value }) }));
1502
+ return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(PasswordBaseInput, { ...rest, "aria-labelledby": htmlFor + "-label", className: className, dataTestId: dataTestId, disabled: rest.readOnly, id: htmlFor, isInvalid: renderAsInvalid, maxLength: maxLength, onChange: handleChange, ref: ref, value: value }) }));
1352
1503
  };
1353
1504
  PasswordField.displayName = "PasswordField";
1354
1505
 
1355
- /**
1356
- * @param phoneNumber - a phone number as a string
1357
- * @returns {boolean} true if the phone number starts with a plus sign
1358
- * @example checkIfPhoneNumberHasPlus("123456789") // false
1359
- * checkIfPhoneNumberHasPlus("+123456789") // true
1360
- */
1361
- const checkIfPhoneNumberHasPlus = (phoneNumber) => {
1362
- return phoneNumber.startsWith("+");
1363
- };
1364
- /**
1365
- * @param phoneNumber - a phone number as a string
1366
- * @returns {string|number} the phone number with a plus sign in front of it
1367
- * @example getPhoneNumberWithPlus("123456789") // "+123456789"
1368
- */
1369
- const getPhoneNumberWithPlus = (phoneNumber) => {
1370
- const stringPhoneNumber = phoneNumber.toString();
1371
- return checkIfPhoneNumberHasPlus(stringPhoneNumber) ? stringPhoneNumber : `+${stringPhoneNumber}`;
1372
- };
1373
- /**
1374
- * Generates a flag emoji based on the given country code.
1375
- *
1376
- * @param {string} countryCode - The two-letter country code (ISO 3166-1 alpha-2).
1377
- * @returns {string} - The corresponding flag emoji for the given country code.
1378
- * @example getPhoneNumberWithPlus("DK") // "🇩🇰"
1379
- */
1380
- const countryCodeToFlagEmoji = (countryCode) => {
1381
- let code = countryCode;
1382
- if (countryCode.startsWith("+")) {
1383
- code = getCountryAbbreviation(countryCode.substring(1));
1384
- }
1385
- else if (!isNaN(Number(countryCode))) {
1386
- code = getCountryAbbreviation(countryCode);
1387
- }
1388
- return parsePhoneNumberFromString.isSupportedCountry(code.toUpperCase())
1389
- ? code.toUpperCase().replace(/./g, char => String.fromCodePoint(127397 + char.charCodeAt(0)))
1390
- : "";
1391
- };
1392
- /**
1393
- * Retrieves the ISO 3166-1 alpha-2 country code associated with a given international calling code.
1394
- *
1395
- * @param {string} callCode - The international calling code for a country.
1396
- * @returns {string} The abbreviation for a country or an empty string if no matching country is found.
1397
- * @example getCountryAbbreviation("45") // "DK"
1398
- * @example getCountryAbbreviation("+45") // "DK"
1399
- */
1400
- const getCountryAbbreviation = (callCode) => {
1401
- let code = callCode;
1402
- if (callCode.startsWith("+")) {
1403
- code = callCode.substring(1);
1404
- }
1405
- return parsePhoneNumberFromString.getCountries().find(c => parsePhoneNumberFromString.getCountryCallingCode(c) === code) || "";
1406
- };
1407
-
1408
- const DEFAULT_COUNTRY_CODE = undefined;
1409
- /**
1410
- * A component for inputting phone numbers with an optional action button for initiating a phone call.
1411
- *
1412
- * @param {string} [dataTestId] - The data test ID for the component.
1413
- * @param {string|number} [value] - The value of the input field. The value should include the country code as well.
1414
- * @param {boolean} [disabled=false] - Whether the component is disabled or not.
1415
- * @param {string} [fieldSize="medium"] - The size of the input field.
1416
- * @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
1417
- */
1418
- const PhoneInput = ({ dataTestId, isInvalid, disabled = false, value, defaultValue, fieldSize = "medium", disableAction = false, onChange, readOnly, onFocus, onBlur, name, ref, ...rest }) => {
1419
- const [innerValue, setInnerValue] = react.useState(() => {
1420
- return (value?.toString() || defaultValue?.toString()) ?? "";
1421
- });
1422
- const fieldIsFocused = react.useRef(false);
1423
- const [countryCode, setCountryCode] = react.useState(DEFAULT_COUNTRY_CODE);
1424
- const determineCountry = react.useCallback((newValue) => {
1425
- const asYouType = new parsePhoneNumberFromString.AsYouType();
1426
- asYouType.input(newValue);
1427
- setCountryCode(asYouType.getCountry());
1428
- }, []);
1429
- const handleChange = react.useCallback(event => {
1430
- const newValue = event.target.value;
1431
- event.target.value = parsePhoneNumberFromString.parseIncompletePhoneNumber(newValue);
1432
- onChange?.(event);
1433
- setInnerValue(newValue);
1434
- determineCountry(newValue);
1435
- }, [onChange, determineCountry]);
1436
- const makePretty = react.useCallback((newValue) => {
1437
- const asYouType = new parsePhoneNumberFromString.AsYouType();
1438
- const pretty = asYouType.input(newValue);
1439
- setInnerValue(pretty);
1440
- setCountryCode(asYouType.getCountry());
1441
- }, []);
1442
- react.useEffect(() => {
1443
- if (!fieldIsFocused.current) {
1444
- makePretty(typeof value === "string" ? value : "");
1445
- }
1446
- }, [makePretty, value]);
1447
- const handleBlur = react.useCallback(event => {
1448
- const newValue = event.target.value;
1449
- makePretty(newValue);
1450
- onBlur?.(event);
1451
- fieldIsFocused.current = false;
1452
- }, [makePretty, onBlur]);
1453
- const handleFocus = react.useCallback(event => {
1454
- const newValue = event.target.value;
1455
- const noneFormattedValue = parsePhoneNumberFromString.parseIncompletePhoneNumber(newValue);
1456
- setInnerValue(noneFormattedValue);
1457
- onFocus?.(event);
1458
- fieldIsFocused.current = true;
1459
- }, [onFocus]);
1460
- return (jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2", "data-testid": dataTestId ? `${dataTestId}-container` : null, children: jsxRuntime.jsx(BaseInput, { actions: !disableAction && innerValue && innerValue.length > 0 ? (jsxRuntime.jsx(ActionButton, { dataTestId: dataTestId ? `${dataTestId}-phoneIcon` : undefined, disabled: isInvalid, size: fieldSize ?? undefined, type: "PHONE_NUMBER", value: value?.toString() || "" })) : null, dataTestId: dataTestId ? `${dataTestId}-phoneNumberInput` : undefined, disabled: disabled, fieldSize: fieldSize, id: "phoneInput-number", isInvalid: isInvalid, name: name, onBlur: handleBlur, onChange: handleChange, onFocus: handleFocus, prefix: (countryCode && countryCodeToFlagEmoji(countryCode)) || undefined, readOnly: readOnly, ref: ref, type: "tel", value: innerValue, ...rest }) }));
1461
- };
1462
- PhoneInput.displayName = "PhoneInput";
1463
-
1464
1506
  /**
1465
1507
  * Validates a phone number
1466
1508
  */
@@ -1560,7 +1602,7 @@ const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value,
1560
1602
  }
1561
1603
  onBlur?.(event);
1562
1604
  }, [errorMessage, onBlur, rest.required]);
1563
- return (jsxRuntime.jsx(FormGroup, { className: className, dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(PhoneInput, { "aria-labelledby": htmlForId + "-label", dataTestId: dataTestId, defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, name: name, onBlur: handleBlur, ref: ref, value: value, ...rest }) }));
1605
+ return (jsxRuntime.jsx(FormGroup, { className: className, dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(PhoneBaseInput, { "aria-labelledby": htmlForId + "-label", dataTestId: dataTestId, defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, name: name, onBlur: handleBlur, ref: ref, value: value, ...rest }) }));
1564
1606
  };
1565
1607
  PhoneField.displayName = "PhoneField";
1566
1608
 
@@ -1901,14 +1943,6 @@ const hasConsecutiveDays = (schedule) => {
1901
1943
  return schedule.every(({ day }, index) => day === days[index]);
1902
1944
  };
1903
1945
 
1904
- /**
1905
- * A thin wrapper around the `BaseInput` component for text input fields.
1906
- *
1907
- * NOTE: If shown with a label, please use the `TextField` component instead.
1908
- */
1909
- const TextInput = ({ ref, ...rest }) => jsxRuntime.jsx(BaseInput, { ref: ref, type: "text", ...rest });
1910
- TextInput.displayName = "TextInput";
1911
-
1912
1946
  const cvaSearch = cssClassVarianceUtilities.cvaMerge([
1913
1947
  "shadow-none",
1914
1948
  "component-search-border",
@@ -1940,7 +1974,7 @@ const cvaSearch = cssClassVarianceUtilities.cvaMerge([
1940
1974
  */
1941
1975
  const Search = ({ className, placeholder, value, widenInputOnFocus, hideBorderWhenNotInFocus = false, disabled, onKeyUp, onChange, onFocus, onBlur, name, onClear, dataTestId, autoComplete = "on", loading, inputClassName, iconName = "MagnifyingGlass", style, xMarkRef, ref, ...rest }) => {
1942
1976
  const { t } = useTranslation();
1943
- return (jsxRuntime.jsx(TextInput, { ...rest, autoComplete: autoComplete, className: cvaSearch({ className, border: hideBorderWhenNotInFocus, widenOnFocus: widenInputOnFocus }), dataTestId: dataTestId, disabled: disabled, inputClassName: inputClassName, name: name, onBlur: onBlur, onChange: onChange, onFocus: onFocus, onKeyUp: onKeyUp, placeholder: placeholder ?? t("search.placeholder"), prefix: loading ? (jsxRuntime.jsx(reactComponents.Spinner, { centering: "centered", size: rest.fieldSize ?? undefined })) : (jsxRuntime.jsx(reactComponents.Icon, { name: iconName, size: rest.fieldSize ?? undefined })), ref: ref, suffix:
1977
+ return (jsxRuntime.jsx(TextBaseInput, { ...rest, autoComplete: autoComplete, className: cvaSearch({ className, border: hideBorderWhenNotInFocus, widenOnFocus: widenInputOnFocus }), dataTestId: dataTestId, disabled: disabled, inputClassName: inputClassName, name: name, onBlur: onBlur, onChange: onChange, onFocus: onFocus, onKeyUp: onKeyUp, placeholder: placeholder ?? t("search.placeholder"), prefix: loading ? (jsxRuntime.jsx(reactComponents.Spinner, { centering: "centered", size: rest.fieldSize ?? undefined })) : (jsxRuntime.jsx(reactComponents.Icon, { name: iconName, size: rest.fieldSize ?? undefined })), ref: ref, suffix:
1944
1978
  //only show the clear button if there is a value and the onClear function is provided
1945
1979
  onClear && value ? (jsxRuntime.jsx("button", { className: "flex", "data-testid": dataTestId ? `${dataTestId}_suffix_component` : null, onClick: () => {
1946
1980
  onClear();
@@ -2706,47 +2740,6 @@ const SelectField = ({ ref, ...props }) => {
2706
2740
  };
2707
2741
  SelectField.displayName = "SelectField";
2708
2742
 
2709
- const cvaTextArea = cssClassVarianceUtilities.cvaMerge([
2710
- cvaInputBase(),
2711
- "block",
2712
- "overflow-auto",
2713
- "appearance-none",
2714
- "px-3",
2715
- "py-2",
2716
- "text-base",
2717
- "text-slate-900",
2718
- "placeholder-slate-400",
2719
- "w-full",
2720
- "h-20",
2721
- "transition",
2722
- ], {
2723
- variants: {
2724
- disabled: {
2725
- true: cvaInputBaseDisabled(),
2726
- false: "",
2727
- },
2728
- invalid: {
2729
- true: cvaInputBaseInvalid(),
2730
- false: "",
2731
- },
2732
- resize: {
2733
- both: "resize",
2734
- vertical: "resize-y",
2735
- horizontal: "resize-x",
2736
- none: "resize-none",
2737
- },
2738
- },
2739
- });
2740
-
2741
- /**
2742
- * The TextArea is a base component, and should not be used very often.
2743
- * For most cases the TextAreaField is the correct component.
2744
- */
2745
- const TextArea = ({ id, name, value, rows, disabled, placeholder, readOnly, tabIndex, onChange, onFocus, onBlur, maxLength, resize = "vertical", defaultValue, required, dataTestId, isInvalid, className, ref, ...rest }) => {
2746
- return (jsxRuntime.jsx("textarea", { className: cvaTextArea({ className, resize, invalid: isInvalid, disabled }), defaultValue: defaultValue, disabled: disabled, id: id, maxLength: maxLength, name: name, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, readOnly: readOnly, ref: ref, required: required, rows: rows, tabIndex: tabIndex, value: value, ...rest, "data-testid": dataTestId, onChange: onChange }));
2747
- };
2748
- TextArea.displayName = "TextArea";
2749
-
2750
2743
  /**
2751
2744
  * The TextLengthIndicator component shows a `{length}/{maxLength}` label.
2752
2745
  * Used for TextFields to communicate a maximum allowed input length.
@@ -2772,7 +2765,7 @@ const TextAreaField = ({ id, label, tip, helpText, helpAddon, errorMessage, isIn
2772
2765
  }
2773
2766
  }, [onChange]);
2774
2767
  return (jsxRuntime.jsx(FormGroup, { className: tailwindMerge.twMerge(className, "grid", "grid-rows-[auto_1fr_auto]"), dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon ||
2775
- (typeof maxLength === "number" && jsxRuntime.jsx(TextLengthIndicator, { length: valueLength, maxLength: maxLength })), helpText: errorMessage || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(TextArea, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, ref: ref, value: value, ...rest, className: "h-auto", dataTestId: dataTestId, onChange: handleChange }) }));
2768
+ (typeof maxLength === "number" && jsxRuntime.jsx(TextLengthIndicator, { length: valueLength, maxLength: maxLength })), helpText: errorMessage || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(TextAreaBaseInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, ref: ref, value: value, ...rest, className: "h-auto", dataTestId: dataTestId, onChange: handleChange }) }));
2776
2769
  };
2777
2770
  TextAreaField.displayName = "TextAreaField";
2778
2771
 
@@ -2790,7 +2783,7 @@ const TextField = ({ id, label, tip, helpText, helpAddon, errorMessage, isInvali
2790
2783
  }
2791
2784
  }, [onChange]);
2792
2785
  return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon ||
2793
- (typeof maxLength === "number" && jsxRuntime.jsx(TextLengthIndicator, { length: valueLength, maxLength: maxLength })), helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, isWarning: isWarning, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(TextInput, { "aria-labelledby": htmlFor + "-label", id: htmlFor, isInvalid: renderAsInvalid, isWarning: isWarning, maxLength: maxLength, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId, onChange: handleChange }) }));
2786
+ (typeof maxLength === "number" && jsxRuntime.jsx(TextLengthIndicator, { length: valueLength, maxLength: maxLength })), helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, isWarning: isWarning, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(TextBaseInput, { "aria-labelledby": htmlFor + "-label", id: htmlFor, isInvalid: renderAsInvalid, isWarning: isWarning, maxLength: maxLength, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId, onChange: handleChange }) }));
2794
2787
  };
2795
2788
  TextField.displayName = "TextField";
2796
2789
 
@@ -3014,12 +3007,11 @@ const validateUrl = (url, required) => {
3014
3007
  *
3015
3008
  * NOTE: If shown with a label, please use the `UrlField` component instead.
3016
3009
  */
3017
- const UrlInput = ({ dataTestId, isInvalid, disabled = false, fieldSize = "medium", disableAction = false, value, defaultValue, ref, ...rest }) => {
3010
+ const UrlBaseInput = ({ dataTestId, isInvalid, disabled = false, fieldSize = "medium", disableAction = false, value, defaultValue, ref, ...rest }) => {
3018
3011
  const [url, setUrl] = react.useState(value?.toString() || defaultValue?.toString());
3019
3012
  const renderAsInvalid = (url && typeof url === "string" && !validateUrlAddress(url)) || isInvalid;
3020
3013
  return (jsxRuntime.jsx(BaseInput, { dataTestId: dataTestId ? `${dataTestId}-url-input` : undefined, disabled: disabled, id: "url-input", isInvalid: renderAsInvalid, onChange: e => setUrl(e.target.value), placeholder: rest.placeholder || "https://www.example.com", ref: ref, type: "url", value: url, ...rest, actions: !disableAction && (jsxRuntime.jsx(ActionButton, { dataTestId: (dataTestId && `${dataTestId}-url-input-Icon`) || "url-input-action-icon", disabled: renderAsInvalid || Boolean(disabled) || disableAction, size: fieldSize ?? undefined, type: "WEB_ADDRESS", value: url })) }));
3021
3014
  };
3022
- UrlInput.displayName = "UrlField";
3023
3015
 
3024
3016
  /**
3025
3017
  * The UrlField component is used to enter url.
@@ -3041,7 +3033,7 @@ const UrlField = ({ label, id, tip, helpText, errorMessage, helpAddon, className
3041
3033
  setRenderAsInvalid(!!validateUrl(newValue, rest.required));
3042
3034
  onBlur?.(event);
3043
3035
  }, [onBlur, rest.required]);
3044
- return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: renderAsInvalid ? error : helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(UrlInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, onBlur: handleBlur, ref: ref, value: value || defaultValue, ...rest, className: className, dataTestId: dataTestId }) }));
3036
+ return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: renderAsInvalid ? error : helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(UrlBaseInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, onBlur: handleBlur, ref: ref, value: value || defaultValue, ...rest, className: className, dataTestId: dataTestId }) }));
3045
3037
  };
3046
3038
  UrlField.displayName = "UrlField";
3047
3039
 
@@ -3166,25 +3158,24 @@ exports.ColorField = ColorField;
3166
3158
  exports.CreatableSelect = CreatableSelect;
3167
3159
  exports.CreatableSelectField = CreatableSelectField;
3168
3160
  exports.DEFAULT_TIME = DEFAULT_TIME;
3161
+ exports.DateBaseInput = DateBaseInput;
3169
3162
  exports.DateField = DateField;
3170
- exports.DateInput = DateInput;
3171
3163
  exports.DropZone = DropZone;
3172
3164
  exports.DropZoneDefaultLabel = DropZoneDefaultLabel;
3173
3165
  exports.EMAIL_REGEX = EMAIL_REGEX;
3174
3166
  exports.EmailField = EmailField;
3175
- exports.EmailInput = EmailInput;
3176
3167
  exports.FormFieldSelectAdapter = FormFieldSelectAdapter;
3177
3168
  exports.FormGroup = FormGroup;
3178
3169
  exports.Label = Label;
3179
3170
  exports.MultiSelectMenuItem = MultiSelectMenuItem;
3171
+ exports.NumberBaseInput = NumberBaseInput;
3180
3172
  exports.NumberField = NumberField;
3181
- exports.NumberInput = NumberInput;
3182
3173
  exports.OptionCard = OptionCard;
3174
+ exports.PasswordBaseInput = PasswordBaseInput;
3183
3175
  exports.PasswordField = PasswordField;
3184
- exports.PasswordInput = PasswordInput;
3176
+ exports.PhoneBaseInput = PhoneBaseInput;
3185
3177
  exports.PhoneField = PhoneField;
3186
3178
  exports.PhoneFieldWithController = PhoneFieldWithController;
3187
- exports.PhoneInput = PhoneInput;
3188
3179
  exports.RadioGroup = RadioGroup;
3189
3180
  exports.RadioItem = RadioItem;
3190
3181
  exports.Schedule = Schedule;
@@ -3192,10 +3183,10 @@ exports.Search = Search;
3192
3183
  exports.Select = Select;
3193
3184
  exports.SelectField = SelectField;
3194
3185
  exports.SingleSelectMenuItem = SingleSelectMenuItem;
3195
- exports.TextArea = TextArea;
3186
+ exports.TextAreaBaseInput = TextAreaBaseInput;
3196
3187
  exports.TextAreaField = TextAreaField;
3188
+ exports.TextBaseInput = TextBaseInput;
3197
3189
  exports.TextField = TextField;
3198
- exports.TextInput = TextInput;
3199
3190
  exports.TimeRange = TimeRange;
3200
3191
  exports.TimeRangeField = TimeRangeField;
3201
3192
  exports.ToggleSwitch = ToggleSwitch;
@@ -3203,7 +3194,6 @@ exports.ToggleSwitchOption = ToggleSwitchOption;
3203
3194
  exports.UploadField = UploadField;
3204
3195
  exports.UploadInput = UploadInput;
3205
3196
  exports.UrlField = UrlField;
3206
- exports.UrlInput = UrlInput;
3207
3197
  exports.checkIfPhoneNumberHasPlus = checkIfPhoneNumberHasPlus;
3208
3198
  exports.countryCodeToFlagEmoji = countryCodeToFlagEmoji;
3209
3199
  exports.cvaAccessoriesContainer = cvaAccessoriesContainer;