@trackunit/react-form-components 1.22.26 → 1.22.27

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
@@ -107,12 +107,7 @@ const setupLibraryTranslations = () => {
107
107
  i18nLibraryTranslation.registerTranslations(translations);
108
108
  };
109
109
 
110
- /**
111
- * Builds a synthetic change event for an input with a given value.
112
- * Use when calling onChange from code (e.g. clear, apply, clamped value) so consumers
113
- * that use `onChange={e => setValue(e.target.value)}` still receive the expected shape.
114
- */
115
- function createInputChangeEvent(value, sourceInput) {
110
+ const createSyntheticInputChangeEvent = (value, sourceInput) => {
116
111
  const target = document.createElement("input");
117
112
  target.value = value;
118
113
  if (sourceInput) {
@@ -139,7 +134,17 @@ function createInputChangeEvent(value, sourceInput) {
139
134
  isDefaultPrevented: () => native.defaultPrevented,
140
135
  isPropagationStopped: () => false,
141
136
  };
142
- }
137
+ };
138
+ /**
139
+ * Returns a stable function that builds a synthetic change event for an input with a given value.
140
+ * Use when calling onChange from code (e.g. clear, apply, clamped value) so consumers
141
+ * that use `onChange={e => setValue(e.target.value)}` still receive the expected shape.
142
+ *
143
+ * @example
144
+ * const createInputChangeEvent = useCreateInputChangeEvent();
145
+ * onChange?.(createInputChangeEvent(str, inputRef.current));
146
+ */
147
+ const useCreateInputChangeEvent = () => react.useCallback((value, sourceInput) => createSyntheticInputChangeEvent(value, sourceInput), []);
143
148
 
144
149
  const cvaInputBase = cssClassVarianceUtilities.cvaMerge([
145
150
  "component-baseInput-shadow",
@@ -708,6 +713,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
708
713
  ? (dateAndTimeUtils.parseYYYYMMDDUtil(value) ?? undefined)
709
714
  : parseToDate(isControlled ? value : internalValue);
710
715
  const inputRef = react.useRef(null);
716
+ const createInputChangeEvent = useCreateInputChangeEvent();
711
717
  react.useImperativeHandle(ref, () => inputRef.current ?? document.createElement("input"), []);
712
718
  const syncPendingFromValue = react.useCallback(() => {
713
719
  setPendingDate(selectedDate ?? null);
@@ -728,7 +734,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
728
734
  setInternalValue("");
729
735
  onChange?.(createInputChangeEvent("", inputRef.current));
730
736
  closePopover();
731
- }, [isControlled, onChange]);
737
+ }, [createInputChangeEvent, isControlled, onChange]);
732
738
  const handleCancel = react.useCallback((closePopover) => {
733
739
  closePopover();
734
740
  }, []);
@@ -741,7 +747,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
741
747
  setInternalValue(str);
742
748
  onChange?.(createInputChangeEvent(str, inputRef.current));
743
749
  closePopover();
744
- }, [isControlled, min, max, onChange, pendingDate, timeZoneId]);
750
+ }, [createInputChangeEvent, isControlled, min, max, onChange, pendingDate, timeZoneId]);
745
751
  const handleInputChange = react.useCallback((e) => {
746
752
  const raw = e.target.value;
747
753
  const parsed = parseDateFieldInputForChange(raw, locale);
@@ -759,7 +765,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
759
765
  setInternalValue(raw);
760
766
  onChange?.(e);
761
767
  }
762
- }, [isControlled, locale, min, max, onChange, timeZoneId]);
768
+ }, [createInputChangeEvent, isControlled, locale, min, max, onChange, timeZoneId]);
763
769
  return (jsxRuntime.jsxs(reactComponents.Popover, { onOpenStateChange: open => open && syncPendingFromValue(), placement: "bottom-start", children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("flex w-full min-w-0 cursor-pointer items-center", (Boolean(rest.disabled) || Boolean(rest.readOnly)) && "pointer-events-none"), children: jsxRuntime.jsx(BaseInput, { ...rest, "aria-readonly": true, className: tailwindMerge.twMerge("w-full min-w-0", rest.className), "data-testid": dataTestId ? `${dataTestId}-input` : undefined, onChange: handleInputChange, placeholder: rest.placeholder ?? t("dateField.placeholder"), ref: inputRef, suffix: suffixProp ?? (jsxRuntime.jsx(reactComponents.Icon, { "aria-label": undefined, className: Boolean(rest.disabled) || Boolean(rest.readOnly) ? "text-neutral-500" : undefined, "data-testid": dataTestId ? `${dataTestId}-calendar` : "calendar", name: "Calendar", size: "medium", type: "solid" })), type: "text", value: resolvedValue }) }) }), jsxRuntime.jsx(reactComponents.PopoverContent, { children: closePopover => {
764
770
  const displayDate = pendingDate ?? selectedDate ?? null;
765
771
  return (jsxRuntime.jsxs("div", { className: tailwindMerge.twMerge("flex w-min flex-col overflow-hidden rounded-md border border-neutral-300 bg-white p-0"), children: [jsxRuntime.jsx(ReactCalendar, { allowPartialRange: true, className: tailwindMerge.twMerge("custom-day-picker", "range-picker", "p-0"), defaultActiveStartDate: displayDate ?? undefined, defaultView: "month", locale: locale, onChange: val => {
@@ -5007,6 +5013,7 @@ exports.PhoneBaseInput = PhoneBaseInput;
5007
5013
  exports.PhoneField = PhoneField;
5008
5014
  exports.PhoneFieldWithController = PhoneFieldWithController;
5009
5015
  exports.RadioGroup = RadioGroup;
5016
+ exports.RadioGroupContext = RadioGroupContext;
5010
5017
  exports.RadioItem = RadioItem;
5011
5018
  exports.Schedule = Schedule;
5012
5019
  exports.Search = Search;
@@ -5065,6 +5072,7 @@ exports.parseSchedule = parseSchedule;
5065
5072
  exports.phoneErrorMessage = phoneErrorMessage;
5066
5073
  exports.serializeSchedule = serializeSchedule;
5067
5074
  exports.useCreatableSelect = useCreatableSelect;
5075
+ exports.useCreateInputChangeEvent = useCreateInputChangeEvent;
5068
5076
  exports.useCustomComponents = useCustomComponents;
5069
5077
  exports.useGetPhoneValidationRules = useGetPhoneValidationRules;
5070
5078
  exports.usePhoneInput = usePhoneInput;
package/index.esm.js CHANGED
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { registerTranslations, useNamespaceTranslation, NamespaceTrans } from '@trackunit/i18n-library-translation';
3
3
  import { parseYYYYMMDDUtil, formatShortDateUtil, parseValidDate, toDateUtil, startOfDayUtil, toZonedDateTimeUtil } from '@trackunit/date-and-time-utils';
4
4
  import { IconButton, Icon, Tooltip, Popover, PopoverTrigger, PopoverContent, Button, cvaMenu, cvaMenuList, Tag, useIsTextTruncated, ZStack, MenuItem, useMeasure, useDebounce, useMergeRefs, Spinner, useScrollBlock, Text, Heading, useIsFirstRender } from '@trackunit/react-components';
5
- import { useRef, useEffect, useImperativeHandle, useState, useCallback, cloneElement, isValidElement, useLayoutEffect, useMemo, useReducer, createContext, useContext, useId } from 'react';
5
+ import { useCallback, useRef, useEffect, useImperativeHandle, useState, cloneElement, isValidElement, useLayoutEffect, useMemo, useReducer, createContext, useContext, useId } from 'react';
6
6
  import ReactCalendar from 'react-calendar';
7
7
  import { twMerge } from 'tailwind-merge';
8
8
  import { themeSpacing } from '@trackunit/ui-design-tokens';
@@ -106,12 +106,7 @@ const setupLibraryTranslations = () => {
106
106
  registerTranslations(translations);
107
107
  };
108
108
 
109
- /**
110
- * Builds a synthetic change event for an input with a given value.
111
- * Use when calling onChange from code (e.g. clear, apply, clamped value) so consumers
112
- * that use `onChange={e => setValue(e.target.value)}` still receive the expected shape.
113
- */
114
- function createInputChangeEvent(value, sourceInput) {
109
+ const createSyntheticInputChangeEvent = (value, sourceInput) => {
115
110
  const target = document.createElement("input");
116
111
  target.value = value;
117
112
  if (sourceInput) {
@@ -138,7 +133,17 @@ function createInputChangeEvent(value, sourceInput) {
138
133
  isDefaultPrevented: () => native.defaultPrevented,
139
134
  isPropagationStopped: () => false,
140
135
  };
141
- }
136
+ };
137
+ /**
138
+ * Returns a stable function that builds a synthetic change event for an input with a given value.
139
+ * Use when calling onChange from code (e.g. clear, apply, clamped value) so consumers
140
+ * that use `onChange={e => setValue(e.target.value)}` still receive the expected shape.
141
+ *
142
+ * @example
143
+ * const createInputChangeEvent = useCreateInputChangeEvent();
144
+ * onChange?.(createInputChangeEvent(str, inputRef.current));
145
+ */
146
+ const useCreateInputChangeEvent = () => useCallback((value, sourceInput) => createSyntheticInputChangeEvent(value, sourceInput), []);
142
147
 
143
148
  const cvaInputBase = cvaMerge([
144
149
  "component-baseInput-shadow",
@@ -707,6 +712,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
707
712
  ? (parseYYYYMMDDUtil(value) ?? undefined)
708
713
  : parseToDate(isControlled ? value : internalValue);
709
714
  const inputRef = useRef(null);
715
+ const createInputChangeEvent = useCreateInputChangeEvent();
710
716
  useImperativeHandle(ref, () => inputRef.current ?? document.createElement("input"), []);
711
717
  const syncPendingFromValue = useCallback(() => {
712
718
  setPendingDate(selectedDate ?? null);
@@ -727,7 +733,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
727
733
  setInternalValue("");
728
734
  onChange?.(createInputChangeEvent("", inputRef.current));
729
735
  closePopover();
730
- }, [isControlled, onChange]);
736
+ }, [createInputChangeEvent, isControlled, onChange]);
731
737
  const handleCancel = useCallback((closePopover) => {
732
738
  closePopover();
733
739
  }, []);
@@ -740,7 +746,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
740
746
  setInternalValue(str);
741
747
  onChange?.(createInputChangeEvent(str, inputRef.current));
742
748
  closePopover();
743
- }, [isControlled, min, max, onChange, pendingDate, timeZoneId]);
749
+ }, [createInputChangeEvent, isControlled, min, max, onChange, pendingDate, timeZoneId]);
744
750
  const handleInputChange = useCallback((e) => {
745
751
  const raw = e.target.value;
746
752
  const parsed = parseDateFieldInputForChange(raw, locale);
@@ -758,7 +764,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
758
764
  setInternalValue(raw);
759
765
  onChange?.(e);
760
766
  }
761
- }, [isControlled, locale, min, max, onChange, timeZoneId]);
767
+ }, [createInputChangeEvent, isControlled, locale, min, max, onChange, timeZoneId]);
762
768
  return (jsxs(Popover, { onOpenStateChange: open => open && syncPendingFromValue(), placement: "bottom-start", children: [jsx(PopoverTrigger, { children: jsx("div", { className: twMerge("flex w-full min-w-0 cursor-pointer items-center", (Boolean(rest.disabled) || Boolean(rest.readOnly)) && "pointer-events-none"), children: jsx(BaseInput, { ...rest, "aria-readonly": true, className: twMerge("w-full min-w-0", rest.className), "data-testid": dataTestId ? `${dataTestId}-input` : undefined, onChange: handleInputChange, placeholder: rest.placeholder ?? t("dateField.placeholder"), ref: inputRef, suffix: suffixProp ?? (jsx(Icon, { "aria-label": undefined, className: Boolean(rest.disabled) || Boolean(rest.readOnly) ? "text-neutral-500" : undefined, "data-testid": dataTestId ? `${dataTestId}-calendar` : "calendar", name: "Calendar", size: "medium", type: "solid" })), type: "text", value: resolvedValue }) }) }), jsx(PopoverContent, { children: closePopover => {
763
769
  const displayDate = pendingDate ?? selectedDate ?? null;
764
770
  return (jsxs("div", { className: twMerge("flex w-min flex-col overflow-hidden rounded-md border border-neutral-300 bg-white p-0"), children: [jsx(ReactCalendar, { allowPartialRange: true, className: twMerge("custom-day-picker", "range-picker", "p-0"), defaultActiveStartDate: displayDate ?? undefined, defaultView: "month", locale: locale, onChange: val => {
@@ -4977,4 +4983,4 @@ const useZodValidators = () => {
4977
4983
  */
4978
4984
  setupLibraryTranslations();
4979
4985
 
4980
- export { ActionButton, BaseInput, BaseSelect, Checkbox, CheckboxField, ColorField, CreatableSelect, CreatableSelectField, DEFAULT_TIME, DateBaseInput, DateField, DropZone, DropZoneDefaultLabel, EMAIL_REGEX, EmailField, FormFieldSelectAdapter, FormGroup, Label, MultiSelectField, NumberBaseInput, NumberField, OptionCard, PasswordBaseInput, PasswordField, PhoneBaseInput, PhoneField, PhoneFieldWithController, RadioGroup, RadioItem, Schedule, ScheduleVariant, Search, SelectField, TextAreaBaseInput, TextAreaField, TextBaseInput, TextField, TimeRange, TimeRangeField, ToggleSwitch, ToggleSwitchOption, UploadField, UploadInput, UrlField, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaAccessoriesContainer, cvaActionButton, cvaActionContainer, cvaInput$1 as cvaInput, cvaInputAddon, cvaInputBase, cvaInputBaseDisabled, cvaInputBaseInvalid, cvaInputBaseReadOnly, cvaInputBaseSize, cvaInputElement, cvaInputGroup, cvaInputItemPlacementManager, cvaInputPrefix, cvaInputSuffix, cvaLabel, cvaRadioItem, cvaSelectClearIndicator, cvaSelectContainer, cvaSelectControl, cvaSelectDropdownIconContainer, cvaSelectDropdownIndicator, cvaSelectIndicatorsContainer, cvaSelectLoadingMessage, cvaSelectMenu, cvaSelectMenuList, cvaSelectMultiValue, cvaSelectNoOptionsMessage, cvaSelectPlaceholder, cvaSelectPrefixSuffix, cvaSelectSingleValue, cvaSelectValueContainer, getCountryAbbreviation, getPhoneNumberWithPlus, isInvalidCountryCode, isInvalidPhoneNumber, isValidHEXColor, parseSchedule, phoneErrorMessage, serializeSchedule, useCreatableSelect, useCustomComponents, useGetPhoneValidationRules, usePhoneInput, useRadioItemChecked, useSelect, useZodValidators, validateEmailAddress, validatePhoneNumber, weekDay };
4986
+ export { ActionButton, BaseInput, BaseSelect, Checkbox, CheckboxField, ColorField, CreatableSelect, CreatableSelectField, DEFAULT_TIME, DateBaseInput, DateField, DropZone, DropZoneDefaultLabel, EMAIL_REGEX, EmailField, FormFieldSelectAdapter, FormGroup, Label, MultiSelectField, NumberBaseInput, NumberField, OptionCard, PasswordBaseInput, PasswordField, PhoneBaseInput, PhoneField, PhoneFieldWithController, RadioGroup, RadioGroupContext, RadioItem, Schedule, ScheduleVariant, Search, SelectField, TextAreaBaseInput, TextAreaField, TextBaseInput, TextField, TimeRange, TimeRangeField, ToggleSwitch, ToggleSwitchOption, UploadField, UploadInput, UrlField, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaAccessoriesContainer, cvaActionButton, cvaActionContainer, cvaInput$1 as cvaInput, cvaInputAddon, cvaInputBase, cvaInputBaseDisabled, cvaInputBaseInvalid, cvaInputBaseReadOnly, cvaInputBaseSize, cvaInputElement, cvaInputGroup, cvaInputItemPlacementManager, cvaInputPrefix, cvaInputSuffix, cvaLabel, cvaRadioItem, cvaSelectClearIndicator, cvaSelectContainer, cvaSelectControl, cvaSelectDropdownIconContainer, cvaSelectDropdownIndicator, cvaSelectIndicatorsContainer, cvaSelectLoadingMessage, cvaSelectMenu, cvaSelectMenuList, cvaSelectMultiValue, cvaSelectNoOptionsMessage, cvaSelectPlaceholder, cvaSelectPrefixSuffix, cvaSelectSingleValue, cvaSelectValueContainer, getCountryAbbreviation, getPhoneNumberWithPlus, isInvalidCountryCode, isInvalidPhoneNumber, isValidHEXColor, parseSchedule, phoneErrorMessage, serializeSchedule, useCreatableSelect, useCreateInputChangeEvent, useCustomComponents, useGetPhoneValidationRules, usePhoneInput, useRadioItemChecked, useSelect, useZodValidators, validateEmailAddress, validatePhoneNumber, weekDay };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-form-components",
3
- "version": "1.22.26",
3
+ "version": "1.22.27",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
package/src/index.d.ts CHANGED
@@ -35,6 +35,7 @@ export * from "./components/PhoneField/PhoneField";
35
35
  export * from "./components/PhoneFieldWithController/PhoneFieldWithController";
36
36
  export * from "./components/RadioGroup/RadioGroup";
37
37
  export * from "./components/RadioGroup/RadioGroup.variants";
38
+ export * from "./components/RadioGroup/RadioGroupContext";
38
39
  export * from "./components/RadioGroup/RadioItem";
39
40
  export * from "./components/RadioGroup/useRadioItemChecked";
40
41
  export * from "./components/Schedule/Schedule";
@@ -53,6 +54,7 @@ export * from "./components/UploadField/UploadField";
53
54
  export * from "./components/UploadInput/UploadInput";
54
55
  export * from "./components/UrlField/UrlField";
55
56
  export * from "./utilities/emailUtils";
57
+ export * from "./utilities/useCreateInputChangeEvent";
56
58
  export * from "./utilities/useGetPhoneValidationRules";
57
59
  export * from "./utilities/usePhoneInput";
58
60
  export * from "./utilities/useZodValidators";
@@ -0,0 +1,11 @@
1
+ import { type ChangeEvent } from "react";
2
+ /**
3
+ * Returns a stable function that builds a synthetic change event for an input with a given value.
4
+ * Use when calling onChange from code (e.g. clear, apply, clamped value) so consumers
5
+ * that use `onChange={e => setValue(e.target.value)}` still receive the expected shape.
6
+ *
7
+ * @example
8
+ * const createInputChangeEvent = useCreateInputChangeEvent();
9
+ * onChange?.(createInputChangeEvent(str, inputRef.current));
10
+ */
11
+ export declare const useCreateInputChangeEvent: () => ((value: string, sourceInput: HTMLInputElement | null) => ChangeEvent<HTMLInputElement>);
@@ -1,7 +0,0 @@
1
- import { type ChangeEvent } from "react";
2
- /**
3
- * Builds a synthetic change event for an input with a given value.
4
- * Use when calling onChange from code (e.g. clear, apply, clamped value) so consumers
5
- * that use `onChange={e => setValue(e.target.value)}` still receive the expected shape.
6
- */
7
- export declare function createInputChangeEvent(value: string, sourceInput: HTMLInputElement | null): ChangeEvent<HTMLInputElement>;