@trackunit/react-form-components 1.8.145 → 1.8.151

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/index.cjs.js CHANGED
@@ -2378,6 +2378,7 @@ EmailField.displayName = "EmailField";
2378
2378
  function isWritableRef(r) {
2379
2379
  return typeof r === "object" && r !== null && "current" in r;
2380
2380
  }
2381
+ const IGNORED_RS_ACTIONS = new Set(["set-value", "input-blur", "menu-close"]);
2381
2382
  /**
2382
2383
  * Multi adapter:
2383
2384
  * - keeps TOption[] semantics (via `MultiValue<TOption>`)
@@ -2390,9 +2391,11 @@ function isWritableRef(r) {
2390
2391
  * @returns {ReactElement} FormFieldSelectAdapterMulti component
2391
2392
  */
2392
2393
  const FormFieldSelectAdapterMulti = (props) => {
2393
- const { className, "data-testid": dataTestId, helpText, helpAddon, tip, label, isInvalid, errorMessage, name, onBlur, options, value, defaultValue, id, htmlFor: htmlForProp, onChange, children, ref, ...selectProps } = props;
2394
+ const { className, "data-testid": dataTestId, helpText, helpAddon, tip, label, isInvalid, errorMessage, name, onBlur, options, value, defaultValue, id, htmlFor: htmlForProp, onChange, children, ref, onInputChange, ...selectProps } = props;
2395
+ const [inputValue, setInputValue] = react.useState("");
2394
2396
  // Hidden select for a stable DOM ref target (API parity with single adapter)
2395
2397
  const innerRef = react.useRef(null);
2398
+ const onInputChangeRef = react.useRef(undefined);
2396
2399
  // Bridge external ref (supports both callback and object refs)
2397
2400
  react.useEffect(() => {
2398
2401
  if (typeof ref === "function") {
@@ -2414,6 +2417,20 @@ const FormFieldSelectAdapterMulti = (props) => {
2414
2417
  : undefined, [selectPropsWithAccessors]);
2415
2418
  // Compute selected options snapshot for hidden inputs (prefer controlled `value`)
2416
2419
  const selectedOptions = react.useMemo(() => value ?? defaultValue ?? [], [value, defaultValue]);
2420
+ react.useEffect(() => {
2421
+ onInputChangeRef.current = onInputChange;
2422
+ }, [onInputChange]);
2423
+ const handleInputChange = react.useCallback((nextValue, meta) => {
2424
+ if (IGNORED_RS_ACTIONS.has(meta.action)) {
2425
+ return inputValue; // keep current visible value
2426
+ }
2427
+ if (nextValue !== inputValue) {
2428
+ setInputValue(nextValue);
2429
+ }
2430
+ // Call the latest external callback from ref
2431
+ onInputChangeRef.current?.(nextValue, meta);
2432
+ return nextValue;
2433
+ }, [inputValue]);
2417
2434
  // Build the exact prop bag for BaseSelect (multi=true).
2418
2435
  const childProps = react.useMemo(() => ({
2419
2436
  ...selectProps,
@@ -2425,7 +2442,9 @@ const FormFieldSelectAdapterMulti = (props) => {
2425
2442
  value: value ?? null,
2426
2443
  defaultValue,
2427
2444
  onChange,
2428
- }), [selectProps, dataTestId, controlId, onBlur, options, value, defaultValue, onChange]);
2445
+ onInputChange: handleInputChange,
2446
+ inputValue,
2447
+ }), [selectProps, dataTestId, controlId, onBlur, options, value, defaultValue, onChange, handleInputChange, inputValue]);
2429
2448
  return (jsxRuntime.jsxs(FormGroup, { className: className, "data-testid": dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: controlId, isInvalid: renderAsInvalid, label: label, required: "required" in selectProps && selectProps.required
2430
2449
  ? !(("disabled" in selectProps && Boolean(selectProps.disabled)) ||
2431
2450
  ("readOnly" in selectProps && Boolean(selectProps.readOnly)))
package/index.esm.js CHANGED
@@ -2377,6 +2377,7 @@ EmailField.displayName = "EmailField";
2377
2377
  function isWritableRef(r) {
2378
2378
  return typeof r === "object" && r !== null && "current" in r;
2379
2379
  }
2380
+ const IGNORED_RS_ACTIONS = new Set(["set-value", "input-blur", "menu-close"]);
2380
2381
  /**
2381
2382
  * Multi adapter:
2382
2383
  * - keeps TOption[] semantics (via `MultiValue<TOption>`)
@@ -2389,9 +2390,11 @@ function isWritableRef(r) {
2389
2390
  * @returns {ReactElement} FormFieldSelectAdapterMulti component
2390
2391
  */
2391
2392
  const FormFieldSelectAdapterMulti = (props) => {
2392
- const { className, "data-testid": dataTestId, helpText, helpAddon, tip, label, isInvalid, errorMessage, name, onBlur, options, value, defaultValue, id, htmlFor: htmlForProp, onChange, children, ref, ...selectProps } = props;
2393
+ const { className, "data-testid": dataTestId, helpText, helpAddon, tip, label, isInvalid, errorMessage, name, onBlur, options, value, defaultValue, id, htmlFor: htmlForProp, onChange, children, ref, onInputChange, ...selectProps } = props;
2394
+ const [inputValue, setInputValue] = useState("");
2393
2395
  // Hidden select for a stable DOM ref target (API parity with single adapter)
2394
2396
  const innerRef = useRef(null);
2397
+ const onInputChangeRef = useRef(undefined);
2395
2398
  // Bridge external ref (supports both callback and object refs)
2396
2399
  useEffect(() => {
2397
2400
  if (typeof ref === "function") {
@@ -2413,6 +2416,20 @@ const FormFieldSelectAdapterMulti = (props) => {
2413
2416
  : undefined, [selectPropsWithAccessors]);
2414
2417
  // Compute selected options snapshot for hidden inputs (prefer controlled `value`)
2415
2418
  const selectedOptions = useMemo(() => value ?? defaultValue ?? [], [value, defaultValue]);
2419
+ useEffect(() => {
2420
+ onInputChangeRef.current = onInputChange;
2421
+ }, [onInputChange]);
2422
+ const handleInputChange = useCallback((nextValue, meta) => {
2423
+ if (IGNORED_RS_ACTIONS.has(meta.action)) {
2424
+ return inputValue; // keep current visible value
2425
+ }
2426
+ if (nextValue !== inputValue) {
2427
+ setInputValue(nextValue);
2428
+ }
2429
+ // Call the latest external callback from ref
2430
+ onInputChangeRef.current?.(nextValue, meta);
2431
+ return nextValue;
2432
+ }, [inputValue]);
2416
2433
  // Build the exact prop bag for BaseSelect (multi=true).
2417
2434
  const childProps = useMemo(() => ({
2418
2435
  ...selectProps,
@@ -2424,7 +2441,9 @@ const FormFieldSelectAdapterMulti = (props) => {
2424
2441
  value: value ?? null,
2425
2442
  defaultValue,
2426
2443
  onChange,
2427
- }), [selectProps, dataTestId, controlId, onBlur, options, value, defaultValue, onChange]);
2444
+ onInputChange: handleInputChange,
2445
+ inputValue,
2446
+ }), [selectProps, dataTestId, controlId, onBlur, options, value, defaultValue, onChange, handleInputChange, inputValue]);
2428
2447
  return (jsxs(FormGroup, { className: className, "data-testid": dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: controlId, isInvalid: renderAsInvalid, label: label, required: "required" in selectProps && selectProps.required
2429
2448
  ? !(("disabled" in selectProps && Boolean(selectProps.disabled)) ||
2430
2449
  ("readOnly" in selectProps && Boolean(selectProps.readOnly)))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-form-components",
3
- "version": "1.8.145",
3
+ "version": "1.8.151",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -14,12 +14,12 @@
14
14
  "zod": "^3.23.8",
15
15
  "react-hook-form": "7.62.0",
16
16
  "tailwind-merge": "^2.0.0",
17
- "@trackunit/css-class-variance-utilities": "1.7.97",
18
- "@trackunit/react-components": "1.10.73",
19
- "@trackunit/ui-icons": "1.7.98",
20
- "@trackunit/shared-utils": "1.9.97",
21
- "@trackunit/ui-design-tokens": "1.7.97",
22
- "@trackunit/i18n-library-translation": "1.7.115",
17
+ "@trackunit/css-class-variance-utilities": "1.7.103",
18
+ "@trackunit/react-components": "1.10.79",
19
+ "@trackunit/ui-icons": "1.7.104",
20
+ "@trackunit/shared-utils": "1.9.103",
21
+ "@trackunit/ui-design-tokens": "1.7.103",
22
+ "@trackunit/i18n-library-translation": "1.7.121",
23
23
  "string-ts": "^2.0.0",
24
24
  "@js-temporal/polyfill": "^0.5.1",
25
25
  "es-toolkit": "^1.39.10",
@@ -1,7 +1,7 @@
1
1
  import { CommonProps } from "@trackunit/react-components";
2
2
  import { MappedOmit } from "@trackunit/shared-utils";
3
3
  import { FocusEvent, ReactElement, ReactNode, Ref } from "react";
4
- import { GroupBase, MultiValue } from "react-select";
4
+ import { GroupBase, InputActionMeta, MultiValue } from "react-select";
5
5
  import { SelectProps } from "../BaseSelect/useSelect";
6
6
  import { FormGroupProps } from "../FormGroup/FormGroup";
7
7
  import { BaseOptionType } from "../SelectField/FormFieldSelectAdapter";
@@ -40,6 +40,8 @@ export type MultiSelectFieldProps<TOption extends BaseOptionType = BaseOptionTyp
40
40
  name?: string;
41
41
  /** Field id; also propagated to BaseSelect via child props */
42
42
  id?: string;
43
+ /** Optional passthrough onInputChange (will be called in addition to internal logic) */
44
+ onInputChange?: (value: string, meta: InputActionMeta) => void;
43
45
  };
44
46
  interface FormFieldSelectAdapterMultiProps<TOption extends BaseOptionType = BaseOptionType, TIsAsync extends boolean = false, TGroup extends GroupBase<TOption> = GroupBase<TOption>> extends MultiSelectFieldProps<TOption, TIsAsync, TGroup> {
45
47
  /**