@simplybusiness/mobius 6.4.3 → 6.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -3825,9 +3825,9 @@ var Segment = (props) => {
3825
3825
  Segment.displayName = "Segment";
3826
3826
 
3827
3827
  // src/components/Select/Select.tsx
3828
+ import { chevronDown as chevronDown2 } from "@simplybusiness/icons";
3828
3829
  import classNames46 from "classnames/dedupe";
3829
3830
  import { forwardRef as forwardRef41, useId as useId11 } from "react";
3830
- import { chevronDown as chevronDown2 } from "@simplybusiness/icons";
3831
3831
  import { jsx as jsx55, jsxs as jsxs27 } from "react/jsx-runtime";
3832
3832
  var Select = forwardRef41((props, ref) => {
3833
3833
  const {
@@ -3896,6 +3896,7 @@ var Select = forwardRef41((props, ref) => {
3896
3896
  "aria-invalid": !!errorMessage,
3897
3897
  "aria-describedby": describedBy,
3898
3898
  "aria-required": isRequired,
3899
+ required: isRequired,
3899
3900
  onChange: handleChange
3900
3901
  }
3901
3902
  ),
@@ -4499,102 +4500,136 @@ var ExpandableText = forwardRef55((props, ref) => {
4499
4500
  ExpandableText.displayName = "ExpandableText";
4500
4501
 
4501
4502
  // src/components/MaskedField/MaskedField.tsx
4502
- import { forwardRef as forwardRef56, useEffect as useEffect26 } from "react";
4503
+ import { forwardRef as forwardRef56, useCallback as useCallback7, useEffect as useEffect26 } from "react";
4503
4504
  import { useIMask } from "react-imask";
4504
4505
  import { jsx as jsx71 } from "react/jsx-runtime";
4505
- var createSyntheticEvent = (options) => {
4506
- const { event, useMaskedValue, maskedValue, unmaskedValue, name } = options;
4507
- const valueToEmit = useMaskedValue ? maskedValue : unmaskedValue;
4508
- return {
4509
- ...event,
4510
- target: {
4511
- ...event.target,
4512
- value: valueToEmit,
4513
- name
4506
+ var useAcceptHandler = (onChange, useMaskedValue, name) => {
4507
+ return useCallback7(
4508
+ (maskedValue, maskInstance) => {
4509
+ if (!onChange) {
4510
+ return;
4511
+ }
4512
+ const formattedValue = maskedValue;
4513
+ const rawValue = maskInstance.unmaskedValue;
4514
+ const valueToEmit = useMaskedValue ? formattedValue : rawValue;
4515
+ onChange({
4516
+ target: { name, value: valueToEmit }
4517
+ });
4514
4518
  },
4515
- currentTarget: {
4516
- ...event.currentTarget,
4517
- value: valueToEmit,
4518
- name
4519
- }
4520
- };
4519
+ [onChange, useMaskedValue, name]
4520
+ );
4521
4521
  };
4522
- var MaskedField = forwardRef56((props, ref) => {
4523
- const {
4524
- mask,
4525
- value,
4526
- defaultValue,
4527
- useMaskedValue = false,
4528
- onChange,
4529
- onBlur,
4530
- "aria-describedby": ariaDescribedBy,
4531
- "aria-label": ariaLabel,
4532
- ...textFieldProps
4533
- } = props;
4534
- const {
4535
- ref: maskRef,
4536
- value: maskedValue,
4537
- unmaskedValue,
4538
- setValue
4539
- } = useIMask(mask, {
4540
- defaultValue: value || defaultValue
4541
- });
4522
+ var useCombinedRef = (imaskRef, forwardedRef) => {
4523
+ return useCallback7(
4524
+ (element) => {
4525
+ imaskRef.current = element;
4526
+ if (typeof forwardedRef === "function") {
4527
+ forwardedRef(element);
4528
+ } else if (forwardedRef) {
4529
+ forwardedRef.current = element;
4530
+ }
4531
+ },
4532
+ [imaskRef, forwardedRef]
4533
+ );
4534
+ };
4535
+ var useBlurHandler = (onBlur, maskRef, useMaskedValue, name) => {
4536
+ return useCallback7(
4537
+ (event) => {
4538
+ if (!onBlur || !maskRef.current) {
4539
+ return;
4540
+ }
4541
+ const formattedValue = maskRef.current.value;
4542
+ const rawValue = maskRef.current.unmaskedValue;
4543
+ const valueToEmit = useMaskedValue ? formattedValue : rawValue;
4544
+ onBlur({
4545
+ ...event,
4546
+ target: { ...event.target, name, value: valueToEmit }
4547
+ });
4548
+ },
4549
+ [onBlur, maskRef, useMaskedValue, name]
4550
+ );
4551
+ };
4552
+ var ControlledMaskedField = ({
4553
+ mask,
4554
+ useMaskedValue = false,
4555
+ value,
4556
+ onChange,
4557
+ onBlur,
4558
+ name,
4559
+ forwardedRef,
4560
+ ...textFieldProps
4561
+ }) => {
4562
+ const onAccept = useAcceptHandler(onChange, useMaskedValue, name);
4563
+ const { ref: imaskRef, maskRef, setValue } = useIMask(mask, { onAccept });
4564
+ const combinedRef = useCombinedRef(imaskRef, forwardedRef);
4565
+ const handleBlur = useBlurHandler(onBlur, maskRef, useMaskedValue, name);
4542
4566
  useEffect26(() => {
4543
- const valueToCompare = useMaskedValue ? maskedValue : unmaskedValue;
4544
- if (value !== void 0 && value !== valueToCompare) {
4545
- setValue(value);
4546
- }
4547
- }, [value, setValue]);
4548
- const handleChange = (event) => {
4549
- if (onChange) {
4550
- onChange(
4551
- createSyntheticEvent({
4552
- event,
4553
- useMaskedValue,
4554
- maskedValue,
4555
- unmaskedValue,
4556
- name: textFieldProps.name
4557
- })
4558
- );
4559
- }
4560
- };
4561
- const handleBlur = (event) => {
4562
- if (onBlur) {
4563
- onBlur(
4564
- createSyntheticEvent({
4565
- event,
4566
- useMaskedValue,
4567
- maskedValue,
4568
- unmaskedValue,
4569
- name: textFieldProps.name
4570
- })
4571
- );
4567
+ if (!maskRef.current) {
4568
+ return;
4572
4569
  }
4573
- };
4574
- const inputRef = (node) => {
4575
- if (maskRef) {
4576
- maskRef.current = node;
4570
+ const stringValue = value.toString();
4571
+ const currentMasked = maskRef.current.value;
4572
+ const currentUnmasked = maskRef.current.unmaskedValue;
4573
+ if (currentMasked !== stringValue && currentUnmasked !== stringValue) {
4574
+ setValue(stringValue);
4577
4575
  }
4578
- if (ref) {
4579
- if (typeof ref === "function") {
4580
- ref(node);
4581
- } else {
4582
- ref.current = node;
4583
- }
4576
+ }, [value, maskRef, setValue, imaskRef]);
4577
+ return /* @__PURE__ */ jsx71(
4578
+ TextField,
4579
+ {
4580
+ ...textFieldProps,
4581
+ ref: combinedRef,
4582
+ name,
4583
+ onBlur: handleBlur
4584
4584
  }
4585
- };
4585
+ );
4586
+ };
4587
+ var UncontrolledMaskedField = ({
4588
+ mask,
4589
+ useMaskedValue = false,
4590
+ defaultValue,
4591
+ onChange,
4592
+ onBlur,
4593
+ name,
4594
+ forwardedRef,
4595
+ ...textFieldProps
4596
+ }) => {
4597
+ const onAccept = useAcceptHandler(onChange, useMaskedValue, name);
4598
+ const { ref: imaskRef, maskRef } = useIMask(mask, { onAccept });
4599
+ const combinedRef = useCombinedRef(imaskRef, forwardedRef);
4600
+ const handleBlur = useBlurHandler(onBlur, maskRef, useMaskedValue, name);
4586
4601
  return /* @__PURE__ */ jsx71(
4587
4602
  TextField,
4588
4603
  {
4589
4604
  ...textFieldProps,
4590
- ref: inputRef,
4591
- value: maskedValue,
4592
- onChange: handleChange,
4605
+ ref: combinedRef,
4606
+ name,
4593
4607
  onBlur: handleBlur,
4594
- "aria-describedby": ariaDescribedBy,
4595
- "aria-label": ariaLabel
4608
+ defaultValue: defaultValue?.toString()
4596
4609
  }
4597
4610
  );
4611
+ };
4612
+ var MaskedField = forwardRef56((props, forwardedRef) => {
4613
+ const { value, defaultValue, ...rest } = props;
4614
+ if ("value" in props) {
4615
+ return /* @__PURE__ */ jsx71(
4616
+ ControlledMaskedField,
4617
+ {
4618
+ ...rest,
4619
+ value: value ?? "",
4620
+ forwardedRef
4621
+ }
4622
+ );
4623
+ } else {
4624
+ return /* @__PURE__ */ jsx71(
4625
+ UncontrolledMaskedField,
4626
+ {
4627
+ ...rest,
4628
+ defaultValue,
4629
+ forwardedRef
4630
+ }
4631
+ );
4632
+ }
4598
4633
  });
4599
4634
  MaskedField.displayName = "MaskedField";
4600
4635
  export {
@@ -1,14 +1,27 @@
1
1
  import type { Ref, RefAttributes } from "react";
2
- import type { ReactMaskOpts } from "react-imask";
3
- import type { ForwardedRefComponent } from "../../types/components";
4
- import type { DOMProps } from "../../types/dom";
5
- import { type TextFieldProps } from "../TextField";
2
+ import type { FactoryOpts } from "imask";
3
+ import type { ForwardedRefComponent } from "../../types";
4
+ import type { TextFieldProps } from "../TextField";
6
5
  export type MaskedFieldElementType = HTMLInputElement;
7
- export interface MaskedFieldProps extends Omit<TextFieldProps, "type">, DOMProps, RefAttributes<MaskedFieldElementType> {
8
- /** The mask configuration to apply */
9
- mask: ReactMaskOpts;
10
- /** Whether to return the masked (formatted) value in onChange. Defaults to false (unmasked value) */
6
+ export interface MaskedFieldProps extends Omit<TextFieldProps, "type" | "ref">, RefAttributes<MaskedFieldElementType> {
7
+ mask: FactoryOpts;
8
+ /**
9
+ * If true, onChange and onBlur events will emit the masked (formatted) value.
10
+ * If false (default), events will emit the unmasked (raw) value.
11
+ *
12
+ * @example
13
+ * // TelephoneQuestion uses useMaskedValue={true}
14
+ * // User types: 5551234567
15
+ * // onChange receives: "(555) 123-4567" (formatted for display/storage)
16
+ *
17
+ * @example
18
+ * // CurrencyQuestion uses useMaskedValue={false}
19
+ * // User types: 1234
20
+ * // User sees: "1,234" (with thousands separator)
21
+ * // onChange receives: "1234" (raw number for calculations)
22
+ */
11
23
  useMaskedValue?: boolean;
12
24
  }
13
25
  export type MaskedFieldRef = Ref<MaskedFieldElementType>;
14
- export declare const MaskedField: ForwardedRefComponent<MaskedFieldProps, MaskedFieldElementType>;
26
+ declare const MaskedField: ForwardedRefComponent<MaskedFieldProps, MaskedFieldElementType>;
27
+ export { MaskedField };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@simplybusiness/mobius",
3
3
  "license": "UNLICENSED",
4
- "version": "6.4.3",
4
+ "version": "6.4.4",
5
5
  "description": "Core library of Mobius react components",
6
6
  "repository": {
7
7
  "type": "git",