@refraktor/dates 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/build/components/date-range-picker/date-range-picker.d.ts +4 -0
  3. package/build/components/date-range-picker/date-range-picker.d.ts.map +1 -0
  4. package/build/components/date-range-picker/date-range-picker.js +379 -0
  5. package/build/components/date-range-picker/date-range-picker.types.d.ts +100 -0
  6. package/build/components/date-range-picker/date-range-picker.types.d.ts.map +1 -0
  7. package/build/components/date-range-picker/date-range-picker.types.js +1 -0
  8. package/build/components/date-range-picker/index.d.ts +3 -0
  9. package/build/components/date-range-picker/index.d.ts.map +1 -0
  10. package/build/components/date-range-picker/index.js +1 -0
  11. package/build/components/time-input/index.d.ts +1 -1
  12. package/build/components/time-input/index.d.ts.map +1 -1
  13. package/build/components/time-input/time-input.d.ts.map +1 -1
  14. package/build/components/time-input/time-input.js +7 -196
  15. package/build/components/time-input/time-input.types.d.ts +5 -83
  16. package/build/components/time-input/time-input.types.d.ts.map +1 -1
  17. package/build/components/time-picker/index.d.ts +1 -1
  18. package/build/components/time-picker/index.d.ts.map +1 -1
  19. package/build/components/time-picker/time-picker.d.ts.map +1 -1
  20. package/build/components/time-picker/time-picker.js +498 -350
  21. package/build/components/time-picker/time-picker.types.d.ts +96 -61
  22. package/build/components/time-picker/time-picker.types.d.ts.map +1 -1
  23. package/build/style.css +1 -1
  24. package/package.json +3 -3
  25. package/src/components/time-input/index.ts +6 -23
  26. package/src/components/time-input/time-input.tsx +48 -453
  27. package/src/components/time-input/time-input.types.ts +30 -163
  28. package/src/components/time-picker/index.ts +10 -19
  29. package/src/components/time-picker/time-picker.tsx +1088 -737
  30. package/src/components/time-picker/time-picker.types.ts +166 -135
