@povio/ui 2.2.9-rc.2 → 2.2.9-rc.21

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 (95) hide show
  1. package/dist/components/buttons/InlineIconButton/InlineIconButton.d.ts +1 -1
  2. package/dist/components/buttons/InlineIconButton/InlineIconButton.js +2 -2
  3. package/dist/components/inputs/Checkbox/Checkbox.js +6 -1
  4. package/dist/components/inputs/Checkbox/checkbox.cva.d.ts +3 -0
  5. package/dist/components/inputs/Checkbox/checkbox.cva.js +2 -1
  6. package/dist/components/inputs/DateTime/DatePicker/DatePicker.d.ts +9 -4
  7. package/dist/components/inputs/DateTime/DatePicker/DatePicker.js +97 -9
  8. package/dist/components/inputs/DateTime/DateRangePicker/DateRangePicker.d.ts +9 -4
  9. package/dist/components/inputs/DateTime/DateRangePicker/DateRangePicker.js +116 -7
  10. package/dist/components/inputs/DateTime/DateTimePicker/DateTimePicker.d.ts +10 -4
  11. package/dist/components/inputs/DateTime/DateTimePicker/DateTimePicker.js +92 -7
  12. package/dist/components/inputs/DateTime/TimePicker/TimePicker.d.ts +5 -3
  13. package/dist/components/inputs/DateTime/TimePicker/TimePicker.js +80 -6
  14. package/dist/components/inputs/DateTime/shared/Calendar.d.ts +5 -2
  15. package/dist/components/inputs/DateTime/shared/Calendar.js +23 -6
  16. package/dist/components/inputs/DateTime/shared/CalendarCell.d.ts +1 -1
  17. package/dist/components/inputs/DateTime/shared/CalendarCell.js +3 -3
  18. package/dist/components/inputs/DateTime/shared/CalendarGrid.d.ts +1 -1
  19. package/dist/components/inputs/DateTime/shared/DatePickerInput.d.ts +5 -2
  20. package/dist/components/inputs/DateTime/shared/DatePickerInput.js +21 -12
  21. package/dist/components/inputs/DateTime/shared/TimePickerInput.js +7 -3
  22. package/dist/components/inputs/DateTime/shared/datePicker.types.d.ts +3 -0
  23. package/dist/components/inputs/DateTime/shared/datePickerInput.cva.d.ts +7 -0
  24. package/dist/components/inputs/DateTime/shared/datePickerInput.cva.js +13 -0
  25. package/dist/components/inputs/DateTime/shared/datePickerTodayIcon.d.ts +6 -0
  26. package/dist/components/inputs/DateTime/shared/datePickerTodayIcon.js +20 -0
  27. package/dist/components/inputs/FormField/FormField.d.ts +3 -3
  28. package/dist/components/inputs/FormField/FormFieldHeader.js +3 -1
  29. package/dist/components/inputs/FormField/formFieldHeader.cva.d.ts +6 -0
  30. package/dist/components/inputs/FormField/formFieldHeader.cva.js +11 -0
  31. package/dist/components/inputs/Input/NumberInput/NumberInput.d.ts +5 -2
  32. package/dist/components/inputs/Input/NumberInput/NumberInput.js +92 -8
  33. package/dist/components/inputs/Input/NumberRangeInput/NumberRangeInput.d.ts +38 -0
  34. package/dist/components/inputs/Input/NumberRangeInput/NumberRangeInput.js +318 -0
  35. package/dist/components/inputs/Input/TextInput/TextInput.d.ts +3 -1
  36. package/dist/components/inputs/Input/TextInput/TextInput.js +95 -8
  37. package/dist/components/inputs/Inputs/InputItem.d.ts +15 -18
  38. package/dist/components/inputs/Inputs/InputItem.js +2 -0
  39. package/dist/components/inputs/RadioGroup/RadioGroup.js +17 -9
  40. package/dist/components/inputs/RadioGroup/radio.cva.d.ts +3 -0
  41. package/dist/components/inputs/RadioGroup/radio.cva.js +2 -1
  42. package/dist/components/inputs/Selection/Autocomplete/Autocomplete.d.ts +6 -2
  43. package/dist/components/inputs/Selection/Autocomplete/Autocomplete.js +87 -6
  44. package/dist/components/inputs/Selection/Autocomplete/QueryAutocomplete.d.ts +1 -1
  45. package/dist/components/inputs/Selection/Autocomplete/QueryAutocomplete.js +15 -10
  46. package/dist/components/inputs/Selection/Autocomplete/queryAutocomplete.types.d.ts +25 -19
  47. package/dist/components/inputs/Selection/Select/QuerySelect.d.ts +1 -2
  48. package/dist/components/inputs/Selection/Select/QuerySelect.js +5 -3
  49. package/dist/components/inputs/Selection/Select/Select.d.ts +7 -3
  50. package/dist/components/inputs/Selection/Select/Select.js +86 -4
  51. package/dist/components/inputs/Selection/shared/SelectBase.d.ts +4 -1
  52. package/dist/components/inputs/Selection/shared/SelectBase.js +3 -2
  53. package/dist/components/inputs/Selection/shared/SelectDesktop.d.ts +1 -1
  54. package/dist/components/inputs/Selection/shared/SelectDesktop.js +8 -4
  55. package/dist/components/inputs/Selection/shared/SelectInput.d.ts +2 -2
  56. package/dist/components/inputs/Selection/shared/SelectInput.js +12 -2
  57. package/dist/components/inputs/Selection/shared/SelectListBox.d.ts +2 -2
  58. package/dist/components/inputs/Selection/shared/SelectListBox.js +3 -3
  59. package/dist/components/inputs/Selection/shared/SelectMobile.d.ts +1 -1
  60. package/dist/components/inputs/Selection/shared/SelectMobile.js +5 -3
  61. package/dist/components/inputs/Selection/shared/select.context.d.ts +3 -2
  62. package/dist/components/inputs/Selection/shared/select.context.js +22 -4
  63. package/dist/components/inputs/Selection/shared/select.types.d.ts +3 -2
  64. package/dist/components/inputs/Selection/shared/selectDesktop.cva.d.ts +3 -0
  65. package/dist/components/inputs/Selection/shared/selectDesktop.cva.js +5 -0
  66. package/dist/components/inputs/Selection/shared/staticSelect.utils.d.ts +23 -0
  67. package/dist/components/inputs/Selection/shared/staticSelect.utils.js +35 -0
  68. package/dist/components/inputs/Toggle/Toggle.js +6 -1
  69. package/dist/components/inputs/Toggle/toggle.cva.d.ts +3 -0
  70. package/dist/components/inputs/Toggle/toggle.cva.js +2 -1
  71. package/dist/components/inputs/shared/CheckContent.d.ts +2 -1
  72. package/dist/components/inputs/shared/CheckContent.js +3 -4
  73. package/dist/components/inputs/shared/StaticInput.d.ts +37 -0
  74. package/dist/components/inputs/shared/StaticInput.js +91 -0
  75. package/dist/components/inputs/shared/TooltipWrapper.js +5 -1
  76. package/dist/components/inputs/shared/input.cva.d.ts +5 -0
  77. package/dist/components/inputs/shared/input.cva.js +10 -1
  78. package/dist/components/inputs/shared/tooltipWrapper.cva.d.ts +4 -0
  79. package/dist/components/inputs/shared/tooltipWrapper.cva.js +5 -0
  80. package/dist/config/uiConfig.context.d.ts +8 -2
  81. package/dist/config/uiConfig.context.js +11 -1
  82. package/dist/config/uiStyle.context.d.ts +19 -3
  83. package/dist/helpers/dynamicInputs.d.ts +5 -5
  84. package/dist/helpers/dynamicInputs.js +3 -0
  85. package/dist/hooks/useIntersectionObserver.d.ts +1 -1
  86. package/dist/hooks/useIntersectionObserver.js +29 -10
  87. package/dist/hooks/useQueryAutocomplete.d.ts +5 -16
  88. package/dist/hooks/useQueryAutocomplete.js +13 -3
  89. package/dist/index.d.ts +7 -0
  90. package/dist/index.js +4 -2
  91. package/dist/utils/date-time.utils.d.ts +23 -9
  92. package/dist/utils/date-time.utils.js +97 -1
  93. package/dist/utils/query.utils.d.ts +4 -0
  94. package/dist/utils/query.utils.js +8 -0
  95. package/package.json +1 -1
