@refraktor/dates 0.0.3 → 0.0.5
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/build/components/date-range-picker/date-range-picker.d.ts +4 -0
- package/build/components/date-range-picker/date-range-picker.d.ts.map +1 -0
- package/build/components/date-range-picker/date-range-picker.js +379 -0
- package/build/components/date-range-picker/date-range-picker.types.d.ts +100 -0
- package/build/components/date-range-picker/date-range-picker.types.d.ts.map +1 -0
- package/build/components/date-range-picker/date-range-picker.types.js +1 -0
- package/build/components/date-range-picker/index.d.ts +3 -0
- package/build/components/date-range-picker/index.d.ts.map +1 -0
- package/build/components/date-range-picker/index.js +1 -0
- package/build/components/time-input/index.d.ts +1 -1
- package/build/components/time-input/index.d.ts.map +1 -1
- package/build/components/time-input/time-input.d.ts.map +1 -1
- package/build/components/time-input/time-input.js +7 -196
- package/build/components/time-input/time-input.types.d.ts +5 -83
- package/build/components/time-input/time-input.types.d.ts.map +1 -1
- package/build/components/time-picker/index.d.ts +1 -1
- package/build/components/time-picker/index.d.ts.map +1 -1
- package/build/components/time-picker/time-picker.d.ts.map +1 -1
- package/build/components/time-picker/time-picker.js +498 -350
- package/build/components/time-picker/time-picker.types.d.ts +96 -61
- package/build/components/time-picker/time-picker.types.d.ts.map +1 -1
- package/build/style.css +2 -2
- package/package.json +33 -4
- package/.turbo/turbo-build.log +0 -4
- package/refraktor-dates-0.0.1-alpha.0.tgz +0 -0
- package/src/components/date-input/date-input.tsx +0 -379
- package/src/components/date-input/date-input.types.ts +0 -161
- package/src/components/date-input/index.ts +0 -13
- package/src/components/date-picker/date-picker.tsx +0 -649
- package/src/components/date-picker/date-picker.types.ts +0 -145
- package/src/components/date-picker/index.ts +0 -15
- package/src/components/dates-provider/context.ts +0 -18
- package/src/components/dates-provider/dates-provider.tsx +0 -136
- package/src/components/dates-provider/index.ts +0 -10
- package/src/components/dates-provider/types.ts +0 -33
- package/src/components/dates-provider/use-dates.ts +0 -5
- package/src/components/index.ts +0 -9
- package/src/components/month-input/index.ts +0 -13
- package/src/components/month-input/month-input.tsx +0 -366
- package/src/components/month-input/month-input.types.ts +0 -139
- package/src/components/month-picker/index.ts +0 -14
- package/src/components/month-picker/month-picker.tsx +0 -458
- package/src/components/month-picker/month-picker.types.ts +0 -117
- package/src/components/picker-shared/index.ts +0 -7
- package/src/components/picker-shared/picker-header.tsx +0 -178
- package/src/components/picker-shared/picker-header.types.ts +0 -49
- package/src/components/picker-shared/picker.styles.ts +0 -69
- package/src/components/picker-shared/picker.types.ts +0 -4
- package/src/components/time-input/index.ts +0 -23
- package/src/components/time-input/time-input.tsx +0 -453
- package/src/components/time-input/time-input.types.ts +0 -163
- package/src/components/time-picker/index.ts +0 -19
- package/src/components/time-picker/time-picker.tsx +0 -737
- package/src/components/time-picker/time-picker.types.ts +0 -135
- package/src/components/year-input/index.ts +0 -13
- package/src/components/year-input/year-input.tsx +0 -350
- package/src/components/year-input/year-input.types.ts +0 -118
- package/src/components/year-picker/index.ts +0 -15
- package/src/components/year-picker/year-picker.tsx +0 -504
- package/src/components/year-picker/year-picker.types.ts +0 -108
- package/src/index.ts +0 -3
- package/src/style.css +0 -1
- package/tsconfig.json +0 -13
|
@@ -1,403 +1,551 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useId, useUncontrolled } from "@refraktor/utils";
|
|
3
|
-
import { useMemo } from "react";
|
|
4
|
-
import { createClassNamesConfig, createComponentConfig, factory, useClassNames, useProps, useTheme } from "@refraktor/core";
|
|
5
|
-
import {
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { createClassNamesConfig, createComponentConfig, factory, Input, useClassNames, useProps, useTheme } from "@refraktor/core";
|
|
5
|
+
import { autoUpdate, flip, FloatingFocusManager, FloatingPortal, offset, shift, useClick, useDismiss, useFloating, useInteractions, useRole } from "@floating-ui/react";
|
|
6
|
+
import { getPickerSizeStyles } from "../picker-shared";
|
|
6
7
|
const HOURS_IN_DAY = 24;
|
|
7
8
|
const MINUTES_IN_HOUR = 60;
|
|
8
9
|
const SECONDS_IN_MINUTE = 60;
|
|
9
|
-
const
|
|
10
|
-
const DEFAULT_MODE = "24h";
|
|
11
|
-
const TIME_SEGMENT_PATTERN = /^\d{1,2}$/;
|
|
10
|
+
const PLACEHOLDER = "--";
|
|
12
11
|
const defaultProps = {
|
|
13
|
-
|
|
12
|
+
format: "24h",
|
|
13
|
+
withSeconds: false,
|
|
14
|
+
withDropdown: false,
|
|
15
|
+
clearable: false,
|
|
14
16
|
disabled: false,
|
|
17
|
+
readOnly: false,
|
|
18
|
+
variant: "default",
|
|
15
19
|
size: "md",
|
|
16
|
-
radius: "default"
|
|
20
|
+
radius: "default",
|
|
21
|
+
hoursStep: 1,
|
|
22
|
+
minutesStep: 1,
|
|
23
|
+
secondsStep: 1,
|
|
24
|
+
amPmLabels: { am: "AM", pm: "PM" }
|
|
17
25
|
};
|
|
18
26
|
const pad = (value) => String(value).padStart(2, "0");
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
23
|
-
const to24Hour = (hour12, period) => {
|
|
24
|
-
const normalizedHour = hour12 % 12;
|
|
25
|
-
return period === "pm" ? normalizedHour + 12 : normalizedHour;
|
|
26
|
-
};
|
|
27
|
-
const toSecondsOfDay = (hours24, minutes, seconds) => hours24 * MINUTES_IN_HOUR * SECONDS_IN_MINUTE + minutes * SECONDS_IN_MINUTE + seconds;
|
|
28
|
-
const createTimeParts = (hours24, minutes, seconds) => {
|
|
29
|
-
const normalizedHours24 = hours24 % HOURS_IN_DAY;
|
|
30
|
-
return {
|
|
31
|
-
hours24: normalizedHours24,
|
|
32
|
-
hour12: to12Hour(normalizedHours24),
|
|
33
|
-
minutes,
|
|
34
|
-
seconds,
|
|
35
|
-
period: normalizedHours24 >= 12 ? "pm" : "am"
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
const parseTimeValue = (value) => {
|
|
39
|
-
if (typeof value !== "string") {
|
|
40
|
-
return undefined;
|
|
27
|
+
const parseValue = (value, withSeconds) => {
|
|
28
|
+
if (!value || value === "") {
|
|
29
|
+
return { hours: null, minutes: null, seconds: null, amPm: null };
|
|
41
30
|
}
|
|
42
31
|
const segments = value.trim().split(":");
|
|
43
|
-
if (segments.length
|
|
44
|
-
|
|
45
|
-
return undefined;
|
|
32
|
+
if (segments.length < 2) {
|
|
33
|
+
return { hours: null, minutes: null, seconds: null, amPm: null };
|
|
46
34
|
}
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
35
|
+
const hours = Number.parseInt(segments[0], 10);
|
|
36
|
+
const minutes = Number.parseInt(segments[1], 10);
|
|
37
|
+
const seconds = segments.length >= 3 ? Number.parseInt(segments[2], 10) : 0;
|
|
38
|
+
if (Number.isNaN(hours) ||
|
|
39
|
+
Number.isNaN(minutes) ||
|
|
40
|
+
Number.isNaN(seconds) ||
|
|
41
|
+
hours < 0 ||
|
|
42
|
+
hours >= HOURS_IN_DAY ||
|
|
53
43
|
minutes < 0 ||
|
|
54
44
|
minutes >= MINUTES_IN_HOUR ||
|
|
55
45
|
seconds < 0 ||
|
|
56
46
|
seconds >= SECONDS_IN_MINUTE) {
|
|
57
|
-
return
|
|
47
|
+
return { hours: null, minutes: null, seconds: null, amPm: null };
|
|
58
48
|
}
|
|
59
|
-
return
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const minutes = Math.floor((normalizedSeconds % (MINUTES_IN_HOUR * SECONDS_IN_MINUTE)) /
|
|
66
|
-
SECONDS_IN_MINUTE);
|
|
67
|
-
const remainingSeconds = normalizedSeconds % SECONDS_IN_MINUTE;
|
|
68
|
-
return createTimeParts(hours24, minutes, remainingSeconds);
|
|
49
|
+
return {
|
|
50
|
+
hours,
|
|
51
|
+
minutes,
|
|
52
|
+
seconds: withSeconds ? seconds : null,
|
|
53
|
+
amPm: hours >= 12 ? "PM" : "AM"
|
|
54
|
+
};
|
|
69
55
|
};
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return toTimePartsFromSeconds(bounds.minSeconds);
|
|
56
|
+
const formatValue = (parts, withSeconds) => {
|
|
57
|
+
if (parts.hours === null || parts.minutes === null) {
|
|
58
|
+
return "";
|
|
74
59
|
}
|
|
75
|
-
|
|
76
|
-
|
|
60
|
+
const base = `${pad(parts.hours)}:${pad(parts.minutes)}`;
|
|
61
|
+
if (withSeconds) {
|
|
62
|
+
return `${base}:${pad(parts.seconds ?? 0)}`;
|
|
77
63
|
}
|
|
78
|
-
return
|
|
79
|
-
};
|
|
80
|
-
const getCurrentTimeParts = () => {
|
|
81
|
-
const current = new Date();
|
|
82
|
-
return createTimeParts(current.getHours(), current.getMinutes(), current.getSeconds());
|
|
64
|
+
return base;
|
|
83
65
|
};
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const hasMax = maxParts !== undefined;
|
|
89
|
-
const minSeconds = hasMin
|
|
90
|
-
? toSecondsOfDay(minParts.hours24, minParts.minutes, minParts.seconds)
|
|
91
|
-
: Number.NEGATIVE_INFINITY;
|
|
92
|
-
const maxSeconds = hasMax
|
|
93
|
-
? toSecondsOfDay(maxParts.hours24, maxParts.minutes, maxParts.seconds)
|
|
94
|
-
: Number.POSITIVE_INFINITY;
|
|
95
|
-
if (hasMin && hasMax && minSeconds > maxSeconds) {
|
|
96
|
-
return {
|
|
97
|
-
minSeconds: maxSeconds,
|
|
98
|
-
maxSeconds: minSeconds,
|
|
99
|
-
hasMin: true,
|
|
100
|
-
hasMax: true
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
return {
|
|
104
|
-
minSeconds,
|
|
105
|
-
maxSeconds,
|
|
106
|
-
hasMin,
|
|
107
|
-
hasMax
|
|
108
|
-
};
|
|
66
|
+
const to12Hour = (hours24) => {
|
|
67
|
+
if (hours24 === 0 || hours24 === 12)
|
|
68
|
+
return 12;
|
|
69
|
+
return hours24 % 12;
|
|
109
70
|
};
|
|
110
|
-
const
|
|
111
|
-
(
|
|
112
|
-
|
|
113
|
-
const getSelectablePeriodRange = (period, bounds) => {
|
|
114
|
-
const periodStart = period === "am" ? 0 : SECONDS_IN_DAY / 2;
|
|
115
|
-
const periodEnd = period === "am" ? SECONDS_IN_DAY / 2 - 1 : SECONDS_IN_DAY - 1;
|
|
116
|
-
const start = Math.max(periodStart, bounds.minSeconds);
|
|
117
|
-
const end = Math.min(periodEnd, bounds.maxSeconds);
|
|
118
|
-
if (start > end) {
|
|
119
|
-
return undefined;
|
|
71
|
+
const to24Hour = (hour12, amPm) => {
|
|
72
|
+
if (amPm === "AM") {
|
|
73
|
+
return hour12 === 12 ? 0 : hour12;
|
|
120
74
|
}
|
|
121
|
-
return
|
|
75
|
+
return hour12 === 12 ? 12 : hour12 + 12;
|
|
122
76
|
};
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
if (!options[index].disabled) {
|
|
127
|
-
return index;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return -1;
|
|
77
|
+
const clampValue = (value, min, max, step) => {
|
|
78
|
+
const clamped = Math.max(min, Math.min(max, value));
|
|
79
|
+
return Math.round(clamped / step) * step;
|
|
131
80
|
};
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
81
|
+
const parseMinMax = (timeStr) => {
|
|
82
|
+
if (!timeStr)
|
|
83
|
+
return null;
|
|
84
|
+
const segments = timeStr.trim().split(":");
|
|
85
|
+
if (segments.length < 2)
|
|
86
|
+
return null;
|
|
87
|
+
const hours = Number.parseInt(segments[0], 10);
|
|
88
|
+
const minutes = Number.parseInt(segments[1], 10);
|
|
89
|
+
const seconds = segments.length >= 3 ? Number.parseInt(segments[2], 10) : 0;
|
|
90
|
+
if (Number.isNaN(hours) || Number.isNaN(minutes) || Number.isNaN(seconds))
|
|
91
|
+
return null;
|
|
92
|
+
return { hours, minutes, seconds };
|
|
141
93
|
};
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (firstEnabledIndex === -1 || lastEnabledIndex === -1) {
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
const selectedIndex = options.findIndex((option) => option.selected);
|
|
149
|
-
if (event.key === "Home") {
|
|
150
|
-
event.preventDefault();
|
|
151
|
-
onSelect(options[firstEnabledIndex].value);
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
if (event.key === "End") {
|
|
155
|
-
event.preventDefault();
|
|
156
|
-
onSelect(options[lastEnabledIndex].value);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
const applyStep = (direction, repeat = 1) => {
|
|
160
|
-
event.preventDefault();
|
|
161
|
-
let index = selectedIndex === -1
|
|
162
|
-
? direction === 1
|
|
163
|
-
? firstEnabledIndex
|
|
164
|
-
: lastEnabledIndex
|
|
165
|
-
: selectedIndex;
|
|
166
|
-
for (let step = 0; step < repeat; step += 1) {
|
|
167
|
-
const nextIndex = findNextEnabledIndex(options, index, direction);
|
|
168
|
-
if (nextIndex === index) {
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
index = nextIndex;
|
|
172
|
-
}
|
|
173
|
-
onSelect(options[index].value);
|
|
174
|
-
};
|
|
175
|
-
if (event.key === "ArrowDown") {
|
|
176
|
-
applyStep(1);
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
if (event.key === "ArrowUp") {
|
|
180
|
-
applyStep(-1);
|
|
181
|
-
return;
|
|
94
|
+
const setRef = (ref, node) => {
|
|
95
|
+
if (typeof ref === "function") {
|
|
96
|
+
ref(node);
|
|
182
97
|
}
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
if (event.key === "PageUp") {
|
|
188
|
-
applyStep(-1, 5);
|
|
98
|
+
else if (ref && "current" in ref) {
|
|
99
|
+
ref.current = node;
|
|
189
100
|
}
|
|
190
101
|
};
|
|
102
|
+
const inputSizes = {
|
|
103
|
+
xs: "h-5 px-2 text-[8px]",
|
|
104
|
+
sm: "h-6 px-2.5 text-[10px]",
|
|
105
|
+
md: "h-8 px-3 text-xs",
|
|
106
|
+
lg: "h-10 px-3.5 text-sm",
|
|
107
|
+
xl: "h-12 px-4 text-base"
|
|
108
|
+
};
|
|
109
|
+
const inputVariants = {
|
|
110
|
+
default: "bg-[var(--refraktor-bg)] text-[var(--refraktor-text)] border border-[var(--refraktor-border)]",
|
|
111
|
+
filled: "bg-[var(--refraktor-bg)] text-[var(--refraktor-text)]",
|
|
112
|
+
outline: "bg-transparent text-[var(--refraktor-text)] border border-[var(--refraktor-border)]"
|
|
113
|
+
};
|
|
114
|
+
const segmentWidths = {
|
|
115
|
+
xs: "w-[1.25rem]",
|
|
116
|
+
sm: "w-[1.5rem]",
|
|
117
|
+
md: "w-[1.75rem]",
|
|
118
|
+
lg: "w-[2rem]",
|
|
119
|
+
xl: "w-[2.5rem]"
|
|
120
|
+
};
|
|
121
|
+
const amPmWidths = {
|
|
122
|
+
xs: "w-[1.75rem]",
|
|
123
|
+
sm: "w-[2rem]",
|
|
124
|
+
md: "w-[2.25rem]",
|
|
125
|
+
lg: "w-[2.75rem]",
|
|
126
|
+
xl: "w-[3.25rem]"
|
|
127
|
+
};
|
|
128
|
+
const separatorSizes = {
|
|
129
|
+
xs: "text-[8px]",
|
|
130
|
+
sm: "text-[10px]",
|
|
131
|
+
md: "text-xs",
|
|
132
|
+
lg: "text-sm",
|
|
133
|
+
xl: "text-base"
|
|
134
|
+
};
|
|
191
135
|
const TimePicker = factory((_props, ref) => {
|
|
192
136
|
const { cx, getRadius } = useTheme();
|
|
193
|
-
const { id, value, defaultValue, onChange,
|
|
137
|
+
const { id, value, defaultValue, onChange, format, withSeconds, withDropdown, clearable, min, max, hoursStep, minutesStep, secondsStep, amPmLabels, disabled, readOnly, variant, size, radius, label, description, error, required, withAsterisk, leftSection, rightSection, hoursRef: hoursRefProp, minutesRef: minutesRefProp, secondsRef: secondsRefProp, amPmRef: amPmRefProp, hoursInputLabel, minutesInputLabel, secondsInputLabel, amPmInputLabel, popoverProps, onFocus, onBlur, className, classNames, ...props } = useProps("TimePicker", defaultProps, _props);
|
|
194
138
|
const classes = useClassNames("TimePicker", classNames);
|
|
195
139
|
const _id = useId(id);
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
const
|
|
140
|
+
const is12h = format === "12h";
|
|
141
|
+
const hoursRef = useRef(null);
|
|
142
|
+
const minutesRef = useRef(null);
|
|
143
|
+
const secondsRef = useRef(null);
|
|
144
|
+
const amPmRef = useRef(null);
|
|
145
|
+
const wrapperRef = useRef(null);
|
|
146
|
+
const blurTimeoutRef = useRef(null);
|
|
147
|
+
const minParsed = useMemo(() => parseMinMax(min), [min]);
|
|
148
|
+
const maxParsed = useMemo(() => parseMinMax(max), [max]);
|
|
149
|
+
const [internalValue, setInternalValue] = useUncontrolled({
|
|
199
150
|
value,
|
|
200
151
|
defaultValue,
|
|
201
|
-
finalValue:
|
|
202
|
-
onChange
|
|
203
|
-
|
|
204
|
-
|
|
152
|
+
finalValue: "",
|
|
153
|
+
onChange
|
|
154
|
+
});
|
|
155
|
+
const [parts, setParts] = useState(() => parseValue(internalValue, withSeconds));
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
const parsed = parseValue(internalValue, withSeconds);
|
|
158
|
+
setParts(parsed);
|
|
159
|
+
}, [internalValue, withSeconds]);
|
|
160
|
+
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
161
|
+
const isDropdownVisible = withDropdown && dropdownOpen && !disabled;
|
|
162
|
+
const floating = useFloating({
|
|
163
|
+
placement: popoverProps?.placement ?? "bottom-start",
|
|
164
|
+
open: isDropdownVisible,
|
|
165
|
+
onOpenChange: (open) => {
|
|
166
|
+
if (!disabled && !readOnly)
|
|
167
|
+
setDropdownOpen(open);
|
|
168
|
+
},
|
|
169
|
+
middleware: [
|
|
170
|
+
offset(popoverProps?.offset ?? 4),
|
|
171
|
+
flip(),
|
|
172
|
+
shift()
|
|
173
|
+
],
|
|
174
|
+
whileElementsMounted: autoUpdate,
|
|
175
|
+
strategy: "fixed"
|
|
176
|
+
});
|
|
177
|
+
const click = useClick(floating.context, {
|
|
178
|
+
enabled: withDropdown && !disabled && !readOnly
|
|
179
|
+
});
|
|
180
|
+
const dismiss = useDismiss(floating.context);
|
|
181
|
+
const role = useRole(floating.context, { role: "dialog" });
|
|
182
|
+
const { getReferenceProps, getFloatingProps } = useInteractions([
|
|
183
|
+
click,
|
|
184
|
+
dismiss,
|
|
185
|
+
role
|
|
186
|
+
]);
|
|
187
|
+
const emitValue = useCallback((nextParts) => {
|
|
188
|
+
const allFilled = nextParts.hours !== null &&
|
|
189
|
+
nextParts.minutes !== null &&
|
|
190
|
+
(!withSeconds || nextParts.seconds !== null) &&
|
|
191
|
+
(!is12h || nextParts.amPm !== null);
|
|
192
|
+
const allEmpty = nextParts.hours === null &&
|
|
193
|
+
nextParts.minutes === null &&
|
|
194
|
+
(nextParts.seconds === null || !withSeconds);
|
|
195
|
+
if (allFilled) {
|
|
196
|
+
let hours = nextParts.hours;
|
|
197
|
+
if (is12h && nextParts.amPm !== null) {
|
|
198
|
+
hours = to24Hour(hours, nextParts.amPm);
|
|
205
199
|
}
|
|
200
|
+
const formatted = formatValue({ ...nextParts, hours }, withSeconds);
|
|
201
|
+
setInternalValue(formatted);
|
|
206
202
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const parsed = parseTimeValue(selectedTimeState);
|
|
210
|
-
if (!parsed) {
|
|
211
|
-
return undefined;
|
|
203
|
+
else if (allEmpty) {
|
|
204
|
+
setInternalValue("");
|
|
212
205
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
206
|
+
}, [is12h, setInternalValue, withSeconds]);
|
|
207
|
+
const updateParts = useCallback((updater) => {
|
|
208
|
+
setParts((prev) => {
|
|
209
|
+
const next = updater(prev);
|
|
210
|
+
emitValue(next);
|
|
211
|
+
return next;
|
|
212
|
+
});
|
|
213
|
+
}, [emitValue]);
|
|
214
|
+
const getDisplayHours = useCallback((hours24) => {
|
|
215
|
+
if (hours24 === null)
|
|
216
|
+
return PLACEHOLDER;
|
|
217
|
+
if (is12h)
|
|
218
|
+
return pad(to12Hour(hours24));
|
|
219
|
+
return pad(hours24);
|
|
220
|
+
}, [is12h]);
|
|
221
|
+
const handleClear = useCallback(() => {
|
|
222
|
+
if (disabled || readOnly)
|
|
223
|
+
return;
|
|
224
|
+
const empty = {
|
|
225
|
+
hours: null,
|
|
226
|
+
minutes: null,
|
|
227
|
+
seconds: null,
|
|
228
|
+
amPm: null
|
|
229
|
+
};
|
|
230
|
+
setParts(empty);
|
|
231
|
+
setInternalValue("");
|
|
232
|
+
hoursRef.current?.focus();
|
|
233
|
+
}, [disabled, readOnly, setInternalValue]);
|
|
234
|
+
const createSegmentKeyHandler = useCallback((segment, prevRef, nextRef) => {
|
|
235
|
+
return (event) => {
|
|
236
|
+
if (disabled || readOnly)
|
|
237
|
+
return;
|
|
238
|
+
const step = segment === "hours"
|
|
239
|
+
? hoursStep
|
|
240
|
+
: segment === "minutes"
|
|
241
|
+
? minutesStep
|
|
242
|
+
: secondsStep;
|
|
243
|
+
const maxVal = segment === "hours"
|
|
244
|
+
? is12h
|
|
245
|
+
? 12
|
|
246
|
+
: HOURS_IN_DAY - 1
|
|
247
|
+
: segment === "minutes"
|
|
248
|
+
? MINUTES_IN_HOUR - 1
|
|
249
|
+
: SECONDS_IN_MINUTE - 1;
|
|
250
|
+
const minVal = segment === "hours" && is12h ? 1 : 0;
|
|
251
|
+
if (event.key === "ArrowUp") {
|
|
252
|
+
event.preventDefault();
|
|
253
|
+
updateParts((prev) => {
|
|
254
|
+
const current = prev[segment] ?? minVal;
|
|
255
|
+
let next = current + step;
|
|
256
|
+
if (next > maxVal)
|
|
257
|
+
next = minVal;
|
|
258
|
+
return { ...prev, [segment]: next };
|
|
259
|
+
});
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (event.key === "ArrowDown") {
|
|
263
|
+
event.preventDefault();
|
|
264
|
+
updateParts((prev) => {
|
|
265
|
+
const current = prev[segment] ?? maxVal;
|
|
266
|
+
let next = current - step;
|
|
267
|
+
if (next < minVal)
|
|
268
|
+
next = maxVal;
|
|
269
|
+
return { ...prev, [segment]: next };
|
|
270
|
+
});
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (event.key === "ArrowRight") {
|
|
274
|
+
event.preventDefault();
|
|
275
|
+
nextRef.current?.focus();
|
|
276
|
+
nextRef.current?.select();
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (event.key === "ArrowLeft") {
|
|
280
|
+
event.preventDefault();
|
|
281
|
+
prevRef.current?.focus();
|
|
282
|
+
prevRef.current?.select();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (event.key === "Home") {
|
|
286
|
+
event.preventDefault();
|
|
287
|
+
updateParts((prev) => ({ ...prev, [segment]: minVal }));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (event.key === "End") {
|
|
291
|
+
event.preventDefault();
|
|
292
|
+
updateParts((prev) => ({ ...prev, [segment]: maxVal }));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (event.key === "Backspace") {
|
|
296
|
+
event.preventDefault();
|
|
297
|
+
updateParts((prev) => {
|
|
298
|
+
if (prev[segment] === null) {
|
|
299
|
+
prevRef.current?.focus();
|
|
300
|
+
prevRef.current?.select();
|
|
301
|
+
return prev;
|
|
302
|
+
}
|
|
303
|
+
return { ...prev, [segment]: null };
|
|
304
|
+
});
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (event.key === "Tab") {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (/^\d$/.test(event.key)) {
|
|
311
|
+
event.preventDefault();
|
|
312
|
+
const digit = Number.parseInt(event.key, 10);
|
|
313
|
+
updateParts((prev) => {
|
|
314
|
+
const current = prev[segment];
|
|
315
|
+
let next;
|
|
316
|
+
if (current === null || current >= 10) {
|
|
317
|
+
next = digit;
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
next = current * 10 + digit;
|
|
321
|
+
}
|
|
322
|
+
if (next > maxVal) {
|
|
323
|
+
next = digit;
|
|
324
|
+
}
|
|
325
|
+
const result = { ...prev, [segment]: next };
|
|
326
|
+
if (next >= (maxVal + 1) / 10 || (current !== null && current < 10)) {
|
|
327
|
+
requestAnimationFrame(() => {
|
|
328
|
+
nextRef.current?.focus();
|
|
329
|
+
nextRef.current?.select();
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
return result;
|
|
333
|
+
});
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (!event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
337
|
+
event.preventDefault();
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}, [disabled, hoursStep, is12h, minutesStep, readOnly, secondsStep, updateParts]);
|
|
341
|
+
const handleAmPmKeyDown = useCallback((event) => {
|
|
342
|
+
if (disabled || readOnly)
|
|
343
|
+
return;
|
|
344
|
+
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
345
|
+
event.preventDefault();
|
|
346
|
+
updateParts((prev) => ({
|
|
347
|
+
...prev,
|
|
348
|
+
amPm: prev.amPm === "AM" ? "PM" : "AM"
|
|
349
|
+
}));
|
|
222
350
|
return;
|
|
223
351
|
}
|
|
224
|
-
|
|
225
|
-
|
|
352
|
+
if (event.key === "ArrowLeft") {
|
|
353
|
+
event.preventDefault();
|
|
354
|
+
const prev = withSeconds ? secondsRef : minutesRef;
|
|
355
|
+
prev.current?.focus();
|
|
356
|
+
prev.current?.select();
|
|
226
357
|
return;
|
|
227
358
|
}
|
|
228
|
-
|
|
229
|
-
|
|
359
|
+
if (event.key.toLowerCase() === "a" ||
|
|
360
|
+
event.key.toLowerCase() === "p") {
|
|
361
|
+
event.preventDefault();
|
|
362
|
+
const nextAmPm = event.key.toLowerCase() === "a" ? "AM" : "PM";
|
|
363
|
+
updateParts((prev) => ({ ...prev, amPm: nextAmPm }));
|
|
230
364
|
return;
|
|
231
365
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
};
|
|
244
|
-
const setPeriod = (period) => {
|
|
245
|
-
const selectableRange = getSelectablePeriodRange(period, bounds);
|
|
246
|
-
if (!selectableRange) {
|
|
366
|
+
if (event.key === "Backspace") {
|
|
367
|
+
event.preventDefault();
|
|
368
|
+
updateParts((prev) => {
|
|
369
|
+
if (prev.amPm === null) {
|
|
370
|
+
const prev2 = withSeconds ? secondsRef : minutesRef;
|
|
371
|
+
prev2.current?.focus();
|
|
372
|
+
prev2.current?.select();
|
|
373
|
+
return prev;
|
|
374
|
+
}
|
|
375
|
+
return { ...prev, amPm: null };
|
|
376
|
+
});
|
|
247
377
|
return;
|
|
248
378
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
379
|
+
if (event.key === "Tab") {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (!event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
383
|
+
event.preventDefault();
|
|
384
|
+
}
|
|
385
|
+
}, [disabled, readOnly, updateParts, withSeconds]);
|
|
386
|
+
const handleWrapperFocus = useCallback((event) => {
|
|
387
|
+
if (blurTimeoutRef.current !== null) {
|
|
388
|
+
clearTimeout(blurTimeoutRef.current);
|
|
389
|
+
blurTimeoutRef.current = null;
|
|
390
|
+
}
|
|
391
|
+
if (!wrapperRef.current?.contains(event.relatedTarget)) {
|
|
392
|
+
onFocus?.(event);
|
|
393
|
+
if (withDropdown && !disabled && !readOnly) {
|
|
394
|
+
setDropdownOpen(true);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}, [disabled, onFocus, readOnly, withDropdown]);
|
|
398
|
+
const handleWrapperBlur = useCallback((event) => {
|
|
399
|
+
blurTimeoutRef.current = setTimeout(() => {
|
|
400
|
+
if (!wrapperRef.current?.contains(document.activeElement) &&
|
|
401
|
+
!floating.refs.floating.current?.contains(document.activeElement)) {
|
|
402
|
+
onBlur?.(event);
|
|
403
|
+
setDropdownOpen(false);
|
|
404
|
+
}
|
|
405
|
+
}, 0);
|
|
406
|
+
}, [floating.refs.floating, onBlur]);
|
|
407
|
+
const displayHours = is12h
|
|
408
|
+
? parts.hours !== null
|
|
409
|
+
? pad(to12Hour(parts.hours))
|
|
410
|
+
: PLACEHOLDER
|
|
411
|
+
: parts.hours !== null
|
|
412
|
+
? pad(parts.hours)
|
|
413
|
+
: PLACEHOLDER;
|
|
414
|
+
const displayMinutes = parts.minutes !== null ? pad(parts.minutes) : PLACEHOLDER;
|
|
415
|
+
const displaySeconds = parts.seconds !== null ? pad(parts.seconds) : PLACEHOLDER;
|
|
416
|
+
const displayAmPm = parts.amPm ?? PLACEHOLDER;
|
|
417
|
+
const hasValue = parts.hours !== null ||
|
|
418
|
+
parts.minutes !== null ||
|
|
419
|
+
(withSeconds && parts.seconds !== null);
|
|
420
|
+
const showClearButton = clearable && hasValue && !disabled && !readOnly;
|
|
421
|
+
const effectiveRightSection = showClearButton ? (_jsx("button", { type: "button", tabIndex: -1, "aria-label": "Clear time", className: cx("inline-flex items-center justify-center text-[var(--refraktor-text-secondary)] hover:text-[var(--refraktor-text)] transition-colors cursor-pointer"), onClick: handleClear, onMouseDown: (e) => e.preventDefault(), children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 16 16", fill: "currentColor", className: "size-3.5", children: _jsx("path", { d: "M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.75.75 0 1 1 1.06 1.06L9.06 8l3.22 3.22a.75.75 0 1 1-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 0 1-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z" }) }) })) : (rightSection);
|
|
422
|
+
const sizeClass = inputSizes[size] ?? inputSizes.md;
|
|
423
|
+
const variantClass = inputVariants[variant] ?? inputVariants.default;
|
|
424
|
+
const segmentWidth = segmentWidths[size] ?? segmentWidths.md;
|
|
425
|
+
const amPmWidth = amPmWidths[size] ?? amPmWidths.md;
|
|
426
|
+
const sepSize = separatorSizes[size] ?? separatorSizes.md;
|
|
427
|
+
const hoursKeyHandler = createSegmentKeyHandler("hours", { current: null }, minutesRef);
|
|
428
|
+
const minutesKeyHandler = createSegmentKeyHandler("minutes", hoursRef, withSeconds ? secondsRef : is12h ? amPmRef : { current: null });
|
|
429
|
+
const secondsKeyHandler = createSegmentKeyHandler("seconds", minutesRef, is12h ? amPmRef : { current: null });
|
|
430
|
+
const renderDropdown = () => {
|
|
431
|
+
if (!withDropdown)
|
|
432
|
+
return null;
|
|
433
|
+
const sizeStyles = getPickerSizeStyles(size);
|
|
434
|
+
const hoursCount = is12h ? 12 : HOURS_IN_DAY;
|
|
435
|
+
const hoursStart = is12h ? 1 : 0;
|
|
436
|
+
const hourOptions = [];
|
|
437
|
+
for (let i = hoursStart; i < hoursStart + hoursCount; i += hoursStep) {
|
|
438
|
+
hourOptions.push(i);
|
|
439
|
+
}
|
|
440
|
+
const minuteOptions = [];
|
|
441
|
+
for (let i = 0; i < MINUTES_IN_HOUR; i += minutesStep) {
|
|
442
|
+
minuteOptions.push(i);
|
|
443
|
+
}
|
|
444
|
+
const secondOptions = [];
|
|
445
|
+
for (let i = 0; i < SECONDS_IN_MINUTE; i += secondsStep) {
|
|
446
|
+
secondOptions.push(i);
|
|
447
|
+
}
|
|
448
|
+
const currentHourDisplay = is12h
|
|
449
|
+
? parts.hours !== null
|
|
450
|
+
? to12Hour(parts.hours)
|
|
451
|
+
: null
|
|
452
|
+
: parts.hours;
|
|
453
|
+
const renderColumn = (columnLabel, options, selectedValue, onSelect, extraClassName) => (_jsxs("div", { className: cx("flex flex-col min-w-0", classes.dropdownColumn, extraClassName), children: [_jsx("div", { className: cx("py-1.5 text-center font-medium text-[var(--refraktor-text-secondary)] border-b border-[var(--refraktor-border)] bg-[var(--refraktor-bg-subtle)]", sizeStyles.label, classes.dropdownColumnLabel), children: columnLabel }), _jsx("div", { className: cx("refraktor-scrollbar flex max-h-52 flex-col gap-0.5 p-1 overflow-y-auto"), children: options.map((opt) => {
|
|
454
|
+
const isSelected = opt === selectedValue;
|
|
455
|
+
const displayLabel = typeof opt === "number" ? pad(opt) : opt;
|
|
456
|
+
return (_jsx("button", { type: "button", tabIndex: -1, className: cx("inline-flex w-full items-center justify-center font-medium transition-colors", isSelected
|
|
457
|
+
? "bg-[var(--refraktor-primary)] text-[var(--refraktor-primary-text)]"
|
|
458
|
+
: "hover:bg-[var(--refraktor-bg-hover)] text-[var(--refraktor-text)]", sizeStyles.cell, getRadius(radius), classes.dropdownOption, isSelected && classes.dropdownOptionActive), onMouseDown: (e) => e.preventDefault(), onClick: () => onSelect(opt), children: displayLabel }, String(opt)));
|
|
459
|
+
}) })] }));
|
|
460
|
+
const handleDropdownHourSelect = (val) => {
|
|
461
|
+
const hourVal = typeof val === "number" ? val : Number(val);
|
|
462
|
+
updateParts((prev) => {
|
|
463
|
+
const next = { ...prev, hours: is12h ? to24Hour(hourVal, prev.amPm ?? "AM") : hourVal };
|
|
464
|
+
if (next.minutes === null) {
|
|
465
|
+
requestAnimationFrame(() => {
|
|
466
|
+
minutesRef.current?.focus();
|
|
467
|
+
minutesRef.current?.select();
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
return next;
|
|
471
|
+
});
|
|
301
472
|
};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return {
|
|
315
|
-
value: second,
|
|
316
|
-
label: getSecondLabel ? getSecondLabel(second) : pad(second),
|
|
317
|
-
ariaLabel: getSecondAriaLabel
|
|
318
|
-
? getSecondAriaLabel(second, selected)
|
|
319
|
-
: selected
|
|
320
|
-
? `Second ${pad(second)}, selected`
|
|
321
|
-
: `Choose second ${pad(second)}`,
|
|
322
|
-
selected,
|
|
323
|
-
disabled: isTimeDisabled(nextSeconds, disabled ?? false, bounds)
|
|
473
|
+
const handleDropdownMinuteSelect = (val) => {
|
|
474
|
+
const minVal = typeof val === "number" ? val : Number(val);
|
|
475
|
+
updateParts((prev) => {
|
|
476
|
+
const next = { ...prev, minutes: minVal };
|
|
477
|
+
if (withSeconds && next.seconds === null) {
|
|
478
|
+
requestAnimationFrame(() => {
|
|
479
|
+
secondsRef.current?.focus();
|
|
480
|
+
secondsRef.current?.select();
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
return next;
|
|
484
|
+
});
|
|
324
485
|
};
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
bounds,
|
|
329
|
-
disabled,
|
|
330
|
-
getSecondAriaLabel,
|
|
331
|
-
getSecondLabel,
|
|
332
|
-
selectedParts
|
|
333
|
-
]);
|
|
334
|
-
const periodOptions = useMemo(() => ["am", "pm"].map((period) => {
|
|
335
|
-
const selected = selectedParts?.period === period;
|
|
336
|
-
return {
|
|
337
|
-
value: period,
|
|
338
|
-
label: getPeriodLabel
|
|
339
|
-
? getPeriodLabel(period)
|
|
340
|
-
: period.toUpperCase(),
|
|
341
|
-
ariaLabel: getPeriodAriaLabel
|
|
342
|
-
? getPeriodAriaLabel(period, selected)
|
|
343
|
-
: selected
|
|
344
|
-
? `${period.toUpperCase()}, selected`
|
|
345
|
-
: `Choose ${period.toUpperCase()}`,
|
|
346
|
-
selected,
|
|
347
|
-
disabled: (disabled ?? false) ||
|
|
348
|
-
!getSelectablePeriodRange(period, bounds)
|
|
486
|
+
const handleDropdownSecondSelect = (val) => {
|
|
487
|
+
const secVal = typeof val === "number" ? val : Number(val);
|
|
488
|
+
updateParts((prev) => ({ ...prev, seconds: secVal }));
|
|
349
489
|
};
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
})
|
|
490
|
+
const handleDropdownAmPmSelect = (val) => {
|
|
491
|
+
const amPmVal = val;
|
|
492
|
+
updateParts((prev) => {
|
|
493
|
+
if (prev.hours === null)
|
|
494
|
+
return { ...prev, amPm: amPmVal };
|
|
495
|
+
const hour12 = to12Hour(prev.hours);
|
|
496
|
+
const newHours24 = to24Hour(hour12, amPmVal);
|
|
497
|
+
return { ...prev, hours: newHours24, amPm: amPmVal };
|
|
498
|
+
});
|
|
499
|
+
};
|
|
500
|
+
const columnCount = (withSeconds ? 4 : 3) + (is12h ? 1 : 0) - (withSeconds ? 0 : 1);
|
|
501
|
+
const gridColsClass = columnCount === 2
|
|
502
|
+
? "grid-cols-2"
|
|
503
|
+
: columnCount === 3
|
|
504
|
+
? "grid-cols-3"
|
|
505
|
+
: "grid-cols-4";
|
|
506
|
+
return (_jsx(FloatingPortal, { children: isDropdownVisible && (_jsx(FloatingFocusManager, { context: floating.context, modal: false, initialFocus: -1, returnFocus: false, children: _jsx("div", { ref: floating.refs.setFloating, style: {
|
|
507
|
+
...floating.floatingStyles,
|
|
508
|
+
zIndex: 1000
|
|
509
|
+
}, className: cx("border border-[var(--refraktor-border)] bg-[var(--refraktor-bg)] shadow-md overflow-hidden", getRadius(radius), classes.dropdown), ...getFloatingProps(), children: _jsxs("div", { className: cx("grid divide-x divide-[var(--refraktor-border)]", gridColsClass), children: [renderColumn("Hour", hourOptions, currentHourDisplay, handleDropdownHourSelect), renderColumn("Min", minuteOptions, parts.minutes, handleDropdownMinuteSelect), withSeconds &&
|
|
510
|
+
renderColumn("Sec", secondOptions, parts.seconds, handleDropdownSecondSelect), is12h &&
|
|
511
|
+
renderColumn(amPmLabels.am + "/" + amPmLabels.pm, [amPmLabels.am, amPmLabels.pm], parts.amPm ===
|
|
512
|
+
"AM"
|
|
513
|
+
? amPmLabels.am
|
|
514
|
+
: parts.amPm === "PM"
|
|
515
|
+
? amPmLabels.pm
|
|
516
|
+
: null, (val) => {
|
|
517
|
+
const normalized = val === amPmLabels.am
|
|
518
|
+
? "AM"
|
|
519
|
+
: "PM";
|
|
520
|
+
handleDropdownAmPmSelect(normalized);
|
|
521
|
+
})] }) }) })) }));
|
|
370
522
|
};
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
options: periodOptions,
|
|
398
|
-
onSelect: setPeriod,
|
|
399
|
-
className: classes.periodSection
|
|
400
|
-
})] }) }));
|
|
523
|
+
const hasWrapper = label || description || error;
|
|
524
|
+
const inputContent = (_jsxs("div", { ref: (node) => {
|
|
525
|
+
if (wrapperRef)
|
|
526
|
+
wrapperRef.current = node;
|
|
527
|
+
floating.refs.setReference(node);
|
|
528
|
+
}, className: cx("relative w-full inline-flex items-center transition-all", sizeClass, variantClass, getRadius(radius), "focus-within:border-[var(--refraktor-primary)]", error && typeof error !== "boolean" && "border-[var(--refraktor-colors-red-6)]", disabled && "opacity-50 cursor-not-allowed", classes.fieldsWrapper, !hasWrapper && className), onFocus: handleWrapperFocus, onBlur: handleWrapperBlur, ...(!hasWrapper ? getReferenceProps(props) : getReferenceProps()), children: [leftSection && (_jsx("div", { className: "flex h-full items-center justify-center text-[var(--refraktor-text-secondary)] shrink-0 select-none", children: leftSection })), _jsxs("div", { className: cx("flex items-center flex-1 min-w-0 gap-0.5"), children: [_jsx("input", { ref: (node) => {
|
|
529
|
+
hoursRef.current = node;
|
|
530
|
+
setRef(hoursRefProp, node);
|
|
531
|
+
}, id: `${_id}-hours`, type: "text", inputMode: "numeric", autoComplete: "off", placeholder: PLACEHOLDER, value: parts.hours !== null ? (is12h ? pad(to12Hour(parts.hours)) : pad(parts.hours)) : "", "aria-label": hoursInputLabel ?? "Hours", readOnly: true, tabIndex: disabled ? -1 : 0, disabled: disabled, className: cx("bg-transparent border-none outline-none text-center text-[var(--refraktor-text)] placeholder:text-[var(--refraktor-text-tertiary)] cursor-default select-all p-0", segmentWidth, classes.field), onKeyDown: hoursKeyHandler, onFocus: (e) => e.target.select() }), _jsx("span", { className: cx("text-[var(--refraktor-text-secondary)] select-none leading-none", sepSize, classes.separator), children: ":" }), _jsx("input", { ref: (node) => {
|
|
532
|
+
minutesRef.current = node;
|
|
533
|
+
setRef(minutesRefProp, node);
|
|
534
|
+
}, id: `${_id}-minutes`, type: "text", inputMode: "numeric", autoComplete: "off", placeholder: PLACEHOLDER, value: parts.minutes !== null ? pad(parts.minutes) : "", "aria-label": minutesInputLabel ?? "Minutes", readOnly: true, tabIndex: disabled ? -1 : 0, disabled: disabled, className: cx("bg-transparent border-none outline-none text-center text-[var(--refraktor-text)] placeholder:text-[var(--refraktor-text-tertiary)] cursor-default select-all p-0", segmentWidth, classes.field), onKeyDown: minutesKeyHandler, onFocus: (e) => e.target.select() }), withSeconds && (_jsxs(_Fragment, { children: [_jsx("span", { className: cx("text-[var(--refraktor-text-secondary)] select-none leading-none", sepSize, classes.separator), children: ":" }), _jsx("input", { ref: (node) => {
|
|
535
|
+
secondsRef.current = node;
|
|
536
|
+
setRef(secondsRefProp, node);
|
|
537
|
+
}, id: `${_id}-seconds`, type: "text", inputMode: "numeric", autoComplete: "off", placeholder: PLACEHOLDER, value: parts.seconds !== null
|
|
538
|
+
? pad(parts.seconds)
|
|
539
|
+
: "", "aria-label": secondsInputLabel ?? "Seconds", readOnly: true, tabIndex: disabled ? -1 : 0, disabled: disabled, className: cx("bg-transparent border-none outline-none text-center text-[var(--refraktor-text)] placeholder:text-[var(--refraktor-text-tertiary)] cursor-default select-all p-0", segmentWidth, classes.field), onKeyDown: secondsKeyHandler, onFocus: (e) => e.target.select() })] })), is12h && (_jsx("input", { ref: (node) => {
|
|
540
|
+
amPmRef.current = node;
|
|
541
|
+
setRef(amPmRefProp, node);
|
|
542
|
+
}, id: `${_id}-ampm`, type: "text", autoComplete: "off", placeholder: PLACEHOLDER, value: parts.amPm !== null
|
|
543
|
+
? parts.amPm === "AM"
|
|
544
|
+
? amPmLabels.am
|
|
545
|
+
: amPmLabels.pm
|
|
546
|
+
: "", "aria-label": amPmInputLabel ?? "AM/PM", readOnly: true, tabIndex: disabled ? -1 : 0, disabled: disabled, className: cx("bg-transparent border-none outline-none text-center text-[var(--refraktor-text)] placeholder:text-[var(--refraktor-text-tertiary)] cursor-default select-all p-0 ml-1", amPmWidth, classes.amPmInput), onKeyDown: handleAmPmKeyDown, onFocus: (e) => e.target.select() }))] }), effectiveRightSection && (_jsx("div", { className: "flex h-full items-center justify-center text-[var(--refraktor-text-secondary)] shrink-0 select-none", children: effectiveRightSection }))] }));
|
|
547
|
+
const content = hasWrapper ? (_jsxs(Input.Wrapper, { ref: ref, label: label, description: description, error: error, required: required, withAsterisk: withAsterisk, inputId: `${_id}-hours`, className: cx(classes.root, className), children: [inputContent, renderDropdown()] })) : (_jsxs("div", { ref: ref, className: cx(classes.root, className), children: [inputContent, renderDropdown()] }));
|
|
548
|
+
return content;
|
|
401
549
|
});
|
|
402
550
|
TimePicker.displayName = "@refraktor/dates/TimePicker";
|
|
403
551
|
TimePicker.configure = createComponentConfig();
|