@@ -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 { getGridColumns, getPickerSizeStyles } from "../picker-shared";
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 SECONDS_IN_DAY = HOURS_IN_DAY * MINUTES_IN_HOUR * SECONDS_IN_MINUTE;
10
- const DEFAULT_MODE = "24h";
11
- const TIME_SEGMENT_PATTERN = /^\d{1,2}$/;
10
+ const PLACEHOLDER = "--";
12
11
  const defaultProps = {
13
- mode: DEFAULT_MODE,
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 to12Hour = (hours24) => {
20
- const normalized = hours24 % 12;
21
- return normalized === 0 ? 12 : normalized;
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 !== 3 ||
44
- !segments.every((segment) => TIME_SEGMENT_PATTERN.test(segment))) {
45
- return undefined;
32
+ if (segments.length < 2) {
33
+ return { hours: null, minutes: null, seconds: null, amPm: null };
46
34
  }
47
- const [hoursText, minutesText, secondsText] = segments;
48
- const hours24 = Number.parseInt(hoursText, 10);
49
- const minutes = Number.parseInt(minutesText, 10);
50
- const seconds = Number.parseInt(secondsText, 10);
51
- if (hours24 < 0 ||
52
- hours24 >= HOURS_IN_DAY ||
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 undefined;
47
+ return { hours: null, minutes: null, seconds: null, amPm: null };
58
48
  }
59
- return createTimeParts(hours24, minutes, seconds);
60
- };
61
- const formatTimeValue = (hours24, minutes, seconds) => `${pad(hours24)}:${pad(minutes)}:${pad(seconds)}`;
62
- const toTimePartsFromSeconds = (seconds) => {
63
- const normalizedSeconds = ((seconds % SECONDS_IN_DAY) + SECONDS_IN_DAY) % SECONDS_IN_DAY;
64
- const hours24 = Math.floor(normalizedSeconds / (MINUTES_IN_HOUR * SECONDS_IN_MINUTE));
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 clampTimeParts = (parts, bounds) => {
71
- const seconds = toSecondsOfDay(parts.hours24, parts.minutes, parts.seconds);
72
- if (bounds.hasMin && seconds < bounds.minSeconds) {
73
- return toTimePartsFromSeconds(bounds.minSeconds);
56
+ const formatValue = (parts, withSeconds) => {
57
+ if (parts.hours === null || parts.minutes === null) {
58
+ return "";
74
59
  }
75
- if (bounds.hasMax && seconds > bounds.maxSeconds) {
76
- return toTimePartsFromSeconds(bounds.maxSeconds);
60
+ const base = `${pad(parts.hours)}:${pad(parts.minutes)}`;
61
+ if (withSeconds) {
62
+ return `${base}:${pad(parts.seconds ?? 0)}`;
77
63
  }
78
- return parts;
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 getTimeBounds = (minTime, maxTime) => {
85
- const minParts = parseTimeValue(minTime);
86
- const maxParts = parseTimeValue(maxTime);
87
- const hasMin = minParts !== undefined;
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 isTimeDisabled = (seconds, disabled, bounds) => disabled ||
111
- (bounds.hasMin && seconds < bounds.minSeconds) ||
112
- (bounds.hasMax && seconds > bounds.maxSeconds);
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 { start, end };
75
+ return hour12 === 12 ? 12 : hour12 + 12;
122
76
  };
123
- const getFirstEnabledIndex = (options) => options.findIndex((option) => !option.disabled);
124
- const getLastEnabledIndex = (options) => {
125
- for (let index = options.length - 1; index >= 0; index -= 1) {
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 findNextEnabledIndex = (options, startIndex, direction) => {
133
- let index = startIndex + direction;
134
- while (index >= 0 && index < options.length) {
135
- if (!options[index].disabled) {
136
- return index;
137
- }
138
- index += direction;
139
- }
140
- return startIndex;
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 handleListKeyDown = (event, options, onSelect) => {
143
- const firstEnabledIndex = getFirstEnabledIndex(options);
144
- const lastEnabledIndex = getLastEnabledIndex(options);
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 (event.key === "PageDown") {
184
- applyStep(1, 5);
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, minTime, maxTime, mode, disabled, size, radius, getHourLabel, getMinuteLabel, getSecondLabel, getPeriodLabel, getHourAriaLabel, getMinuteAriaLabel, getSecondAriaLabel, getPeriodAriaLabel, className, classNames, ...props } = useProps("TimePicker", defaultProps, _props);
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 sizeStyles = getPickerSizeStyles(size);
197
- const bounds = useMemo(() => getTimeBounds(minTime, maxTime), [minTime, maxTime]);
198
- const [selectedTimeState, setSelectedTime] = useUncontrolled({
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: undefined,
202
- onChange: (nextTime) => {
203
- if (nextTime !== undefined) {
204
- onChange?.(nextTime);
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
- const selectedParts = useMemo(() => {
209
- const parsed = parseTimeValue(selectedTimeState);
210
- if (!parsed) {
211
- return undefined;
203
+ else if (allEmpty) {
204
+ setInternalValue("");
212
205
  }
213
- return clampTimeParts(parsed, bounds);
214
- }, [bounds, selectedTimeState]);
215
- const selectedTime = useMemo(() => selectedParts
216
- ? formatTimeValue(selectedParts.hours24, selectedParts.minutes, selectedParts.seconds)
217
- : undefined, [selectedParts]);
218
- const fallbackParts = useMemo(() => clampTimeParts(getCurrentTimeParts(), bounds), [bounds]);
219
- const activeParts = selectedParts ?? fallbackParts;
220
- const applyTime = (hours24, minutes, seconds) => {
221
- if (disabled) {
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
- const nextSeconds = toSecondsOfDay(hours24, minutes, seconds);
225
- if (isTimeDisabled(nextSeconds, false, bounds)) {
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
- const nextTime = formatTimeValue(hours24, minutes, seconds);
229
- if (selectedTime === nextTime) {
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
- setSelectedTime(nextTime);
233
- };
234
- const setHour = (hour) => {
235
- const nextHour = mode === "12h" ? to24Hour(hour, activeParts.period) : hour;
236
- applyTime(nextHour, activeParts.minutes, activeParts.seconds);
237
- };
238
- const setMinute = (minute) => {
239
- applyTime(activeParts.hours24, minute, activeParts.seconds);
240
- };
241
- const setSecond = (second) => {
242
- applyTime(activeParts.hours24, activeParts.minutes, second);
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
- const nextHour24 = to24Hour(activeParts.hour12, period);
250
- const candidateSeconds = toSecondsOfDay(nextHour24, activeParts.minutes, activeParts.seconds);
251
- const nextSeconds = Math.min(selectableRange.end, Math.max(selectableRange.start, candidateSeconds));
252
- const nextParts = toTimePartsFromSeconds(nextSeconds);
253
- applyTime(nextParts.hours24, nextParts.minutes, nextParts.seconds);
254
- };
255
- const hourOptions = useMemo(() => {
256
- const totalHours = mode === "12h" ? 12 : HOURS_IN_DAY;
257
- return Array.from({ length: totalHours }, (_, index) => {
258
- const hour = mode === "12h" ? index + 1 : index;
259
- const hours24 = mode === "12h" ? to24Hour(hour, activeParts.period) : hour;
260
- const nextSeconds = toSecondsOfDay(hours24, activeParts.minutes, activeParts.seconds);
261
- const selected = selectedParts !== undefined &&
262
- (mode === "12h"
263
- ? selectedParts.hour12 === hour
264
- : selectedParts.hours24 === hour);
265
- return {
266
- value: hour,
267
- label: getHourLabel ? getHourLabel(hour, mode) : pad(hour),
268
- ariaLabel: getHourAriaLabel
269
- ? getHourAriaLabel(hour, mode, selected)
270
- : selected
271
- ? `Hour ${pad(hour)}, selected`
272
- : `Choose hour ${pad(hour)}`,
273
- selected,
274
- disabled: isTimeDisabled(nextSeconds, disabled ?? false, bounds)
275
- };
276
- });
277
- }, [
278
- activeParts.minutes,
279
- activeParts.period,
280
- activeParts.seconds,
281
- bounds,
282
- disabled,
283
- getHourAriaLabel,
284
- getHourLabel,
285
- mode,
286
- selectedParts
287
- ]);
288
- const minuteOptions = useMemo(() => Array.from({ length: MINUTES_IN_HOUR }, (_, minute) => {
289
- const nextSeconds = toSecondsOfDay(activeParts.hours24, minute, activeParts.seconds);
290
- const selected = selectedParts?.minutes === minute;
291
- return {
292
- value: minute,
293
- label: getMinuteLabel ? getMinuteLabel(minute) : pad(minute),
294
- ariaLabel: getMinuteAriaLabel
295
- ? getMinuteAriaLabel(minute, selected)
296
- : selected
297
- ? `Minute ${pad(minute)}, selected`
298
- : `Choose minute ${pad(minute)}`,
299
- selected,
300
- disabled: isTimeDisabled(nextSeconds, disabled ?? false, bounds)
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
- activeParts.hours24,
304
- activeParts.seconds,
305
- bounds,
306
- disabled,
307
- getMinuteAriaLabel,
308
- getMinuteLabel,
309
- selectedParts
310
- ]);
311
- const secondOptions = useMemo(() => Array.from({ length: SECONDS_IN_MINUTE }, (_, second) => {
312
- const nextSeconds = toSecondsOfDay(activeParts.hours24, activeParts.minutes, second);
313
- const selected = selectedParts?.seconds === second;
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
- activeParts.hours24,
327
- activeParts.minutes,
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
- bounds,
352
- disabled,
353
- getPeriodAriaLabel,
354
- getPeriodLabel,
355
- selectedParts
356
- ]);
357
- const renderSection = ({ label, labelId, listLabel, options, onSelect, className }) => {
358
- const hasVisibleSelection = options.some((option) => option.selected);
359
- const firstEnabledIndex = getFirstEnabledIndex(options);
360
- return (_jsxs("div", { role: "group", "aria-labelledby": labelId, className: cx("flex flex-col min-w-0", classes.section, className), children: [_jsx("div", { id: labelId, className: cx("py-2 text-center font-medium text-[var(--refraktor-text-secondary)] border-b border-[var(--refraktor-border)] bg-[var(--refraktor-bg-subtle)]", sizeStyles.label, classes.sectionLabel), children: label }), _jsx("div", { role: "listbox", "aria-label": listLabel, className: cx("refraktor-scrollbar flex max-h-64 flex-col p-1 overflow-y-auto", sizeStyles.gridGap, classes.list), onKeyDown: (event) => handleListKeyDown(event, options, onSelect), children: options.map((option, index) => {
361
- const tabIndex = option.selected ||
362
- (!hasVisibleSelection && index === firstEnabledIndex)
363
- ? 0
364
- : -1;
365
- return (_jsx("button", { type: "button", role: "option", "aria-selected": option.selected, "aria-label": option.ariaLabel, "data-active": option.selected, "data-disabled": option.disabled, disabled: option.disabled, tabIndex: tabIndex, className: cx("inline-flex w-full items-center justify-center font-medium text-[var(--refraktor-text)] transition-colors", option.selected
366
- ? "bg-[var(--refraktor-primary)] text-[var(--refraktor-primary-text)]"
367
- : "hover:bg-[var(--refraktor-bg-hover)]", option.disabled &&
368
- "pointer-events-none cursor-not-allowed opacity-50", sizeStyles.cell, getRadius(radius), classes.option, option.selected && classes.optionActive, option.disabled && classes.optionDisabled), onClick: () => onSelect(option.value), children: option.label }, `${labelId}-${String(option.value)}`));
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
- return (_jsx("div", { ref: ref, id: _id, className: cx("inline-flex w-full flex-col bg-[var(--refraktor-bg)] overflow-hidden border border-[var(--refraktor-border)]", getRadius(radius), classes.root, className), ...props, children: _jsxs("div", { className: cx("grid divide-x divide-[var(--refraktor-border)]", getGridColumns(mode === "12h" ? 4 : 3), classes.grid), children: [renderSection({
372
- label: "Hour",
373
- labelId: `${_id}-hour-label`,
374
- listLabel: "Hour options",
375
- options: hourOptions,
376
- onSelect: setHour,
377
- className: classes.hourSection
378
- }), renderSection({
379
- label: "Minute",
380
- labelId: `${_id}-minute-label`,
381
- listLabel: "Minute options",
382
- options: minuteOptions,
383
- onSelect: setMinute,
384
- className: classes.minuteSection
385
- }), renderSection({
386
- label: "Second",
387
- labelId: `${_id}-second-label`,
388
- listLabel: "Second options",
389
- options: secondOptions,
390
- onSelect: setSecond,
391
- className: classes.secondSection
392
- }), mode === "12h" &&
393
- renderSection({
394
- label: "Period",
395
- labelId: `${_id}-period-label`,
396
- listLabel: "AM or PM options",
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();