@@ -0,0 +1,13 @@
1
+ import { cva } from "class-variance-authority";
2
+ //#region src/components/inputs/DateTime/shared/datePickerInput.cva.ts
3
+ var datePickerInputContentRow = cva("flex items-center gap-input-gap-input-text-to-elements", {
4
+ variants: { size: {
5
+ "extra-small": "",
6
+ small: "",
7
+ default: "",
8
+ large: ""
9
+ } },
10
+ defaultVariants: { size: "default" }
11
+ });
12
+ //#endregion
13
+ export { datePickerInputContentRow };
@@ -0,0 +1,6 @@
1
+ import { FC, ReactElement, SVGProps } from 'react';
2
+ import { DatePickerTodayIcon, DatePickerTodayIconButtonSize } from './datePicker.types';
3
+ type TodayIconComponent = FC<SVGProps<SVGSVGElement>> | ReactElement;
4
+ export declare const getDatePickerTodayIcon: (todayIcon: DatePickerTodayIcon | undefined) => TodayIconComponent | null;
5
+ export declare const renderDatePickerTodayIcon: (todayIcon: DatePickerTodayIcon | undefined, size?: DatePickerTodayIconButtonSize, className?: string) => import("react/jsx-runtime").JSX.Element | undefined;
6
+ export {};
@@ -0,0 +1,20 @@
1
+ import { UIStyle } from "../../../../config/uiStyle.context.js";
2
+ import { buttonIconSize } from "../../../buttons/Button/button.cva.js";
3
+ import { TodayIcon } from "../../../../assets/icons/Today.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { clsx } from "clsx";
6
+ import { isValidElement } from "react";
7
+ //#region src/components/inputs/DateTime/shared/datePickerTodayIcon.tsx
8
+ var getDatePickerTodayIcon = (todayIcon) => {
9
+ if (!todayIcon) return null;
10
+ return todayIcon === true ? TodayIcon : todayIcon;
11
+ };
12
+ var renderDatePickerTodayIcon = (todayIcon, size = "none", className) => {
13
+ const buttonIconSizeCva = UIStyle.useCva("button.iconSize", buttonIconSize);
14
+ const icon = getDatePickerTodayIcon(todayIcon);
15
+ if (!icon) return;
16
+ if (isValidElement(icon)) return icon;
17
+ return /* @__PURE__ */ jsx(icon, { className: clsx(buttonIconSizeCva({ size }), "text-interactive-text-secondary-idle", className) });
18
+ };
19
+ //#endregion
20
+ export { getDatePickerTodayIcon, renderDatePickerTodayIcon };
@@ -1,4 +1,4 @@
1
- import { PropsWithChildren, Ref } from 'react';
1
+ import { FocusEventHandler, MouseEventHandler, PropsWithChildren, Ref } from 'react';
2
2
  import { FormFieldErrorProps } from './FormFieldError';
