@simplybusiness/mobius 6.1.1 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,10 @@
1
1
  "use client";
2
2
 
3
3
  import classNames from "classnames/dedupe";
4
+ import type React from "react";
5
+ import { useCallback, useEffect, useRef } from "react";
4
6
  import { type Ref, type RefAttributes, forwardRef } from "react";
5
- import type { ForwardedRefComponent } from "../../types/components";
7
+ import type { ForwardedRefComponent } from "../../types";
6
8
  import {
7
9
  TextField,
8
10
  type TextFieldElementType,
@@ -44,6 +46,16 @@ export const NumberField: ForwardedRefComponent<
44
46
  ...otherProps
45
47
  } = props;
46
48
 
49
+ const focusedInputRef = useRef<HTMLInputElement | null>(null);
50
+ const wheelHandler = useCallback((ev: Event) => ev.preventDefault(), []);
51
+
52
+ useEffect(() => {
53
+ return () => {
54
+ focusedInputRef.current?.removeEventListener("wheel", wheelHandler);
55
+ focusedInputRef.current = null;
56
+ };
57
+ }, [wheelHandler]);
58
+
47
59
  const containerClasses = classNames("mobius-number-field", className, {
48
60
  "--hide-spin-buttons": hideSpinButtons,
49
61
  });
@@ -60,9 +72,37 @@ export const NumberField: ForwardedRefComponent<
60
72
  }
61
73
  };
62
74
 
75
+ const {
76
+ onFocus: customOnFocus,
77
+ onBlur: customOnBlur,
78
+ ...rest
79
+ } = otherProps as Omit<TextFieldProps, "onFocus" | "onBlur"> & {
80
+ onFocus?: React.FocusEventHandler<HTMLInputElement>;
81
+ onBlur?: React.FocusEventHandler<HTMLInputElement>;
82
+ };
83
+
84
+ const forwardedProps: TextFieldProps = {
85
+ ...rest,
86
+ onFocus: e => {
87
+ const el = e.currentTarget as HTMLInputElement;
88
+ focusedInputRef.current?.removeEventListener("wheel", wheelHandler);
89
+ focusedInputRef.current = el;
90
+ el.addEventListener("wheel", wheelHandler, { passive: false });
91
+ customOnFocus?.(e as React.FocusEvent<HTMLInputElement>);
92
+ },
93
+ onBlur: e => {
94
+ const el = e.currentTarget as HTMLInputElement;
95
+ el.removeEventListener("wheel", wheelHandler);
96
+ if (focusedInputRef.current === el) {
97
+ focusedInputRef.current = null;
98
+ }
99
+ customOnBlur?.(e as React.FocusEvent<HTMLInputElement>);
100
+ },
101
+ };
102
+
63
103
  return (
64
104
  <TextField
65
- {...otherProps}
105
+ {...forwardedProps}
66
106
  className={containerClasses}
67
107
  onBeforeInput={handleBeforeInput}
68
108
  type="number"
@@ -793,7 +793,7 @@ describe("controlled vs uncontrolled RadioGroup onChange behavior", () => {
793
793
  });
794
794
  });
795
795
 
796
- describe("focus behavior", () => {
796
+ describe.skip("focus behavior", () => {
797
797
  it("should focus the selected radio option when value changes", () => {
798
798
  const redValue = "red";
799
799
  const blueValue = "blue";
@@ -9,7 +9,6 @@ import {
9
9
  isValidElement,
10
10
  useEffect,
11
11
  useId,
12
- useRef,
13
12
  useState,
14
13
  } from "react";
15
14
  import { useValidationClasses } from "../../hooks";
@@ -97,7 +96,6 @@ const RadioGroup: ForwardedRefComponent<
97
96
  } = props;
98
97
  const defaultSelected = getDefaultVal(children, value || defaultValue);
99
98
  const [selected, setSelected] = useState<string>(defaultSelected);
100
- const selectedRef = useRef<HTMLInputElement | null>(null);
101
99
 
102
100
  // Handle controlled behavior - update state when value prop changes
103
101
  useEffect(() => {
@@ -106,11 +104,6 @@ const RadioGroup: ForwardedRefComponent<
106
104
  }
107
105
  }, [value]);
108
106
 
109
- // Focus the selected option on re-render
110
- useEffect(() => {
111
- selectedRef.current?.focus();
112
- });
113
-
114
107
  const validationClasses = useValidationClasses({
115
108
  validationState,
116
109
  isInvalid,
@@ -167,7 +160,6 @@ const RadioGroup: ForwardedRefComponent<
167
160
  <div className={radioWrapperClasses}>
168
161
  {Children.map(children, child => {
169
162
  if (isValidElement(child)) {
170
- const props = child.props as { value?: string };
171
163
  return cloneElement(
172
164
  child as ReactElement,
173
165
  {
@@ -179,7 +171,6 @@ const RadioGroup: ForwardedRefComponent<
179
171
  isRequired,
180
172
  "aria-describedby": describedBy,
181
173
  onChange,
182
- ref: props.value === selected ? selectedRef : undefined,
183
174
  } as Record<string, unknown>,
184
175
  );
185
176
  }
@@ -45,3 +45,4 @@ export * from "./Title";
45
45
  export * from "./Trust";
46
46
  export * from "./ExpandableText";
47
47
  export * from "./VisuallyHidden";
48
+ export * from "./MaskedField";