@povio/ui 2.2.7 → 2.2.8-rc
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/README.md +2 -0
- package/dist/components/inputs/DateTime/DatePicker/DatePicker.js +60 -3
- package/dist/components/inputs/DateTime/DateRangePicker/DateRangePicker.js +89 -3
- package/dist/components/inputs/DateTime/DateTimePicker/DateTimePicker.js +60 -3
- package/dist/components/inputs/DateTime/TimePicker/TimePicker.d.ts +1 -0
- package/dist/components/inputs/DateTime/TimePicker/TimePicker.js +61 -5
- package/dist/components/inputs/DateTime/shared/TimePickerInput.d.ts +2 -1
- package/dist/components/inputs/DateTime/shared/TimePickerInput.js +4 -5
- package/dist/components/inputs/Input/NumberInput/NumberInput.d.ts +1 -0
- package/dist/components/inputs/Input/NumberInput/NumberInput.js +79 -7
- package/dist/components/inputs/Input/TextInput/TextInput.d.ts +1 -0
- package/dist/components/inputs/Input/TextInput/TextInput.js +82 -7
- package/dist/components/inputs/Selection/Autocomplete/Autocomplete.js +62 -2
- package/dist/components/inputs/Selection/Select/Select.js +63 -2
- package/dist/components/inputs/shared/StaticInput.d.ts +18 -0
- package/dist/components/inputs/shared/StaticInput.js +69 -0
- package/dist/config/uiConfig.context.d.ts +1 -0
- package/dist/config/uiConfig.context.js +1 -0
- package/dist/utils/date-time.utils.d.ts +10 -0
- package/dist/utils/date-time.utils.js +82 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ This is required for buttons to behave as expected. It is based on [Tailwind Upg
|
|
|
31
31
|
|
|
32
32
|
In order for Tailwind to also compile classes for @povio/ui package, you need to include @source directive in Tailwind config.
|
|
33
33
|
In your globals.css add (make sure path is correct):
|
|
34
|
+
|
|
34
35
|
```css
|
|
35
36
|
@source "../../node_modules/@povio/ui/dist";
|
|
36
37
|
```
|
|
@@ -42,6 +43,7 @@ We are using `react-aria-components` for our UI components including their plugi
|
|
|
42
43
|
### Custom Tailwind plugin
|
|
43
44
|
|
|
44
45
|
We also use a custom tailwind plugin to shorten some selectors inside the @povio/ui package. Install it by adding the following line to your `base.css`.
|
|
46
|
+
|
|
45
47
|
```css
|
|
46
48
|
@plugin "@povio/ui/tw-ui-plugin";
|
|
47
49
|
```
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
import { CalendarIcon } from "../../../../assets/icons/Calendar.js";
|
|
1
2
|
import { UIConfig } from "../../../../config/uiConfig.context.js";
|
|
3
|
+
import { TodayIcon } from "../../../../assets/icons/Today.js";
|
|
2
4
|
import { Calendar } from "../shared/Calendar.js";
|
|
3
5
|
import { DatePickerInput } from "../shared/DatePickerInput.js";
|
|
4
6
|
import { DateTimeDialog } from "../shared/DateTimeDialog.js";
|
|
5
7
|
import { DateTimeDialogFooter } from "../shared/DateTimeDialogFooter.js";
|
|
6
8
|
import { FormField } from "../../FormField/FormField.js";
|
|
9
|
+
import { StaticInput } from "../../shared/StaticInput.js";
|
|
7
10
|
import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
|
|
8
11
|
import { DateTimeUtils } from "../../../../utils/date-time.utils.js";
|
|
9
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
13
|
import { clsx } from "clsx";
|
|
11
|
-
import { useImperativeHandle, useMemo, useRef } from "react";
|
|
14
|
+
import { useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
12
15
|
import { useDatePicker, useLocale } from "react-aria";
|
|
13
16
|
import { mergeRefs } from "@react-aria/utils";
|
|
14
|
-
import { Controller } from "react-hook-form";
|
|
17
|
+
import { Controller, useWatch } from "react-hook-form";
|
|
15
18
|
import { createCalendar, getLocalTimeZone, toCalendarDate, today } from "@internationalized/date";
|
|
16
19
|
import { DateTime } from "luxon";
|
|
17
20
|
import { useCalendarState, useDatePickerState } from "react-stately";
|
|
@@ -151,6 +154,18 @@ var DatePickerBase = (props) => {
|
|
|
151
154
|
});
|
|
152
155
|
};
|
|
153
156
|
var DatePicker = ({ fullIso = true, minValue, maxValue, ...props }) => {
|
|
157
|
+
const ui = UIConfig.useConfig();
|
|
158
|
+
const { locale } = useLocale();
|
|
159
|
+
const [renderInput, setRenderInput] = useState(!ui.renderStaticInput);
|
|
160
|
+
const [shouldFocus, setShouldFocus] = useState(false);
|
|
161
|
+
const inputRef = useRef(null);
|
|
162
|
+
const watchedValue = "formControl" in props && props.formControl ? useWatch({
|
|
163
|
+
control: props.formControl.control,
|
|
164
|
+
name: props.formControl.name
|
|
165
|
+
}) : props.value;
|
|
166
|
+
let isFormControlDisabled = false;
|
|
167
|
+
if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
|
|
168
|
+
const rawValue = watchedValue ?? props.value ?? null;
|
|
154
169
|
const formatCalendarDate = (calendarDate) => {
|
|
155
170
|
if (calendarDate === null) return null;
|
|
156
171
|
if (fullIso) return DateTimeUtils.fromCalendarDateToUTCISO(calendarDate);
|
|
@@ -167,6 +182,47 @@ var DatePicker = ({ fullIso = true, minValue, maxValue, ...props }) => {
|
|
|
167
182
|
minValue: typeof minValue === "string" ? parseCalendarDate(minValue) : minValue,
|
|
168
183
|
maxValue: typeof maxValue === "string" ? parseCalendarDate(maxValue) : maxValue
|
|
169
184
|
};
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
if (!renderInput || !shouldFocus) return;
|
|
187
|
+
requestAnimationFrame(() => {
|
|
188
|
+
((inputRef.current?.getContainer?.() ?? inputRef.current)?.querySelector("input, button, [tabindex]:not([tabindex='-1'])"))?.focus();
|
|
189
|
+
});
|
|
190
|
+
setShouldFocus(false);
|
|
191
|
+
}, [renderInput, shouldFocus]);
|
|
192
|
+
if (!renderInput) {
|
|
193
|
+
const as = props.as ?? ui.input.as;
|
|
194
|
+
const size = props.size ?? ui.input.size;
|
|
195
|
+
const variant = props.variant ?? ui.input.variant;
|
|
196
|
+
const hideLabel = props.hideLabel ?? ui.input.hideLabel;
|
|
197
|
+
const isHeaderHidden = props.isHeaderHidden || as === "inline" || as === "filter" || as === "floating";
|
|
198
|
+
let isDisabled = !!props.isDisabled;
|
|
199
|
+
if (isFormControlDisabled) isDisabled = true;
|
|
200
|
+
const todayIcon = props.todayIcon ?? ui.dateInput.todayIcon;
|
|
201
|
+
const disableManualEntry = props.disableManualEntry ?? ui.dateInput.disableManualEntry;
|
|
202
|
+
const showDropdown = !props.disableDropdown || disableManualEntry;
|
|
203
|
+
const staticPlaceholder = props.placeholder ?? DateTimeUtils.getDatePlaceholder(locale);
|
|
204
|
+
const staticDateValue = rawValue ? parseCalendarDate(rawValue) : null;
|
|
205
|
+
const displayValue = staticDateValue ? DateTimeUtils.formatCalendarDateLocalized(staticDateValue, locale) : "";
|
|
206
|
+
return /* @__PURE__ */ jsx(StaticInput, {
|
|
207
|
+
...props,
|
|
208
|
+
onInteract: (focus) => {
|
|
209
|
+
setShouldFocus(focus);
|
|
210
|
+
setRenderInput(true);
|
|
211
|
+
},
|
|
212
|
+
className: clsx("relative inline-flex w-full flex-col text-left", props.className),
|
|
213
|
+
as,
|
|
214
|
+
size,
|
|
215
|
+
variant,
|
|
216
|
+
hideLabel,
|
|
217
|
+
isHeaderHidden,
|
|
218
|
+
isDisabled,
|
|
219
|
+
placeholder: staticPlaceholder,
|
|
220
|
+
displayValue,
|
|
221
|
+
isEmpty: !displayValue,
|
|
222
|
+
leadingVisual: todayIcon ? /* @__PURE__ */ jsx(TodayIcon, { className: "size-6 text-interactive-text-secondary-idle" }) : void 0,
|
|
223
|
+
trailingVisual: showDropdown ? /* @__PURE__ */ jsx(CalendarIcon, { className: "size-6 text-interactive-text-secondary-idle" }) : void 0
|
|
224
|
+
});
|
|
225
|
+
}
|
|
170
226
|
if ("formControl" in props && props.formControl) {
|
|
171
227
|
const { formControl, ref, ...innerProps } = props;
|
|
172
228
|
return /* @__PURE__ */ jsx(Controller, {
|
|
@@ -175,7 +231,7 @@ var DatePicker = ({ fullIso = true, minValue, maxValue, ...props }) => {
|
|
|
175
231
|
render: ({ field, fieldState: { error, isDirty } }) => /* @__PURE__ */ jsx(DatePickerBase, {
|
|
176
232
|
...innerProps,
|
|
177
233
|
...dateLimits,
|
|
178
|
-
ref: mergeRefs(ref, field.ref),
|
|
234
|
+
ref: mergeRefs(ref, field.ref, inputRef),
|
|
179
235
|
value: parseCalendarDate(field.value),
|
|
180
236
|
onChange: (value) => field.onChange(formatCalendarDate(value)),
|
|
181
237
|
onBlur: field.onBlur,
|
|
@@ -188,6 +244,7 @@ var DatePicker = ({ fullIso = true, minValue, maxValue, ...props }) => {
|
|
|
188
244
|
return /* @__PURE__ */ jsx(DatePickerBase, {
|
|
189
245
|
...props,
|
|
190
246
|
...dateLimits,
|
|
247
|
+
ref: mergeRefs(props.ref, inputRef),
|
|
191
248
|
value: parseCalendarDate(props.value),
|
|
192
249
|
onChange: (value) => props.onChange?.(formatCalendarDate(value))
|
|
193
250
|
});
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
+
import { CalendarIcon } from "../../../../assets/icons/Calendar.js";
|
|
1
2
|
import { Typography } from "../../../text/Typography/Typography.js";
|
|
2
3
|
import { UIConfig } from "../../../../config/uiConfig.context.js";
|
|
3
4
|
import "../../../../config/i18n.js";
|
|
5
|
+
import { TodayIcon } from "../../../../assets/icons/Today.js";
|
|
4
6
|
import { DatePickerInput } from "../shared/DatePickerInput.js";
|
|
5
7
|
import { DateTimeDialog } from "../shared/DateTimeDialog.js";
|
|
6
8
|
import { DateTimeDialogFooter } from "../shared/DateTimeDialogFooter.js";
|
|
7
9
|
import { FormField } from "../../FormField/FormField.js";
|
|
10
|
+
import { StaticInput } from "../../shared/StaticInput.js";
|
|
8
11
|
import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
|
|
9
12
|
import { DateTimeUtils } from "../../../../utils/date-time.utils.js";
|
|
10
13
|
import { RangeCalendar } from "../shared/RangeCalendar.js";
|
|
11
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
15
|
import { clsx } from "clsx";
|
|
13
|
-
import { useCallback, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
16
|
+
import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
14
17
|
import { Button } from "react-aria-components";
|
|
15
18
|
import { useDateRangePicker, useLocale as useLocale$1 } from "react-aria";
|
|
16
19
|
import { mergeRefs } from "@react-aria/utils";
|
|
17
20
|
import { useTranslation } from "react-i18next";
|
|
18
|
-
import { Controller } from "react-hook-form";
|
|
21
|
+
import { Controller, useWatch } from "react-hook-form";
|
|
19
22
|
import { createCalendar, endOfMonth, endOfWeek, endOfYear, getLocalTimeZone, startOfMonth, startOfWeek, startOfYear, toCalendarDate, today } from "@internationalized/date";
|
|
20
23
|
import { DateTime } from "luxon";
|
|
21
24
|
import { useDateRangePickerState, useRangeCalendarState } from "react-stately";
|
|
@@ -530,6 +533,18 @@ var DateRangePickerBase = (props) => {
|
|
|
530
533
|
});
|
|
531
534
|
};
|
|
532
535
|
var DateRangePicker = ({ fullIso = true, minValue, maxValue, ...props }) => {
|
|
536
|
+
const ui = UIConfig.useConfig();
|
|
537
|
+
const { locale } = useLocale$1();
|
|
538
|
+
const [renderInput, setRenderInput] = useState(!ui.renderStaticInput);
|
|
539
|
+
const [shouldFocus, setShouldFocus] = useState(false);
|
|
540
|
+
const inputRef = useRef(null);
|
|
541
|
+
const watchedValue = "formControl" in props && props.formControl ? useWatch({
|
|
542
|
+
control: props.formControl.control,
|
|
543
|
+
name: props.formControl.name
|
|
544
|
+
}) : props.value;
|
|
545
|
+
let isFormControlDisabled = false;
|
|
546
|
+
if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
|
|
547
|
+
const rawValue = watchedValue ?? props.value ?? null;
|
|
533
548
|
const formatDateRange = (range) => {
|
|
534
549
|
if (!range?.start || !range?.end) return null;
|
|
535
550
|
if (fullIso) return {
|
|
@@ -568,6 +583,76 @@ var DateRangePicker = ({ fullIso = true, minValue, maxValue, ...props }) => {
|
|
|
568
583
|
minValue: typeof minValue === "string" ? parseCalendarDate(minValue) : minValue,
|
|
569
584
|
maxValue: typeof maxValue === "string" ? parseCalendarDate(maxValue) : maxValue
|
|
570
585
|
};
|
|
586
|
+
useEffect(() => {
|
|
587
|
+
if (!renderInput || !shouldFocus) return;
|
|
588
|
+
requestAnimationFrame(() => {
|
|
589
|
+
((inputRef.current?.getContainer?.() ?? inputRef.current)?.querySelector("input, button, [tabindex]:not([tabindex='-1'])"))?.focus();
|
|
590
|
+
});
|
|
591
|
+
setShouldFocus(false);
|
|
592
|
+
}, [renderInput, shouldFocus]);
|
|
593
|
+
if (!renderInput) {
|
|
594
|
+
const as = props.as ?? ui.input.as;
|
|
595
|
+
const size = props.size ?? ui.input.size;
|
|
596
|
+
const variant = props.variant ?? ui.input.variant;
|
|
597
|
+
const hideLabel = props.hideLabel ?? ui.input.hideLabel;
|
|
598
|
+
const isHeaderHidden = props.isHeaderHidden || as === "inline" || as === "filter" || as === "floating";
|
|
599
|
+
let isDisabled = !!props.isDisabled;
|
|
600
|
+
if (isFormControlDisabled) isDisabled = true;
|
|
601
|
+
const todayIcon = props.todayIcon ?? ui.dateInput.todayIcon;
|
|
602
|
+
const disableManualEntry = props.disableManualEntry ?? ui.dateInput.disableManualEntry;
|
|
603
|
+
const showDropdown = !props.disableDropdown || disableManualEntry;
|
|
604
|
+
const defaultDatePlaceholder = DateTimeUtils.getDatePlaceholder(locale);
|
|
605
|
+
const staticPlaceholder = props.placeholder ?? /* @__PURE__ */ jsxs("span", {
|
|
606
|
+
className: "inline-flex items-center gap-input-gap-input-text-to-elements",
|
|
607
|
+
children: [
|
|
608
|
+
/* @__PURE__ */ jsx("span", { children: defaultDatePlaceholder }),
|
|
609
|
+
/* @__PURE__ */ jsx("span", {
|
|
610
|
+
className: "pointer-events-none select-none",
|
|
611
|
+
children: "–"
|
|
612
|
+
}),
|
|
613
|
+
/* @__PURE__ */ jsx("span", { children: defaultDatePlaceholder })
|
|
614
|
+
]
|
|
615
|
+
});
|
|
616
|
+
const formatStaticDate = (value) => {
|
|
617
|
+
if (!value) return "";
|
|
618
|
+
const parsedDate = parseCalendarDate(value);
|
|
619
|
+
if (!parsedDate) return "";
|
|
620
|
+
return DateTimeUtils.formatCalendarDateLocalized(parsedDate, locale);
|
|
621
|
+
};
|
|
622
|
+
const start = formatStaticDate(rawValue?.start ?? null);
|
|
623
|
+
const end = formatStaticDate(rawValue?.end ?? null);
|
|
624
|
+
const hasRangeValue = !!(start && end);
|
|
625
|
+
const displayValue = hasRangeValue ? /* @__PURE__ */ jsxs("span", {
|
|
626
|
+
className: "inline-flex items-center gap-input-gap-input-text-to-elements",
|
|
627
|
+
children: [
|
|
628
|
+
/* @__PURE__ */ jsx("span", { children: start }),
|
|
629
|
+
/* @__PURE__ */ jsx("span", {
|
|
630
|
+
className: "pointer-events-none select-none",
|
|
631
|
+
children: "–"
|
|
632
|
+
}),
|
|
633
|
+
/* @__PURE__ */ jsx("span", { children: end })
|
|
634
|
+
]
|
|
635
|
+
}) : void 0;
|
|
636
|
+
return /* @__PURE__ */ jsx(StaticInput, {
|
|
637
|
+
...props,
|
|
638
|
+
onInteract: (focus) => {
|
|
639
|
+
setShouldFocus(focus);
|
|
640
|
+
setRenderInput(true);
|
|
641
|
+
},
|
|
642
|
+
className: clsx("relative inline-flex w-full flex-col text-left", props.className),
|
|
643
|
+
as,
|
|
644
|
+
size,
|
|
645
|
+
variant,
|
|
646
|
+
hideLabel,
|
|
647
|
+
isHeaderHidden,
|
|
648
|
+
isDisabled,
|
|
649
|
+
placeholder: staticPlaceholder,
|
|
650
|
+
displayValue,
|
|
651
|
+
isEmpty: !hasRangeValue,
|
|
652
|
+
leadingVisual: todayIcon ? /* @__PURE__ */ jsx(TodayIcon, { className: "size-6 text-interactive-text-secondary-idle" }) : void 0,
|
|
653
|
+
trailingVisual: showDropdown ? /* @__PURE__ */ jsx(CalendarIcon, { className: "size-6 text-interactive-text-secondary-idle" }) : void 0
|
|
654
|
+
});
|
|
655
|
+
}
|
|
571
656
|
if ("formControl" in props && props.formControl) {
|
|
572
657
|
const { formControl, ref, ...innerProps } = props;
|
|
573
658
|
return /* @__PURE__ */ jsx(Controller, {
|
|
@@ -576,7 +661,7 @@ var DateRangePicker = ({ fullIso = true, minValue, maxValue, ...props }) => {
|
|
|
576
661
|
render: ({ field, fieldState: { error, isDirty } }) => /* @__PURE__ */ jsx(DateRangePickerBase, {
|
|
577
662
|
...innerProps,
|
|
578
663
|
...dateLimits,
|
|
579
|
-
ref: mergeRefs(ref, field.ref),
|
|
664
|
+
ref: mergeRefs(ref, field.ref, inputRef),
|
|
580
665
|
value: parseDateRange(field.value),
|
|
581
666
|
onChange: (value) => field.onChange(formatDateRange(value)),
|
|
582
667
|
onBlur: field.onBlur,
|
|
@@ -589,6 +674,7 @@ var DateRangePicker = ({ fullIso = true, minValue, maxValue, ...props }) => {
|
|
|
589
674
|
return /* @__PURE__ */ jsx(DateRangePickerBase, {
|
|
590
675
|
...props,
|
|
591
676
|
...dateLimits,
|
|
677
|
+
ref: mergeRefs(props.ref, inputRef),
|
|
592
678
|
value: parseDateRange(props.value),
|
|
593
679
|
onChange: (value) => props.onChange?.(formatDateRange(value))
|
|
594
680
|
});
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
import { DateTimeIcon } from "../../../../assets/icons/DateTime.js";
|
|
1
2
|
import { UIConfig } from "../../../../config/uiConfig.context.js";
|
|
3
|
+
import { TodayIcon } from "../../../../assets/icons/Today.js";
|
|
2
4
|
import { Calendar } from "../shared/Calendar.js";
|
|
3
5
|
import { DatePickerInput } from "../shared/DatePickerInput.js";
|
|
4
6
|
import { DateTimeDialog } from "../shared/DateTimeDialog.js";
|
|
5
7
|
import { DateTimeDialogFooter } from "../shared/DateTimeDialogFooter.js";
|
|
6
8
|
import { FormField } from "../../FormField/FormField.js";
|
|
9
|
+
import { StaticInput } from "../../shared/StaticInput.js";
|
|
7
10
|
import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
|
|
8
11
|
import { DateTimeUtils } from "../../../../utils/date-time.utils.js";
|
|
9
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import { useEffect, useImperativeHandle, useMemo, useRef } from "react";
|
|
13
|
+
import { useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
11
14
|
import { useDatePicker, useLocale } from "react-aria";
|
|
12
15
|
import { mergeRefs } from "@react-aria/utils";
|
|
13
|
-
import { Controller } from "react-hook-form";
|
|
16
|
+
import { Controller, useWatch } from "react-hook-form";
|
|
14
17
|
import { Time, createCalendar, getLocalTimeZone, now, toCalendarDateTime, today } from "@internationalized/date";
|
|
15
18
|
import { useCalendarState, useDatePickerState } from "react-stately";
|
|
16
19
|
//#region src/components/inputs/DateTime/DateTimePicker/DateTimePicker.tsx
|
|
@@ -174,6 +177,18 @@ var DateTimePickerBase = (props) => {
|
|
|
174
177
|
});
|
|
175
178
|
};
|
|
176
179
|
var DateTimePicker = ({ fullIso = true, ...props }) => {
|
|
180
|
+
const ui = UIConfig.useConfig();
|
|
181
|
+
const { locale } = useLocale();
|
|
182
|
+
const [renderInput, setRenderInput] = useState(!ui.renderStaticInput);
|
|
183
|
+
const [shouldFocus, setShouldFocus] = useState(false);
|
|
184
|
+
const inputRef = useRef(null);
|
|
185
|
+
const watchedValue = "formControl" in props && props.formControl ? useWatch({
|
|
186
|
+
control: props.formControl.control,
|
|
187
|
+
name: props.formControl.name
|
|
188
|
+
}) : props.value;
|
|
189
|
+
let isFormControlDisabled = false;
|
|
190
|
+
if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
|
|
191
|
+
const rawValue = watchedValue ?? props.value ?? null;
|
|
177
192
|
const formatDateValue = (dateValue) => {
|
|
178
193
|
if (dateValue === null) return null;
|
|
179
194
|
if (fullIso) return DateTimeUtils.fromCalendarDateTimeToUTCISO(dateValue);
|
|
@@ -183,6 +198,47 @@ var DateTimePicker = ({ fullIso = true, ...props }) => {
|
|
|
183
198
|
if (isoString == null) return isoString;
|
|
184
199
|
return DateTimeUtils.fromUTCISOToCalendarDateTime(isoString);
|
|
185
200
|
};
|
|
201
|
+
useEffect(() => {
|
|
202
|
+
if (!renderInput || !shouldFocus) return;
|
|
203
|
+
requestAnimationFrame(() => {
|
|
204
|
+
((inputRef.current?.getContainer?.() ?? inputRef.current)?.querySelector("input, button, [tabindex]:not([tabindex='-1'])"))?.focus();
|
|
205
|
+
});
|
|
206
|
+
setShouldFocus(false);
|
|
207
|
+
}, [renderInput, shouldFocus]);
|
|
208
|
+
if (!renderInput) {
|
|
209
|
+
const as = props.as ?? ui.input.as;
|
|
210
|
+
const size = props.size ?? ui.input.size;
|
|
211
|
+
const variant = props.variant ?? ui.input.variant;
|
|
212
|
+
const hideLabel = props.hideLabel ?? ui.input.hideLabel;
|
|
213
|
+
const isHeaderHidden = props.isHeaderHidden || as === "inline" || as === "filter" || as === "floating";
|
|
214
|
+
let isDisabled = !!props.isDisabled;
|
|
215
|
+
if (isFormControlDisabled) isDisabled = true;
|
|
216
|
+
const todayIcon = props.todayIcon ?? ui.dateInput.todayIcon;
|
|
217
|
+
const disableManualEntry = props.disableManualEntry ?? ui.dateInput.disableManualEntry;
|
|
218
|
+
const showDropdown = !props.disableDropdown || disableManualEntry;
|
|
219
|
+
const staticPlaceholder = props.placeholder ?? DateTimeUtils.getDateTimePlaceholder(locale);
|
|
220
|
+
const staticDateTimeValue = rawValue ? parseDateValue(rawValue) : null;
|
|
221
|
+
const displayValue = staticDateTimeValue && "hour" in staticDateTimeValue ? DateTimeUtils.formatCalendarDateTimeLocalized(staticDateTimeValue, locale) : "";
|
|
222
|
+
return /* @__PURE__ */ jsx(StaticInput, {
|
|
223
|
+
...props,
|
|
224
|
+
onInteract: (focus) => {
|
|
225
|
+
setShouldFocus(focus);
|
|
226
|
+
setRenderInput(true);
|
|
227
|
+
},
|
|
228
|
+
className: props.className ? `relative inline-flex w-full flex-col text-left ${props.className}` : "relative inline-flex w-full flex-col text-left",
|
|
229
|
+
as,
|
|
230
|
+
size,
|
|
231
|
+
variant,
|
|
232
|
+
hideLabel,
|
|
233
|
+
isHeaderHidden,
|
|
234
|
+
isDisabled,
|
|
235
|
+
placeholder: staticPlaceholder,
|
|
236
|
+
displayValue,
|
|
237
|
+
isEmpty: !displayValue,
|
|
238
|
+
leadingVisual: todayIcon ? /* @__PURE__ */ jsx(TodayIcon, { className: "size-6 text-interactive-text-secondary-idle" }) : void 0,
|
|
239
|
+
trailingVisual: showDropdown ? /* @__PURE__ */ jsx(DateTimeIcon, { className: "size-6 text-interactive-text-secondary-idle" }) : void 0
|
|
240
|
+
});
|
|
241
|
+
}
|
|
186
242
|
if ("formControl" in props && props.formControl) {
|
|
187
243
|
const { formControl, ref, ...innerProps } = props;
|
|
188
244
|
return /* @__PURE__ */ jsx(Controller, {
|
|
@@ -190,7 +246,7 @@ var DateTimePicker = ({ fullIso = true, ...props }) => {
|
|
|
190
246
|
name: formControl.name,
|
|
191
247
|
render: ({ field, fieldState: { error, isDirty } }) => /* @__PURE__ */ jsx(DateTimePickerBase, {
|
|
192
248
|
...innerProps,
|
|
193
|
-
ref: mergeRefs(ref, field.ref),
|
|
249
|
+
ref: mergeRefs(ref, field.ref, inputRef),
|
|
194
250
|
value: parseDateValue(field.value),
|
|
195
251
|
onChange: (value) => field.onChange(formatDateValue(value)),
|
|
196
252
|
onBlur: field.onBlur,
|
|
@@ -202,6 +258,7 @@ var DateTimePicker = ({ fullIso = true, ...props }) => {
|
|
|
202
258
|
}
|
|
203
259
|
return /* @__PURE__ */ jsx(DateTimePickerBase, {
|
|
204
260
|
...props,
|
|
261
|
+
ref: mergeRefs(props.ref, inputRef),
|
|
205
262
|
value: parseDateValue(props.value),
|
|
206
263
|
onChange: (value) => props.onChange?.(formatDateValue(value))
|
|
207
264
|
});
|
|
@@ -12,6 +12,7 @@ interface TimePickerBaseProps extends FormFieldProps, InputVariantProps, Omit<Ar
|
|
|
12
12
|
isDirty?: boolean;
|
|
13
13
|
disableManualEntry?: boolean;
|
|
14
14
|
placeholder?: string;
|
|
15
|
+
inputClassName?: string;
|
|
15
16
|
}
|
|
16
17
|
export interface TimePickerProps extends Omit<TimePickerBaseProps, "value" | "onChange"> {
|
|
17
18
|
value?: string | null;
|
|
@@ -1,23 +1,26 @@
|
|
|
1
|
+
import { ClockIcon } from "../../../../assets/icons/Clock.js";
|
|
1
2
|
import { UIConfig } from "../../../../config/uiConfig.context.js";
|
|
2
3
|
import { TimePickerForm } from "../shared/TimePickerForm.js";
|
|
3
4
|
import { DateTimeDialog } from "../shared/DateTimeDialog.js";
|
|
4
5
|
import { DateTimeDialogFooter } from "../shared/DateTimeDialogFooter.js";
|
|
5
6
|
import { FormField } from "../../FormField/FormField.js";
|
|
7
|
+
import { StaticInput } from "../../shared/StaticInput.js";
|
|
6
8
|
import { TooltipWrapper } from "../../shared/TooltipWrapper.js";
|
|
7
9
|
import { DateTimeUtils } from "../../../../utils/date-time.utils.js";
|
|
8
10
|
import { TimePickerInput } from "../shared/TimePickerInput.js";
|
|
9
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
import { clsx } from "clsx";
|
|
10
13
|
import { useEffect, useRef, useState } from "react";
|
|
11
14
|
import { useLocale, useTimeField } from "react-aria";
|
|
12
15
|
import { mergeRefs } from "@react-aria/utils";
|
|
13
|
-
import { Controller } from "react-hook-form";
|
|
16
|
+
import { Controller, useWatch } from "react-hook-form";
|
|
14
17
|
import { getLocalTimeZone, now, toTime } from "@internationalized/date";
|
|
15
18
|
import { DateTime } from "luxon";
|
|
16
19
|
import { useTimeFieldState } from "react-stately";
|
|
17
20
|
//#region src/components/inputs/DateTime/TimePicker/TimePicker.tsx
|
|
18
21
|
var TimePickerBase = (props) => {
|
|
19
22
|
const ui = UIConfig.useConfig();
|
|
20
|
-
const { ref, label, tooltipText, helperText, isRequired, rightContent, isDisabled, isDirty, headerClassName, errorClassName, isHeaderHidden, error, onChange, value, disableDropdown, placeholder, variant = ui.input.variant, as = ui.input.as, size = ui.input.size, hideLabel = ui.input.hideLabel, isClearable = ui.input.isClearable, disableManualEntry = ui.dateInput.disableManualEntry, ...rest } = props;
|
|
23
|
+
const { ref, label, tooltipText, helperText, isRequired, rightContent, isDisabled, isDirty, headerClassName, errorClassName, isHeaderHidden, error, onChange, value, disableDropdown, placeholder, className, inputClassName, variant = ui.input.variant, as = ui.input.as, size = ui.input.size, hideLabel = ui.input.hideLabel, isClearable = ui.input.isClearable, disableManualEntry = ui.dateInput.disableManualEntry, ...rest } = props;
|
|
21
24
|
const formFieldProps = {
|
|
22
25
|
error,
|
|
23
26
|
label,
|
|
@@ -90,7 +93,7 @@ var TimePickerBase = (props) => {
|
|
|
90
93
|
...formFieldProps,
|
|
91
94
|
as,
|
|
92
95
|
labelProps,
|
|
93
|
-
className: "relative inline-flex w-full flex-col text-left",
|
|
96
|
+
className: clsx("relative inline-flex w-full flex-col text-left", className),
|
|
94
97
|
tabIndex: as === "inline" ? -1 : void 0,
|
|
95
98
|
children: [/* @__PURE__ */ jsx(TimePickerInput, {
|
|
96
99
|
ref: mergeRefs(ref, timeFieldRef),
|
|
@@ -107,7 +110,8 @@ var TimePickerBase = (props) => {
|
|
|
107
110
|
isClearable,
|
|
108
111
|
headerProps,
|
|
109
112
|
disableManualEntry,
|
|
110
|
-
placeholder
|
|
113
|
+
placeholder,
|
|
114
|
+
className: inputClassName
|
|
111
115
|
}), (!disableDropdown || disableManualEntry) && /* @__PURE__ */ jsx(DateTimeDialog, {
|
|
112
116
|
footer: /* @__PURE__ */ jsx(DateTimeDialogFooter, {
|
|
113
117
|
isDisabled,
|
|
@@ -124,6 +128,18 @@ var TimePickerBase = (props) => {
|
|
|
124
128
|
});
|
|
125
129
|
};
|
|
126
130
|
var TimePicker = (props) => {
|
|
131
|
+
const ui = UIConfig.useConfig();
|
|
132
|
+
const { locale } = useLocale();
|
|
133
|
+
const [renderInput, setRenderInput] = useState(!ui.renderStaticInput);
|
|
134
|
+
const [shouldFocus, setShouldFocus] = useState(false);
|
|
135
|
+
const inputRef = useRef(null);
|
|
136
|
+
const watchedValue = "formControl" in props && props.formControl ? useWatch({
|
|
137
|
+
control: props.formControl.control,
|
|
138
|
+
name: props.formControl.name
|
|
139
|
+
}) : props.value;
|
|
140
|
+
let isFormControlDisabled = false;
|
|
141
|
+
if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
|
|
142
|
+
const rawValue = watchedValue ?? props.value ?? null;
|
|
127
143
|
const formatTimeValue = (timeValue) => {
|
|
128
144
|
if (timeValue === null) return null;
|
|
129
145
|
const parsedDate = props.date ? DateTime.fromISO(props.date).toJSDate() : void 0;
|
|
@@ -134,6 +150,45 @@ var TimePicker = (props) => {
|
|
|
134
150
|
if (isoString == null) return isoString;
|
|
135
151
|
return toTime(DateTimeUtils.fromISOtoZonedDateTime(isoString));
|
|
136
152
|
};
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (!renderInput || !shouldFocus) return;
|
|
155
|
+
requestAnimationFrame(() => {
|
|
156
|
+
(inputRef.current?.querySelector("input, button, [tabindex]:not([tabindex='-1'])"))?.focus();
|
|
157
|
+
});
|
|
158
|
+
setShouldFocus(false);
|
|
159
|
+
}, [renderInput, shouldFocus]);
|
|
160
|
+
if (!renderInput) {
|
|
161
|
+
const as = props.as ?? ui.input.as;
|
|
162
|
+
const size = props.size ?? ui.input.size;
|
|
163
|
+
const variant = props.variant ?? ui.input.variant;
|
|
164
|
+
const hideLabel = props.hideLabel ?? ui.input.hideLabel;
|
|
165
|
+
const isHeaderHidden = props.isHeaderHidden || as === "inline" || as === "filter" || as === "floating";
|
|
166
|
+
let isDisabled = !!props.isDisabled;
|
|
167
|
+
if (isFormControlDisabled) isDisabled = true;
|
|
168
|
+
const disableManualEntry = props.disableManualEntry ?? ui.dateInput.disableManualEntry;
|
|
169
|
+
const showDropdown = !props.disableDropdown || disableManualEntry;
|
|
170
|
+
const staticPlaceholder = props.placeholder ?? DateTimeUtils.getTimePlaceholder(locale);
|
|
171
|
+
const staticTimeValue = rawValue ? parseTimeValue(rawValue) : null;
|
|
172
|
+
const displayValue = staticTimeValue ? DateTimeUtils.formatTimeLocalized(staticTimeValue, locale) : "";
|
|
173
|
+
return /* @__PURE__ */ jsx(StaticInput, {
|
|
174
|
+
...props,
|
|
175
|
+
onInteract: (focus) => {
|
|
176
|
+
setShouldFocus(focus);
|
|
177
|
+
setRenderInput(true);
|
|
178
|
+
},
|
|
179
|
+
className: clsx("relative inline-flex w-full flex-col text-left", props.className),
|
|
180
|
+
as,
|
|
181
|
+
size,
|
|
182
|
+
variant,
|
|
183
|
+
hideLabel,
|
|
184
|
+
isHeaderHidden,
|
|
185
|
+
isDisabled,
|
|
186
|
+
placeholder: staticPlaceholder,
|
|
187
|
+
displayValue,
|
|
188
|
+
isEmpty: !displayValue,
|
|
189
|
+
trailingVisual: showDropdown ? /* @__PURE__ */ jsx(ClockIcon, { className: "size-6 text-interactive-text-secondary-idle" }) : void 0
|
|
190
|
+
});
|
|
191
|
+
}
|
|
137
192
|
if ("formControl" in props && props.formControl) {
|
|
138
193
|
const { formControl, ref, ...innerProps } = props;
|
|
139
194
|
return /* @__PURE__ */ jsx(Controller, {
|
|
@@ -141,7 +196,7 @@ var TimePicker = (props) => {
|
|
|
141
196
|
name: formControl.name,
|
|
142
197
|
render: ({ field, fieldState: { error } }) => /* @__PURE__ */ jsx(TimePickerBase, {
|
|
143
198
|
...innerProps,
|
|
144
|
-
ref: mergeRefs(ref, field.ref),
|
|
199
|
+
ref: mergeRefs(ref, field.ref, inputRef),
|
|
145
200
|
value: parseTimeValue(field.value),
|
|
146
201
|
onChange: (value) => field.onChange(formatTimeValue(value)),
|
|
147
202
|
onBlur: field.onBlur,
|
|
@@ -152,6 +207,7 @@ var TimePicker = (props) => {
|
|
|
152
207
|
}
|
|
153
208
|
return /* @__PURE__ */ jsx(TimePickerBase, {
|
|
154
209
|
...props,
|
|
210
|
+
ref: mergeRefs(props.ref, inputRef),
|
|
155
211
|
value: parseTimeValue(props.value),
|
|
156
212
|
onChange: (value) => props.onChange?.(formatTimeValue(value))
|
|
157
213
|
});
|
|
@@ -15,7 +15,8 @@ interface DatePickerInputProps extends InputVariantProps {
|
|
|
15
15
|
isClearable?: boolean;
|
|
16
16
|
disableManualEntry?: boolean;
|
|
17
17
|
placeholder?: string;
|
|
18
|
+
className?: string;
|
|
18
19
|
onPress: () => void;
|
|
19
20
|
}
|
|
20
|
-
export declare const TimePickerInput: ({ ref, as, fieldProps, state, isDisabled, isDirty, isInvalid, disableDropdown, variant, size, isClearable, headerProps, disableManualEntry, placeholder, onPress, ...props }: DatePickerInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export declare const TimePickerInput: ({ ref, as, fieldProps, state, isDisabled, isDirty, isInvalid, disableDropdown, variant, size, isClearable, headerProps, disableManualEntry, placeholder, className, onPress, ...props }: DatePickerInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
22
|
export {};
|
|
@@ -12,7 +12,7 @@ import { useState } from "react";
|
|
|
12
12
|
import { Button } from "react-aria-components";
|
|
13
13
|
import { useFocusVisible, useFocusWithin, useHover } from "react-aria";
|
|
14
14
|
//#region src/components/inputs/DateTime/shared/TimePickerInput.tsx
|
|
15
|
-
var TimePickerInput = ({ ref, as, fieldProps, state, isDisabled, isDirty, isInvalid, disableDropdown, variant, size, isClearable, headerProps, disableManualEntry, placeholder, onPress, ...props }) => {
|
|
15
|
+
var TimePickerInput = ({ ref, as, fieldProps, state, isDisabled, isDirty, isInvalid, disableDropdown, variant, size, isClearable, headerProps, disableManualEntry, placeholder, className, onPress, ...props }) => {
|
|
16
16
|
const inputBaseCva = UIStyle.useCva("input.baseCva", inputBase);
|
|
17
17
|
const inputSizeCva = UIStyle.useCva("input.sizeCva", inputSize);
|
|
18
18
|
const { hoverProps, isHovered } = useHover({ isDisabled });
|
|
@@ -23,12 +23,11 @@ var TimePickerInput = ({ ref, as, fieldProps, state, isDisabled, isDirty, isInva
|
|
|
23
23
|
const canClear = state.segments.some((segment) => segment.type !== "literal" && segment.isPlaceholder === false);
|
|
24
24
|
return /* @__PURE__ */ jsxs("div", {
|
|
25
25
|
ref,
|
|
26
|
-
className: inputBaseCva({
|
|
26
|
+
className: clsx(inputBaseCva({
|
|
27
27
|
variant,
|
|
28
28
|
as,
|
|
29
|
-
...props
|
|
30
|
-
|
|
31
|
-
}),
|
|
29
|
+
...props
|
|
30
|
+
}), "group/date-picker-content relative min-w-input-width-min-width", "flex items-center justify-between gap-input-gap-input-text-to-elements", className),
|
|
32
31
|
"data-rac": "",
|
|
33
32
|
"data-datetime-input": "",
|
|
34
33
|
"data-hovered": isHovered || void 0,
|
|
@@ -13,6 +13,7 @@ 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
18
|
export type NumberInputProps = NumberInputBaseProps;
|
|
18
19
|
export type ControlledNumberInputProps<TFieldValues extends FieldValues> = ControlProps<NumberInputProps, TFieldValues>;
|
|
@@ -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,
|
|
@@ -113,7 +119,68 @@ var NumberInputBase = (props) => {
|
|
|
113
119
|
})
|
|
114
120
|
});
|
|
115
121
|
};
|
|
122
|
+
var renderIconVisual = (icon) => {
|
|
123
|
+
if (!icon) return null;
|
|
124
|
+
if (isValidElement(icon)) return icon;
|
|
125
|
+
return /* @__PURE__ */ jsx(icon, { className: "size-6 text-interactive-text-secondary-idle" });
|
|
126
|
+
};
|
|
116
127
|
var NumberInput = (props) => {
|
|
128
|
+
const ui = UIConfig.useConfig();
|
|
129
|
+
const [renderInput, setRenderInput] = useState(!ui.renderStaticInput);
|
|
130
|
+
const [shouldFocus, setShouldFocus] = useState(false);
|
|
131
|
+
const inputRef = useRef(null);
|
|
132
|
+
const watchedValue = "formControl" in props && props.formControl ? useWatch({
|
|
133
|
+
control: props.formControl.control,
|
|
134
|
+
name: props.formControl.name
|
|
135
|
+
}) : props.value;
|
|
136
|
+
let isFormControlDisabled = false;
|
|
137
|
+
if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if (!renderInput || !shouldFocus) return;
|
|
140
|
+
requestAnimationFrame(() => inputRef.current?.focus());
|
|
141
|
+
setShouldFocus(false);
|
|
142
|
+
}, [renderInput, shouldFocus]);
|
|
143
|
+
if (!renderInput) {
|
|
144
|
+
const staticValue = watchedValue ?? props.value ?? props.defaultValue;
|
|
145
|
+
const displayValue = staticValue == null ? "" : `${staticValue}`;
|
|
146
|
+
const hasValue = displayValue !== "";
|
|
147
|
+
const as = props.as ?? ui.input.as;
|
|
148
|
+
const size = props.size ?? ui.input.size;
|
|
149
|
+
const variant = props.variant ?? ui.input.variant;
|
|
150
|
+
const hideLabel = props.hideLabel ?? ui.input.hideLabel;
|
|
151
|
+
const isHeaderHidden = props.isHeaderHidden || as === "inline" || as === "filter" || as === "floating";
|
|
152
|
+
let isDisabled = !!props.isDisabled;
|
|
153
|
+
if (isFormControlDisabled) isDisabled = true;
|
|
154
|
+
const trailingVisual = !!props.unit || !!props.isLoading || !!props.action && !props.isLoading || !!props.trailingIcon && !props.isLoading && !props.action ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
155
|
+
props.unit && /* @__PURE__ */ jsx("span", {
|
|
156
|
+
className: "text-label-2 text-text-default-3",
|
|
157
|
+
children: props.unit
|
|
158
|
+
}),
|
|
159
|
+
props.isLoading && /* @__PURE__ */ jsx(Loader, {}),
|
|
160
|
+
!props.isLoading && props.action && renderIconVisual(props.action.icon),
|
|
161
|
+
!props.isLoading && !props.action && props.trailingIcon && renderIconVisual(props.trailingIcon)
|
|
162
|
+
] }) : void 0;
|
|
163
|
+
return /* @__PURE__ */ jsx(StaticInput, {
|
|
164
|
+
...props,
|
|
165
|
+
onInteract: (focus) => {
|
|
166
|
+
setShouldFocus(focus);
|
|
167
|
+
setRenderInput(true);
|
|
168
|
+
},
|
|
169
|
+
as,
|
|
170
|
+
size,
|
|
171
|
+
variant,
|
|
172
|
+
hideLabel,
|
|
173
|
+
isHeaderHidden,
|
|
174
|
+
isDisabled,
|
|
175
|
+
className: clsx("group w-full", as === "inline" && "h-full", props.className),
|
|
176
|
+
inputClassName: props.inputClassName,
|
|
177
|
+
placeholder: as === "floating" ? "" : props.placeholder,
|
|
178
|
+
displayValue,
|
|
179
|
+
isEmpty: !hasValue,
|
|
180
|
+
leadingVisual: renderIconVisual(props.leadingIcon),
|
|
181
|
+
trailingVisual
|
|
182
|
+
});
|
|
183
|
+
}
|
|
117
184
|
if ("formControl" in props && props.formControl) {
|
|
118
185
|
const { formControl, ref, ...innerProps } = props;
|
|
119
186
|
return /* @__PURE__ */ jsx(Controller, {
|
|
@@ -121,17 +188,22 @@ var NumberInput = (props) => {
|
|
|
121
188
|
name: formControl.name,
|
|
122
189
|
render: ({ field, fieldState: { error, isDirty } }) => /* @__PURE__ */ jsx(NumberInputBase, {
|
|
123
190
|
...innerProps,
|
|
124
|
-
ref: mergeRefs(ref, field.ref),
|
|
191
|
+
ref: mergeRefs(ref, field.ref, inputRef),
|
|
125
192
|
value: field.value,
|
|
126
193
|
onChange: field.onChange,
|
|
127
194
|
onBlur: field.onBlur,
|
|
128
195
|
isDirty,
|
|
129
196
|
isDisabled: field.disabled || props.isDisabled,
|
|
130
|
-
error: props.error ?? error?.message
|
|
197
|
+
error: props.error ?? error?.message,
|
|
198
|
+
autoFocusOnMount: shouldFocus
|
|
131
199
|
}, field.value === null || field.value === void 0 ? "empty" : "filled")
|
|
132
200
|
});
|
|
133
201
|
}
|
|
134
|
-
return /* @__PURE__ */ jsx(NumberInputBase, {
|
|
202
|
+
return /* @__PURE__ */ jsx(NumberInputBase, {
|
|
203
|
+
...props,
|
|
204
|
+
ref: mergeRefs(props.ref, inputRef),
|
|
205
|
+
autoFocusOnMount: shouldFocus
|
|
206
|
+
}, props.value === null || props.value === void 0 ? "empty" : "filled");
|
|
135
207
|
};
|
|
136
208
|
//#endregion
|
|
137
209
|
export { NumberInput };
|
|
@@ -13,6 +13,7 @@ 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 {
|
|
18
19
|
}
|
|
@@ -1,22 +1,24 @@
|
|
|
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 { useRef } from "react";
|
|
11
|
+
import { isValidElement, useEffect, useRef, useState } from "react";
|
|
10
12
|
import { Input } from "react-aria-components";
|
|
11
13
|
import { useFocusVisible, useTextField } 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
|
//#region src/components/inputs/Input/TextInput/TextInput.tsx
|
|
15
17
|
var TextInputBase = (props) => {
|
|
16
18
|
const ui = UIConfig.useConfig();
|
|
17
19
|
const inputBaseCva = UIStyle.useCva("input.baseCva", inputBase);
|
|
18
20
|
const inputRef = useRef(null);
|
|
19
|
-
const { ref, inputClassName, label, tooltipText, helperText, isRequired, rightContent, isDisabled, isDirty, headerClassName, errorClassName, isHeaderHidden, error, className, unit, isLoading, action, leadingIcon, trailingIcon, value, onChange, onBlur, as = ui.input.as, hideLabel = ui.input.hideLabel, variant = ui.input.variant, size = ui.input.size, isClearable = ui.input.isClearable, ...rest } = props;
|
|
21
|
+
const { ref, inputClassName, label, tooltipText, helperText, isRequired, rightContent, isDisabled, isDirty, headerClassName, errorClassName, isHeaderHidden, error, className, unit, isLoading, action, leadingIcon, trailingIcon, value, onChange, onBlur, as = ui.input.as, hideLabel = ui.input.hideLabel, variant = ui.input.variant, size = ui.input.size, isClearable = ui.input.isClearable, autoFocusOnMount, ...rest } = props;
|
|
20
22
|
const textFieldRef = useRef(null);
|
|
21
23
|
const { isFocusVisible } = useFocusVisible();
|
|
22
24
|
const { labelProps, inputProps } = useTextField({
|
|
@@ -29,6 +31,10 @@ var TextInputBase = (props) => {
|
|
|
29
31
|
onChange,
|
|
30
32
|
onBlur
|
|
31
33
|
}, textFieldRef);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!autoFocusOnMount || isDisabled) return;
|
|
36
|
+
requestAnimationFrame(() => inputRef.current?.focus());
|
|
37
|
+
}, [autoFocusOnMount, isDisabled]);
|
|
32
38
|
const formFieldProps = {
|
|
33
39
|
error,
|
|
34
40
|
label,
|
|
@@ -106,7 +112,71 @@ var TextInputBase = (props) => {
|
|
|
106
112
|
})
|
|
107
113
|
});
|
|
108
114
|
};
|
|
115
|
+
var renderIconVisual = (icon) => {
|
|
116
|
+
if (!icon) return null;
|
|
117
|
+
if (isValidElement(icon)) return icon;
|
|
118
|
+
return /* @__PURE__ */ jsx(icon, { className: "size-6 text-interactive-text-secondary-idle" });
|
|
119
|
+
};
|
|
109
120
|
var TextInput = (props) => {
|
|
121
|
+
const ui = UIConfig.useConfig();
|
|
122
|
+
const [renderInput, setRenderInput] = useState(!ui.renderStaticInput);
|
|
123
|
+
const [shouldFocus, setShouldFocus] = useState(false);
|
|
124
|
+
const inputRef = useRef(null);
|
|
125
|
+
const watchedValue = "formControl" in props && props.formControl ? useWatch({
|
|
126
|
+
control: props.formControl.control,
|
|
127
|
+
name: props.formControl.name
|
|
128
|
+
}) : props.value;
|
|
129
|
+
let isFormControlDisabled = false;
|
|
130
|
+
if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
|
|
131
|
+
const staticValue = watchedValue ?? props.value ?? props.defaultValue ?? "";
|
|
132
|
+
const inputType = props.type;
|
|
133
|
+
if (!renderInput && inputType === "password" && `${staticValue}`.length > 0) setRenderInput(true);
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
if (!renderInput || !shouldFocus) return;
|
|
136
|
+
requestAnimationFrame(() => inputRef.current?.focus());
|
|
137
|
+
setShouldFocus(false);
|
|
138
|
+
}, [renderInput, shouldFocus]);
|
|
139
|
+
if (!renderInput) {
|
|
140
|
+
const as = props.as ?? ui.input.as;
|
|
141
|
+
const size = props.size ?? ui.input.size;
|
|
142
|
+
const variant = props.variant ?? ui.input.variant;
|
|
143
|
+
const hideLabel = props.hideLabel ?? ui.input.hideLabel;
|
|
144
|
+
const isHeaderHidden = props.isHeaderHidden || as === "inline" || as === "filter" || as === "floating";
|
|
145
|
+
let isDisabled = !!props.isDisabled;
|
|
146
|
+
if (isFormControlDisabled) isDisabled = true;
|
|
147
|
+
const maskedPasswordValue = inputType === "password" && `${staticValue}`.length > 0 ? "•".repeat(`${staticValue}`.length) : staticValue;
|
|
148
|
+
const displayValue = maskedPasswordValue == null ? "" : `${maskedPasswordValue}`;
|
|
149
|
+
const hasValue = displayValue !== "";
|
|
150
|
+
const trailingVisual = !!props.unit || !!props.isLoading || !!props.action && !props.isLoading || !!props.trailingIcon && !props.isLoading && !props.action ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
151
|
+
props.unit && /* @__PURE__ */ jsx("span", {
|
|
152
|
+
className: "text-label-2 text-text-default-3",
|
|
153
|
+
children: props.unit
|
|
154
|
+
}),
|
|
155
|
+
props.isLoading && /* @__PURE__ */ jsx(Loader, {}),
|
|
156
|
+
!props.isLoading && props.action && renderIconVisual(props.action.icon),
|
|
157
|
+
!props.isLoading && !props.action && props.trailingIcon && renderIconVisual(props.trailingIcon)
|
|
158
|
+
] }) : void 0;
|
|
159
|
+
return /* @__PURE__ */ jsx(StaticInput, {
|
|
160
|
+
...props,
|
|
161
|
+
onInteract: (focus) => {
|
|
162
|
+
setShouldFocus(focus);
|
|
163
|
+
setRenderInput(true);
|
|
164
|
+
},
|
|
165
|
+
as,
|
|
166
|
+
size,
|
|
167
|
+
variant,
|
|
168
|
+
hideLabel,
|
|
169
|
+
isHeaderHidden,
|
|
170
|
+
isDisabled,
|
|
171
|
+
className: clsx("group w-full", as === "inline" && "h-full", props.className),
|
|
172
|
+
inputClassName: props.inputClassName,
|
|
173
|
+
placeholder: as === "floating" ? "" : props.placeholder,
|
|
174
|
+
displayValue,
|
|
175
|
+
isEmpty: !hasValue,
|
|
176
|
+
leadingVisual: renderIconVisual(props.leadingIcon),
|
|
177
|
+
trailingVisual
|
|
178
|
+
});
|
|
179
|
+
}
|
|
110
180
|
if ("formControl" in props && props.formControl) {
|
|
111
181
|
const { formControl, ref, ...innerProps } = props;
|
|
112
182
|
return /* @__PURE__ */ jsx(Controller, {
|
|
@@ -114,17 +184,22 @@ var TextInput = (props) => {
|
|
|
114
184
|
name: formControl.name,
|
|
115
185
|
render: ({ field, fieldState: { error, isDirty } }) => /* @__PURE__ */ jsx(TextInputBase, {
|
|
116
186
|
...innerProps,
|
|
117
|
-
ref: mergeRefs(ref, field.ref),
|
|
187
|
+
ref: mergeRefs(ref, field.ref, inputRef),
|
|
118
188
|
value: field.value,
|
|
119
189
|
onChange: field.onChange,
|
|
120
190
|
onBlur: field.onBlur,
|
|
121
191
|
isDirty,
|
|
122
192
|
isDisabled: field.disabled || props.isDisabled,
|
|
123
|
-
error: props.error ?? error?.message
|
|
193
|
+
error: props.error ?? error?.message,
|
|
194
|
+
autoFocusOnMount: shouldFocus
|
|
124
195
|
})
|
|
125
196
|
});
|
|
126
197
|
}
|
|
127
|
-
return /* @__PURE__ */ jsx(TextInputBase, {
|
|
198
|
+
return /* @__PURE__ */ jsx(TextInputBase, {
|
|
199
|
+
...props,
|
|
200
|
+
ref: mergeRefs(props.ref, inputRef),
|
|
201
|
+
autoFocusOnMount: shouldFocus
|
|
202
|
+
});
|
|
128
203
|
};
|
|
129
204
|
//#endregion
|
|
130
205
|
export { TextInput };
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { ArrowDropDownIcon } from "../../../../assets/icons/ArrowDropDown.js";
|
|
2
|
+
import { UIConfig } from "../../../../config/uiConfig.context.js";
|
|
3
|
+
import { StaticInput } from "../../shared/StaticInput.js";
|
|
1
4
|
import { SelectBase } from "../shared/SelectBase.js";
|
|
2
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { isValidElement, useEffect, useRef, useState } from "react";
|
|
3
7
|
import { mergeRefs } from "@react-aria/utils";
|
|
4
|
-
import { Controller } from "react-hook-form";
|
|
8
|
+
import { Controller, useWatch } from "react-hook-form";
|
|
5
9
|
//#region src/components/inputs/Selection/Autocomplete/Autocomplete.tsx
|
|
6
|
-
var
|
|
10
|
+
var _Autocomplete = (props) => {
|
|
7
11
|
if ("formControl" in props && props.formControl) {
|
|
8
12
|
const { formControl, ref, ...innerProps } = props;
|
|
9
13
|
return /* @__PURE__ */ jsx(Controller, {
|
|
@@ -26,5 +30,61 @@ var Autocomplete = (props) => {
|
|
|
26
30
|
isSearchable: true
|
|
27
31
|
});
|
|
28
32
|
};
|
|
33
|
+
var Autocomplete = (props) => {
|
|
34
|
+
const ui = UIConfig.useConfig();
|
|
35
|
+
const [renderInput, setRenderInput] = useState(!ui.renderStaticInput);
|
|
36
|
+
const [shouldFocus, setShouldFocus] = useState(false);
|
|
37
|
+
const rootRef = useRef(null);
|
|
38
|
+
const currentValue = ("formControl" in props && props.formControl ? useWatch({
|
|
39
|
+
control: props.formControl.control,
|
|
40
|
+
name: props.formControl.name
|
|
41
|
+
}) : props.value) ?? props.value;
|
|
42
|
+
let isFormControlDisabled = false;
|
|
43
|
+
if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!renderInput || !shouldFocus) return;
|
|
46
|
+
requestAnimationFrame(() => {
|
|
47
|
+
(rootRef.current?.querySelector("input, [data-type='select-trigger'], button, [tabindex]"))?.focus();
|
|
48
|
+
});
|
|
49
|
+
setShouldFocus(false);
|
|
50
|
+
}, [renderInput, shouldFocus]);
|
|
51
|
+
if (!renderInput) {
|
|
52
|
+
const getItemLabel = (id) => {
|
|
53
|
+
const item = props.items.find((innerItem) => innerItem.id === id);
|
|
54
|
+
if (!item) return "";
|
|
55
|
+
if (props.showSelectionContent && item.content) return isValidElement(item.content) ? item.label : item.content;
|
|
56
|
+
return item.label;
|
|
57
|
+
};
|
|
58
|
+
const mode = props.selectionMode ?? ui.select.selectionMode;
|
|
59
|
+
let displayValue = "";
|
|
60
|
+
if (mode === "multiple") {
|
|
61
|
+
if (Array.isArray(currentValue) && currentValue.length > 0) displayValue = currentValue.map((id) => getItemLabel(id)).filter(Boolean).join(", ");
|
|
62
|
+
} else if (currentValue != null) displayValue = getItemLabel(currentValue);
|
|
63
|
+
const as = props.as ?? ui.input.as;
|
|
64
|
+
let isDisabled = !!props.isDisabled;
|
|
65
|
+
if (isFormControlDisabled) isDisabled = true;
|
|
66
|
+
return /* @__PURE__ */ jsx(StaticInput, {
|
|
67
|
+
...props,
|
|
68
|
+
onInteract: (focus) => {
|
|
69
|
+
setShouldFocus(focus);
|
|
70
|
+
setRenderInput(true);
|
|
71
|
+
},
|
|
72
|
+
as,
|
|
73
|
+
size: props.size ?? ui.input.size,
|
|
74
|
+
variant: props.variant ?? ui.input.variant,
|
|
75
|
+
isHeaderHidden: props.isHeaderHidden || as === "inline",
|
|
76
|
+
hideLabel: props.hideLabel ?? ui.input.hideLabel,
|
|
77
|
+
isDisabled,
|
|
78
|
+
placeholder: as === "floating" ? "" : props.placeholder,
|
|
79
|
+
displayValue,
|
|
80
|
+
isEmpty: !displayValue,
|
|
81
|
+
trailingVisual: /* @__PURE__ */ jsx(ArrowDropDownIcon, { className: "size-6 shrink-0 text-interactive-text-secondary-idle" })
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return /* @__PURE__ */ jsx(_Autocomplete, {
|
|
85
|
+
...props,
|
|
86
|
+
ref: mergeRefs(props.ref, rootRef)
|
|
87
|
+
});
|
|
88
|
+
};
|
|
29
89
|
//#endregion
|
|
30
90
|
export { Autocomplete };
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { ArrowDropDownIcon } from "../../../../assets/icons/ArrowDropDown.js";
|
|
2
|
+
import { UIConfig } from "../../../../config/uiConfig.context.js";
|
|
3
|
+
import { StaticInput } from "../../shared/StaticInput.js";
|
|
1
4
|
import { SelectBase } from "../shared/SelectBase.js";
|
|
2
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { isValidElement, useEffect, useRef, useState } from "react";
|
|
3
7
|
import { mergeRefs } from "@react-aria/utils";
|
|
4
|
-
import { Controller } from "react-hook-form";
|
|
8
|
+
import { Controller, useWatch } from "react-hook-form";
|
|
5
9
|
//#region src/components/inputs/Selection/Select/Select.tsx
|
|
6
|
-
var
|
|
10
|
+
var _Select = (props) => {
|
|
7
11
|
if ("formControl" in props && props.formControl) {
|
|
8
12
|
const { formControl, ref, ...innerProps } = props;
|
|
9
13
|
return /* @__PURE__ */ jsx(Controller, {
|
|
@@ -22,5 +26,62 @@ var Select = (props) => {
|
|
|
22
26
|
}
|
|
23
27
|
return /* @__PURE__ */ jsx(SelectBase, { ...props });
|
|
24
28
|
};
|
|
29
|
+
var Select = (props) => {
|
|
30
|
+
const ui = UIConfig.useConfig();
|
|
31
|
+
const [renderInput, setRenderInput] = useState(!ui.renderStaticInput);
|
|
32
|
+
const [shouldFocus, setShouldFocus] = useState(false);
|
|
33
|
+
const rootRef = useRef(null);
|
|
34
|
+
const currentValue = ("formControl" in props && props.formControl ? useWatch({
|
|
35
|
+
control: props.formControl.control,
|
|
36
|
+
name: props.formControl.name
|
|
37
|
+
}) : props.value) ?? props.value;
|
|
38
|
+
let isFormControlDisabled = false;
|
|
39
|
+
if ("formControl" in props && props.formControl) isFormControlDisabled = !!props.formControl.control._options?.disabled;
|
|
40
|
+
if (!renderInput && props.selectionMode !== "multiple" && !!props.showSelectionContent && currentValue != null) setRenderInput(true);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (!renderInput || !shouldFocus) return;
|
|
43
|
+
requestAnimationFrame(() => {
|
|
44
|
+
(rootRef.current?.querySelector("[data-type='select-trigger'], input, button, [tabindex]"))?.focus();
|
|
45
|
+
});
|
|
46
|
+
setShouldFocus(false);
|
|
47
|
+
}, [renderInput, shouldFocus]);
|
|
48
|
+
if (!renderInput) {
|
|
49
|
+
const getItemLabel = (id) => {
|
|
50
|
+
const item = props.items.find((innerItem) => innerItem.id === id);
|
|
51
|
+
if (!item) return "";
|
|
52
|
+
if (props.showSelectionContent && item.content) return isValidElement(item.content) ? item.label : item.content;
|
|
53
|
+
return item.label;
|
|
54
|
+
};
|
|
55
|
+
const mode = props.selectionMode ?? ui.select.selectionMode;
|
|
56
|
+
let displayValue = "";
|
|
57
|
+
if (mode === "multiple") {
|
|
58
|
+
if (Array.isArray(currentValue) && currentValue.length > 0) displayValue = currentValue.map((id) => getItemLabel(id)).filter(Boolean).join(", ");
|
|
59
|
+
} else if (currentValue != null) displayValue = getItemLabel(currentValue);
|
|
60
|
+
const as = props.as ?? ui.input.as;
|
|
61
|
+
let isDisabled = !!props.isDisabled;
|
|
62
|
+
if (isFormControlDisabled) isDisabled = true;
|
|
63
|
+
return /* @__PURE__ */ jsx(StaticInput, {
|
|
64
|
+
...props,
|
|
65
|
+
onInteract: (focus) => {
|
|
66
|
+
setShouldFocus(focus);
|
|
67
|
+
setRenderInput(true);
|
|
68
|
+
},
|
|
69
|
+
as,
|
|
70
|
+
size: props.size ?? ui.input.size,
|
|
71
|
+
variant: props.variant ?? ui.input.variant,
|
|
72
|
+
isHeaderHidden: props.isHeaderHidden || as === "inline",
|
|
73
|
+
hideLabel: props.hideLabel ?? ui.input.hideLabel,
|
|
74
|
+
isDisabled,
|
|
75
|
+
placeholder: as === "floating" ? "" : props.placeholder,
|
|
76
|
+
displayValue,
|
|
77
|
+
isEmpty: !displayValue,
|
|
78
|
+
trailingVisual: /* @__PURE__ */ jsx(ArrowDropDownIcon, { className: "size-6 shrink-0 text-interactive-text-secondary-idle" })
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return /* @__PURE__ */ jsx(_Select, {
|
|
82
|
+
...props,
|
|
83
|
+
ref: mergeRefs(props.ref, rootRef)
|
|
84
|
+
});
|
|
85
|
+
};
|
|
25
86
|
//#endregion
|
|
26
87
|
export { Select };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { FormFieldProps } from '../FormField/FormField';
|
|
3
|
+
import { TextInputProps } from '../Input/TextInput/TextInput';
|
|
4
|
+
import { InputSizeProps, InputVariantProps } from './input.cva';
|
|
5
|
+
interface StaticInputProps extends FormFieldProps {
|
|
6
|
+
onInteract: (shouldFocus: boolean) => void;
|
|
7
|
+
as?: TextInputProps["as"];
|
|
8
|
+
size?: InputSizeProps["size"];
|
|
9
|
+
variant?: InputVariantProps["variant"];
|
|
10
|
+
placeholder?: ReactNode;
|
|
11
|
+
displayValue?: ReactNode;
|
|
12
|
+
isEmpty?: boolean;
|
|
13
|
+
leadingVisual?: ReactNode;
|
|
14
|
+
trailingVisual?: ReactNode;
|
|
15
|
+
inputClassName?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const StaticInput: ({ onInteract, as, size, variant, placeholder, displayValue, isEmpty, leadingVisual, trailingVisual, inputClassName, className, ...formFieldProps }: StaticInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { UIStyle } from "../../../config/uiStyle.context.js";
|
|
2
|
+
import { FormFieldLabel } from "../FormField/FormFieldLabel.js";
|
|
3
|
+
import { inputBase, inputSize } from "./input.cva.js";
|
|
4
|
+
import { FormField } from "../FormField/FormField.js";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { clsx } from "clsx";
|
|
7
|
+
//#region src/components/inputs/shared/StaticInput.tsx
|
|
8
|
+
var StaticInput = ({ onInteract, as, size, variant, placeholder, displayValue, isEmpty, leadingVisual, trailingVisual, inputClassName, className, ...formFieldProps }) => {
|
|
9
|
+
const inputBaseCva = UIStyle.useCva("input.baseCva", inputBase);
|
|
10
|
+
const inputSizeCva = UIStyle.useCva("input.sizeCva", inputSize);
|
|
11
|
+
let hasValue = !!displayValue;
|
|
12
|
+
if (isEmpty != null) hasValue = !isEmpty;
|
|
13
|
+
let staticDisplayContent = placeholder;
|
|
14
|
+
if (hasValue) staticDisplayContent = displayValue;
|
|
15
|
+
else if (as === "floating") staticDisplayContent = null;
|
|
16
|
+
const shouldRenderFloatingLineSpacer = as === "floating" && !hasValue;
|
|
17
|
+
return /* @__PURE__ */ jsx(FormField, {
|
|
18
|
+
...formFieldProps,
|
|
19
|
+
as,
|
|
20
|
+
className,
|
|
21
|
+
onMouseEnter: () => onInteract(false),
|
|
22
|
+
tabIndex: as === "inline" ? -1 : void 0,
|
|
23
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
24
|
+
tabIndex: formFieldProps.isDisabled ? -1 : 0,
|
|
25
|
+
onFocus: () => onInteract(true),
|
|
26
|
+
onClick: () => onInteract(true),
|
|
27
|
+
onPointerDown: () => onInteract(true),
|
|
28
|
+
"data-is-empty": !hasValue || void 0,
|
|
29
|
+
"data-disabled": formFieldProps.isDisabled || void 0,
|
|
30
|
+
"data-is-disabled": formFieldProps.isDisabled || void 0,
|
|
31
|
+
"data-has-selection": hasValue || void 0,
|
|
32
|
+
"data-rac": "",
|
|
33
|
+
className: clsx("group/static-input group/input-content group/select-content relative flex min-w-input-width-min-width items-center justify-between gap-input-gap-input-text-to-elements", inputBaseCva({
|
|
34
|
+
as,
|
|
35
|
+
variant
|
|
36
|
+
}), inputClassName),
|
|
37
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
38
|
+
className: clsx(inputSizeCva({
|
|
39
|
+
size,
|
|
40
|
+
as
|
|
41
|
+
}), "flex w-full items-center gap-input-gap-input-text-to-elements pr-0!"),
|
|
42
|
+
children: [leadingVisual && /* @__PURE__ */ jsx("div", {
|
|
43
|
+
className: "pointer-events-none shrink-0",
|
|
44
|
+
children: leadingVisual
|
|
45
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
46
|
+
className: clsx("flex w-full truncate", as === "floating" && "flex-col", as === "filter" && "gap-input-gap-input-text-to-elements"),
|
|
47
|
+
children: [as && ["filter", "floating"].includes(as) && /* @__PURE__ */ jsx(FormFieldLabel, {
|
|
48
|
+
as,
|
|
49
|
+
size,
|
|
50
|
+
label: formFieldProps.label,
|
|
51
|
+
isRequired: formFieldProps.isRequired,
|
|
52
|
+
isDisabled: formFieldProps.isDisabled
|
|
53
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
54
|
+
className: clsx("truncate", !hasValue && "text-text-default-3"),
|
|
55
|
+
children: [staticDisplayContent, shouldRenderFloatingLineSpacer && /* @__PURE__ */ jsx(Fragment, { children: "\xA0" })]
|
|
56
|
+
})]
|
|
57
|
+
})]
|
|
58
|
+
}), trailingVisual && /* @__PURE__ */ jsx("div", {
|
|
59
|
+
className: clsx(inputSizeCva({
|
|
60
|
+
size,
|
|
61
|
+
as
|
|
62
|
+
}), "pointer-events-none flex items-center gap-input-gap-trailing-elements py-0! pl-0!"),
|
|
63
|
+
children: trailingVisual
|
|
64
|
+
})]
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { StaticInput };
|
|
@@ -19,6 +19,7 @@ export declare namespace UIConfig {
|
|
|
19
19
|
[P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : Exclude<T[P], null | undefined>;
|
|
20
20
|
};
|
|
21
21
|
export interface Options {
|
|
22
|
+
renderStaticInput: boolean;
|
|
22
23
|
input: Pick<TextInputProps, "variant" | "isClearable" | "hideLabel" | "as" | "size">;
|
|
23
24
|
button: Pick<ButtonProps, "variant" | "size">;
|
|
24
25
|
numberInput: Pick<NumberInputProps, "formatOptions">;
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { CalendarDate, CalendarDateTime, DateValue, ZonedDateTime } from '@internationalized/date';
|
|
2
2
|
export declare namespace DateTimeUtils {
|
|
3
|
+
function getDatePlaceholder(locale?: string): string;
|
|
4
|
+
function getTimePlaceholder(locale?: string): string;
|
|
5
|
+
function getDateTimePlaceholder(locale?: string): string;
|
|
6
|
+
function getDateRangePlaceholder(locale?: string): string;
|
|
7
|
+
function formatCalendarDateLocalized(calendarDate: CalendarDate, locale?: string): string;
|
|
8
|
+
function formatTimeLocalized(timeValue: {
|
|
9
|
+
hour: number;
|
|
10
|
+
minute: number;
|
|
11
|
+
}, locale?: string): string;
|
|
12
|
+
function formatCalendarDateTimeLocalized(calendarDateTime: Pick<CalendarDateTime, "day" | "month" | "year" | "hour" | "minute">, locale?: string): string;
|
|
3
13
|
function fromISOtoZonedDateTime(isoString: string): ZonedDateTime;
|
|
4
14
|
function fromDateValueToISO(dateValue: DateValue): string;
|
|
5
15
|
function fromLocalToZonedDateTime(date: Date): ZonedDateTime;
|
|
@@ -1,7 +1,88 @@
|
|
|
1
|
-
import { CalendarDate, CalendarDateTime, fromDate, getLocalTimeZone, parseAbsolute, parseAbsoluteToLocal } from "@internationalized/date";
|
|
1
|
+
import { CalendarDate, CalendarDateTime, DateFormatter, fromDate, getLocalTimeZone, parseAbsolute, parseAbsoluteToLocal } from "@internationalized/date";
|
|
2
2
|
//#region src/utils/date-time.utils.ts
|
|
3
3
|
var DateTimeUtils;
|
|
4
4
|
(function(_DateTimeUtils) {
|
|
5
|
+
const DATE_SAMPLE_DATE_UTC = new Date(Date.UTC(2e3, 10, 22));
|
|
6
|
+
const TIME_SAMPLE_DATE_UTC = new Date(Date.UTC(2e3, 10, 22, 13, 45));
|
|
7
|
+
const getDatePlaceholderFormatter = (locale) => new Intl.DateTimeFormat(locale, {
|
|
8
|
+
day: "2-digit",
|
|
9
|
+
month: "2-digit",
|
|
10
|
+
year: "numeric"
|
|
11
|
+
});
|
|
12
|
+
const getTimePlaceholderFormatter = (locale) => new Intl.DateTimeFormat(locale, {
|
|
13
|
+
hour: "2-digit",
|
|
14
|
+
minute: "2-digit",
|
|
15
|
+
hourCycle: "h23"
|
|
16
|
+
});
|
|
17
|
+
const getResolvedLocale = (locale) => {
|
|
18
|
+
if (locale) return locale;
|
|
19
|
+
return new Intl.DateTimeFormat().resolvedOptions().locale;
|
|
20
|
+
};
|
|
21
|
+
const getDateFormatter = (locale) => new DateFormatter(getResolvedLocale(locale), {
|
|
22
|
+
day: "2-digit",
|
|
23
|
+
month: "2-digit",
|
|
24
|
+
year: "numeric",
|
|
25
|
+
timeZone: "UTC"
|
|
26
|
+
});
|
|
27
|
+
const getTimeFormatter = (locale) => new DateFormatter(getResolvedLocale(locale), {
|
|
28
|
+
hour: "2-digit",
|
|
29
|
+
minute: "2-digit",
|
|
30
|
+
hourCycle: "h23",
|
|
31
|
+
timeZone: "UTC"
|
|
32
|
+
});
|
|
33
|
+
const getDateTimeFormatter = (locale) => new DateFormatter(getResolvedLocale(locale), {
|
|
34
|
+
day: "2-digit",
|
|
35
|
+
month: "2-digit",
|
|
36
|
+
year: "numeric",
|
|
37
|
+
hour: "2-digit",
|
|
38
|
+
minute: "2-digit",
|
|
39
|
+
hourCycle: "h23",
|
|
40
|
+
timeZone: "UTC"
|
|
41
|
+
});
|
|
42
|
+
const mapTypeToPlaceholder = (type) => {
|
|
43
|
+
switch (type) {
|
|
44
|
+
case "day": return "dd";
|
|
45
|
+
case "month": return "mm";
|
|
46
|
+
case "year": return "yyyy";
|
|
47
|
+
case "hour": return "hh";
|
|
48
|
+
case "minute": return "mm";
|
|
49
|
+
default: return null;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const formatPlaceholder = (formatter, sampleDate) => {
|
|
53
|
+
return formatter.formatToParts(sampleDate).map((part) => mapTypeToPlaceholder(part.type) ?? part.value).join("");
|
|
54
|
+
};
|
|
55
|
+
function getDatePlaceholder(locale) {
|
|
56
|
+
return formatPlaceholder(getDatePlaceholderFormatter(locale), DATE_SAMPLE_DATE_UTC);
|
|
57
|
+
}
|
|
58
|
+
_DateTimeUtils.getDatePlaceholder = getDatePlaceholder;
|
|
59
|
+
function getTimePlaceholder(locale) {
|
|
60
|
+
return formatPlaceholder(getTimePlaceholderFormatter(locale), TIME_SAMPLE_DATE_UTC);
|
|
61
|
+
}
|
|
62
|
+
_DateTimeUtils.getTimePlaceholder = getTimePlaceholder;
|
|
63
|
+
function getDateTimePlaceholder(locale) {
|
|
64
|
+
return `${getDatePlaceholder(locale)}, ${getTimePlaceholder(locale)}`;
|
|
65
|
+
}
|
|
66
|
+
_DateTimeUtils.getDateTimePlaceholder = getDateTimePlaceholder;
|
|
67
|
+
function getDateRangePlaceholder(locale) {
|
|
68
|
+
const datePlaceholder = getDatePlaceholder(locale);
|
|
69
|
+
return `${datePlaceholder} – ${datePlaceholder}`;
|
|
70
|
+
}
|
|
71
|
+
_DateTimeUtils.getDateRangePlaceholder = getDateRangePlaceholder;
|
|
72
|
+
function formatCalendarDateLocalized(calendarDate, locale) {
|
|
73
|
+
return getDateFormatter(locale).format(calendarDate.toDate("UTC"));
|
|
74
|
+
}
|
|
75
|
+
_DateTimeUtils.formatCalendarDateLocalized = formatCalendarDateLocalized;
|
|
76
|
+
function formatTimeLocalized(timeValue, locale) {
|
|
77
|
+
const dateTime = new CalendarDateTime(2e3, 11, 22, timeValue.hour, timeValue.minute);
|
|
78
|
+
return getTimeFormatter(locale).format(dateTime.toDate("UTC"));
|
|
79
|
+
}
|
|
80
|
+
_DateTimeUtils.formatTimeLocalized = formatTimeLocalized;
|
|
81
|
+
function formatCalendarDateTimeLocalized(calendarDateTime, locale) {
|
|
82
|
+
const normalizedValue = new CalendarDateTime(calendarDateTime.year, calendarDateTime.month, calendarDateTime.day, calendarDateTime.hour, calendarDateTime.minute);
|
|
83
|
+
return getDateTimeFormatter(locale).format(normalizedValue.toDate("UTC"));
|
|
84
|
+
}
|
|
85
|
+
_DateTimeUtils.formatCalendarDateTimeLocalized = formatCalendarDateTimeLocalized;
|
|
5
86
|
function fromISOtoZonedDateTime(isoString) {
|
|
6
87
|
return parseAbsoluteToLocal(isoString);
|
|
7
88
|
}
|