3
3
  import { FormFieldHeaderProps } from './FormFieldHeader';
4
4
  import { TextInputProps } from '../Input/TextInput/TextInput';
@@ -13,8 +13,8 @@ interface FormFieldComponentProps extends PropsWithChildren<FormFieldProps> {
13
13
  labelProps?: FormFieldHeaderProps["labelProps"];
14
14
  as?: TextInputProps["as"];
15
15
  tabIndex?: number;
16
- onMouseEnter?: () => void;
17
- onFocusCapture?: () => void;
16
+ onMouseEnter?: MouseEventHandler<HTMLDivElement>;
17
+ onFocusCapture?: FocusEventHandler<HTMLDivElement>;
18
18
  }
19
19
  export declare const FormField: ({ ref, as, label, tooltipText, helperText, isRequired, rightContent, isDisabled, error, hideLabel, headerClassName, errorClassName, children, className, labelProps, isHeaderHidden, tabIndex, onMouseEnter, onFocusCapture, }: FormFieldComponentProps) => import("react/jsx-runtime").JSX.Element;
20
20
  export {};
@@ -1,14 +1,16 @@
1
1
  import { InfoIcon } from "../../../assets/icons/Info.js";
2
+ import { UIStyle } from "../../../config/uiStyle.context.js";
2
3
  import { Typography } from "../../text/Typography/Typography.js";
3
4
  import { Tooltip as Tooltip$1 } from "../../overlays/Tooltip/Tooltip.js";
4
5
  import { FormFieldLabel } from "./FormFieldLabel.js";
6
+ import { formFieldHeader } from "./formFieldHeader.cva.js";
5
7
  import { jsx, jsxs } from "react/jsx-runtime";
6
8
  import { clsx } from "clsx";
7
9
  import { Focusable } from "react-aria-components";
8
10
  //#region src/components/inputs/FormField/FormFieldHeader.tsx
