@povio/ui 2.2.9-rc.32 → 2.2.9-rc.34

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.
@@ -11,10 +11,11 @@ import { getStaticCalendarDateSegments } from "../shared/staticDateTimeSegments.
11
11
  import { FormField } from "../../FormField/FormField.js";
12
12
  import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
13
13
  import { InputFrame } from "../../Skeleton/InputFrame.js";
14
+ import { useStaticInputHandoff } from "../../shared/useStaticInputHandoff.js";
14
15
  import { useDebounceCallback } from "../../../../hooks/useDebounceCallback.js";
15
16
  import { jsx, jsxs } from "react/jsx-runtime";
16
17
  import { clsx } from "clsx";
17
- import { useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
18
+ import { useImperativeHandle, useMemo, useRef, useState } from "react";
18
19
  import { useDatePicker, useLocale } from "react-aria";
19
20
  import { mergeRefs } from "@react-aria/utils";
20
21
  import { Controller, useWatch } from "react-hook-form";
@@ -176,8 +177,15 @@ var DatePicker = ({ fullIso = true, minValue, maxValue, renderStaticInput, ...pr
176
177
  const { locale } = useLocale();
177
178
  const shouldForceLeadingZeros = props.shouldForceLeadingZeros ?? ui.dateInput.shouldForceLeadingZeros;
178
179
  const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
179
- const [shouldFocus, setShouldFocus] = useState(false);
180
180
  const inputRef = useRef(null);
181
+ const { renderRealInput } = useStaticInputHandoff({
182
+ inputRef,
183
+ renderInput,
184
+ setRenderInput,
185
+ getFocusTarget: (input) => {
186
+ return (input.getContainer?.() ?? input).querySelector("input, button, [tabindex]:not([tabindex='-1'])");
187
+ }
188
+ });
181
189
  const watchedValue = "formControl" in props && props.formControl ? useWatch({
182
190
  control: props.formControl.control,
183
191
  name: props.formControl.name
@@ -201,13 +209,6 @@ var DatePicker = ({ fullIso = true, minValue, maxValue, renderStaticInput, ...pr
201
209
  minValue: typeof minValue === "string" ? parseCalendarDate(minValue) : minValue,
202
210
  maxValue: typeof maxValue === "string" ? parseCalendarDate(maxValue) : maxValue
203
211
  };
204
- useEffect(() => {
205
- if (!renderInput || !shouldFocus) return;
206
- requestAnimationFrame(() => {
207
- ((inputRef.current?.getContainer?.() ?? inputRef.current)?.querySelector("input, button, [tabindex]:not([tabindex='-1'])"))?.focus();
208
- });
209
- setShouldFocus(false);
210
- }, [renderInput, shouldFocus]);
211
212
  if (!renderInput) {
212
213
  const dateValue = rawValue ? parseCalendarDate(rawValue) : null;
213
214
  const as = props.as ?? ui.input.as;
@@ -245,10 +246,7 @@ var DatePicker = ({ fullIso = true, minValue, maxValue, renderStaticInput, ...pr
245
246
  dataHasSelection: dateValue !== null
246
247
  },
247
248
  renderStatic: true,
248
- onStaticInteract: (focus) => {
249
- setShouldFocus(focus);
250
- setRenderInput(true);
251
- },
249
+ onStaticInteract: renderRealInput,
252
250
  actionContent: staticTodayIcon,
253
251
  actionContentPlacement: todayIconPlacement === "fieldLabel" ? "content-row" : "content-wrapper",
254
252
  trailingContent: showDropdown ? ui.dateInput.calendarIcon : void 0,
@@ -12,11 +12,12 @@ import { getStaticDateRangeSegments } from "../shared/staticDateTimeSegments.js"
12
12
  import { FormField } from "../../FormField/FormField.js";
13
13
  import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
14
14
  import { InputFrame } from "../../Skeleton/InputFrame.js";
15
+ import { useStaticInputHandoff } from "../../shared/useStaticInputHandoff.js";
15
16
  import { useDebounceCallback } from "../../../../hooks/useDebounceCallback.js";
16
17
  import { RangeCalendar } from "../shared/RangeCalendar.js";
17
18
  import { jsx, jsxs } from "react/jsx-runtime";
18
19
  import { clsx } from "clsx";
19
- import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
20
+ import { useCallback, useImperativeHandle, useMemo, useRef, useState } from "react";
20
21
  import { Button } from "react-aria-components";
21
22
  import { useDateRangePicker, useLocale as useLocale$1 } from "react-aria";
22
23
  import { mergeRefs } from "@react-aria/utils";
@@ -552,8 +553,15 @@ var DateRangePicker = ({ fullIso = true, minValue, maxValue, renderStaticInput,
552
553
  const { locale } = useLocale$1();
553
554
  const shouldForceLeadingZeros = props.shouldForceLeadingZeros ?? ui.dateInput.shouldForceLeadingZeros;
554
555
  const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
555
- const [shouldFocus, setShouldFocus] = useState(false);
556
556
  const inputRef = useRef(null);
557
+ const { renderRealInput } = useStaticInputHandoff({
558
+ inputRef,
559
+ renderInput,
560
+ setRenderInput,
561
+ getFocusTarget: (input) => {
562
+ return (input.getContainer?.() ?? input).querySelector("input, button, [tabindex]:not([tabindex='-1'])");
563
+ }
564
+ });
557
565
  const watchedValue = "formControl" in props && props.formControl ? useWatch({
558
566
  control: props.formControl.control,
559
567
  name: props.formControl.name
@@ -599,13 +607,6 @@ var DateRangePicker = ({ fullIso = true, minValue, maxValue, renderStaticInput,
599
607
  minValue: typeof minValue === "string" ? parseCalendarDate(minValue) : minValue,
600
608
  maxValue: typeof maxValue === "string" ? parseCalendarDate(maxValue) : maxValue
601
609
  };
602
- useEffect(() => {
603
- if (!renderInput || !shouldFocus) return;
604
- requestAnimationFrame(() => {
605
- ((inputRef.current?.getContainer?.() ?? inputRef.current)?.querySelector("input, button, [tabindex]:not([tabindex='-1'])"))?.focus();
606
- });
607
- setShouldFocus(false);
608
- }, [renderInput, shouldFocus]);
609
610
  if (!renderInput) {
610
611
  const startDateValue = parseCalendarDate(rawValue?.start ?? null);
611
612
  const endDateValue = parseCalendarDate(rawValue?.end ?? null);
@@ -646,10 +647,7 @@ var DateRangePicker = ({ fullIso = true, minValue, maxValue, renderStaticInput,
646
647
  dataHasSelection: hasProvidedRangeValue
647
648
  },
648
649
  renderStatic: true,
649
- onStaticInteract: (focus) => {
650
- setShouldFocus(focus);
651
- setRenderInput(true);
652
- },
650
+ onStaticInteract: renderRealInput,
653
651
  actionContent: staticTodayIcon,
654
652
  actionContentPlacement: todayIconPlacement === "fieldLabel" ? "content-row" : "content-wrapper",
655
653
  trailingContent: showDropdown ? ui.dateInput.calendarIcon : void 0,
@@ -11,6 +11,7 @@ import { getStaticCalendarDateTimeSegments } from "../shared/staticDateTimeSegme
11
11
  import { FormField } from "../../FormField/FormField.js";
12
12
  import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
13
13
  import { InputFrame } from "../../Skeleton/InputFrame.js";
14
+ import { useStaticInputHandoff } from "../../shared/useStaticInputHandoff.js";
14
15
  import { useDebounceCallback } from "../../../../hooks/useDebounceCallback.js";
15
16
  import { jsx, jsxs } from "react/jsx-runtime";
16
17
  import { clsx } from "clsx";
@@ -197,8 +198,15 @@ var DateTimePicker = ({ fullIso = true, renderStaticInput, ...props }) => {
197
198
  const { locale } = useLocale();
198
199
  const shouldForceLeadingZeros = props.shouldForceLeadingZeros ?? ui.dateInput.shouldForceLeadingZeros;
199
200
  const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
200
- const [shouldFocus, setShouldFocus] = useState(false);
201
201
  const inputRef = useRef(null);
202
+ const { renderRealInput } = useStaticInputHandoff({
203
+ inputRef,
204
+ renderInput,
205
+ setRenderInput,
206
+ getFocusTarget: (input) => {
207
+ return (input.getContainer?.() ?? input).querySelector("input, button, [tabindex]:not([tabindex='-1'])");
208
+ }
209
+ });
202
210
  const watchedValue = "formControl" in props && props.formControl ? useWatch({
203
211
  control: props.formControl.control,
204
212
  name: props.formControl.name
@@ -215,13 +223,6 @@ var DateTimePicker = ({ fullIso = true, renderStaticInput, ...props }) => {
215
223
  if (isoString == null) return isoString;
216
224
  return DateTimeUtils.fromUTCISOToCalendarDateTime(isoString);
217
225
  };
218
- useEffect(() => {
219
- if (!renderInput || !shouldFocus) return;
220
- requestAnimationFrame(() => {
221
- ((inputRef.current?.getContainer?.() ?? inputRef.current)?.querySelector("input, button, [tabindex]:not([tabindex='-1'])"))?.focus();
222
- });
223
- setShouldFocus(false);
224
- }, [renderInput, shouldFocus]);
225
226
  if (!renderInput) {
226
227
  const dateTimeValue = rawValue ? parseDateValue(rawValue) : null;
227
228
  const as = props.as ?? ui.input.as;
@@ -259,10 +260,7 @@ var DateTimePicker = ({ fullIso = true, renderStaticInput, ...props }) => {
259
260
  dataHasSelection: dateTimeValue !== null
260
261
  },
261
262
  renderStatic: true,
262
- onStaticInteract: (focus) => {
263
- setShouldFocus(focus);
264
- setRenderInput(true);
265
- },
263
+ onStaticInteract: renderRealInput,
266
264
  actionContent: staticTodayIcon,
267
265
  actionContentPlacement: todayIconPlacement === "fieldLabel" ? "content-row" : "content-wrapper",
268
266
  trailingContent: showDropdown ? ui.dateInput.dateTimeIcon : void 0,
@@ -7,6 +7,7 @@ import { getStaticTimeSegments } from "../shared/staticDateTimeSegments.js";
7
7
  import { FormField } from "../../FormField/FormField.js";
8
8
  import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
9
9
  import { InputFrame } from "../../Skeleton/InputFrame.js";
10
+ import { useStaticInputHandoff } from "../../shared/useStaticInputHandoff.js";
10
11
  import { useDebounceCallback } from "../../../../hooks/useDebounceCallback.js";
11
12
  import { TimePickerInput } from "../shared/TimePickerInput.js";
12
13
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -142,8 +143,13 @@ var TimePicker = ({ renderStaticInput, ...props }) => {
142
143
  const ui = UIConfig.useConfig();
143
144
  const { locale } = useLocale();
144
145
  const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
145
- const [shouldFocus, setShouldFocus] = useState(false);
146
146
  const inputRef = useRef(null);
147
+ const { renderRealInput } = useStaticInputHandoff({
148
+ inputRef,
149
+ renderInput,
150
+ setRenderInput,
151
+ getFocusTarget: (input) => input.querySelector("input, button, [tabindex]:not([tabindex='-1'])")
152
+ });
147
153
  const watchedValue = "formControl" in props && props.formControl ? useWatch({
148
154
  control: props.formControl.control,
149
155
  name: props.formControl.name
@@ -161,13 +167,6 @@ var TimePicker = ({ renderStaticInput, ...props }) => {
161
167
  if (isoString == null) return isoString;
162
168
  return toTime(DateTimeUtils.fromISOtoZonedDateTime(isoString));
163
169
  };
164
- useEffect(() => {
165
- if (!renderInput || !shouldFocus) return;
166
- requestAnimationFrame(() => {
167
- (inputRef.current?.querySelector("input, button, [tabindex]:not([tabindex='-1'])"))?.focus();
168
- });
169
- setShouldFocus(false);
170
- }, [renderInput, shouldFocus]);
171
170
  if (!renderInput) {
172
171
  const timeValue = rawValue ? parseTimeValue(rawValue) : null;
173
172
  const as = props.as ?? ui.input.as;
@@ -198,10 +197,7 @@ var TimePicker = ({ renderStaticInput, ...props }) => {
198
197
  dataHasSelection: timeValue !== null
199
198
  },
200
199
  renderStatic: true,
201
- onStaticInteract: (focus) => {
202
- setShouldFocus(focus);
203
- setRenderInput(true);
204
- },
200
+ onStaticInteract: renderRealInput,
205
201
  trailingContent: showDropdown ? ui.dateInput.timeIcon : void 0,
206
202
  children: staticSegments
207
203
  });
@@ -4,6 +4,7 @@ import { inputBase } from "../../shared/input.cva.js";
4
4
  import { FormField } from "../../FormField/FormField.js";
5
5
  import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
6
6
  import { InputFrame } from "../../Skeleton/InputFrame.js";
7
+ import { useStaticInputHandoff } from "../../shared/useStaticInputHandoff.js";
7
8
  import { InputContent } from "../shared/InputContent.js";
8
9
  import { getStaticNumberDisplayValue } from "../shared/numberStatic.utils.js";
9
10
  import { jsx } from "react/jsx-runtime";
@@ -124,19 +125,18 @@ var NumberInput = ({ renderStaticInput, ...props }) => {
124
125
  const ui = UIConfig.useConfig();
125
126
  const { locale } = useLocale();
126
127
  const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
127
- const [shouldFocus, setShouldFocus] = useState(false);
128
128
  const inputRef = useRef(null);
129
+ const { shouldFocus, renderRealInput, replayStaticInputChange } = useStaticInputHandoff({
130
+ inputRef,
131
+ renderInput,
132
+ setRenderInput
133
+ });
129
134
  const watchedValue = "formControl" in props && props.formControl ? useWatch({
130
135
  control: props.formControl.control,
131
136
  name: props.formControl.name
132
137
  }) : props.value;
133
138
  let isFormControlDisabled = false;
134
139
  if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
135
- useEffect(() => {
136
- if (!renderInput || !shouldFocus) return;
137
- requestAnimationFrame(() => inputRef.current?.focus());
138
- setShouldFocus(false);
139
- }, [renderInput, shouldFocus]);
140
140
  if (!renderInput) {
141
141
  const staticValue = watchedValue ?? props.value ?? props.defaultValue;
142
142
  const formatOptions = props.formatOptions ?? ui.numberInput.formatOptions;
@@ -161,19 +161,16 @@ var NumberInput = ({ renderStaticInput, ...props }) => {
161
161
  className: clsx("group w-full", as === "inline" && "h-full", props.className),
162
162
  dataAttributes,
163
163
  renderStatic: true,
164
- onStaticInteract: (focus) => {
165
- setShouldFocus(focus);
166
- setRenderInput(true);
167
- },
164
+ onStaticInteract: renderRealInput,
168
165
  inputClassName: props.inputClassName,
169
166
  children: (dataAttributeProps) => /* @__PURE__ */ jsx("input", {
170
167
  ref: inputRef,
171
- readOnly: true,
172
168
  disabled: isDisabled,
173
169
  tabIndex: -1,
174
170
  value: displayValue,
175
171
  placeholder: as === "floating" ? "" : props.placeholder,
176
172
  className: "w-full bg-transparent outline-none placeholder:text-text-default-3 disabled:text-interactive-text-secondary-disabled",
173
+ onChange: (event) => replayStaticInputChange(event.target.value),
177
174
  ...dataAttributeProps,
178
175
  "data-rac": true
179
176
  })
@@ -3,11 +3,12 @@ import { UIConfig } from "../../../../config/uiConfig.context.js";
3
3
  import { InputClear } from "../../shared/InputClear.js";
4
4
  import { inputBase, inputSize } from "../../shared/input.cva.js";
5
5
  import { InputFrame } from "../../Skeleton/InputFrame.js";
6
+ import { useStaticInputHandoff } from "../../shared/useStaticInputHandoff.js";
6
7
  import { getStaticNumberDisplayValue } from "../shared/numberStatic.utils.js";
7
8
  import { NumberRangeField } from "./NumberRangeField.js";
8
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
10
  import { clsx } from "clsx";
10
- import { useEffect, useState } from "react";
11
+ import { useRef, useState } from "react";
11
12
  import { useLocale } from "react-aria-components";
12
13
  import { useFocusVisible, useFocusWithin, useHover } from "react-aria";
13
14
  import { Controller, useWatch } from "react-hook-form";
@@ -122,17 +123,17 @@ var NumberRangeInput = ({ renderStaticInput, ...props }) => {
122
123
  const ui = UIConfig.useConfig();
123
124
  const { locale } = useLocale();
124
125
  const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
125
- const [shouldFocus, setShouldFocus] = useState(false);
126
+ const { shouldFocus, renderRealInput } = useStaticInputHandoff({
127
+ inputRef: useRef(null),
128
+ renderInput,
129
+ setRenderInput
130
+ });
126
131
  const watchedValue = "formControl" in props && props.formControl ? useWatch({
127
132
  control: props.formControl.control,
128
133
  name: props.formControl.name
129
134
  }) : props.value;
130
135
  let isFormControlDisabled = false;
131
136
  if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
132
- useEffect(() => {
133
- if (!renderInput || !shouldFocus) return;
134
- setShouldFocus(false);
135
- }, [renderInput, shouldFocus]);
136
137
  if (!renderInput) {
137
138
  const staticValue = normalizeRangeValue(watchedValue, props.minValue, props.maxValue);
138
139
  const formatOptions = props.formatOptions ?? ui.numberInput.formatOptions;
@@ -165,10 +166,7 @@ var NumberRangeInput = ({ renderStaticInput, ...props }) => {
165
166
  contentWrapperClassName: "flex w-full items-center gap-input-gap-input-text-to-elements",
166
167
  dataAttributes,
167
168
  renderStatic: true,
168
- onStaticInteract: (focus) => {
169
- setShouldFocus(focus);
170
- setRenderInput(true);
171
- },
169
+ onStaticInteract: renderRealInput,
172
170
  isClearable: false,
173
171
  labelPlacement: "content-row",
174
172
  children: ({ id, ...dataAttributeProps }) => /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -4,6 +4,7 @@ import { inputBase } from "../../shared/input.cva.js";
4
4
  import { FormField } from "../../FormField/FormField.js";
5
5
  import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
6
6
  import { InputFrame } from "../../Skeleton/InputFrame.js";
7
+ import { useStaticInputHandoff } from "../../shared/useStaticInputHandoff.js";
7
8
  import { InputContent } from "../shared/InputContent.js";
8
9
  import { jsx } from "react/jsx-runtime";
9
10
  import { clsx } from "clsx";
@@ -119,8 +120,12 @@ var TextInputBase = (props) => {
119
120
  var TextInput = ({ renderStaticInput, ...props }) => {
120
121
  const ui = UIConfig.useConfig();
121
122
  const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
122
- const [shouldFocus, setShouldFocus] = useState(false);
123
123
  const inputRef = useRef(null);
124
+ const { shouldFocus, renderRealInput, replayStaticInputChange } = useStaticInputHandoff({
125
+ inputRef,
126
+ renderInput,
127
+ setRenderInput
128
+ });
124
129
  const watchedValue = "formControl" in props && props.formControl ? useWatch({
125
130
  control: props.formControl.control,
126
131
  name: props.formControl.name
@@ -130,11 +135,6 @@ var TextInput = ({ renderStaticInput, ...props }) => {
130
135
  const staticValue = watchedValue ?? props.value ?? props.defaultValue ?? "";
131
136
  const inputType = props.type;
132
137
  if (!renderInput && inputType === "password" && `${staticValue}`.length > 0) setRenderInput(true);
133
- useEffect(() => {
134
- if (!renderInput || !shouldFocus) return;
135
- requestAnimationFrame(() => inputRef.current?.focus());
136
- setShouldFocus(false);
137
- }, [renderInput, shouldFocus]);
138
138
  if (!renderInput) {
139
139
  const as = props.as ?? ui.input.as;
140
140
  let isDisabled = !!props.isDisabled;
@@ -158,20 +158,17 @@ var TextInput = ({ renderStaticInput, ...props }) => {
158
158
  className: clsx("group w-full", as === "inline" && "h-full", props.className),
159
159
  dataAttributes,
160
160
  renderStatic: true,
161
- onStaticInteract: (focus) => {
162
- setShouldFocus(focus);
163
- setRenderInput(true);
164
- },
161
+ onStaticInteract: renderRealInput,
165
162
  inputClassName: props.inputClassName,
166
163
  children: (dataAttributeProps) => /* @__PURE__ */ jsx("input", {
167
164
  ref: inputRef,
168
165
  type: inputType === "hidden" ? "password" : inputType,
169
- readOnly: true,
170
166
  disabled: isDisabled,
171
167
  tabIndex: -1,
172
168
  value: displayValue,
173
169
  placeholder: as === "floating" ? "" : props.placeholder,
174
170
  className: "w-full bg-transparent outline-none placeholder:text-text-default-3 disabled:text-interactive-text-secondary-disabled",
171
+ onChange: (event) => replayStaticInputChange(event.target.value),
175
172
  ...dataAttributeProps,
176
173
  "data-rac": true
177
174
  })
@@ -1,11 +1,12 @@
1
1
  import { ArrowDropDownIcon } from "../../../../assets/icons/ArrowDropDown.js";
2
2
  import { UIConfig } from "../../../../config/uiConfig.context.js";
3
3
  import { InputFrame } from "../../Skeleton/InputFrame.js";
4
+ import { useStaticInputHandoff } from "../../shared/useStaticInputHandoff.js";
4
5
  import { SelectBase } from "../shared/SelectBase.js";
5
6
  import { getStaticSelectValue } from "../shared/staticSelect.utils.js";
6
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
8
  import { clsx } from "clsx";
8
- import { useEffect, useRef, useState } from "react";
9
+ import { useRef, useState } from "react";
9
10
  import { mergeRefs } from "@react-aria/utils";
10
11
  import { Controller, useWatch } from "react-hook-form";
11
12
  //#region src/components/inputs/Selection/Autocomplete/Autocomplete.tsx
@@ -37,8 +38,13 @@ function _Autocomplete(props) {
37
38
  function Autocomplete({ renderStaticInput, ...props }) {
38
39
  const ui = UIConfig.useConfig();
39
40
  const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
40
- const [shouldFocus, setShouldFocus] = useState(false);
41
41
  const rootRef = useRef(null);
42
+ const { renderRealInput, replayStaticInputChange } = useStaticInputHandoff({
43
+ inputRef: rootRef,
44
+ renderInput,
45
+ setRenderInput,
46
+ getFocusTarget: (root) => root.querySelector("input, [data-type='select-trigger'], button, [tabindex]")
47
+ });
42
48
  const currentValue = ("formControl" in props && props.formControl ? useWatch({
43
49
  control: props.formControl.control,
44
50
  name: props.formControl.name
@@ -46,13 +52,6 @@ function Autocomplete({ renderStaticInput, ...props }) {
46
52
  let isFormControlDisabled = false;
47
53
  if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
48
54
  if (!renderInput && !!props.customTrigger) setRenderInput(true);
49
- useEffect(() => {
50
- if (!renderInput || !shouldFocus) return;
51
- requestAnimationFrame(() => {
52
- (rootRef.current?.querySelector("input, [data-type='select-trigger'], button, [tabindex]"))?.focus();
53
- });
54
- setShouldFocus(false);
55
- }, [renderInput, shouldFocus]);
56
55
  if (!renderInput) {
57
56
  const as = props.as ?? ui.input.as;
58
57
  let isDisabled = !!props.isDisabled;
@@ -94,22 +93,19 @@ function Autocomplete({ renderStaticInput, ...props }) {
94
93
  labelPlacement: "content-row",
95
94
  dataAttributes,
96
95
  renderStatic: true,
97
- onStaticInteract: (focus) => {
98
- setShouldFocus(focus);
99
- setRenderInput(true);
100
- },
96
+ onStaticInteract: renderRealInput,
101
97
  leadingContent: props.leadingContent && /* @__PURE__ */ jsx("div", {
102
98
  className: "ml-input-side-default flex shrink-0 items-center",
103
99
  children: props.leadingContent
104
100
  }),
105
101
  trailingContent,
106
102
  children: (dataAttributeProps) => /* @__PURE__ */ jsxs(Fragment, { children: [isMultiple && !isEmpty && displayValue, /* @__PURE__ */ jsx("input", {
107
- readOnly: true,
108
103
  disabled: isDisabled,
109
104
  tabIndex: -1,
110
105
  value: inputValue,
111
106
  placeholder: isMultiple && shouldRenderPlaceholderAfterValue ? props.placeholder : placeholder ?? void 0,
112
107
  className: clsx("w-full flex-1 bg-transparent outline-none placeholder:text-text-default-3 disabled:text-interactive-text-secondary-disabled", props.inputClassName),
108
+ onChange: (event) => replayStaticInputChange(event.target.value),
113
109
  ...dataAttributeProps,
114
110
  "data-rac": true
115
111
  })] })
@@ -1,11 +1,12 @@
1
1
  import { ArrowDropDownIcon } from "../../../../assets/icons/ArrowDropDown.js";
2
2
  import { UIConfig } from "../../../../config/uiConfig.context.js";
3
3
  import { InputFrame } from "../../Skeleton/InputFrame.js";
4
+ import { useStaticInputHandoff } from "../../shared/useStaticInputHandoff.js";
4
5
  import { SelectBase } from "../shared/SelectBase.js";
5
6
  import { getStaticSelectValue } from "../shared/staticSelect.utils.js";
6
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
8
  import { clsx } from "clsx";
8
- import { useEffect, useRef, useState } from "react";
9
+ import { useRef, useState } from "react";
9
10
  import { mergeRefs } from "@react-aria/utils";
10
11
  import { Controller, useWatch } from "react-hook-form";
11
12
  //#region src/components/inputs/Selection/Select/Select.tsx
@@ -32,8 +33,13 @@ function _Select(props) {
32
33
  function Select({ renderStaticInput, ...props }) {
33
34
  const ui = UIConfig.useConfig();
34
35
  const [renderInput, setRenderInput] = useState(!(renderStaticInput ?? ui.renderStaticInput));
35
- const [shouldFocus, setShouldFocus] = useState(false);
36
36
  const rootRef = useRef(null);
37
+ const { renderRealInput, replayStaticInputChange } = useStaticInputHandoff({
38
+ inputRef: rootRef,
39
+ renderInput,
40
+ setRenderInput,
41
+ getFocusTarget: (root) => root.querySelector("[data-type='select-trigger'], input, button, [tabindex]")
42
+ });
37
43
  const currentValue = ("formControl" in props && props.formControl ? useWatch({
38
44
  control: props.formControl.control,
39
45
  name: props.formControl.name
@@ -42,13 +48,6 @@ function Select({ renderStaticInput, ...props }) {
42
48
  if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
43
49
  if (!renderInput && props.selectionMode !== "multiple" && !!props.showSelectionContent && currentValue != null) setRenderInput(true);
44
50
  if (!renderInput && !!props.customTrigger) setRenderInput(true);
45
- useEffect(() => {
46
- if (!renderInput || !shouldFocus) return;
47
- requestAnimationFrame(() => {
48
- (rootRef.current?.querySelector("[data-type='select-trigger'], input, button, [tabindex]"))?.focus();
49
- });
50
- setShouldFocus(false);
51
- }, [renderInput, shouldFocus]);
52
51
  if (!renderInput) {
53
52
  const as = props.as ?? ui.input.as;
54
53
  let isDisabled = !!props.isDisabled;
@@ -95,10 +94,7 @@ function Select({ renderStaticInput, ...props }) {
95
94
  labelPlacement: "content-row",
96
95
  dataAttributes,
97
96
  renderStatic: true,
98
- onStaticInteract: (focus) => {
99
- setShouldFocus(focus);
100
- setRenderInput(true);
101
- },
97
+ onStaticInteract: renderRealInput,
102
98
  leadingContent: props.leadingContent && /* @__PURE__ */ jsx("div", {
103
99
  className: "ml-input-side-default flex shrink-0 items-center",
104
100
  children: props.leadingContent
@@ -106,12 +102,12 @@ function Select({ renderStaticInput, ...props }) {
106
102
  showClear: false,
107
103
  trailingContent,
108
104
  children: (dataAttributeProps) => /* @__PURE__ */ jsxs(Fragment, { children: [isMultiple && !isEmpty && displayValue, isSearchable ? /* @__PURE__ */ jsx("input", {
109
- readOnly: true,
110
105
  disabled: isDisabled,
111
106
  tabIndex: -1,
112
107
  value: inputValue,
113
108
  placeholder: shouldRenderPlaceholderAfterValue ? props.placeholder : placeholder ?? void 0,
114
109
  className: clsx("w-full flex-1 bg-transparent outline-none placeholder:text-text-default-3 disabled:text-interactive-text-secondary-disabled", props.inputClassName),
110
+ onChange: (event) => replayStaticInputChange(event.target.value),
115
111
  ...dataAttributeProps,
116
112
  "data-rac": true
117
113
  }) : /* @__PURE__ */ jsx("button", {
@@ -0,0 +1,13 @@
1
+ import { Dispatch, RefObject, SetStateAction } from 'react';
2
+ interface StaticInputHandoffOptions<TElement extends HTMLElement> {
3
+ inputRef: RefObject<TElement | null>;
4
+ renderInput: boolean;
5
+ setRenderInput: Dispatch<SetStateAction<boolean>>;
6
+ getFocusTarget?: (element: TElement) => HTMLElement | null | undefined;
7
+ }
8
+ export declare const useStaticInputHandoff: <TElement extends HTMLElement = HTMLInputElement>({ inputRef, renderInput, setRenderInput, getFocusTarget, }: StaticInputHandoffOptions<TElement>) => {
9
+ shouldFocus: boolean;
10
+ renderRealInput: (focus: boolean) => void;
11
+ replayStaticInputChange: (value: string) => void;
12
+ };
13
+ export {};
@@ -0,0 +1,47 @@
1
+ import { useLayoutEffect, useRef, useState } from "react";
2
+ //#region src/components/inputs/shared/useStaticInputHandoff.ts
3
+ var useStaticInputHandoff = ({ inputRef, renderInput, setRenderInput, getFocusTarget }) => {
4
+ const [shouldFocus, setShouldFocus] = useState(false);
5
+ const pendingStaticChangeRef = useRef(null);
6
+ useLayoutEffect(() => {
7
+ if (!renderInput || !shouldFocus) return;
8
+ const focusRealInput = (replayPendingChange) => {
9
+ const input = inputRef.current;
10
+ const pendingValue = pendingStaticChangeRef.current;
11
+ const focusTarget = input ? getFocusTarget?.(input) ?? input : null;
12
+ if (replayPendingChange && focusTarget instanceof HTMLInputElement && pendingValue != null) {
13
+ (Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set)?.call(focusTarget, pendingValue);
14
+ focusTarget.dispatchEvent(new Event("input", { bubbles: true }));
15
+ pendingStaticChangeRef.current = null;
16
+ }
17
+ focusTarget?.focus();
18
+ };
19
+ focusRealInput(true);
20
+ const frame = requestAnimationFrame(() => {
21
+ focusRealInput(false);
22
+ setShouldFocus(false);
23
+ });
24
+ return () => {
25
+ cancelAnimationFrame(frame);
26
+ };
27
+ }, [
28
+ getFocusTarget,
29
+ inputRef,
30
+ renderInput,
31
+ shouldFocus
32
+ ]);
33
+ return {
34
+ shouldFocus,
35
+ renderRealInput: (focus) => {
36
+ setShouldFocus(focus);
37
+ setRenderInput(true);
38
+ },
39
+ replayStaticInputChange: (value) => {
40
+ pendingStaticChangeRef.current = value;
41
+ setShouldFocus(true);
42
+ setRenderInput(true);
43
+ }
44
+ };
45
+ };
46
+ //#endregion
47
+ export { useStaticInputHandoff };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@povio/ui",
3
- "version": "2.2.9-rc.32",
3
+ "version": "2.2.9-rc.34",
4
4
  "type": "module",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",