9
11
  var FormFieldHeader = ({ label, tooltipText, helperText, isRequired, rightContent, isHeaderHidden, isDisabled, className, labelProps }) => {
10
12
  return /* @__PURE__ */ jsxs("div", {
11
- className: clsx(isHeaderHidden ? "sr-only" : "mb-1", className),
13
+ className: clsx(UIStyle.useCva("formField.headerCva", formFieldHeader)({ visible: !isHeaderHidden }), className),
12
14
  children: [/* @__PURE__ */ jsxs("div", {
13
15
  className: "flex items-start justify-between",
14
16
  children: [/* @__PURE__ */ jsxs("div", {
@@ -0,0 +1,6 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ export declare const formFieldHeader: (props?: ({
3
+ visible?: boolean | null | undefined;
4
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
5
+ export interface FormFieldHeaderVariantProps extends VariantProps<typeof formFieldHeader> {
6
+ }
@@ -0,0 +1,11 @@
1
+ import { cva } from "class-variance-authority";
2
+ //#region src/components/inputs/FormField/formFieldHeader.cva.ts
3
+ var formFieldHeader = cva("", {
4
+ variants: { visible: {
5
+ true: "mb-1",
6
+ false: "sr-only"
7
+ } },
8
+ defaultVariants: { visible: true }
9
+ });
10
+ //#endregion
11
+ export { formFieldHeader };
@@ -13,8 +13,11 @@ interface NumberInputBaseProps extends FormFieldProps, InputVariantProps, Omit<I
13
13
  value?: number | null;
14
14
  onChange?: (value: number | null) => void;
15
15
  onBlur?: (e: FocusEvent<HTMLInputElement>) => void;
16
+ autoFocusOnMount?: boolean;
16
17
  }
17
- export type NumberInputProps = NumberInputBaseProps;
18
+ export type NumberInputProps = NumberInputBaseProps & {
19
+ renderStaticInput?: boolean;
20
+ };
18
21
  export type ControlledNumberInputProps<TFieldValues extends FieldValues> = ControlProps<NumberInputProps, TFieldValues>;
19
- export declare const NumberInput: <TFieldValues extends FieldValues>(props: ControlledNumberInputProps<TFieldValues>) => import("react/jsx-runtime").JSX.Element;
22
+ export declare const NumberInput: <TFieldValues extends FieldValues>({ renderStaticInput, ...props }: ControlledNumberInputProps<TFieldValues>) => import("react/jsx-runtime").JSX.Element;
20
23
  export {};
@@ -1,23 +1,25 @@
1
1
  import { UIStyle } from "../../../../config/uiStyle.context.js";
2
+ import { Loader } from "../../../status/Loader/Loader.js";
2
3
  import { UIConfig } from "../../../../config/uiConfig.context.js";
3
4
  import { inputBase } from "../../shared/input.cva.js";
4
5
  import { FormField } from "../../FormField/FormField.js";
6
+ import { StaticInput } from "../../shared/StaticInput.js";
5
7
  import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
6
8
  import { InputContent } from "../shared/InputContent.js";
7
- import { jsx } from "react/jsx-runtime";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
10
  import { clsx } from "clsx";
9
- import { useCallback, useRef } from "react";
11
+ import { isValidElement, useCallback, useEffect, useRef, useState } from "react";
10
12
  import { Input, useLocale } from "react-aria-components";
11
13
  import { useFocusVisible, useNumberField } from "react-aria";
12
14
  import { mergeRefs } from "@react-aria/utils";
13
- import { Controller } from "react-hook-form";
15
+ import { Controller, useWatch } from "react-hook-form";
14
16
  import { useNumberFieldState } from "react-stately";
15
17
  //#region src/components/inputs/Input/NumberInput/NumberInput.tsx
16
18
  var NumberInputBase = (props) => {
17
19
  const ui = UIConfig.useConfig();
18
20
  const inputBaseCva = UIStyle.useCva("input.baseCva", inputBase);
19
21
  const inputRef = useRef(null);
20
- const { ref, inputClassName, label, tooltipText, helperText, isRequired, rightContent, isDisabled, isDirty, headerClassName, errorClassName, isHeaderHidden, error, className, unit, isLoading, action, leadingIcon, trailingIcon, value, onChange, onBlur, formatOptions = ui.numberInput.formatOptions, variant = ui.input.variant, as = ui.input.as, size = ui.input.size, hideLabel = ui.input.hideLabel, isClearable = ui.input.isClearable, ...rest } = props;
22
+ const { ref, inputClassName, label, tooltipText, helperText, isRequired, rightContent, isDisabled, isDirty, headerClassName, errorClassName, isHeaderHidden, error, className, unit, isLoading, action, leadingIcon, trailingIcon, value, onChange, onBlur, formatOptions = ui.numberInput.formatOptions, variant = ui.input.variant, as = ui.input.as, size = ui.input.size, hideLabel = ui.input.hideLabel, isClearable = ui.input.isClearable, autoFocusOnMount, ...rest } = props;
21
23
  const numberFieldRef = useRef(null);
22
24
  const { isFocusVisible } = useFocusVisible();
23
25
  const { locale } = useLocale();
@@ -34,6 +36,10 @@ var NumberInputBase = (props) => {
34
36
  formatOptions
35
37
  };
36
38
  const { labelProps, inputProps } = useNumberField(numberProps, useNumberFieldState(numberProps), numberFieldRef);
39
+ useEffect(() => {
40
+ if (!autoFocusOnMount || isDisabled) return;
41
+ requestAnimationFrame(() => inputRef.current?.focus());
42
+ }, [autoFocusOnMount, isDisabled]);
37
43
  const formFieldProps = {
38
44
  error,
39
45
  label,
@@ -114,7 +120,80 @@ var NumberInputBase = (props) => {
114
120
  })
115
121
  });
116
122
  };
117
- var NumberInput = (props) => {
123
+ var renderIconVisual = (icon) => {
124
+ if (!icon) return null;
125
+ if (isValidElement(icon)) return icon;
126
+ return /* @__PURE__ */ jsx(icon, { className: "size-6 text-interactive-text-secondary-idle" });
127
+ };
128
+ var NumberInput = ({ renderStaticInput, ...props }) => {
129
+ const ui = UIConfig.useConfig();
130
+ const { locale } = useLocale();
131
+ const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
132
+ const [shouldFocus, setShouldFocus] = useState(false);
133
+ const inputRef = useRef(null);
134
+ const watchedValue = "formControl" in props && props.formControl ? useWatch({
135
+ control: props.formControl.control,
136
+ name: props.formControl.name
137
+ }) : props.value;
138
+ let isFormControlDisabled = false;
139
+ if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
140
+ useEffect(() => {
141
+ if (!renderInput || !shouldFocus) return;
142
+ requestAnimationFrame(() => inputRef.current?.focus());
143
+ setShouldFocus(false);
144
+ }, [renderInput, shouldFocus]);
145
+ if (!renderInput) {
146
+ const staticValue = watchedValue ?? props.value ?? props.defaultValue;
147
+ const formatOptions = props.formatOptions ?? ui.numberInput.formatOptions;
148
+ const displayValue = staticValue == null ? "" : new Intl.NumberFormat(locale, formatOptions).format(staticValue);
149
+ const hasValue = displayValue !== "";
150
+ const as = props.as ?? ui.input.as;
151
+ const size = props.size ?? ui.input.size;
152
+ const variant = props.variant ?? ui.input.variant;
153
+ const hideLabel = props.hideLabel ?? ui.input.hideLabel;
154
+ const isHeaderHidden = props.isHeaderHidden || as === "inline" || as === "filter" || as === "floating";
155
+ let isDisabled = !!props.isDisabled;
156
+ if (isFormControlDisabled) isDisabled = true;
157
+ const trailingContent = !!props.unit || !!props.isLoading || !!props.action && !props.isLoading || !!props.trailingIcon && !props.isLoading && !props.action ? /* @__PURE__ */ jsxs(Fragment, { children: [
158
+ props.unit && /* @__PURE__ */ jsx("span", {
159
+ className: "text-label-2 text-text-default-3",
160
+ children: props.unit
161
+ }),
162
+ props.isLoading && /* @__PURE__ */ jsx(Loader, {}),
163
+ !props.isLoading && props.action && renderIconVisual(props.action.icon),
164
+ !props.isLoading && !props.action && props.trailingIcon && renderIconVisual(props.trailingIcon)
165
+ ] }) : void 0;
166
+ return /* @__PURE__ */ jsx(StaticInput, {
167
+ ...props,
168
+ onInteract: (focus) => {
169
+ setShouldFocus(focus);
170
+ setRenderInput(true);
171
+ },
172
+ as,
173
+ size,
174
+ variant,
175
+ hideLabel,
176
+ isHeaderHidden,
177
+ isDisabled,
178
+ className: clsx("group w-full", as === "inline" && "h-full", props.className),
179
+ inputClassName: props.inputClassName,
180
+ placeholder: props.placeholder,
181
+ displayValue,
182
+ isEmpty: !hasValue,
183
+ dataAttributes: {
184
+ dataIsEmpty: !staticValue,
185
+ dataIsFilled: !(`${staticValue}` === "" || staticValue === null || staticValue === void 0),
186
+ dataIsDirty: props.isDirty,
187
+ dataIsRequired: props.isRequired,
188
+ dataIsDisabled: isDisabled,
189
+ dataDisabled: isDisabled,
190
+ dataInvalid: !!props.error,
191
+ dataHasSelection: hasValue
192
+ },
193
+ leadingVisual: renderIconVisual(props.leadingIcon),
194
+ trailingContent
195
+ });
196
+ }
118
197
  if ("formControl" in props && props.formControl) {
119
198
  const { formControl, ref, ...innerProps } = props;
120
199
  return /* @__PURE__ */ jsx(Controller, {
@@ -122,17 +201,22 @@ var NumberInput = (props) => {
122
201
  name: formControl.name,
123
202
  render: ({ field, fieldState: { error, isDirty } }) => /* @__PURE__ */ jsx(NumberInputBase, {
124
203
  ...innerProps,
125
- ref: mergeRefs(ref, field.ref),
204
+ ref: mergeRefs(ref, field.ref, inputRef),
126
205
  value: field.value,
127
206
  onChange: field.onChange,
128
207
  onBlur: field.onBlur,
129
208
  isDirty,
130
209
  isDisabled: field.disabled || props.isDisabled,
131
- error: props.error ?? error?.message
210
+ error: props.error ?? error?.message,
211
+ autoFocusOnMount: shouldFocus
132
212
  }, field.value === null || field.value === void 0 ? "empty" : "filled")
133
213
  });
134
214
  }
135
- return /* @__PURE__ */ jsx(NumberInputBase, { ...props }, props.value === null || props.value === void 0 ? "empty" : "filled");
215
+ return /* @__PURE__ */ jsx(NumberInputBase, {
216
+ ...props,
217
+ ref: mergeRefs(props.ref, inputRef),
218
+ autoFocusOnMount: shouldFocus
219
+ }, props.value === null || props.value === void 0 ? "empty" : "filled");
136
220
  };
137
221
  //#endregion
138
222
  export { NumberInput };
@@ -0,0 +1,38 @@
1
+ import { FocusEvent, Ref } from 'react';
2
+ import { NumberFieldProps as AriaNumberFieldProps } from 'react-aria-components';
3
+ import { FieldValues } from 'react-hook-form';
4
+ import { FormFieldProps } from '../../FormField/FormField';
5
+ import { ControlProps } from '../../shared/form.types';
6
+ import { InputVariantProps } from '../../shared/input.cva';
7
+ export interface NumberRangeValue {
8
+ min: number | null;
9
+ max: number | null;
10
+ }
11
+ interface NumberRangeInputBaseProps extends FormFieldProps, InputVariantProps, Omit<AriaNumberFieldProps, "className" | "defaultValue" | "label" | "maxValue" | "minValue" | "onBlur" | "onChange" | "value"> {
12
+ ref?: Ref<HTMLDivElement>;
13
+ value?: NumberRangeValue | null;
14
+ minValue?: number | null;
15
+ maxValue?: number | null;
16
+ minPlaceholder?: string;
17
+ maxPlaceholder?: string;
18
+ minLabel?: string;
19
+ maxLabel?: string;
20
+ invalidRangeError?: string;
21
+ inputClassName?: string;
22
+ minInputClassName?: string;
23
+ maxInputClassName?: string;
24
+ hideInnerLabels?: boolean;
25
+ isDirty?: boolean;
26
+ isClearable?: boolean;
27
+ autoFocusOnMount?: boolean;
28
+ onChange?: (value: NumberRangeValue) => void;
29
+ onMinChange?: (value: number | null) => void;
30
+ onMaxChange?: (value: number | null) => void;
31
+ onBlur?: (e: FocusEvent<HTMLInputElement>) => void;
32
+ }
33
+ export type NumberRangeInputProps = NumberRangeInputBaseProps & {
34
+ renderStaticInput?: boolean;
35
+ };
36
+ export type ControlledNumberRangeInputProps<TFieldValues extends FieldValues> = ControlProps<NumberRangeInputProps, TFieldValues>;
37
+ export declare const NumberRangeInput: <TFieldValues extends FieldValues>({ renderStaticInput, ...props }: ControlledNumberRangeInputProps<TFieldValues>) => import("react/jsx-runtime").JSX.Element;
38
+ export {};
@@ -0,0 +1,318 @@
1
+ import { UIStyle } from "../../../../config/uiStyle.context.js";
2
+ import { UIConfig } from "../../../../config/uiConfig.context.js";
3
+ import { FormFieldLabel } from "../../FormField/FormFieldLabel.js";
4
+ import { InputClear } from "../../shared/InputClear.js";
5
+ import { inputBase, inputSize } from "../../shared/input.cva.js";
6
+ import { FormField } from "../../FormField/FormField.js";
7
+ import { StaticInput } from "../../shared/StaticInput.js";
8
+ import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ import { clsx } from "clsx";
11
+ import { useEffect, useRef, useState } from "react";
12
+ import { Input, useLocale } from "react-aria-components";
13
+ import { useFocusVisible, useFocusWithin, useHover, useNumberField } from "react-aria";
14
+ import { mergeRefs } from "@react-aria/utils";
15
+ import { Controller, useWatch } from "react-hook-form";
16
+ import { useNumberFieldState } from "react-stately";
17
+ //#region src/components/inputs/Input/NumberRangeInput/NumberRangeInput.tsx
18
+ var EMPTY_RANGE = {
19
+ min: null,
20
+ max: null
21
+ };
22
+ var normalizeRangeValue = (value, minValue, maxValue) => {
23
+ if (value) return value;
24
+ return {
25
+ min: minValue ?? null,
26
+ max: maxValue ?? null
27
+ };
28
+ };
29
+ var NumberRangeField = ({ label, value, placeholder, isDisabled, isInvalid, isRequired, formatOptions, hideInnerLabels, autoFocusOnMount, className, onChange, onBlur, ...rest }) => {
30
+ const ui = UIConfig.useConfig();
31
+ const { locale } = useLocale();
32
+ const { isFocusVisible } = useFocusVisible();
33
+ const inputRef = useRef(null);
34
+ const numberFieldRef = useRef(null);
35
+ useEffect(() => {
36
+ if (!autoFocusOnMount || isDisabled) return;
37
+ requestAnimationFrame(() => inputRef.current?.focus());
38
+ }, [autoFocusOnMount, isDisabled]);
39
+ const numberProps = {
40
+ ...rest,
41
+ label,
42
+ value: value ?? void 0,
43
+ placeholder,
44
+ isDisabled,
45
+ isInvalid,
46
+ isRequired,
47
+ onChange,
48
+ onBlur: (e) => onBlur?.({ target: e.target }),
49
+ locale,
50
+ formatOptions: formatOptions ?? ui.numberInput.formatOptions
51
+ };
52
+ const { labelProps, inputProps } = useNumberField(numberProps, useNumberFieldState(numberProps), numberFieldRef);
53
+ return /* @__PURE__ */ jsxs("div", {
54
+ className: "min-w-0 flex-1",
55
+ children: [/* @__PURE__ */ jsx(FormFieldLabel, {
56
+ label,
57
+ labelProps,
58
+ isRequired,
59
+ isDisabled,
60
+ className: clsx(hideInnerLabels && "sr-only")
61
+ }), /* @__PURE__ */ jsx(Input, {
62
+ ...inputProps,
63
+ ref: mergeRefs(inputRef, numberFieldRef),
64
+ placeholder: inputProps.placeholder,
65
+ className: clsx("w-full bg-transparent outline-none", className),
66
+ onFocus: (e) => {
67
+ inputProps.onFocus?.(e);
68
+ if (isFocusVisible) e.target.select();
69
+ }
70
+ })]
71
+ });
72
+ };
73
+ var NumberRangeInputBase = (props) => {
74
+ const ui = UIConfig.useConfig();
75
+ const inputBaseCva = UIStyle.useCva("input.baseCva", inputBase);
76
+ const inputSizeCva = UIStyle.useCva("input.sizeCva", inputSize);
77
+ const { ref, label, tooltipText, helperText, isRequired, rightContent, isDisabled, headerClassName, errorClassName, isHeaderHidden, error, className, inputClassName, minInputClassName, maxInputClassName, value, minValue, maxValue, minPlaceholder = "Min", maxPlaceholder = "Max", minLabel = "Minimum", maxLabel = "Maximum", invalidRangeError = "Minimum cannot be greater than maximum", hideInnerLabels = true, isDirty, autoFocusOnMount, onChange, onMinChange, onMaxChange, onBlur, isClearable: isClearableProps, as: asProp, variant: variantProps, size: sizeProps, hideLabel: hideLabelProps, ...rest } = props;
78
+ const isClearable = isClearableProps ?? ui.input.isClearable;
79
+ const as = asProp ?? ui.input.as;
80
+ const variant = variantProps ?? ui.input.variant;
81
+ const size = sizeProps ?? ui.input.size;
82
+ const hideLabel = hideLabelProps ?? ui.input.hideLabel;
83
+ const rangeValue = normalizeRangeValue(value, minValue, maxValue);
84
+ const isEmpty = rangeValue.min === null && rangeValue.max === null;
85
+ const rangeError = rangeValue.min !== null && rangeValue.max !== null && rangeValue.min > rangeValue.max ? invalidRangeError : void 0;
86
+ const effectiveError = error || rangeError;
87
+ const { hoverProps, isHovered } = useHover({ isDisabled });
88
+ const { isFocusVisible } = useFocusVisible();
89
+ const [isFocused, setIsFocused] = useState(false);
90
+ const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setIsFocused });
91
+ const formFieldProps = {
92
+ error: effectiveError,
93
+ label,
94
+ tooltipText,
95
+ helperText,
96
+ isRequired,
97
+ rightContent,
98
+ isHeaderHidden: isHeaderHidden || as === "inline" || as === "filter" || as === "floating",
99
+ hideLabel,
100
+ isDisabled,
101
+ headerClassName,
102
+ errorClassName
103
+ };
104
+ const headerProps = {
105
+ label,
106
+ tooltipText,
107
+ helperText,
108
+ isRequired,
109
+ rightContent,
110
+ isHeaderHidden: hideLabel || isHeaderHidden,
111
+ isDisabled,
112
+ className: headerClassName
113
+ };
114
+ const updateRange = (side, nextValue) => {
115
+ const nextRange = {
116
+ ...rangeValue,
117
+ [side]: nextValue
118
+ };
119
+ onChange?.(nextRange);
120
+ if (side === "min") onMinChange?.(nextValue);
121
+ else onMaxChange?.(nextValue);
122
+ };
123
+ const onClear = () => {
124
+ const nextRange = { ...EMPTY_RANGE };
125
+ onChange?.(nextRange);
126
+ onMinChange?.(null);
127
+ onMaxChange?.(null);
128
+ onBlur?.({ target: { value: "" } });
129
+ };
130
+ return /* @__PURE__ */ jsx(TooltipWrapper, {
131
+ as,
132
+ error: effectiveError,
133
+ triggerTabIndex: as === "inline" ? -1 : void 0,
134
+ children: /* @__PURE__ */ jsx(FormField, {
135
+ ...formFieldProps,
136
+ ref,
137
+ as,
138
+ className: clsx("group w-full", className),
139
+ tabIndex: as === "inline" ? -1 : void 0,
140
+ children: /* @__PURE__ */ jsxs("div", {
141
+ className: clsx(inputBaseCva({
142
+ variant,
143
+ as
144
+ }), "group/date-picker-content relative flex min-w-input-width-min-width items-center justify-between gap-2", inputClassName),
145
+ "data-rac": "",
146
+ "data-hovered": isHovered || void 0,
147
+ "data-disabled": isDisabled || void 0,
148
+ "data-invalid": !!effectiveError || void 0,
149
+ "data-is-empty": isEmpty || void 0,
150
+ "data-focus-within": isFocused || void 0,
151
+ "data-focus-visible": isFocused && isFocusVisible || void 0,
152
+ "data-has-selection": !isEmpty || void 0,
153
+ "data-is-dirty": isDirty || void 0,
154
+ "data-is-required": isRequired || void 0,
155
+ "data-is-filled": !isEmpty || void 0,
156
+ ...focusWithinProps,
157
+ ...hoverProps,
158
+ children: [/* @__PURE__ */ jsxs("div", {
159
+ className: clsx("flex w-full items-center gap-input-gap-input-text-to-elements pr-0!", inputSizeCva({
160
+ size,
161
+ as
162
+ })),
163
+ children: [
164
+ as && ["filter", "floating"].includes(as) && headerProps && /* @__PURE__ */ jsx(FormFieldLabel, {
165
+ as,
166
+ ...headerProps
167
+ }),
168
+ /* @__PURE__ */ jsx(NumberRangeField, {
169
+ ...rest,
170
+ label: minLabel,
171
+ placeholder: minPlaceholder,
172
+ value: rangeValue.min,
173
+ onChange: (nextValue) => {
174
+ updateRange("min", nextValue);
175
+ },
176
+ onBlur,
177
+ isDisabled,
178
+ isInvalid: !!effectiveError,
179
+ isRequired,
180
+ hideInnerLabels,
181
+ autoFocusOnMount,
182
+ className: minInputClassName
183
+ }),
184
+ /* @__PURE__ */ jsx("span", {
185
+ className: clsx("pointer-events-none shrink-0 select-none text-label-2 text-text-default-3", isDisabled && "text-interactive-text-secondary-disabled"),
186
+ children: "-"
187
+ }),
188
+ /* @__PURE__ */ jsx(NumberRangeField, {
189
+ ...rest,
190
+ label: maxLabel,
191
+ placeholder: maxPlaceholder,
192
+ value: rangeValue.max,
193
+ onChange: (nextValue) => {
194
+ updateRange("max", nextValue);
195
+ },
196
+ onBlur,
197
+ isDisabled,
198
+ isInvalid: !!effectiveError,
199
+ isRequired,
200
+ hideInnerLabels,
201
+ className: maxInputClassName
202
+ })
203
+ ]
204
+ }), /* @__PURE__ */ jsx("div", {
205
+ className: clsx("flex items-center gap-input-gap-trailing-elements py-0! pl-0!", inputSizeCva({
206
+ size,
207
+ as
208
+ })),
209
+ children: isClearable && /* @__PURE__ */ jsx(InputClear, {
210
+ onClear,
211
+ show: !isEmpty && !isDisabled
212
+ })
213
+ })]
214
+ })
215
+ })
216
+ });
217
+ };
218
+ var NumberRangeInput = ({ renderStaticInput, ...props }) => {
219
+ const ui = UIConfig.useConfig();
220
+ const { locale } = useLocale();
221
+ const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
222
+ const [shouldFocus, setShouldFocus] = useState(false);
223
+ const watchedValue = "formControl" in props && props.formControl ? useWatch({
224
+ control: props.formControl.control,
225
+ name: props.formControl.name
226
+ }) : props.value;
227
+ let isFormControlDisabled = false;
228
+ if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
229
+ useEffect(() => {
230
+ if (!renderInput || !shouldFocus) return;
231
+ setShouldFocus(false);
232
+ }, [renderInput, shouldFocus]);
233
+ if (!renderInput) {
234
+ const staticValue = normalizeRangeValue(watchedValue, props.minValue, props.maxValue);
235
+ const formatOptions = props.formatOptions ?? ui.numberInput.formatOptions;
236
+ const formatter = new Intl.NumberFormat(locale, formatOptions);
237
+ const minDisplay = staticValue.min == null ? null : formatter.format(staticValue.min);
238
+ const maxDisplay = staticValue.max == null ? null : formatter.format(staticValue.max);
239
+ const hasValue = minDisplay !== "" || maxDisplay !== "";
240
+ const displayValue = /* @__PURE__ */ jsxs(Fragment, { children: [
241
+ /* @__PURE__ */ jsx("span", {
242
+ className: clsx("w-full bg-transparent outline-none", minDisplay ? props.minInputClassName : "text-text-default-3"),
243
+ children: minDisplay ?? props.minPlaceholder
244
+ }),
245
+ /* @__PURE__ */ jsx("span", {
246
+ className: "pointer-events-none shrink-0 select-none text-label-2 text-text-default-3",
247
+ children: "-"
248
+ }),
249
+ /* @__PURE__ */ jsx("span", {
250
+ className: clsx("w-full bg-transparent outline-none", maxDisplay ? props.maxInputClassName : "text-text-default-3"),
251
+ children: maxDisplay ?? props.maxPlaceholder
252
+ })
253
+ ] });
254
+ const rangeError = staticValue.min !== null && staticValue.max !== null && staticValue.min > staticValue.max ? props.invalidRangeError ?? "Minimum cannot be greater than maximum" : void 0;
255
+ const effectiveError = props.error || rangeError;
256
+ const as = props.as ?? ui.input.as;
257
+ const size = props.size ?? ui.input.size;
258
+ const variant = props.variant ?? ui.input.variant;
259
+ const hideLabel = props.hideLabel ?? ui.input.hideLabel;
260
+ const isHeaderHidden = props.isHeaderHidden || as === "inline" || as === "filter" || as === "floating";
261
+ let isDisabled = !!props.isDisabled;
262
+ if (isFormControlDisabled) isDisabled = true;
263
+ return /* @__PURE__ */ jsx(StaticInput, {
264
+ ...props,
265
+ error: effectiveError,
266
+ onInteract: (focus) => {
267
+ setShouldFocus(focus);
268
+ setRenderInput(true);
269
+ },
270
+ as,
271
+ size,
272
+ variant,
273
+ hideLabel,
274
+ isHeaderHidden,
275
+ isDisabled,
276
+ className: clsx("group w-full", as === "inline" && "h-full", props.className),
277
+ inputClassName: props.inputClassName,
278
+ displayValue,
279
+ trailingContent: /* @__PURE__ */ jsx(InputClear, {
280
+ show: !hasValue && !props.isDisabled && props.isClearable,
281
+ onClear: () => {}
282
+ }),
283
+ dataAttributes: {
284
+ dataIsEmpty: !hasValue,
285
+ dataIsFilled: hasValue,
286
+ dataIsDirty: props.isDirty,
287
+ dataIsRequired: props.isRequired,
288
+ dataIsDisabled: isDisabled,
289
+ dataDisabled: isDisabled,
290
+ dataInvalid: !!effectiveError,
291
+ dataHasSelection: hasValue
292
+ }
293
+ });
294
+ }
295
+ if ("formControl" in props && props.formControl) {
296
+ const { formControl, ref, ...innerProps } = props;
297
+ return /* @__PURE__ */ jsx(Controller, {
298
+ control: formControl.control,
299
+ name: formControl.name,
300
+ render: ({ field, fieldState: { error } }) => /* @__PURE__ */ jsx(NumberRangeInputBase, {
301
+ ...innerProps,
302
+ ref,
303
+ value: field.value ?? EMPTY_RANGE,
304
+ onChange: field.onChange,
305
+ onBlur: field.onBlur,
306
+ isDisabled: field.disabled || props.isDisabled,
307
+ error: props.error ?? error?.message,
308
+ autoFocusOnMount: shouldFocus
309
+ })
310
+ });
311
+ }
312
+ return /* @__PURE__ */ jsx(NumberRangeInputBase, {
313
+ ...props,
314
+ autoFocusOnMount: shouldFocus
315
+ });
316
+ };
317
+ //#endregion
318
+ export { NumberRangeInput };
@@ -13,9 +13,11 @@ interface TextInputBaseProps extends FormFieldProps, InputVariantProps, Omit<Inp
13
13
  type?: AllowedHTMLInputTypeAttribute;
14
14
  todayIcon?: boolean;
15
15
  isDirty?: boolean;
16
+ autoFocusOnMount?: boolean;
16
17
  }
17
18
  export interface TextInputProps extends TextInputBaseProps {
19
+ renderStaticInput?: boolean;
18
20
  }
19
21
  export type ControlledTextInputProps<TFieldValues extends FieldValues> = ControlProps<TextInputProps, TFieldValues>;
20
- export declare const TextInput: <TFieldValues extends FieldValues>(props: ControlledTextInputProps<TFieldValues>) => import("react/jsx-runtime").JSX.Element;
22
+ export declare const TextInput: <TFieldValues extends FieldValues>({ renderStaticInput, ...props }: ControlledTextInputProps<TFieldValues>) => import("react/jsx-runtime").JSX.Element;
21
23
  export {};