@mesob/ui 0.5.8 → 0.5.9

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.
@@ -8386,7 +8386,7 @@ function DatePickerContent({
8386
8386
  }
8387
8387
  )
8388
8388
  ] }),
8389
- view === "days" && /* @__PURE__ */ jsx76(Fragment14, { children: (() => {
8389
+ view === "days" && (() => {
8390
8390
  const dayGridClass = withWeekNumbers ? "grid grid-cols-[2rem_repeat(7,minmax(0,1fr))]" : "grid grid-cols-7";
8391
8391
  const rowCount = cells.length / 7;
8392
8392
  const labels = weekdayHeaderLabels(firstDayOfWeek);
@@ -8512,7 +8512,7 @@ function DatePickerContent({
8512
8512
  }
8513
8513
  )
8514
8514
  ] });
8515
- })() }),
8515
+ })(),
8516
8516
  view === "months" && /* @__PURE__ */ jsx76("div", { className: "grid grid-cols-3 gap-1 py-2", children: monthShortList.map((m, i) => {
8517
8517
  const sel = calendarType === "EC" ? (() => {
8518
8518
  if (!primaryDate) {
@@ -11851,7 +11851,8 @@ var DateTimeTriggerButton = forwardRef5(function DateTimeTriggerButton2({
11851
11851
  variant = "default",
11852
11852
  leftSection,
11853
11853
  leftSectionPointerEvents = "auto",
11854
- "aria-label": ariaLabel
11854
+ "aria-label": ariaLabel,
11855
+ rightSection
11855
11856
  }, ref) {
11856
11857
  const filled = variant === "filled";
11857
11858
  return /* @__PURE__ */ jsxs68(
@@ -11863,7 +11864,7 @@ var DateTimeTriggerButton = forwardRef5(function DateTimeTriggerButton2({
11863
11864
  "aria-label": ariaLabel,
11864
11865
  "aria-invalid": !!error || void 0,
11865
11866
  className: cn(
11866
- "relative w-full overflow-hidden border pr-10 text-left transition-colors focus:outline-none",
11867
+ "relative flex w-full items-center overflow-hidden border pr-10 text-left transition-colors focus:outline-none",
11867
11868
  TRIGGER_SIZE_CLASSES[size],
11868
11869
  leftSection && "pl-10",
11869
11870
  TRIGGER_RADIUS_CLASSES[radius],
@@ -11884,7 +11885,17 @@ var DateTimeTriggerButton = forwardRef5(function DateTimeTriggerButton2({
11884
11885
  children: leftSection
11885
11886
  }
11886
11887
  ) : null,
11887
- displayValue ? /* @__PURE__ */ jsx100("span", { className: "block truncate text-foreground", children: displayValue }) : /* @__PURE__ */ jsx100("span", { className: error ? "text-destructive" : "text-muted-foreground", children: placeholder })
11888
+ displayValue ? /* @__PURE__ */ jsx100("span", { className: "min-w-0 flex-1 truncate text-foreground", children: displayValue }) : /* @__PURE__ */ jsx100(
11889
+ "span",
11890
+ {
11891
+ className: cn(
11892
+ "min-w-0 flex-1 truncate",
11893
+ error ? "text-destructive" : "text-muted-foreground"
11894
+ ),
11895
+ children: placeholder
11896
+ }
11897
+ ),
11898
+ rightSection ? /* @__PURE__ */ jsx100("span", { className: "ml-2 shrink-0", children: rightSection }) : null
11888
11899
  ]
11889
11900
  }
11890
11901
  );
@@ -11917,6 +11928,8 @@ function DateInputShell({
11917
11928
  triggerRef,
11918
11929
  onClear,
11919
11930
  dropdownClassName,
11931
+ popoverProps,
11932
+ rightSection,
11920
11933
  children,
11921
11934
  buttonRef
11922
11935
  }) {
@@ -11935,7 +11948,8 @@ function DateInputShell({
11935
11948
  variant,
11936
11949
  leftSection,
11937
11950
  leftSectionPointerEvents,
11938
- "aria-label": ariaLabel
11951
+ "aria-label": ariaLabel,
11952
+ rightSection
11939
11953
  }
11940
11954
  );
11941
11955
  const wrapper = /* @__PURE__ */ jsxs69("div", { className: cn("relative inline-block w-full", className), children: [
@@ -12011,14 +12025,16 @@ function DateInputShell({
12011
12025
  PopoverContent,
12012
12026
  {
12013
12027
  anchor: triggerRef,
12014
- side: contentSide,
12028
+ side: popoverProps?.side ?? contentSide,
12015
12029
  sideOffset: 8,
12016
- align: "center",
12030
+ align: popoverProps?.align ?? "center",
12017
12031
  alignOffset: 0,
12018
12032
  className: cn(
12019
12033
  "max-w-[calc(100vw-1rem)] rounded-md border border-border bg-background p-0 shadow-xl",
12034
+ popoverProps?.width === "target" && "w-[var(--anchor-width)]",
12020
12035
  dropdownClassName
12021
12036
  ),
12037
+ style: popoverProps?.width && popoverProps.width !== "target" ? { width: popoverProps.width } : void 0,
12022
12038
  children
12023
12039
  }
12024
12040
  )
@@ -12589,6 +12605,25 @@ function formatDateTimeDisplay(d, calendarType, withSeconds) {
12589
12605
  }
12590
12606
 
12591
12607
  // src/components/date-time/datetime-picker/time-utils.ts
12608
+ function getTimeColumnOptions(field, step2, is12h) {
12609
+ if (field === "h") {
12610
+ const max = is12h ? 12 : 23;
12611
+ const start = is12h ? 1 : 0;
12612
+ const opts = [];
12613
+ for (let i = start; i <= max; i += step2) {
12614
+ opts.push(pad2(i));
12615
+ }
12616
+ return opts;
12617
+ }
12618
+ if (field === "m" || field === "s") {
12619
+ const opts = [];
12620
+ for (let i = 0; i <= 59; i += step2) {
12621
+ opts.push(pad2(i));
12622
+ }
12623
+ return opts;
12624
+ }
12625
+ return [];
12626
+ }
12592
12627
  function clampAndPad(raw, max) {
12593
12628
  if (!raw) {
12594
12629
  return "";
@@ -13107,213 +13142,584 @@ function TextDateInput({
13107
13142
  }
13108
13143
 
13109
13144
  // src/components/date-time/datetime-picker/time-grid.tsx
13110
- import { jsx as jsx107 } from "react/jsx-runtime";
13111
- function buildSlots(stepMinutes, minHour, maxHour) {
13112
- const slots = [];
13113
- const d = new Date(0, 0, 1, 0, 0, 0);
13114
- for (let h = minHour; h < maxHour; h++) {
13115
- for (let m = 0; m < 60; m += stepMinutes) {
13116
- d.setHours(h, m, 0, 0);
13117
- slots.push(new Date(d.getTime()));
13118
- }
13145
+ import { useState as useState30 } from "react";
13146
+
13147
+ // src/components/date-time/time-picker/get-time-range.ts
13148
+ function parseToMinutes(str) {
13149
+ const parts = str.trim().split(":");
13150
+ if (parts.length < 2) {
13151
+ return 0;
13152
+ }
13153
+ const h = Number.parseInt(parts[0], 10) || 0;
13154
+ const m = Number.parseInt(parts[1], 10) || 0;
13155
+ const s = parts[2] ? Number.parseInt(parts[2], 10) || 0 : 0;
13156
+ return h * 60 + m + s / 60;
13157
+ }
13158
+ function minutesToTime(totalMins) {
13159
+ const h = Math.floor(totalMins / 60) % 24;
13160
+ const m = Math.floor(totalMins % 60);
13161
+ const s = Math.round(totalMins % 1 * 60);
13162
+ return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
13163
+ }
13164
+ function getTimeRange(options) {
13165
+ const start = options.startTime ?? options.from ?? "00:00";
13166
+ const end = options.endTime ?? options.to ?? "23:59";
13167
+ const step2 = options.interval ?? options.step ?? "01:00";
13168
+ const withSeconds = options.withSeconds;
13169
+ const startMins = parseToMinutes(start);
13170
+ const endMins = parseToMinutes(end);
13171
+ const intervalMins = parseToMinutes(step2);
13172
+ if (intervalMins <= 0) {
13173
+ return [];
13174
+ }
13175
+ const result = [];
13176
+ let current = startMins;
13177
+ while (current <= endMins) {
13178
+ const time = minutesToTime(current);
13179
+ result.push(withSeconds === false ? time.slice(0, 5) : time);
13180
+ current += intervalMins;
13119
13181
  }
13120
- return slots;
13182
+ return result;
13183
+ }
13184
+
13185
+ // src/components/date-time/datetime-picker/time-grid.tsx
13186
+ import { jsx as jsx107 } from "react/jsx-runtime";
13187
+ function to12h(time24) {
13188
+ const [hStr] = time24.split(":");
13189
+ const h = Number.parseInt(hStr ?? "0", 10);
13190
+ if (h === 0) {
13191
+ return { h: 12, amPm: "AM" };
13192
+ }
13193
+ if (h < 12) {
13194
+ return { h, amPm: "AM" };
13195
+ }
13196
+ if (h === 12) {
13197
+ return { h: 12, amPm: "PM" };
13198
+ }
13199
+ return { h: h - 12, amPm: "PM" };
13200
+ }
13201
+ function formatTimeForDisplay(time24, format, withSeconds, amPmLabels) {
13202
+ const parts = time24.split(":");
13203
+ const h = Number.parseInt(parts[0] ?? "0", 10);
13204
+ const m = parts[1] ?? "00";
13205
+ const s = parts[2] ?? "00";
13206
+ if (format === "12h") {
13207
+ const { h: h12, amPm } = to12h(time24);
13208
+ const suffix2 = withSeconds ? `:${s}` : "";
13209
+ const ap = amPm === "AM" ? amPmLabels.am : amPmLabels.pm;
13210
+ return `${h12}:${m}${suffix2} ${ap}`;
13211
+ }
13212
+ const suffix = withSeconds ? `:${s}` : "";
13213
+ return `${pad2(h)}:${m}${suffix}`;
13214
+ }
13215
+ function parseToMinutes2(time) {
13216
+ const parts = time.trim().split(":");
13217
+ if (parts.length < 2) {
13218
+ return 0;
13219
+ }
13220
+ const h = Number.parseInt(parts[0], 10) || 0;
13221
+ const m = Number.parseInt(parts[1], 10) || 0;
13222
+ const s = parts[2] ? Number.parseInt(parts[2], 10) || 0 : 0;
13223
+ return h * 60 + m + s / 60;
13224
+ }
13225
+ function normalizeTimeStr(t) {
13226
+ const parts = t.trim().split(":");
13227
+ const h = Number.parseInt(parts[0], 10) || 0;
13228
+ const m = Number.parseInt(parts[1], 10) || 0;
13229
+ return `${pad2(h)}:${pad2(m)}`;
13230
+ }
13231
+ var SIZE_CLASSES = {
13232
+ xs: "px-2 py-1 text-xs",
13233
+ sm: "px-2.5 py-1.5 text-sm",
13234
+ md: "px-3 py-2 text-sm",
13235
+ lg: "px-4 py-2.5 text-base"
13236
+ };
13237
+ var RADIUS_CLASSES = {
13238
+ xs: "rounded",
13239
+ sm: "rounded",
13240
+ md: "rounded-md",
13241
+ lg: "rounded-lg"
13242
+ };
13243
+ var SPACING_CLASSES = {
13244
+ xs: "gap-2",
13245
+ sm: "gap-3",
13246
+ md: "gap-3",
13247
+ lg: "gap-4"
13248
+ };
13249
+ function buildDataFromLegacy(stepMinutes, minHour, maxHour) {
13250
+ const lastM = stepMinutes >= 60 ? 0 : 60 - stepMinutes;
13251
+ const lastH = stepMinutes >= 60 ? maxHour - 1 : maxHour - 1;
13252
+ return getTimeRange({
13253
+ from: `${pad2(minHour)}:00`,
13254
+ to: `${pad2(lastH)}:${pad2(lastM)}`,
13255
+ step: `00:${pad2(stepMinutes)}`,
13256
+ withSeconds: false
13257
+ });
13121
13258
  }
13122
13259
  function TimeGrid({
13123
- value,
13260
+ data: dataProp,
13261
+ value: controlledValue,
13124
13262
  onChange,
13263
+ defaultValue = null,
13264
+ format = "24h",
13265
+ withSeconds = false,
13266
+ amPmLabels = { am: "AM", pm: "PM" },
13267
+ minTime,
13268
+ maxTime,
13269
+ disableTime = [],
13270
+ allowDeselect = false,
13271
+ disabled = false,
13272
+ size = "md",
13273
+ radius = "md",
13274
+ simpleGridProps = {},
13125
13275
  stepMinutes = 30,
13126
13276
  minHour = 0,
13127
13277
  maxHour = 24,
13128
- baseDate = /* @__PURE__ */ new Date(),
13129
13278
  className
13130
13279
  }) {
13131
- const base = new Date(
13132
- baseDate.getFullYear(),
13133
- baseDate.getMonth(),
13134
- baseDate.getDate()
13135
- );
13136
- const slots = buildSlots(stepMinutes, minHour, maxHour);
13137
- const valueMinutes = value != null ? value.getHours() * 60 + value.getMinutes() : null;
13138
- return /* @__PURE__ */ jsx107(
13280
+ const data = dataProp ?? buildDataFromLegacy(stepMinutes, minHour, maxHour);
13281
+ const isControlled = controlledValue !== void 0;
13282
+ const [internal, setInternal] = useState30(defaultValue);
13283
+ const value = isControlled ? controlledValue : internal;
13284
+ const setValue = (v) => {
13285
+ if (!isControlled) {
13286
+ setInternal(v);
13287
+ }
13288
+ onChange?.(v);
13289
+ };
13290
+ const minMins = minTime != null ? parseToMinutes2(minTime) : -1;
13291
+ const maxMins = maxTime != null ? parseToMinutes2(maxTime) : Number.POSITIVE_INFINITY;
13292
+ const disabledSet = new Set(disableTime.map((t) => normalizeTimeStr(t)));
13293
+ const cols = simpleGridProps.cols ?? 3;
13294
+ const spacing = simpleGridProps.spacing ?? "sm";
13295
+ const colsClass = (() => {
13296
+ if (typeof cols === "number") {
13297
+ if (cols === 1) {
13298
+ return "grid-cols-1";
13299
+ }
13300
+ if (cols === 2) {
13301
+ return "grid-cols-2";
13302
+ }
13303
+ if (cols === 3) {
13304
+ return "grid-cols-3";
13305
+ }
13306
+ if (cols === 4) {
13307
+ return "grid-cols-4";
13308
+ }
13309
+ return "grid-cols-3";
13310
+ }
13311
+ return cn(
13312
+ (cols.base ?? 1) === 1 && "grid-cols-1",
13313
+ (cols.base ?? 1) === 2 && "grid-cols-2",
13314
+ (cols.base ?? 1) === 3 && "grid-cols-3",
13315
+ (cols.base ?? 1) === 4 && "grid-cols-4",
13316
+ cols.sm === 1 && "sm:grid-cols-1",
13317
+ cols.sm === 2 && "sm:grid-cols-2",
13318
+ cols.sm === 3 && "sm:grid-cols-3",
13319
+ cols.sm === 4 && "sm:grid-cols-4",
13320
+ cols.md === 1 && "md:grid-cols-1",
13321
+ cols.md === 2 && "md:grid-cols-2",
13322
+ cols.md === 3 && "md:grid-cols-3",
13323
+ cols.md === 4 && "md:grid-cols-4",
13324
+ cols.lg === 1 && "lg:grid-cols-1",
13325
+ cols.lg === 2 && "lg:grid-cols-2",
13326
+ cols.lg === 3 && "lg:grid-cols-3",
13327
+ cols.lg === 4 && "lg:grid-cols-4"
13328
+ );
13329
+ })();
13330
+ return /* @__PURE__ */ jsx107("div", { className: cn("flex w-full justify-center", className), children: /* @__PURE__ */ jsx107(
13139
13331
  "div",
13140
13332
  {
13141
13333
  className: cn(
13142
- "grid grid-cols-4 gap-1 overflow-y-auto rounded-md border border-border bg-background p-2 max-h-[200px]",
13143
- className
13334
+ "inline-grid w-fit overflow-y-auto rounded-lg border border-border bg-background p-3",
13335
+ colsClass,
13336
+ SPACING_CLASSES[spacing],
13337
+ "max-h-[200px]"
13144
13338
  ),
13145
- children: slots.map((slot) => {
13146
- const slotMinutes = slot.getHours() * 60 + slot.getMinutes();
13147
- const selected = valueMinutes === slotMinutes;
13148
- const date = new Date(base);
13149
- date.setHours(slot.getHours(), slot.getMinutes(), 0, 0);
13150
- const label = `${pad2(slot.getHours())}:${pad2(slot.getMinutes())}`;
13339
+ children: data.map((slot) => {
13340
+ const normalized = normalizeTimeStr(slot);
13341
+ const slotMins = parseToMinutes2(normalized);
13342
+ const isDisabled = disabled || minMins >= 0 && slotMins < minMins || maxMins < Number.POSITIVE_INFINITY && slotMins > maxMins || disabledSet.has(normalized);
13343
+ const selected = value != null && normalizeTimeStr(value) === normalized;
13151
13344
  return /* @__PURE__ */ jsx107(
13152
13345
  "button",
13153
13346
  {
13154
13347
  type: "button",
13155
- onClick: () => onChange(selected ? null : date),
13348
+ disabled: isDisabled,
13349
+ onClick: () => {
13350
+ if (isDisabled) {
13351
+ return;
13352
+ }
13353
+ if (selected && allowDeselect) {
13354
+ setValue(null);
13355
+ } else if (!selected) {
13356
+ setValue(normalized);
13357
+ }
13358
+ },
13156
13359
  className: cn(
13157
- "rounded px-2 py-1.5 text-center text-sm transition-colors",
13158
- selected ? "bg-primary text-primary-foreground" : "text-foreground hover:bg-muted"
13360
+ "rounded border bg-background text-center transition-colors",
13361
+ SIZE_CLASSES[size],
13362
+ RADIUS_CLASSES[radius],
13363
+ isDisabled && "cursor-not-allowed border-gray-200 text-gray-400 dark:border-gray-600 dark:text-gray-500",
13364
+ !isDisabled && (selected ? "border-primary bg-primary text-primary-foreground" : "border-gray-200 text-foreground hover:bg-muted dark:border-gray-600")
13159
13365
  ),
13160
- children: label
13366
+ children: formatTimeForDisplay(
13367
+ normalized,
13368
+ format,
13369
+ withSeconds,
13370
+ amPmLabels
13371
+ )
13161
13372
  },
13162
- label
13373
+ normalized
13163
13374
  );
13164
13375
  })
13165
13376
  }
13166
- );
13377
+ ) });
13167
13378
  }
13168
13379
 
13169
13380
  // src/components/date-time/datetime-picker/time-input.tsx
13170
- import { useCallback as useCallback13, useEffect as useEffect18, useState as useState30 } from "react";
13381
+ import {
13382
+ forwardRef as forwardRef8,
13383
+ useCallback as useCallback13,
13384
+ useEffect as useEffect18,
13385
+ useId as useId5,
13386
+ useImperativeHandle,
13387
+ useRef as useRef13,
13388
+ useState as useState31
13389
+ } from "react";
13171
13390
  import { Fragment as Fragment19, jsx as jsx108, jsxs as jsxs71 } from "react/jsx-runtime";
13172
- function TimeInput({
13173
- value,
13174
- onChange,
13175
- withSeconds = false,
13176
- disabled = false,
13177
- baseDate = /* @__PURE__ */ new Date(),
13178
- className,
13179
- "aria-label": ariaLabel
13180
- }) {
13181
- const base = new Date(
13182
- baseDate.getFullYear(),
13183
- baseDate.getMonth(),
13184
- baseDate.getDate()
13185
- );
13186
- const [h, setH] = useState30(value ? pad2(value.getHours()) : "");
13187
- const [m, setM] = useState30(value ? pad2(value.getMinutes()) : "");
13188
- const [s, setS] = useState30(value ? pad2(value.getSeconds()) : "");
13189
- const [focus, setFocus] = useState30(null);
13190
- useEffect18(() => {
13391
+ function to12h2(hour24) {
13392
+ if (hour24 === 0) {
13393
+ return { h: 12, amPm: "AM" };
13394
+ }
13395
+ if (hour24 < 12) {
13396
+ return { h: hour24, amPm: "AM" };
13397
+ }
13398
+ if (hour24 === 12) {
13399
+ return { h: 12, amPm: "PM" };
13400
+ }
13401
+ return { h: hour24 - 12, amPm: "PM" };
13402
+ }
13403
+ function to24h(h12, amPm) {
13404
+ if (amPm === "AM") {
13405
+ return h12 === 12 ? 0 : h12;
13406
+ }
13407
+ return h12 === 12 ? 12 : h12 + 12;
13408
+ }
13409
+ var TimeInput = forwardRef8(
13410
+ function TimeInput2({
13411
+ value,
13412
+ onChange,
13413
+ withSeconds = false,
13414
+ format = "24h",
13415
+ disabled = false,
13416
+ baseDate = /* @__PURE__ */ new Date(),
13417
+ leftSection,
13418
+ rightSection,
13419
+ label,
13420
+ className,
13421
+ "aria-label": ariaLabel
13422
+ }, ref) {
13423
+ const hoursInputId = useId5();
13424
+ const base = new Date(
13425
+ baseDate.getFullYear(),
13426
+ baseDate.getMonth(),
13427
+ baseDate.getDate()
13428
+ );
13429
+ const is12h = format === "12h";
13430
+ const hourMax = is12h ? 12 : 23;
13431
+ const [h, setH] = useState31(() => {
13432
+ if (!value) {
13433
+ return "";
13434
+ }
13435
+ return is12h ? pad2(to12h2(value.getHours()).h) : pad2(value.getHours());
13436
+ });
13437
+ const [m, setM] = useState31(value ? pad2(value.getMinutes()) : "");
13438
+ const [s, setS] = useState31(value ? pad2(value.getSeconds()) : "");
13439
+ const [amPm, setAmPm] = useState31(
13440
+ () => value ? to12h2(value.getHours()).amPm : "AM"
13441
+ );
13442
+ const [focus, setFocus] = useState31(null);
13443
+ useEffect18(() => {
13444
+ if (value) {
13445
+ if (is12h) {
13446
+ const { h: h12, amPm: ap } = to12h2(value.getHours());
13447
+ setH(pad2(h12));
13448
+ setAmPm(ap);
13449
+ } else {
13450
+ setH(pad2(value.getHours()));
13451
+ }
13452
+ setM(pad2(value.getMinutes()));
13453
+ setS(pad2(value.getSeconds()));
13454
+ } else {
13455
+ setH("");
13456
+ setM("");
13457
+ setS("");
13458
+ if (is12h) {
13459
+ setAmPm("AM");
13460
+ }
13461
+ }
13462
+ }, [value, is12h]);
13463
+ const commit = useCallback13(
13464
+ (hh, mm, ss, ap = "AM") => {
13465
+ const nm = clampAndPad(mm, 59);
13466
+ const ns = withSeconds ? clampAndPad(ss, 59) : "00";
13467
+ if (!(hh && nm)) {
13468
+ onChange?.(null);
13469
+ return;
13470
+ }
13471
+ const h12Raw = Number.parseInt(clampAndPad(hh, 12), 10);
13472
+ const hour24 = is12h ? to24h(h12Raw === 0 ? 12 : h12Raw, ap) : Number.parseInt(clampAndPad(hh, 23), 10);
13473
+ const d = new Date(base);
13474
+ d.setHours(hour24, Number.parseInt(nm, 10), Number.parseInt(ns, 10), 0);
13475
+ onChange?.(d);
13476
+ },
13477
+ [base, onChange, withSeconds, is12h]
13478
+ );
13479
+ const handleBlur = useCallback13(() => {
13480
+ setFocus(null);
13481
+ const nh = clampAndPad(h, hourMax);
13482
+ const nm = clampAndPad(m, 59);
13483
+ const ns = withSeconds ? clampAndPad(s, 59) : "00";
13484
+ if (nh) {
13485
+ setH(nh);
13486
+ }
13487
+ if (nm) {
13488
+ setM(nm);
13489
+ }
13490
+ if (withSeconds && ns) {
13491
+ setS(ns);
13492
+ }
13493
+ commit(nh || h, nm || m, withSeconds ? ns || s : "00", amPm);
13494
+ }, [h, m, s, amPm, commit, withSeconds, hourMax]);
13495
+ const nativeInputRef = useRef13(null);
13496
+ useImperativeHandle(ref, () => nativeInputRef.current);
13497
+ let nativeValue = "";
13191
13498
  if (value) {
13192
- setH(pad2(value.getHours()));
13193
- setM(pad2(value.getMinutes()));
13194
- setS(pad2(value.getSeconds()));
13195
- } else {
13196
- setH("");
13197
- setM("");
13198
- setS("");
13499
+ if (withSeconds) {
13500
+ nativeValue = `${pad2(value.getHours())}:${pad2(value.getMinutes())}:${pad2(value.getSeconds())}`;
13501
+ } else {
13502
+ nativeValue = `${pad2(value.getHours())}:${pad2(value.getMinutes())}`;
13503
+ }
13199
13504
  }
13200
- }, [value]);
13201
- const commit = useCallback13(
13202
- (hh, mm, ss) => {
13203
- const nh = clampAndPad(hh, 23);
13204
- const nm = clampAndPad(mm, 59);
13205
- const ns = withSeconds ? clampAndPad(ss, 59) : "00";
13206
- if (nh && nm) {
13505
+ const handleNativeChange = useCallback13(
13506
+ (e) => {
13507
+ const v = e.target.value;
13508
+ if (!v) {
13509
+ onChange?.(null);
13510
+ return;
13511
+ }
13512
+ const [hh, mm, ss = "00"] = v.split(":").map((x) => x.padStart(2, "0"));
13207
13513
  const d = new Date(base);
13208
13514
  d.setHours(
13209
- Number.parseInt(nh, 10),
13210
- Number.parseInt(nm, 10),
13211
- Number.parseInt(ns, 10),
13515
+ Number.parseInt(hh, 10),
13516
+ Number.parseInt(mm, 10),
13517
+ Number.parseInt(ss, 10),
13212
13518
  0
13213
13519
  );
13214
13520
  onChange?.(d);
13215
- } else {
13216
- onChange?.(null);
13217
- }
13218
- },
13219
- [base, onChange, withSeconds]
13220
- );
13221
- const handleBlur = useCallback13(() => {
13222
- setFocus(null);
13223
- const nh = clampAndPad(h, 23);
13224
- const nm = clampAndPad(m, 59);
13225
- const ns = withSeconds ? clampAndPad(s, 59) : "00";
13226
- if (nh) {
13227
- setH(nh);
13228
- }
13229
- if (nm) {
13230
- setM(nm);
13231
- }
13232
- if (withSeconds && ns) {
13233
- setS(ns);
13234
- }
13235
- commit(nh || h, nm || m, withSeconds ? ns || s : "00");
13236
- }, [h, m, s, commit, withSeconds]);
13237
- return /* @__PURE__ */ jsxs71(
13238
- "fieldset",
13239
- {
13240
- className: cn(
13241
- "flex flex-row items-center gap-0.5 rounded border border-input bg-background px-2.5 py-1.5",
13242
- disabled && "opacity-50 cursor-not-allowed",
13243
- className
13244
- ),
13245
- "aria-label": ariaLabel ?? "Time",
13246
- children: [
13247
- /* @__PURE__ */ jsx108("legend", { className: "sr-only", children: "Time" }),
13248
- /* @__PURE__ */ jsx108(
13249
- "input",
13250
- {
13251
- type: "text",
13252
- inputMode: "numeric",
13253
- value: focus === "h" ? h : h || "--",
13254
- placeholder: "--",
13255
- "aria-label": "Hours",
13256
- disabled,
13257
- onFocus: () => setFocus("h"),
13258
- onBlur: handleBlur,
13259
- onChange: (e) => setH(e.target.value.replace(/\D/g, "").slice(0, 2)),
13260
- className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
13261
- }
13262
- ),
13263
- /* @__PURE__ */ jsx108("span", { className: "select-none text-sm text-muted-foreground", children: ":" }),
13264
- /* @__PURE__ */ jsx108(
13265
- "input",
13266
- {
13267
- type: "text",
13268
- inputMode: "numeric",
13269
- value: focus === "m" ? m : m || "--",
13270
- placeholder: "--",
13271
- "aria-label": "Minutes",
13272
- disabled,
13273
- onFocus: () => setFocus("m"),
13274
- onBlur: handleBlur,
13275
- onChange: (e) => setM(e.target.value.replace(/\D/g, "").slice(0, 2)),
13276
- className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
13277
- }
13521
+ },
13522
+ [base, onChange]
13523
+ );
13524
+ const fieldset = /* @__PURE__ */ jsxs71(
13525
+ "fieldset",
13526
+ {
13527
+ className: cn(
13528
+ "flex min-w-0 flex-1 flex-row items-center gap-0.5 rounded border border-input bg-background px-2.5 py-1.5",
13529
+ disabled && "opacity-50 cursor-not-allowed",
13530
+ leftSection && "pl-9",
13531
+ rightSection && "pr-9",
13532
+ className
13278
13533
  ),
13279
- withSeconds && /* @__PURE__ */ jsxs71(Fragment19, { children: [
13534
+ "aria-label": ariaLabel ?? "Time",
13535
+ children: [
13536
+ /* @__PURE__ */ jsx108("legend", { className: "sr-only", children: "Time" }),
13537
+ /* @__PURE__ */ jsx108(
13538
+ "input",
13539
+ {
13540
+ ref: nativeInputRef,
13541
+ type: "time",
13542
+ value: nativeValue,
13543
+ onChange: handleNativeChange,
13544
+ className: "absolute size-0 opacity-0 pointer-events-none",
13545
+ tabIndex: -1,
13546
+ "aria-hidden": true
13547
+ }
13548
+ ),
13549
+ /* @__PURE__ */ jsx108(
13550
+ "input",
13551
+ {
13552
+ id: hoursInputId,
13553
+ type: "text",
13554
+ inputMode: "numeric",
13555
+ value: focus === "h" ? h : h || "--",
13556
+ placeholder: "--",
13557
+ "aria-label": "Hours",
13558
+ disabled,
13559
+ onFocus: () => setFocus("h"),
13560
+ onBlur: handleBlur,
13561
+ onChange: (e) => {
13562
+ const raw = e.target.value.replace(/\D/g, "").slice(0, 2);
13563
+ if (is12h && raw) {
13564
+ const n = Number.parseInt(raw, 10);
13565
+ if (n > 12) {
13566
+ setH("12");
13567
+ } else {
13568
+ setH(raw);
13569
+ }
13570
+ } else {
13571
+ setH(raw);
13572
+ }
13573
+ },
13574
+ className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
13575
+ }
13576
+ ),
13280
13577
  /* @__PURE__ */ jsx108("span", { className: "select-none text-sm text-muted-foreground", children: ":" }),
13281
13578
  /* @__PURE__ */ jsx108(
13282
13579
  "input",
13283
13580
  {
13284
13581
  type: "text",
13285
13582
  inputMode: "numeric",
13286
- value: focus === "s" ? s : s || "--",
13583
+ value: focus === "m" ? m : m || "--",
13287
13584
  placeholder: "--",
13288
- "aria-label": "Seconds",
13585
+ "aria-label": "Minutes",
13289
13586
  disabled,
13290
- onFocus: () => setFocus("s"),
13587
+ onFocus: () => setFocus("m"),
13291
13588
  onBlur: handleBlur,
13292
- onChange: (e) => setS(e.target.value.replace(/\D/g, "").slice(0, 2)),
13589
+ onChange: (e) => setM(e.target.value.replace(/\D/g, "").slice(0, 2)),
13293
13590
  className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
13294
13591
  }
13295
- )
13296
- ] })
13297
- ]
13592
+ ),
13593
+ withSeconds && /* @__PURE__ */ jsxs71(Fragment19, { children: [
13594
+ /* @__PURE__ */ jsx108("span", { className: "select-none text-sm text-muted-foreground", children: ":" }),
13595
+ /* @__PURE__ */ jsx108(
13596
+ "input",
13597
+ {
13598
+ type: "text",
13599
+ inputMode: "numeric",
13600
+ value: focus === "s" ? s : s || "--",
13601
+ placeholder: "--",
13602
+ "aria-label": "Seconds",
13603
+ disabled,
13604
+ onFocus: () => setFocus("s"),
13605
+ onBlur: handleBlur,
13606
+ onChange: (e) => setS(e.target.value.replace(/\D/g, "").slice(0, 2)),
13607
+ className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
13608
+ }
13609
+ )
13610
+ ] }),
13611
+ is12h && /* @__PURE__ */ jsxs71(Fragment19, { children: [
13612
+ /* @__PURE__ */ jsx108("span", { className: "w-1 shrink-0" }),
13613
+ /* @__PURE__ */ jsx108(
13614
+ "button",
13615
+ {
13616
+ type: "button",
13617
+ disabled,
13618
+ onClick: () => {
13619
+ const next = amPm === "AM" ? "PM" : "AM";
13620
+ setAmPm(next);
13621
+ if (h && m) {
13622
+ commit(h, m, withSeconds ? s || "00" : "00", next);
13623
+ }
13624
+ },
13625
+ className: cn(
13626
+ "rounded px-2 py-0.5 text-sm font-medium transition-colors",
13627
+ "text-muted-foreground hover:bg-muted hover:text-foreground",
13628
+ disabled && "cursor-not-allowed opacity-50"
13629
+ ),
13630
+ "aria-label": amPm === "AM" ? "Switch to PM" : "Switch to AM",
13631
+ children: amPm
13632
+ }
13633
+ )
13634
+ ] })
13635
+ ]
13636
+ }
13637
+ );
13638
+ const wrapper = /* @__PURE__ */ jsxs71("div", { className: "relative flex w-full min-w-0", children: [
13639
+ leftSection && /* @__PURE__ */ jsx108("span", { className: "pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground [&>svg]:size-4", children: leftSection }),
13640
+ fieldset,
13641
+ rightSection && /* @__PURE__ */ jsx108("span", { className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-muted-foreground [&>svg]:size-4 [&_button]:pointer-events-auto", children: rightSection })
13642
+ ] });
13643
+ if (label) {
13644
+ return /* @__PURE__ */ jsxs71("div", { className: "space-y-1.5", children: [
13645
+ /* @__PURE__ */ jsx108(
13646
+ "label",
13647
+ {
13648
+ htmlFor: hoursInputId,
13649
+ className: "block text-sm font-semibold text-foreground",
13650
+ children: label
13651
+ }
13652
+ ),
13653
+ wrapper
13654
+ ] });
13298
13655
  }
13299
- );
13300
- }
13656
+ return wrapper;
13657
+ }
13658
+ );
13301
13659
 
13302
13660
  // src/components/date-time/datetime-picker/time-value.tsx
13303
13661
  import { jsx as jsx109 } from "react/jsx-runtime";
13662
+ function to12h3(hour24) {
13663
+ if (hour24 === 0) {
13664
+ return { h: 12, amPm: "AM" };
13665
+ }
13666
+ if (hour24 < 12) {
13667
+ return { h: hour24, amPm: "AM" };
13668
+ }
13669
+ if (hour24 === 12) {
13670
+ return { h: 12, amPm: "PM" };
13671
+ }
13672
+ return { h: hour24 - 12, amPm: "PM" };
13673
+ }
13674
+ function parseTimeString(str) {
13675
+ const parts = str.trim().split(":");
13676
+ if (parts.length < 2) {
13677
+ return null;
13678
+ }
13679
+ const h = Number.parseInt(parts[0], 10);
13680
+ const m = Number.parseInt(parts[1], 10);
13681
+ const s = parts[2] ? Number.parseInt(parts[2], 10) : 0;
13682
+ if (Number.isNaN(h) || Number.isNaN(m)) {
13683
+ return null;
13684
+ }
13685
+ return { h, m, s };
13686
+ }
13304
13687
  function TimeValue({
13305
13688
  value,
13306
- format,
13689
+ format = "24h",
13307
13690
  withSeconds = false,
13691
+ amPmLabels = { am: "AM", pm: "PM" },
13308
13692
  className
13309
13693
  }) {
13310
- const defaultFormat2 = (d) => `${pad2(d.getHours())}:${pad2(d.getMinutes())}${withSeconds ? `:${pad2(d.getSeconds())}` : ""}`;
13311
- const str = format ? format(value) : defaultFormat2(value);
13694
+ let h;
13695
+ let m;
13696
+ let s;
13697
+ if (value instanceof Date) {
13698
+ h = value.getHours();
13699
+ m = value.getMinutes();
13700
+ s = value.getSeconds();
13701
+ } else {
13702
+ const parsed = parseTimeString(value);
13703
+ if (!parsed) {
13704
+ return /* @__PURE__ */ jsx109("span", { className, children: "--:--" });
13705
+ }
13706
+ ({ h, m, s } = parsed);
13707
+ }
13708
+ let str;
13709
+ if (format === "12h") {
13710
+ const { h: h12, amPm } = to12h3(h);
13711
+ const suffix = withSeconds ? `:${pad2(s)}` : "";
13712
+ const ap = amPm === "AM" ? amPmLabels.am : amPmLabels.pm;
13713
+ str = `${h12}:${pad2(m)}${suffix} ${ap}`;
13714
+ } else {
13715
+ const suffix = withSeconds ? `:${pad2(s)}` : "";
13716
+ str = `${pad2(h)}:${pad2(m)}${suffix}`;
13717
+ }
13312
13718
  return /* @__PURE__ */ jsx109("span", { className, children: str });
13313
13719
  }
13314
13720
 
13315
13721
  // src/components/date-time/mini-calendar/use-mini-calendar.ts
13316
- import { useCallback as useCallback14, useEffect as useEffect19, useState as useState31 } from "react";
13722
+ import { useCallback as useCallback14, useEffect as useEffect19, useState as useState32 } from "react";
13317
13723
  function dayInWindow(day, windowStart, numberOfDays) {
13318
13724
  const end = addDays(windowStart, numberOfDays - 1);
13319
13725
  const t = stripTime2(day).getTime();
@@ -13330,7 +13736,7 @@ function useMiniCalendar(props) {
13330
13736
  maxDate
13331
13737
  } = props;
13332
13738
  const isControlled = valueProp !== void 0;
13333
- const [internalValue, setInternalValue] = useState31(
13739
+ const [internalValue, setInternalValue] = useState32(
13334
13740
  defaultValue
13335
13741
  );
13336
13742
  const selectedIso = valueProp !== void 0 ? valueProp : internalValue;
@@ -13350,7 +13756,7 @@ function useMiniCalendar(props) {
13350
13756
  }
13351
13757
  return parseAnchorDate(defaultDate, today);
13352
13758
  })();
13353
- const [windowStart, setWindowStart] = useState31(() => stripTime2(initialStart));
13759
+ const [windowStart, setWindowStart] = useState32(() => stripTime2(initialStart));
13354
13760
  const setSelected = useCallback14(
13355
13761
  (iso) => {
13356
13762
  if (!isControlled) {
@@ -13778,7 +14184,7 @@ function MonthPickerContent({
13778
14184
  }
13779
14185
 
13780
14186
  // src/components/date-time/month-picker/use-month-picker.ts
13781
- import { useCallback as useCallback15, useEffect as useEffect20, useState as useState32 } from "react";
14187
+ import { useCallback as useCallback15, useEffect as useEffect20, useState as useState33 } from "react";
13782
14188
  function useMonthPicker(props) {
13783
14189
  const {
13784
14190
  defaultCalendarType = "GC",
@@ -13791,13 +14197,13 @@ function useMonthPicker(props) {
13791
14197
  const type = props.type ?? "default";
13792
14198
  const isControlled = props.value !== void 0;
13793
14199
  const isDateControlled = controlledDate !== void 0;
13794
- const [_single, _setSingle] = useState32(
14200
+ const [_single, _setSingle] = useState33(
13795
14201
  type === "default" ? props.defaultValue ?? null : null
13796
14202
  );
13797
- const [_multi, _setMulti] = useState32(
14203
+ const [_multi, _setMulti] = useState33(
13798
14204
  type === "multiple" ? props.defaultValue ?? [] : []
13799
14205
  );
13800
- const [_range, _setRange] = useState32(
14206
+ const [_range, _setRange] = useState33(
13801
14207
  type === "range" ? props.defaultValue ?? [
13802
14208
  null,
13803
14209
  null
@@ -13819,7 +14225,7 @@ function useMonthPicker(props) {
13819
14225
  multiValue = [];
13820
14226
  rangeValue = isControlled ? props.value : _range;
13821
14227
  }
13822
- const [hoveredMonth, setHoveredMonth] = useState32(null);
14228
+ const [hoveredMonth, setHoveredMonth] = useState33(null);
13823
14229
  let hasValue;
13824
14230
  if (type === "default") {
13825
14231
  hasValue = !!singleValue;
@@ -13836,17 +14242,17 @@ function useMonthPicker(props) {
13836
14242
  } else {
13837
14243
  primaryDate = rangeValue[0];
13838
14244
  }
13839
- const [view, setView] = useState32("months");
13840
- const [calendarType, setCalendarType] = useState32(defaultCalendarType);
14245
+ const [view, setView] = useState33("months");
14246
+ const [calendarType, setCalendarType] = useState33(defaultCalendarType);
13841
14247
  const now = /* @__PURE__ */ new Date();
13842
14248
  const initDate = controlledDate ?? defaultDate ?? primaryDate ?? now;
13843
- const [gcViewYear, setGcViewYear] = useState32(initDate.getFullYear());
14249
+ const [gcViewYear, setGcViewYear] = useState33(initDate.getFullYear());
13844
14250
  const initEC = toEC(
13845
14251
  initDate.getFullYear(),
13846
14252
  initDate.getMonth() + 1,
13847
14253
  initDate.getDate()
13848
14254
  );
13849
- const [ecViewYear, setEcViewYear] = useState32(initEC[0]);
14255
+ const [ecViewYear, setEcViewYear] = useState33(initEC[0]);
13850
14256
  useEffect20(() => {
13851
14257
  if (!(isDateControlled && controlledDate)) {
13852
14258
  return;
@@ -14130,7 +14536,7 @@ function MonthPicker(props) {
14130
14536
  }
14131
14537
 
14132
14538
  // src/components/date-time/month-picker-input/month-picker-input.tsx
14133
- import { forwardRef as forwardRef8 } from "react";
14539
+ import { forwardRef as forwardRef9 } from "react";
14134
14540
 
14135
14541
  // src/components/date-time/month-picker-input/use-month-picker-input.ts
14136
14542
  import { useCallback as useCallback16 } from "react";
@@ -14240,7 +14646,7 @@ function useMonthPickerInput(props) {
14240
14646
 
14241
14647
  // src/components/date-time/month-picker-input/month-picker-input.tsx
14242
14648
  import { jsx as jsx113 } from "react/jsx-runtime";
14243
- var MonthPickerInput = forwardRef8(function MonthPickerInput2(props, ref) {
14649
+ var MonthPickerInput = forwardRef9(function MonthPickerInput2(props, ref) {
14244
14650
  const {
14245
14651
  label,
14246
14652
  placeholder = "Pick month",
@@ -14310,9 +14716,10 @@ var MonthPickerInput = forwardRef8(function MonthPickerInput2(props, ref) {
14310
14716
  });
14311
14717
 
14312
14718
  // src/components/date-time/time-picker/time-picker.tsx
14313
- import { forwardRef as forwardRef9 } from "react";
14719
+ import { forwardRef as forwardRef10 } from "react";
14314
14720
 
14315
14721
  // src/components/date-time/time-picker/time-picker-content.tsx
14722
+ import { useEffect as useEffect21, useRef as useRef14 } from "react";
14316
14723
  import { Fragment as Fragment20, jsx as jsx114, jsxs as jsxs74 } from "react/jsx-runtime";
14317
14724
  var CheckIcon = /* @__PURE__ */ jsxs74(
14318
14725
  "svg",
@@ -14329,12 +14736,82 @@ var CheckIcon = /* @__PURE__ */ jsxs74(
14329
14736
  ]
14330
14737
  }
14331
14738
  );
14739
+ function TimeColumn({
14740
+ options,
14741
+ value,
14742
+ onSelect,
14743
+ "aria-label": ariaLabel
14744
+ }) {
14745
+ const listRef = useRef14(null);
14746
+ const itemRef = useRef14(null);
14747
+ useEffect21(() => {
14748
+ if (!(value && listRef.current)) {
14749
+ return;
14750
+ }
14751
+ const el = listRef.current.querySelector(
14752
+ `[data-value="${value}"]`
14753
+ );
14754
+ if (el) {
14755
+ const container = listRef.current;
14756
+ const elementTop = el.offsetTop;
14757
+ const elementHeight = el.offsetHeight;
14758
+ const containerHeight = container.clientHeight;
14759
+ const scrollTop = elementTop - containerHeight / 2 + elementHeight / 2;
14760
+ container.scrollTop = Math.max(0, scrollTop);
14761
+ }
14762
+ }, [value]);
14763
+ return /* @__PURE__ */ jsx114(
14764
+ "div",
14765
+ {
14766
+ ref: listRef,
14767
+ className: "no-scrollbar flex max-h-48 flex-col overflow-y-auto py-1",
14768
+ role: "listbox",
14769
+ "aria-label": ariaLabel,
14770
+ children: options.map((opt) => /* @__PURE__ */ jsx114(
14771
+ "button",
14772
+ {
14773
+ ref: (r) => {
14774
+ if (opt === value) {
14775
+ itemRef.current = r;
14776
+ }
14777
+ },
14778
+ type: "button",
14779
+ role: "option",
14780
+ "data-value": opt,
14781
+ "aria-selected": opt === value,
14782
+ onClick: () => onSelect(opt),
14783
+ className: cn(
14784
+ "mx-0.5 min-w-10 shrink-0 rounded-md px-2 py-1 text-center text-sm transition-colors",
14785
+ opt === value ? "bg-primary text-primary-foreground" : "text-foreground hover:bg-muted"
14786
+ ),
14787
+ children: opt
14788
+ },
14789
+ opt
14790
+ ))
14791
+ }
14792
+ );
14793
+ }
14332
14794
  function TimePickerContent({
14333
14795
  timeH,
14334
14796
  timeM,
14335
14797
  timeS,
14336
14798
  timeFocus,
14337
14799
  withSeconds,
14800
+ is12h = false,
14801
+ amPm = "AM",
14802
+ setAmPm,
14803
+ amPmLabels = { am: "AM", pm: "PM" },
14804
+ isWithinRange: _isWithinRange,
14805
+ hoursStep = 1,
14806
+ minutesStep = 1,
14807
+ secondsStep = 1,
14808
+ presets,
14809
+ readOnly = false,
14810
+ withDropdown = false,
14811
+ onPresetClick,
14812
+ onStep,
14813
+ onColumnSelect,
14814
+ onAmPmSelect,
14338
14815
  onTimeFocus,
14339
14816
  onTimeBlur,
14340
14817
  onTimeHChange,
@@ -14342,96 +14819,309 @@ function TimePickerContent({
14342
14819
  onTimeSChange,
14343
14820
  onConfirm
14344
14821
  }) {
14345
- return /* @__PURE__ */ jsx114("div", { className: "p-3", children: /* @__PURE__ */ jsxs74("div", { className: "flex items-center gap-2", children: [
14346
- /* @__PURE__ */ jsxs74("fieldset", { className: "flex flex-1 flex-row items-center gap-0.5 rounded border border-solid border-input bg-background px-2.5 py-0", children: [
14347
- /* @__PURE__ */ jsx114("legend", { className: "sr-only", children: "Time" }),
14822
+ const handleKeyDown = (field) => (e) => {
14823
+ if (!(!readOnly && onStep)) {
14824
+ return;
14825
+ }
14826
+ if (e.key === "ArrowUp") {
14827
+ e.preventDefault();
14828
+ onStep(field, 1);
14829
+ } else if (e.key === "ArrowDown") {
14830
+ e.preventDefault();
14831
+ onStep(field, -1);
14832
+ }
14833
+ };
14834
+ if (withDropdown && onColumnSelect) {
14835
+ const hourOpts = getTimeColumnOptions("h", hoursStep, is12h);
14836
+ const minOpts = getTimeColumnOptions("m", minutesStep, false);
14837
+ const secOpts = getTimeColumnOptions("s", secondsStep, false);
14838
+ return /* @__PURE__ */ jsxs74("div", { className: "flex p-1", children: [
14348
14839
  /* @__PURE__ */ jsx114(
14349
- "input",
14840
+ TimeColumn,
14350
14841
  {
14351
- type: "text",
14352
- inputMode: "numeric",
14353
- value: timeFocus === "h" ? timeH : timeH || "--",
14354
- placeholder: "--",
14355
- "aria-label": "Hours",
14356
- onFocus: (e) => {
14357
- onTimeFocus("h");
14358
- e.target.select();
14359
- },
14360
- onBlur: () => onTimeBlur("h"),
14361
- onChange: (e) => onTimeHChange(e.target.value.replace(/\D/g, "").slice(0, 2)),
14362
- className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
14842
+ options: hourOpts,
14843
+ value: timeH || hourOpts[0],
14844
+ onSelect: (v) => onColumnSelect("h", v),
14845
+ "aria-label": "Hours"
14363
14846
  }
14364
14847
  ),
14365
- /* @__PURE__ */ jsx114("span", { className: "select-none px-1 text-sm text-muted-foreground", children: ":" }),
14366
14848
  /* @__PURE__ */ jsx114(
14367
- "input",
14849
+ TimeColumn,
14368
14850
  {
14369
- type: "text",
14370
- inputMode: "numeric",
14371
- value: timeFocus === "m" ? timeM : timeM || "--",
14372
- placeholder: "--",
14373
- "aria-label": "Minutes",
14374
- onFocus: (e) => {
14375
- onTimeFocus("m");
14376
- e.target.select();
14377
- },
14378
- onBlur: () => onTimeBlur("m"),
14379
- onChange: (e) => onTimeMChange(e.target.value.replace(/\D/g, "").slice(0, 2)),
14380
- className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
14851
+ options: minOpts,
14852
+ value: timeM || minOpts[0],
14853
+ onSelect: (v) => onColumnSelect("m", v),
14854
+ "aria-label": "Minutes"
14855
+ }
14856
+ ),
14857
+ withSeconds && /* @__PURE__ */ jsx114(
14858
+ TimeColumn,
14859
+ {
14860
+ options: secOpts,
14861
+ value: timeS || secOpts[0],
14862
+ onSelect: (v) => onColumnSelect("s", v),
14863
+ "aria-label": "Seconds"
14381
14864
  }
14382
14865
  ),
14383
- withSeconds && /* @__PURE__ */ jsxs74(Fragment20, { children: [
14866
+ is12h && (onAmPmSelect || setAmPm) && /* @__PURE__ */ jsx114(
14867
+ "div",
14868
+ {
14869
+ className: "no-scrollbar flex max-h-48 flex-col overflow-y-auto py-1",
14870
+ role: "listbox",
14871
+ "aria-label": "AM/PM",
14872
+ children: ["AM", "PM"].map((ap) => /* @__PURE__ */ jsx114(
14873
+ "button",
14874
+ {
14875
+ type: "button",
14876
+ role: "option",
14877
+ "aria-selected": amPm === ap,
14878
+ onClick: () => (onAmPmSelect ?? setAmPm)(ap),
14879
+ className: cn(
14880
+ "mx-0.5 min-w-10 shrink-0 rounded-md px-2 py-1 text-center text-sm transition-colors",
14881
+ amPm === ap ? "bg-primary text-primary-foreground" : "text-foreground hover:bg-muted"
14882
+ ),
14883
+ children: ap === "AM" ? amPmLabels.am : amPmLabels.pm
14884
+ },
14885
+ ap
14886
+ ))
14887
+ }
14888
+ )
14889
+ ] });
14890
+ }
14891
+ return /* @__PURE__ */ jsxs74("div", { className: "p-3", children: [
14892
+ /* @__PURE__ */ jsxs74("div", { className: "flex items-center gap-2", children: [
14893
+ /* @__PURE__ */ jsxs74("fieldset", { className: "flex flex-1 flex-row items-center gap-0.5 rounded border border-solid border-input bg-background px-2.5 py-0", children: [
14894
+ /* @__PURE__ */ jsx114("legend", { className: "sr-only", children: "Time" }),
14895
+ /* @__PURE__ */ jsx114(
14896
+ "input",
14897
+ {
14898
+ type: "text",
14899
+ inputMode: "numeric",
14900
+ value: timeFocus === "h" ? timeH : timeH || "--",
14901
+ placeholder: "--",
14902
+ "aria-label": "Hours",
14903
+ onFocus: (e) => {
14904
+ onTimeFocus("h");
14905
+ e.target.select();
14906
+ },
14907
+ onBlur: () => onTimeBlur("h"),
14908
+ onKeyDown: handleKeyDown("h"),
14909
+ readOnly,
14910
+ onChange: (e) => {
14911
+ const raw = e.target.value.replace(/\D/g, "").slice(0, 2);
14912
+ if (is12h && raw) {
14913
+ const n = Number.parseInt(raw, 10);
14914
+ onTimeHChange(n > 12 ? "12" : raw);
14915
+ } else {
14916
+ onTimeHChange(raw);
14917
+ }
14918
+ },
14919
+ className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
14920
+ }
14921
+ ),
14384
14922
  /* @__PURE__ */ jsx114("span", { className: "select-none px-1 text-sm text-muted-foreground", children: ":" }),
14385
14923
  /* @__PURE__ */ jsx114(
14386
14924
  "input",
14387
14925
  {
14388
14926
  type: "text",
14389
14927
  inputMode: "numeric",
14390
- value: timeFocus === "s" ? timeS : timeS || "--",
14928
+ value: timeFocus === "m" ? timeM : timeM || "--",
14391
14929
  placeholder: "--",
14392
- "aria-label": "Seconds",
14930
+ "aria-label": "Minutes",
14393
14931
  onFocus: (e) => {
14394
- onTimeFocus("s");
14932
+ onTimeFocus("m");
14395
14933
  e.target.select();
14396
14934
  },
14397
- onBlur: () => onTimeBlur("s"),
14398
- onChange: (e) => onTimeSChange(e.target.value.replace(/\D/g, "").slice(0, 2)),
14935
+ onBlur: () => onTimeBlur("m"),
14936
+ onKeyDown: handleKeyDown("m"),
14937
+ readOnly,
14938
+ onChange: (e) => onTimeMChange(e.target.value.replace(/\D/g, "").slice(0, 2)),
14399
14939
  className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
14400
14940
  }
14401
- )
14402
- ] })
14403
- ] }),
14404
- /* @__PURE__ */ jsx114(
14405
- "button",
14406
- {
14407
- type: "button",
14408
- onClick: onConfirm,
14409
- "aria-label": "Apply time",
14410
- className: "flex size-8 shrink-0 items-center justify-center rounded border border-border text-muted-foreground transition-colors hover:bg-muted",
14411
- children: CheckIcon
14412
- }
14413
- )
14414
- ] }) });
14941
+ ),
14942
+ withSeconds && /* @__PURE__ */ jsxs74(Fragment20, { children: [
14943
+ /* @__PURE__ */ jsx114("span", { className: "select-none px-1 text-sm text-muted-foreground", children: ":" }),
14944
+ /* @__PURE__ */ jsx114(
14945
+ "input",
14946
+ {
14947
+ type: "text",
14948
+ inputMode: "numeric",
14949
+ value: timeFocus === "s" ? timeS : timeS || "--",
14950
+ placeholder: "--",
14951
+ "aria-label": "Seconds",
14952
+ onFocus: (e) => {
14953
+ onTimeFocus("s");
14954
+ e.target.select();
14955
+ },
14956
+ onBlur: () => onTimeBlur("s"),
14957
+ onKeyDown: handleKeyDown("s"),
14958
+ readOnly,
14959
+ onChange: (e) => onTimeSChange(e.target.value.replace(/\D/g, "").slice(0, 2)),
14960
+ className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
14961
+ }
14962
+ )
14963
+ ] }),
14964
+ is12h && setAmPm && /* @__PURE__ */ jsxs74(Fragment20, { children: [
14965
+ /* @__PURE__ */ jsx114("span", { className: "w-1 shrink-0" }),
14966
+ /* @__PURE__ */ jsx114(
14967
+ "button",
14968
+ {
14969
+ type: "button",
14970
+ onClick: () => setAmPm(amPm === "AM" ? "PM" : "AM"),
14971
+ className: cn(
14972
+ "rounded px-2 py-0.5 text-sm font-medium transition-colors",
14973
+ "text-muted-foreground hover:bg-muted hover:text-foreground"
14974
+ ),
14975
+ "aria-label": amPm === "AM" ? "Switch to PM" : "Switch to AM",
14976
+ children: amPm === "AM" ? amPmLabels.am : amPmLabels.pm
14977
+ }
14978
+ )
14979
+ ] })
14980
+ ] }),
14981
+ !readOnly && /* @__PURE__ */ jsx114(
14982
+ "button",
14983
+ {
14984
+ type: "button",
14985
+ onClick: onConfirm,
14986
+ "aria-label": "Apply time",
14987
+ className: "flex size-8 shrink-0 items-center justify-center rounded border border-border text-muted-foreground transition-colors hover:bg-muted",
14988
+ children: CheckIcon
14989
+ }
14990
+ )
14991
+ ] }),
14992
+ presets && onPresetClick && presets.length > 0 && /* @__PURE__ */ jsx114("div", { className: "mt-3 border-t border-border pt-3", children: presets.map(
14993
+ (p) => typeof p === "string" ? /* @__PURE__ */ jsx114(
14994
+ "button",
14995
+ {
14996
+ type: "button",
14997
+ onClick: () => onPresetClick(p),
14998
+ className: "mr-2 mb-2 rounded border border-border bg-background px-2.5 py-1 text-sm text-foreground transition-colors hover:bg-muted",
14999
+ children: p
15000
+ },
15001
+ p
15002
+ ) : /* @__PURE__ */ jsxs74("div", { className: "mb-2", children: [
15003
+ /* @__PURE__ */ jsx114("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: p.label }),
15004
+ /* @__PURE__ */ jsx114("div", { className: "flex flex-wrap gap-1", children: p.values.map((v) => /* @__PURE__ */ jsx114(
15005
+ "button",
15006
+ {
15007
+ type: "button",
15008
+ onClick: () => onPresetClick(v),
15009
+ className: "rounded border border-border bg-background px-2.5 py-1 text-sm text-foreground transition-colors hover:bg-muted",
15010
+ children: v
15011
+ },
15012
+ v
15013
+ )) })
15014
+ ] }, p.label)
15015
+ ) })
15016
+ ] });
14415
15017
  }
14416
15018
 
14417
15019
  // src/components/date-time/time-picker/use-time-picker.ts
14418
- import { useCallback as useCallback17, useState as useState33 } from "react";
15020
+ import { useCallback as useCallback17, useEffect as useEffect22, useState as useState34 } from "react";
15021
+ function to12h4(hour24) {
15022
+ if (hour24 === 0) {
15023
+ return { h: 12, amPm: "AM" };
15024
+ }
15025
+ if (hour24 < 12) {
15026
+ return { h: hour24, amPm: "AM" };
15027
+ }
15028
+ if (hour24 === 12) {
15029
+ return { h: 12, amPm: "PM" };
15030
+ }
15031
+ return { h: hour24 - 12, amPm: "PM" };
15032
+ }
15033
+ function to24h2(h12, amPm) {
15034
+ if (amPm === "AM") {
15035
+ return h12 === 12 ? 0 : h12;
15036
+ }
15037
+ return h12 === 12 ? 12 : h12 + 12;
15038
+ }
15039
+ function parseTimeString2(str) {
15040
+ const parts = str.trim().split(":");
15041
+ if (parts.length < 2) {
15042
+ return null;
15043
+ }
15044
+ const h = Number.parseInt(parts[0], 10);
15045
+ const m = Number.parseInt(parts[1], 10);
15046
+ const s = parts[2] ? Number.parseInt(parts[2], 10) : 0;
15047
+ if (Number.isNaN(h) || Number.isNaN(m)) {
15048
+ return null;
15049
+ }
15050
+ return { h, m, s };
15051
+ }
14419
15052
  function useTimePicker(props) {
14420
15053
  const {
14421
15054
  value: controlledValue,
14422
15055
  defaultValue = null,
14423
15056
  onChange,
14424
- withSeconds = false
15057
+ withSeconds = false,
15058
+ format = "24h",
15059
+ amPmLabels = { am: "AM", pm: "PM" },
15060
+ min,
15061
+ max,
15062
+ hoursStep = 1,
15063
+ minutesStep = 1,
15064
+ secondsStep = 1,
15065
+ presets,
15066
+ open: controlledOpen,
15067
+ onOpenChange,
15068
+ readOnly = false,
15069
+ popoverProps
14425
15070
  } = props;
14426
15071
  const isControlled = controlledValue !== void 0;
14427
- const [internal, setInternal] = useState33(defaultValue);
15072
+ const isOpenControlled = controlledOpen !== void 0 || popoverProps?.opened !== void 0;
15073
+ const [internal, setInternal] = useState34(defaultValue);
14428
15074
  const value = isControlled ? controlledValue : internal;
14429
- const { open, setOpen, triggerRef, contentSide, updatePreferredSide } = usePopoverState();
15075
+ const is12h = format === "12h";
15076
+ const hourMax = is12h ? 12 : 23;
15077
+ const popoverState = usePopoverState();
15078
+ const internalOpen = popoverState.open;
15079
+ const internalSetOpen = popoverState.setOpen;
15080
+ const open = popoverProps?.opened ?? (isOpenControlled && controlledOpen !== void 0 ? controlledOpen : internalOpen);
15081
+ const setOpen = useCallback17(
15082
+ (next) => {
15083
+ popoverProps?.onChange?.(next);
15084
+ if (!isOpenControlled) {
15085
+ internalSetOpen(next);
15086
+ }
15087
+ onOpenChange?.(next);
15088
+ },
15089
+ [isOpenControlled, internalSetOpen, onOpenChange, popoverProps]
15090
+ );
15091
+ const { triggerRef, contentSide, updatePreferredSide } = popoverState;
14430
15092
  const now = /* @__PURE__ */ new Date();
14431
- const [timeH, setTimeH] = useState33(value ? pad2(value.getHours()) : "");
14432
- const [timeM, setTimeM] = useState33(value ? pad2(value.getMinutes()) : "");
14433
- const [timeS, setTimeS] = useState33(value ? pad2(value.getSeconds()) : "");
14434
- const [timeFocus, setTimeFocus] = useState33(null);
15093
+ const getInitialH = () => {
15094
+ if (!value) {
15095
+ return "";
15096
+ }
15097
+ return is12h ? pad2(to12h4(value.getHours()).h) : pad2(value.getHours());
15098
+ };
15099
+ const getInitialAmPm = () => value ? to12h4(value.getHours()).amPm : "AM";
15100
+ const [timeH, setTimeH] = useState34(getInitialH);
15101
+ const [timeM, setTimeM] = useState34(value ? pad2(value.getMinutes()) : "");
15102
+ const [timeS, setTimeS] = useState34(value ? pad2(value.getSeconds()) : "");
15103
+ const [amPm, setAmPm] = useState34(getInitialAmPm);
15104
+ const [timeFocus, setTimeFocus] = useState34(null);
15105
+ useEffect22(() => {
15106
+ if (value) {
15107
+ if (is12h) {
15108
+ const { h, amPm: ap } = to12h4(value.getHours());
15109
+ setTimeH(pad2(h));
15110
+ setAmPm(ap);
15111
+ } else {
15112
+ setTimeH(pad2(value.getHours()));
15113
+ }
15114
+ setTimeM(pad2(value.getMinutes()));
15115
+ setTimeS(pad2(value.getSeconds()));
15116
+ } else {
15117
+ setTimeH("");
15118
+ setTimeM("");
15119
+ setTimeS("");
15120
+ if (is12h) {
15121
+ setAmPm("AM");
15122
+ }
15123
+ }
15124
+ }, [value, is12h]);
14435
15125
  const updateValue = useCallback17(
14436
15126
  (d) => {
14437
15127
  if (!isControlled) {
@@ -14444,8 +15134,8 @@ function useTimePicker(props) {
14444
15134
  function handleTimeBlur(field) {
14445
15135
  setTimeFocus(null);
14446
15136
  const raw = { h: timeH, m: timeM, s: timeS }[field];
14447
- const max = field === "h" ? 23 : 59;
14448
- const padded = clampAndPad(raw, max);
15137
+ const maxVal = field === "h" ? hourMax : 59;
15138
+ const padded = clampAndPad(raw, maxVal);
14449
15139
  if (field === "h") {
14450
15140
  setTimeH(padded);
14451
15141
  } else if (field === "m") {
@@ -14455,8 +15145,9 @@ function useTimePicker(props) {
14455
15145
  }
14456
15146
  if (value && padded) {
14457
15147
  const d = new Date(value);
15148
+ const h24 = field === "h" && is12h ? to24h2(Number.parseInt(padded, 10) || 12, amPm) : Number.parseInt(padded, 10);
14458
15149
  if (field === "h") {
14459
- d.setHours(Number.parseInt(padded, 10));
15150
+ d.setHours(is12h ? h24 : Number.parseInt(padded, 10));
14460
15151
  } else if (field === "m") {
14461
15152
  d.setMinutes(Number.parseInt(padded, 10));
14462
15153
  } else {
@@ -14465,8 +15156,33 @@ function useTimePicker(props) {
14465
15156
  updateValue(d);
14466
15157
  }
14467
15158
  }
15159
+ function isWithinRange(d) {
15160
+ if (!(min || max)) {
15161
+ return true;
15162
+ }
15163
+ const mins = d.getHours() * 60 + d.getMinutes() + d.getSeconds() / 60;
15164
+ if (min) {
15165
+ const p = parseTimeString2(min);
15166
+ if (p) {
15167
+ const minMins = p.h * 60 + p.m + p.s / 60;
15168
+ if (mins < minMins) {
15169
+ return false;
15170
+ }
15171
+ }
15172
+ }
15173
+ if (max) {
15174
+ const p = parseTimeString2(max);
15175
+ if (p) {
15176
+ const maxMins = p.h * 60 + p.m + p.s / 60;
15177
+ if (mins > maxMins) {
15178
+ return false;
15179
+ }
15180
+ }
15181
+ }
15182
+ return true;
15183
+ }
14468
15184
  function handleConfirm() {
14469
- const h = clampAndPad(timeH, 23);
15185
+ const h = clampAndPad(timeH, hourMax);
14470
15186
  const m = clampAndPad(timeM, 59);
14471
15187
  const s = clampAndPad(timeS, 59);
14472
15188
  if (h) {
@@ -14478,25 +15194,32 @@ function useTimePicker(props) {
14478
15194
  if (withSeconds && s) {
14479
15195
  setTimeS(s);
14480
15196
  }
15197
+ const h24 = is12h ? to24h2(Number.parseInt(clampAndPad(h, 12), 10) || 12, amPm) : Number.parseInt(h || "0", 10);
14481
15198
  const base = value ?? new Date(now.getFullYear(), now.getMonth(), now.getDate());
14482
15199
  const d = new Date(base);
14483
15200
  d.setHours(
14484
- h ? Number.parseInt(h, 10) : 0,
15201
+ h24,
14485
15202
  m ? Number.parseInt(m, 10) : 0,
14486
15203
  withSeconds && s ? Number.parseInt(s, 10) : 0,
14487
15204
  0
14488
15205
  );
14489
- if (value || h || m || withSeconds && s) {
15206
+ if ((value || h || m || withSeconds && s) && isWithinRange(d)) {
14490
15207
  updateValue(d);
15208
+ setOpen(false);
15209
+ setTimeFocus(null);
14491
15210
  }
14492
- setOpen(false);
14493
- setTimeFocus(null);
14494
15211
  }
14495
15212
  const handleOpenChange = useCallback17(
14496
15213
  (next) => {
14497
15214
  if (next) {
14498
15215
  if (value) {
14499
- setTimeH(pad2(value.getHours()));
15216
+ if (is12h) {
15217
+ const { h, amPm: ap } = to12h4(value.getHours());
15218
+ setTimeH(pad2(h));
15219
+ setAmPm(ap);
15220
+ } else {
15221
+ setTimeH(pad2(value.getHours()));
15222
+ }
14500
15223
  setTimeM(pad2(value.getMinutes()));
14501
15224
  setTimeS(pad2(value.getSeconds()));
14502
15225
  }
@@ -14506,7 +15229,7 @@ function useTimePicker(props) {
14506
15229
  }
14507
15230
  setOpen(next);
14508
15231
  },
14509
- [updatePreferredSide, value, setOpen]
15232
+ [updatePreferredSide, value, setOpen, is12h]
14510
15233
  );
14511
15234
  function handleClear() {
14512
15235
  updateValue(null);
@@ -14514,10 +15237,125 @@ function useTimePicker(props) {
14514
15237
  setTimeM("");
14515
15238
  setTimeS("");
14516
15239
  }
15240
+ function handleStep(field, delta) {
15241
+ let step2;
15242
+ if (field === "h") {
15243
+ step2 = hoursStep;
15244
+ } else if (field === "m") {
15245
+ step2 = minutesStep;
15246
+ } else {
15247
+ step2 = secondsStep;
15248
+ }
15249
+ const maxVal = field === "h" ? hourMax : 59;
15250
+ const raw = { h: timeH, m: timeM, s: timeS }[field];
15251
+ const current = Number.parseInt(raw || "0", 10);
15252
+ let next = current + delta * step2;
15253
+ if (next < 0) {
15254
+ next = field === "h" ? maxVal : 59;
15255
+ }
15256
+ if (next > maxVal) {
15257
+ next = 0;
15258
+ }
15259
+ const padded = pad2(next);
15260
+ if (field === "h") {
15261
+ setTimeH(padded);
15262
+ if (value) {
15263
+ const d = new Date(value);
15264
+ const h24 = is12h ? to24h2(next, amPm) : next;
15265
+ d.setHours(h24);
15266
+ updateValue(d);
15267
+ }
15268
+ } else if (field === "m") {
15269
+ setTimeM(padded);
15270
+ if (value) {
15271
+ const d = new Date(value);
15272
+ d.setMinutes(next);
15273
+ updateValue(d);
15274
+ }
15275
+ } else {
15276
+ setTimeS(padded);
15277
+ if (value) {
15278
+ const d = new Date(value);
15279
+ d.setSeconds(next);
15280
+ updateValue(d);
15281
+ }
15282
+ }
15283
+ }
15284
+ function handleColumnSelect(field, val) {
15285
+ const n = Number.parseInt(val, 10);
15286
+ if (Number.isNaN(n)) {
15287
+ return;
15288
+ }
15289
+ const padded = pad2(n);
15290
+ if (field === "h") {
15291
+ setTimeH(padded);
15292
+ } else if (field === "m") {
15293
+ setTimeM(padded);
15294
+ } else {
15295
+ setTimeS(padded);
15296
+ }
15297
+ const newH = field === "h" ? padded : timeH;
15298
+ const newM = field === "m" ? padded : timeM;
15299
+ const newS = field === "s" ? padded : timeS;
15300
+ const h24 = is12h ? to24h2(Number.parseInt(newH || "12", 10) || 12, amPm) : Number.parseInt(newH || "0", 10);
15301
+ const base = value ?? new Date(now.getFullYear(), now.getMonth(), now.getDate());
15302
+ const d = new Date(base);
15303
+ d.setHours(
15304
+ h24,
15305
+ newM ? Number.parseInt(newM, 10) : 0,
15306
+ withSeconds && newS ? Number.parseInt(newS, 10) : 0,
15307
+ 0
15308
+ );
15309
+ if (isWithinRange(d)) {
15310
+ updateValue(d);
15311
+ }
15312
+ }
15313
+ function handleAmPmSelect(ap) {
15314
+ setAmPm(ap);
15315
+ const h = timeH || (is12h ? "12" : "00");
15316
+ const m = timeM || "00";
15317
+ const s = timeS || "00";
15318
+ const h24 = to24h2(Number.parseInt(h, 10) || 12, ap);
15319
+ const base = value ?? new Date(now.getFullYear(), now.getMonth(), now.getDate());
15320
+ const d = new Date(base);
15321
+ d.setHours(
15322
+ h24,
15323
+ m ? Number.parseInt(m, 10) : 0,
15324
+ withSeconds && s ? Number.parseInt(s, 10) : 0,
15325
+ 0
15326
+ );
15327
+ if (isWithinRange(d)) {
15328
+ updateValue(d);
15329
+ }
15330
+ }
15331
+ function handlePresetClick(presetStr) {
15332
+ const p = parseTimeString2(presetStr);
15333
+ if (!p) {
15334
+ return;
15335
+ }
15336
+ const base = value ?? new Date(now.getFullYear(), now.getMonth(), now.getDate());
15337
+ const d = new Date(base);
15338
+ d.setHours(p.h, p.m, p.s, 0);
15339
+ if (isWithinRange(d)) {
15340
+ updateValue(d);
15341
+ setTimeH(is12h ? pad2(to12h4(p.h).h) : pad2(p.h));
15342
+ setTimeM(pad2(p.m));
15343
+ setTimeS(pad2(p.s));
15344
+ if (is12h) {
15345
+ setAmPm(to12h4(p.h).amPm);
15346
+ }
15347
+ setOpen(false);
15348
+ }
15349
+ }
14517
15350
  let displayValue = null;
14518
15351
  if (value) {
14519
15352
  if (props.valueFormat) {
14520
15353
  displayValue = props.valueFormat(value);
15354
+ } else if (is12h) {
15355
+ const { h, amPm: ap } = to12h4(value.getHours());
15356
+ const suffix = withSeconds ? `:${pad2(value.getSeconds())}` : "";
15357
+ const apLabel = ap === "AM" ? amPmLabels.am : amPmLabels.pm;
15358
+ displayValue = `${pad2(h)}:${pad2(value.getMinutes())}${suffix} ${apLabel}`;
14521
15359
  } else {
14522
15360
  const suffix = withSeconds ? `:${pad2(value.getSeconds())}` : "";
14523
15361
  displayValue = `${pad2(value.getHours())}:${pad2(value.getMinutes())}${suffix}`;
@@ -14542,13 +15380,28 @@ function useTimePicker(props) {
14542
15380
  handleTimeBlur,
14543
15381
  handleConfirm,
14544
15382
  handleOpenChange,
14545
- handleClear
15383
+ handleClear,
15384
+ is12h,
15385
+ amPm,
15386
+ setAmPm,
15387
+ amPmLabels,
15388
+ isWithinRange,
15389
+ hoursStep,
15390
+ minutesStep,
15391
+ secondsStep,
15392
+ presets,
15393
+ readOnly,
15394
+ handlePresetClick,
15395
+ handleStep,
15396
+ handleColumnSelect,
15397
+ handleAmPmSelect,
15398
+ withDropdown: props.withDropdown ?? false
14546
15399
  };
14547
15400
  }
14548
15401
 
14549
15402
  // src/components/date-time/time-picker/time-picker.tsx
14550
15403
  import { jsx as jsx115 } from "react/jsx-runtime";
14551
- var TimePicker = forwardRef9(
15404
+ var TimePicker = forwardRef10(
14552
15405
  function TimePicker2(props, ref) {
14553
15406
  const {
14554
15407
  label,
@@ -14556,9 +15409,11 @@ var TimePicker = forwardRef9(
14556
15409
  disabled = false,
14557
15410
  clearable = false,
14558
15411
  withSeconds = false,
15412
+ withDropdown = false,
14559
15413
  size = "md",
14560
15414
  radius = "md",
14561
15415
  dropdownType = "popover",
15416
+ rightSection,
14562
15417
  "aria-label": ariaLabel,
14563
15418
  className
14564
15419
  } = props;
@@ -14571,7 +15426,7 @@ var TimePicker = forwardRef9(
14571
15426
  description: void 0,
14572
15427
  error: void 0,
14573
15428
  required: false,
14574
- disabled,
15429
+ disabled: disabled || props.readOnly,
14575
15430
  clearable,
14576
15431
  size,
14577
15432
  radius,
@@ -14580,13 +15435,17 @@ var TimePicker = forwardRef9(
14580
15435
  className,
14581
15436
  displayValue: state2.displayValue,
14582
15437
  hasValue: !!state2.value,
14583
- open: state2.open,
14584
- onOpenChange: state2.handleOpenChange,
15438
+ open: props.readOnly ? false : state2.open,
15439
+ onOpenChange: props.readOnly ? () => {
15440
+ return void 0;
15441
+ } : state2.handleOpenChange,
15442
+ popoverProps: props.popoverProps,
14585
15443
  contentSide: state2.contentSide,
14586
15444
  triggerRef: state2.triggerRef,
14587
15445
  onClear: state2.handleClear,
14588
- dropdownClassName: "w-[200px]",
15446
+ dropdownClassName: cn(!props.popoverProps?.width && "w-[200px]"),
14589
15447
  buttonRef: ref,
15448
+ rightSection,
14590
15449
  children: /* @__PURE__ */ jsx115(
14591
15450
  TimePickerContent,
14592
15451
  {
@@ -14595,12 +15454,27 @@ var TimePicker = forwardRef9(
14595
15454
  timeS: state2.timeS,
14596
15455
  timeFocus: state2.timeFocus,
14597
15456
  withSeconds,
15457
+ is12h: state2.is12h,
15458
+ amPm: state2.amPm,
15459
+ setAmPm: state2.setAmPm,
15460
+ amPmLabels: state2.amPmLabels,
15461
+ isWithinRange: state2.isWithinRange,
14598
15462
  onTimeFocus: state2.setTimeFocus,
14599
15463
  onTimeBlur: state2.handleTimeBlur,
14600
15464
  onTimeHChange: state2.setTimeH,
14601
15465
  onTimeMChange: state2.setTimeM,
14602
15466
  onTimeSChange: state2.setTimeS,
14603
- onConfirm: state2.handleConfirm
15467
+ onConfirm: state2.handleConfirm,
15468
+ hoursStep: props.hoursStep,
15469
+ minutesStep: props.minutesStep,
15470
+ secondsStep: props.secondsStep,
15471
+ presets: props.presets,
15472
+ readOnly: props.readOnly,
15473
+ withDropdown,
15474
+ onPresetClick: state2.handlePresetClick,
15475
+ onStep: state2.handleStep,
15476
+ onColumnSelect: state2.handleColumnSelect,
15477
+ onAmPmSelect: state2.handleAmPmSelect
14604
15478
  }
14605
15479
  )
14606
15480
  }
@@ -14632,11 +15506,15 @@ var ChevronRight5 = /* @__PURE__ */ jsx116(
14632
15506
  children: /* @__PURE__ */ jsx116("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" })
14633
15507
  }
14634
15508
  );
15509
+ var SIZE_CLASSES2 = {
15510
+ sm: "px-3 py-2 text-xs",
15511
+ md: "px-4 py-3 text-sm",
15512
+ lg: "px-5 py-4 text-base",
15513
+ xl: "px-6 py-5 text-lg"
15514
+ };
14635
15515
  function YearPickerContent({
14636
15516
  calendarType,
14637
- years,
14638
- decadeStart,
14639
- headerLabel,
15517
+ views,
14640
15518
  onPrev,
14641
15519
  onNext,
14642
15520
  onYearClick,
@@ -14646,28 +15524,103 @@ function YearPickerContent({
14646
15524
  isYearSelected,
14647
15525
  isYearInRange,
14648
15526
  isRangeStart,
14649
- isRangeEnd
14650
- }) {
14651
- return /* @__PURE__ */ jsxs75("div", { className: "min-w-[22rem] p-3", children: [
14652
- /* @__PURE__ */ jsxs75("div", { className: "mb-2 flex items-center justify-between", children: [
15527
+ isRangeEnd,
15528
+ canPrev = true,
15529
+ canNext = true,
15530
+ isYearDisabled = () => false,
15531
+ formatYear = (y) => String(y),
15532
+ getYearControlProps,
15533
+ yearToDate = (y) => new Date(y, 0, 1),
15534
+ size = "md"
15535
+ }) {
15536
+ const sizeClass = SIZE_CLASSES2[size];
15537
+ const renderYearGrid = (view) => /* @__PURE__ */ jsx116(
15538
+ "div",
15539
+ {
15540
+ className: "grid grid-cols-3 gap-x-4 gap-y-3 py-3",
15541
+ onMouseLeave: onGridMouseLeave,
15542
+ children: view.years.map((y) => {
15543
+ const inRange = y >= view.decadeStart && y <= view.decadeStart + 9;
15544
+ const controlProps = getYearControlProps?.(yearToDate(y)) ?? {};
15545
+ const userDisabled = controlProps.disabled === true;
15546
+ const disabled = isYearDisabled(y) || userDisabled;
15547
+ const sel = isYearSelected(y);
15548
+ const inR = isYearInRange(y);
15549
+ const start = isRangeStart(y);
15550
+ const end = isRangeEnd(y);
15551
+ const unselected = !(sel || inR);
15552
+ const inRangeOnly = inR && !sel;
15553
+ const unselectedInRange = unselected && inRange;
15554
+ const unselectedOutRange = unselected && !inRange;
15555
+ const {
15556
+ className: userClassName,
15557
+ style: userStyle,
15558
+ ...restProps
15559
+ } = controlProps;
15560
+ return /* @__PURE__ */ jsx116(
15561
+ "button",
15562
+ {
15563
+ type: "button",
15564
+ disabled,
15565
+ onClick: () => onYearClick(y),
15566
+ onMouseEnter: () => onYearHover(y),
15567
+ className: cn(
15568
+ "rounded transition-colors",
15569
+ sizeClass,
15570
+ disabled && "cursor-not-allowed opacity-40",
15571
+ sel && !disabled && "bg-primary font-medium text-primary-foreground",
15572
+ inRangeOnly && !disabled && "bg-primary/20 text-foreground",
15573
+ start && "rounded-e-none",
15574
+ end && "rounded-s-none",
15575
+ unselectedInRange && !disabled && "text-foreground hover:bg-muted",
15576
+ unselectedOutRange && !disabled && "text-muted-foreground hover:bg-muted/50",
15577
+ userClassName
15578
+ ),
15579
+ style: userStyle,
15580
+ ...restProps,
15581
+ children: formatYear(y)
15582
+ },
15583
+ y
15584
+ );
15585
+ })
15586
+ },
15587
+ view.decadeStart
15588
+ );
15589
+ return /* @__PURE__ */ jsxs75("div", { className: "min-w-[280px] p-3", children: [
15590
+ /* @__PURE__ */ jsxs75("div", { className: "mb-2 flex w-full items-center justify-between", children: [
14653
15591
  /* @__PURE__ */ jsx116(
14654
15592
  "button",
14655
15593
  {
14656
15594
  type: "button",
14657
15595
  onClick: onPrev,
14658
15596
  "aria-label": "Previous decade",
14659
- className: "flex size-7 items-center justify-center rounded text-muted-foreground hover:bg-muted",
15597
+ disabled: !canPrev,
15598
+ className: cn(
15599
+ "flex size-7 items-center justify-center rounded",
15600
+ canPrev ? "text-muted-foreground hover:bg-muted" : "cursor-not-allowed opacity-40"
15601
+ ),
14660
15602
  children: ChevronLeft5
14661
15603
  }
14662
15604
  ),
14663
- /* @__PURE__ */ jsx116("span", { className: "rounded px-3 py-1 text-sm font-semibold text-foreground", children: headerLabel }),
15605
+ /* @__PURE__ */ jsx116("div", { className: "flex flex-1 flex-wrap items-center justify-center gap-2", children: views.map((v) => /* @__PURE__ */ jsx116(
15606
+ "span",
15607
+ {
15608
+ className: "rounded px-3 py-1 text-sm font-semibold text-foreground",
15609
+ children: v.headerLabel
15610
+ },
15611
+ v.decadeStart
15612
+ )) }),
14664
15613
  /* @__PURE__ */ jsx116(
14665
15614
  "button",
14666
15615
  {
14667
15616
  type: "button",
14668
15617
  onClick: onNext,
14669
15618
  "aria-label": "Next decade",
14670
- className: "flex size-7 items-center justify-center rounded text-muted-foreground hover:bg-muted",
15619
+ disabled: !canNext,
15620
+ className: cn(
15621
+ "flex size-7 items-center justify-center rounded",
15622
+ canNext ? "text-muted-foreground hover:bg-muted" : "cursor-not-allowed opacity-40"
15623
+ ),
14671
15624
  children: ChevronRight5
14672
15625
  }
14673
15626
  )
@@ -14675,38 +15628,11 @@ function YearPickerContent({
14675
15628
  /* @__PURE__ */ jsx116(
14676
15629
  "div",
14677
15630
  {
14678
- className: "grid grid-cols-3 gap-1 py-2",
14679
- onMouseLeave: onGridMouseLeave,
14680
- children: years.map((y) => {
14681
- const inRange = y >= decadeStart && y <= decadeStart + 9;
14682
- const sel = isYearSelected(y);
14683
- const inR = isYearInRange(y);
14684
- const start = isRangeStart(y);
14685
- const end = isRangeEnd(y);
14686
- const unselected = !(sel || inR);
14687
- const inRangeOnly = inR && !sel;
14688
- const unselectedInRange = unselected && inRange;
14689
- const unselectedOutRange = unselected && !inRange;
14690
- return /* @__PURE__ */ jsx116(
14691
- "button",
14692
- {
14693
- type: "button",
14694
- onClick: () => onYearClick(y),
14695
- onMouseEnter: () => onYearHover(y),
14696
- className: cn(
14697
- "rounded py-3 text-sm transition-colors",
14698
- sel && "bg-primary font-medium text-primary-foreground",
14699
- inRangeOnly && "bg-primary/20 text-foreground",
14700
- start && "rounded-e-none",
14701
- end && "rounded-s-none",
14702
- unselectedInRange && "text-foreground hover:bg-muted",
14703
- unselectedOutRange && "text-muted-foreground hover:bg-muted/50"
14704
- ),
14705
- children: y
14706
- },
14707
- y
14708
- );
14709
- })
15631
+ className: cn(
15632
+ "flex w-full justify-center",
15633
+ views.length > 1 ? "gap-12 flex-wrap" : "gap-4"
15634
+ ),
15635
+ children: views.map((view) => renderYearGrid(view))
14710
15636
  }
14711
15637
  ),
14712
15638
  /* @__PURE__ */ jsxs75("div", { className: "mt-2 flex justify-end gap-1 border-t border-border pt-2", children: [
@@ -14743,42 +15669,53 @@ function YearPickerContent({
14743
15669
  }
14744
15670
 
14745
15671
  // src/components/date-time/year-picker/use-year-picker.ts
14746
- import { useCallback as useCallback18, useEffect as useEffect21, useState as useState34 } from "react";
15672
+ import { useCallback as useCallback18, useEffect as useEffect23, useState as useState35 } from "react";
14747
15673
  function useYearPicker(props) {
14748
15674
  const {
14749
15675
  defaultCalendarType = "GC",
14750
15676
  allowDeselect = false,
14751
15677
  defaultDate,
14752
15678
  date: controlledDate,
14753
- onDateChange
15679
+ onDateChange,
15680
+ minDate,
15681
+ maxDate,
15682
+ getYearControlProps,
15683
+ numberOfColumns = 1,
15684
+ yearsListFormat = "YYYY",
15685
+ decadeLabelFormat = "YYYY"
14754
15686
  } = props;
14755
15687
  const type = props.type ?? "default";
14756
15688
  const isControlled = props.value !== void 0;
14757
15689
  const isDateControlled = controlledDate !== void 0;
14758
- const [_single, _setSingle] = useState34(
15690
+ const [_single, _setSingle] = useState35(
14759
15691
  type === "default" ? props.defaultValue ?? null : null
14760
15692
  );
14761
- const [_range, _setRange] = useState34(
15693
+ const [_range, _setRange] = useState35(
14762
15694
  type === "range" ? props.defaultValue ?? [
14763
15695
  null,
14764
15696
  null
14765
15697
  ] : [null, null]
14766
15698
  );
15699
+ const [_multi, _setMulti] = useState35(
15700
+ type === "multiple" ? props.defaultValue ?? [] : []
15701
+ );
14767
15702
  const singleValue = type === "default" ? isControlled ? props.value : _single : null;
14768
15703
  const rangeValue = type === "range" ? isControlled ? props.value : _range : [null, null];
14769
- const [hoveredYear, setHoveredYear] = useState34(null);
14770
- const [calendarType, setCalendarType] = useState34(defaultCalendarType);
15704
+ const multiValue = type === "multiple" ? isControlled ? props.value : _multi : [];
15705
+ const [hoveredYear, setHoveredYear] = useState35(null);
15706
+ const [calendarType, setCalendarType] = useState35(defaultCalendarType);
14771
15707
  const now = /* @__PURE__ */ new Date();
14772
- const initDate = controlledDate ?? defaultDate ?? (type === "default" ? singleValue : rangeValue[0]) ?? now;
14773
- const [gcViewYear, setGcViewYear] = useState34(initDate.getFullYear());
14774
- const [ecViewYear, setEcViewYear] = useState34(
15708
+ const primaryForInit = type === "default" ? singleValue : type === "range" ? rangeValue[0] : multiValue[0] ?? null;
15709
+ const initDate = controlledDate ?? defaultDate ?? primaryForInit ?? now;
15710
+ const [gcViewYear, setGcViewYear] = useState35(initDate.getFullYear());
15711
+ const [ecViewYear, setEcViewYear] = useState35(
14775
15712
  toEC(
14776
15713
  initDate.getFullYear(),
14777
15714
  initDate.getMonth() + 1,
14778
15715
  initDate.getDate()
14779
15716
  )[0]
14780
15717
  );
14781
- useEffect21(() => {
15718
+ useEffect23(() => {
14782
15719
  if (!(isDateControlled && controlledDate)) {
14783
15720
  return;
14784
15721
  }
@@ -14800,7 +15737,18 @@ function useYearPicker(props) {
14800
15737
  const activeViewYear = calendarType === "EC" ? ecViewYear : gcViewYear;
14801
15738
  const decadeStart = getDecadeStart(activeViewYear);
14802
15739
  const years = buildYears(activeViewYear);
14803
- const primaryDate = type === "default" ? singleValue : rangeValue[0];
15740
+ const cols = Math.max(1, Math.min(numberOfColumns ?? 1, 3));
15741
+ const formatYear = (y) => yearsListFormat === "YY" ? String(y).slice(-2) : String(y);
15742
+ const formatDecadeLabel = (ds) => decadeLabelFormat === "YY" ? `${String(ds).slice(-2)} \u2013 ${String(ds + 9).slice(-2)}` : `${ds} \u2013 ${ds + 9}`;
15743
+ const decadeViews = cols <= 1 ? [{ decadeStart, years, headerLabel: formatDecadeLabel(decadeStart) }] : Array.from({ length: cols }, (_, i) => {
15744
+ const ds = decadeStart + i * 10;
15745
+ return {
15746
+ decadeStart: ds,
15747
+ years: buildYears(ds),
15748
+ headerLabel: formatDecadeLabel(ds)
15749
+ };
15750
+ });
15751
+ const primaryDate = type === "default" ? singleValue : type === "range" ? rangeValue[0] : multiValue[0] ?? null;
14804
15752
  const hasRange = type === "range" && !!rangeValue[0] && !!(rangeValue[1] ?? hoveredYear);
14805
15753
  function yearToDate(y) {
14806
15754
  if (calendarType === "EC") {
@@ -14815,9 +15763,6 @@ function useYearPicker(props) {
14815
15763
  }
14816
15764
  return d.getFullYear();
14817
15765
  }
14818
- function headerLabel() {
14819
- return `${decadeStart} \u2013 ${decadeStart + 9}`;
14820
- }
14821
15766
  function callOnChange(next) {
14822
15767
  if (props.onChange) {
14823
15768
  props.onChange(next);
@@ -14827,6 +15772,9 @@ function useYearPicker(props) {
14827
15772
  if (type === "default") {
14828
15773
  return !!singleValue && getViewYear(singleValue) === y;
14829
15774
  }
15775
+ if (type === "multiple") {
15776
+ return multiValue.some((d) => getViewYear(d) === y);
15777
+ }
14830
15778
  const y0 = rangeValue[0] ? getViewYear(rangeValue[0]) : null;
14831
15779
  const y1 = rangeValue[1] ? getViewYear(rangeValue[1]) : null;
14832
15780
  return y0 !== null && y0 === y || y1 !== null && y1 === y;
@@ -14851,7 +15799,32 @@ function useYearPicker(props) {
14851
15799
  const end = rangeValue[1] ?? (hoveredYear != null ? yearToDate(hoveredYear) : null);
14852
15800
  return !!(type === "range" && end && getViewYear(end) === y);
14853
15801
  }
15802
+ function getMinMaxYear(ct) {
15803
+ if (!(minDate || maxDate)) {
15804
+ return { min: null, max: null };
15805
+ }
15806
+ return {
15807
+ min: minDate ? ct === "EC" ? toEC(
15808
+ minDate.getFullYear(),
15809
+ minDate.getMonth() + 1,
15810
+ minDate.getDate()
15811
+ )[0] : minDate.getFullYear() : null,
15812
+ max: maxDate ? ct === "EC" ? toEC(
15813
+ maxDate.getFullYear(),
15814
+ maxDate.getMonth() + 1,
15815
+ maxDate.getDate()
15816
+ )[0] : maxDate.getFullYear() : null
15817
+ };
15818
+ }
15819
+ const { min: minYear, max: maxYear } = getMinMaxYear(calendarType);
15820
+ const lastDecadeEnd = decadeStart + (cols - 1) * 10 + 9;
15821
+ const canPrev = minYear == null || decadeStart > minYear;
15822
+ const canNext = maxYear == null || lastDecadeEnd < maxYear;
15823
+ const isYearDisabled = (year) => minYear != null && year < minYear || maxYear != null && year > maxYear;
14854
15824
  function handleYearClick(y) {
15825
+ if (isYearDisabled(y)) {
15826
+ return;
15827
+ }
14855
15828
  const clicked = yearToDate(y);
14856
15829
  if (type === "default") {
14857
15830
  if (allowDeselect && singleValue && getViewYear(singleValue) === y) {
@@ -14865,6 +15838,16 @@ function useYearPicker(props) {
14865
15838
  }
14866
15839
  callOnChange(clicked);
14867
15840
  }
15841
+ } else if (type === "multiple") {
15842
+ const vy = getViewYear(clicked);
15843
+ const idx = multiValue.findIndex((d) => getViewYear(d) === vy);
15844
+ const next = idx >= 0 ? multiValue.filter((_, i) => i !== idx) : [...multiValue, clicked].sort(
15845
+ (a, b) => getViewYear(a) - getViewYear(b)
15846
+ );
15847
+ if (!isControlled) {
15848
+ _setMulti(next);
15849
+ }
15850
+ callOnChange(next);
14868
15851
  } else {
14869
15852
  const [start, end] = rangeValue;
14870
15853
  if (!start || start && end) {
@@ -14899,6 +15882,9 @@ function useYearPicker(props) {
14899
15882
  }
14900
15883
  }
14901
15884
  function handlePrev() {
15885
+ if (!canPrev) {
15886
+ return;
15887
+ }
14902
15888
  if (calendarType === "EC") {
14903
15889
  setEcViewYear((y) => y - 10);
14904
15890
  } else {
@@ -14907,6 +15893,9 @@ function useYearPicker(props) {
14907
15893
  }
14908
15894
  }
14909
15895
  function handleNext() {
15896
+ if (!canNext) {
15897
+ return;
15898
+ }
14910
15899
  if (calendarType === "EC") {
14911
15900
  setEcViewYear((y) => y + 10);
14912
15901
  } else {
@@ -14914,6 +15903,24 @@ function useYearPicker(props) {
14914
15903
  notifyDateChange(gcViewYear + 10);
14915
15904
  }
14916
15905
  }
15906
+ function handleClear() {
15907
+ if (type === "default") {
15908
+ if (!isControlled) {
15909
+ _setSingle(null);
15910
+ }
15911
+ callOnChange(null);
15912
+ } else if (type === "multiple") {
15913
+ if (!isControlled) {
15914
+ _setMulti([]);
15915
+ }
15916
+ callOnChange([]);
15917
+ } else {
15918
+ if (!isControlled) {
15919
+ _setRange([null, null]);
15920
+ }
15921
+ callOnChange([null, null]);
15922
+ }
15923
+ }
14917
15924
  function handleCalendarTypeChange(nextType) {
14918
15925
  if (nextType === calendarType) {
14919
15926
  return;
@@ -14935,23 +15942,32 @@ function useYearPicker(props) {
14935
15942
  calendarType,
14936
15943
  years,
14937
15944
  decadeStart,
15945
+ decadeViews,
14938
15946
  ecViewYear,
14939
15947
  gcViewYear,
14940
15948
  primaryDate,
14941
15949
  hasRange,
14942
15950
  singleValue,
14943
15951
  rangeValue,
14944
- headerLabel,
15952
+ multiValue,
15953
+ formatYear,
15954
+ formatDecadeLabel,
15955
+ getYearControlProps,
15956
+ yearToDate,
14945
15957
  handlePrev,
14946
15958
  handleNext,
14947
15959
  handleYearClick,
14948
15960
  handleYearHover,
15961
+ handleClear,
14949
15962
  handleGridMouseLeave,
14950
15963
  handleCalendarTypeChange,
14951
15964
  isYearSelected,
14952
15965
  isYearInRange,
14953
15966
  isRangeStart,
14954
- isRangeEnd
15967
+ isRangeEnd,
15968
+ canPrev,
15969
+ canNext,
15970
+ isYearDisabled
14955
15971
  };
14956
15972
  }
14957
15973
 
@@ -14964,9 +15980,7 @@ function YearPicker(props) {
14964
15980
  YearPickerContent,
14965
15981
  {
14966
15982
  calendarType: state2.calendarType,
14967
- years: state2.years,
14968
- decadeStart: state2.decadeStart,
14969
- headerLabel: state2.headerLabel(),
15983
+ views: state2.decadeViews,
14970
15984
  onPrev: state2.handlePrev,
14971
15985
  onNext: state2.handleNext,
14972
15986
  onYearClick: state2.handleYearClick,
@@ -14976,13 +15990,20 @@ function YearPicker(props) {
14976
15990
  isYearSelected: state2.isYearSelected,
14977
15991
  isYearInRange: state2.isYearInRange,
14978
15992
  isRangeStart: state2.isRangeStart,
14979
- isRangeEnd: state2.isRangeEnd
15993
+ isRangeEnd: state2.isRangeEnd,
15994
+ canPrev: state2.canPrev,
15995
+ canNext: state2.canNext,
15996
+ isYearDisabled: state2.isYearDisabled,
15997
+ formatYear: state2.formatYear,
15998
+ getYearControlProps: state2.getYearControlProps,
15999
+ yearToDate: state2.yearToDate,
16000
+ size: props.size ?? "md"
14980
16001
  }
14981
16002
  ) });
14982
16003
  }
14983
16004
 
14984
16005
  // src/components/date-time/year-picker-input/year-picker-input.tsx
14985
- import { forwardRef as forwardRef10 } from "react";
16006
+ import { forwardRef as forwardRef11 } from "react";
14986
16007
 
14987
16008
  // src/components/date-time/year-picker-input/use-year-picker-input.ts
14988
16009
  import { useCallback as useCallback19 } from "react";
@@ -15019,12 +16040,21 @@ function useYearPickerInput(props) {
15019
16040
  if (type === "default") {
15020
16041
  return picker.singleValue ? valueFormatter({ type: "default", date: picker.singleValue }) : null;
15021
16042
  }
16043
+ if (type === "multiple") {
16044
+ return valueFormatter({ type: "multiple", date: picker.multiValue });
16045
+ }
15022
16046
  return picker.rangeValue[0] ? valueFormatter({ type: "range", date: picker.rangeValue }) : null;
15023
16047
  }
15024
16048
  function formatWithFmt() {
15025
16049
  if (type === "default") {
15026
16050
  return picker.singleValue ? fmt(picker.singleValue) : null;
15027
16051
  }
16052
+ if (type === "multiple") {
16053
+ if (picker.multiValue.length === 0) {
16054
+ return null;
16055
+ }
16056
+ return [...picker.multiValue].sort((a2, b2) => a2.getFullYear() - b2.getFullYear()).map((d) => fmt(d)).join(", ");
16057
+ }
15028
16058
  if (!picker.rangeValue[0]) {
15029
16059
  return null;
15030
16060
  }
@@ -15032,21 +16062,14 @@ function useYearPickerInput(props) {
15032
16062
  if (!b) {
15033
16063
  return a ? fmt(a) : null;
15034
16064
  }
15035
- const start = picker.rangeValue[0];
15036
- return start ? `${fmt(start)} \u2013 ${fmt(b)}` : null;
16065
+ const y1 = a.getFullYear();
16066
+ const y2 = b.getFullYear();
16067
+ const [lo, hi] = y1 <= y2 ? [a, b] : [b, a];
16068
+ return `${fmt(lo)} \u2013 ${fmt(hi)}`;
15037
16069
  }
15038
16070
  const displayValue = formatWithFormatter() ?? formatWithFmt();
15039
16071
  function handleClear() {
15040
- if (props.onChange) {
15041
- if (type === "default") {
15042
- props.onChange(null);
15043
- } else {
15044
- props.onChange([
15045
- null,
15046
- null
15047
- ]);
15048
- }
15049
- }
16072
+ picker.handleClear();
15050
16073
  }
15051
16074
  return {
15052
16075
  displayValue,
@@ -15062,7 +16085,7 @@ function useYearPickerInput(props) {
15062
16085
 
15063
16086
  // src/components/date-time/year-picker-input/year-picker-input.tsx
15064
16087
  import { jsx as jsx118 } from "react/jsx-runtime";
15065
- var YearPickerInput = forwardRef10(function YearPickerInput2(props, ref) {
16088
+ var YearPickerInput = forwardRef11(function YearPickerInput2(props, ref) {
15066
16089
  const {
15067
16090
  label,
15068
16091
  placeholder = "Pick year",
@@ -15106,9 +16129,7 @@ var YearPickerInput = forwardRef10(function YearPickerInput2(props, ref) {
15106
16129
  YearPickerContent,
15107
16130
  {
15108
16131
  calendarType: p.calendarType,
15109
- years: p.years,
15110
- decadeStart: p.decadeStart,
15111
- headerLabel: p.headerLabel(),
16132
+ views: p.decadeViews,
15112
16133
  onPrev: p.handlePrev,
15113
16134
  onNext: p.handleNext,
15114
16135
  onYearClick: p.handleYearClick,
@@ -15118,7 +16139,14 @@ var YearPickerInput = forwardRef10(function YearPickerInput2(props, ref) {
15118
16139
  isYearSelected: p.isYearSelected,
15119
16140
  isYearInRange: p.isYearInRange,
15120
16141
  isRangeStart: p.isRangeStart,
15121
- isRangeEnd: p.isRangeEnd
16142
+ isRangeEnd: p.isRangeEnd,
16143
+ canPrev: p.canPrev,
16144
+ canNext: p.canNext,
16145
+ isYearDisabled: p.isYearDisabled,
16146
+ formatYear: p.formatYear,
16147
+ getYearControlProps: p.getYearControlProps,
16148
+ yearToDate: p.yearToDate,
16149
+ size: props.size ?? "md"
15122
16150
  }
15123
16151
  )
15124
16152
  }
@@ -15539,7 +16567,7 @@ function Anchor({
15539
16567
  }
15540
16568
 
15541
16569
  // src/components/ui/angle-slider.tsx
15542
- import { useCallback as useCallback20, useRef as useRef13, useState as useState35 } from "react";
16570
+ import { useCallback as useCallback20, useRef as useRef15, useState as useState36 } from "react";
15543
16571
  import { jsx as jsx124, jsxs as jsxs78 } from "react/jsx-runtime";
15544
16572
  var TAU = 2 * Math.PI;
15545
16573
  var px = (n) => `${Math.round(n * 1e4) / 1e4}px`;
@@ -15556,7 +16584,7 @@ function AngleSlider({
15556
16584
  disabled = false,
15557
16585
  ...props
15558
16586
  }) {
15559
- const [internalValue, setInternalValue] = useState35(defaultValue);
16587
+ const [internalValue, setInternalValue] = useState36(defaultValue);
15560
16588
  const value = valueProp ?? internalValue;
15561
16589
  const isControlled = valueProp !== void 0;
15562
16590
  const setValue = useCallback20(
@@ -15569,8 +16597,8 @@ function AngleSlider({
15569
16597
  },
15570
16598
  [isControlled, onChange]
15571
16599
  );
15572
- const ref = useRef13(null);
15573
- const angleRef = useRef13(value);
16600
+ const ref = useRef15(null);
16601
+ const angleRef = useRef15(value);
15574
16602
  const getAngle = useCallback20(
15575
16603
  (clientX, clientY) => {
15576
16604
  const el = ref.current;
@@ -15711,7 +16739,7 @@ function AngleSlider({
15711
16739
  import { useMesob as useMesob8 } from "@mesob/ui/providers";
15712
16740
  import { IconChevronDown as IconChevronDown7 } from "@tabler/icons-react";
15713
16741
  import { motion } from "motion/react";
15714
- import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo12, useRef as useRef14, useState as useState36 } from "react";
16742
+ import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo12, useRef as useRef16, useState as useState37 } from "react";
15715
16743
  import { jsx as jsx125, jsxs as jsxs79 } from "react/jsx-runtime";
15716
16744
  function AnimatedTabs({
15717
16745
  tabs,
@@ -15724,17 +16752,17 @@ function AnimatedTabs({
15724
16752
  const mesob = useMesob8();
15725
16753
  const LinkComponent = linkProp ?? mesob?.navigation?.Link;
15726
16754
  const locale = mesob?.locale;
15727
- const [internalActiveTab, setInternalActiveTab] = useState36(
16755
+ const [internalActiveTab, setInternalActiveTab] = useState37(
15728
16756
  defaultTab ?? tabs[0]?.value ?? ""
15729
16757
  );
15730
16758
  const activeTab = controlledActiveTab ?? internalActiveTab;
15731
- const [visibleTabs, setVisibleTabs] = useState36(tabs);
15732
- const [overflowTabs, setOverflowTabs] = useState36([]);
15733
- const containerRef = useRef14(null);
15734
- const tabsListRef = useRef14(null);
15735
- const dropdownTriggerRef = useRef14(null);
15736
- const tabRefs = useRef14([]);
15737
- const [underlineStyle, setUnderlineStyle] = useState36({ left: 0, width: 0 });
16759
+ const [visibleTabs, setVisibleTabs] = useState37(tabs);
16760
+ const [overflowTabs, setOverflowTabs] = useState37([]);
16761
+ const containerRef = useRef16(null);
16762
+ const tabsListRef = useRef16(null);
16763
+ const dropdownTriggerRef = useRef16(null);
16764
+ const tabRefs = useRef16([]);
16765
+ const [underlineStyle, setUnderlineStyle] = useState37({ left: 0, width: 0 });
15738
16766
  const handleTabChange = (newValue) => {
15739
16767
  if (!controlledActiveTab) {
15740
16768
  setInternalActiveTab(newValue);
@@ -16712,6 +17740,7 @@ var ChartStyle = ({ id, config }) => {
16712
17740
  "style",
16713
17741
  {
16714
17742
  dangerouslySetInnerHTML: {
17743
+ // biome-ignore lint/style/useNamingConvention: React requires `__html` on innerHTML object
16715
17744
  __html: Object.entries(THEMES).map(
16716
17745
  ([theme, prefix]) => `
16717
17746
  ${prefix} [data-chart=${id}] {
@@ -17008,7 +18037,7 @@ function CollapsibleContent({
17008
18037
  // src/components/ui/color-input.tsx
17009
18038
  import { IconColorPicker } from "@tabler/icons-react";
17010
18039
  import * as React14 from "react";
17011
- import { useCallback as useCallback22, useEffect as useEffect25, useRef as useRef17, useState as useState39 } from "react";
18040
+ import { useCallback as useCallback22, useEffect as useEffect27, useRef as useRef19, useState as useState40 } from "react";
17012
18041
 
17013
18042
  // src/lib/color-utils.ts
17014
18043
  function hex2rgb(hex) {
@@ -17210,7 +18239,7 @@ function hasAlpha(format) {
17210
18239
  }
17211
18240
 
17212
18241
  // src/components/ui/color-picker.tsx
17213
- import { useCallback as useCallback21, useEffect as useEffect24, useRef as useRef16, useState as useState38 } from "react";
18242
+ import { useCallback as useCallback21, useEffect as useEffect26, useRef as useRef18, useState as useState39 } from "react";
17214
18243
 
17215
18244
  // src/components/ui/color-swatch.tsx
17216
18245
  import { jsx as jsx139, jsxs as jsxs83 } from "react/jsx-runtime";
@@ -17302,8 +18331,8 @@ function HueAlphaSlider({
17302
18331
  ariaLabel,
17303
18332
  className
17304
18333
  }) {
17305
- const ref = useRef16(null);
17306
- const lastRef = useRef16(value);
18334
+ const ref = useRef18(null);
18335
+ const lastRef = useRef18(value);
17307
18336
  const handleMove = useCallback21(
17308
18337
  (clientX) => {
17309
18338
  const el = ref.current;
@@ -17398,15 +18427,15 @@ function ColorPicker({
17398
18427
  alphaLabel,
17399
18428
  ...inputProps
17400
18429
  }) {
17401
- const [hsva, setHsva] = useState38(
18430
+ const [hsva, setHsva] = useState39(
17402
18431
  () => parseColor(String(value ?? inputProps.defaultValue ?? "#000000"))
17403
18432
  );
17404
18433
  const isControlled = value !== void 0;
17405
- const valueRef = useRef16(value);
17406
- const saturationRef = useRef16(null);
17407
- const lastHsvaRef = useRef16(hsva);
18434
+ const valueRef = useRef18(value);
18435
+ const saturationRef = useRef18(null);
18436
+ const lastHsvaRef = useRef18(hsva);
17408
18437
  lastHsvaRef.current = hsva;
17409
- useEffect24(() => {
18438
+ useEffect26(() => {
17410
18439
  if (value === valueRef.current) {
17411
18440
  return;
17412
18441
  }
@@ -17747,9 +18776,9 @@ var ColorInput = React14.forwardRef(
17747
18776
  placeholder,
17748
18777
  ...inputProps
17749
18778
  }, ref) => {
17750
- const [dropdownOpened, setDropdownOpened] = useState39(false);
17751
- const [lastValidValue, setLastValidValue] = useState39("");
17752
- const [internalValue, setInternalValue] = useState39(
18779
+ const [dropdownOpened, setDropdownOpened] = useState40(false);
18780
+ const [lastValidValue, setLastValidValue] = useState40("");
18781
+ const [internalValue, setInternalValue] = useState40(
17753
18782
  defaultValue ?? valueProp ?? ""
17754
18783
  );
17755
18784
  const isControlled = valueProp !== void 0;
@@ -17766,18 +18795,18 @@ var ColorInput = React14.forwardRef(
17766
18795
  );
17767
18796
  const { supported: eyeDropperSupported, open: openEyeDropper } = useEyeDropper();
17768
18797
  const _withEyeDropper = withEyeDropperProp && eyeDropperSupported;
17769
- const inputRef = useRef17(null);
17770
- const anchorRef = useRef17(null);
17771
- const popoverContentRef = useRef17(null);
17772
- const openTimestampRef = useRef17(0);
17773
- const pointerDownInPopoverRef = useRef17(false);
17774
- useEffect25(() => {
18798
+ const inputRef = useRef19(null);
18799
+ const anchorRef = useRef19(null);
18800
+ const popoverContentRef = useRef19(null);
18801
+ const openTimestampRef = useRef19(0);
18802
+ const pointerDownInPopoverRef = useRef19(false);
18803
+ useEffect27(() => {
17775
18804
  if (isColorValid(value) || value.trim() === "") {
17776
18805
  setLastValidValue(value);
17777
18806
  }
17778
18807
  }, [value]);
17779
- const prevFormatRef = useRef17(format);
17780
- useEffect25(() => {
18808
+ const prevFormatRef = useRef19(format);
18809
+ useEffect27(() => {
17781
18810
  if (prevFormatRef.current !== format && isColorValid(value)) {
17782
18811
  setValue(formatColor(parseColor(value), format));
17783
18812
  prevFormatRef.current = format;
@@ -18010,7 +19039,7 @@ ColorInput.displayName = "ColorInput";
18010
19039
  // src/components/ui/combobox.tsx
18011
19040
  import { Combobox as ComboboxPrimitive } from "@base-ui/react/combobox";
18012
19041
  import { IconCheck as IconCheck4, IconChevronDown as IconChevronDown9 } from "@tabler/icons-react";
18013
- import { useMemo as useMemo13, useState as useState40 } from "react";
19042
+ import { useMemo as useMemo13, useState as useState41 } from "react";
18014
19043
  import { jsx as jsx142, jsxs as jsxs86 } from "react/jsx-runtime";
18015
19044
  var COMBOBOX_CONTENT_BASE_CN = "cn-menu-target group/combobox-content relative max-h-[min(100dvh,var(--available-height,100dvh))] w-[var(--anchor-width,auto)] max-w-[min(100vw,var(--available-width,100vw))] min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) data-[chips=true]:min-w-[var(--anchor-width,auto)]";
18016
19045
  var COMBOBOX_ITEM_BASE_CN = "relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0";
@@ -18025,7 +19054,7 @@ function Combobox({
18025
19054
  className,
18026
19055
  ...props
18027
19056
  }) {
18028
- const [inputValue, setInputValue] = useState40("");
19057
+ const [inputValue, setInputValue] = useState41("");
18029
19058
  const selectedOption = useMemo13(
18030
19059
  () => options.find((opt) => opt.value === value) ?? null,
18031
19060
  [options, value]
@@ -18477,7 +19506,7 @@ function ContextMenuShortcut({
18477
19506
 
18478
19507
  // src/components/ui/copy-button.tsx
18479
19508
  import { IconCheck as IconCheck6, IconCopy } from "@tabler/icons-react";
18480
- import { useState as useState41 } from "react";
19509
+ import { useState as useState42 } from "react";
18481
19510
  import { jsx as jsx145 } from "react/jsx-runtime";
18482
19511
  function CopyButton({
18483
19512
  value,
@@ -18488,7 +19517,7 @@ function CopyButton({
18488
19517
  className,
18489
19518
  ...props
18490
19519
  }) {
18491
- const [copied, setCopied] = useState41(false);
19520
+ const [copied, setCopied] = useState42(false);
18492
19521
  const handleCopy = async () => {
18493
19522
  try {
18494
19523
  await navigator.clipboard.writeText(value);
@@ -19075,7 +20104,7 @@ function DropdownButton({
19075
20104
  }
19076
20105
 
19077
20106
  // src/components/ui/file-button.tsx
19078
- import { useRef as useRef18 } from "react";
20107
+ import { useRef as useRef20 } from "react";
19079
20108
  import { Fragment as Fragment27, jsx as jsx152, jsxs as jsxs93 } from "react/jsx-runtime";
19080
20109
  function FileButton({
19081
20110
  onChange,
@@ -19087,7 +20116,7 @@ function FileButton({
19087
20116
  className,
19088
20117
  ...props
19089
20118
  }) {
19090
- const inputRef = useRef18(null);
20119
+ const inputRef = useRef20(null);
19091
20120
  const handleClick = () => {
19092
20121
  inputRef.current?.click();
19093
20122
  };
@@ -19124,7 +20153,7 @@ function FileButton({
19124
20153
 
19125
20154
  // src/components/ui/file-drop-input.tsx
19126
20155
  import { IconPencil as IconPencil2, IconPhoto as IconPhoto4, IconTrash as IconTrash6 } from "@tabler/icons-react";
19127
- import { useId as useId6, useRef as useRef19, useState as useState44 } from "react";
20156
+ import { useId as useId7, useRef as useRef21, useState as useState45 } from "react";
19128
20157
 
19129
20158
  // src/components/files/file-preview.tsx
19130
20159
  import {
@@ -19134,7 +20163,7 @@ import {
19134
20163
  IconPhoto as IconPhoto3,
19135
20164
  IconVideo as IconVideo2
19136
20165
  } from "@tabler/icons-react";
19137
- import { useEffect as useEffect26, useMemo as useMemo15, useState as useState43 } from "react";
20166
+ import { useEffect as useEffect28, useMemo as useMemo15, useState as useState44 } from "react";
19138
20167
  import { jsx as jsx153 } from "react/jsx-runtime";
19139
20168
  function formatBytes2(size) {
19140
20169
  if (!size) {
@@ -19170,12 +20199,12 @@ function buildPreviewKey(item) {
19170
20199
  return item.id ?? `${item.source}-${item.name}-${item.fileIndex ?? item.url}`;
19171
20200
  }
19172
20201
  function useResolvedPreviewItems(files, previewItems = []) {
19173
- const [localItems, setLocalItems] = useState43([]);
20202
+ const [localItems, setLocalItems] = useState44([]);
19174
20203
  const remoteItems = useMemo15(
19175
20204
  () => previewItems.map((item) => ({ ...item, source: "remote" })),
19176
20205
  [previewItems]
19177
20206
  );
19178
- useEffect26(() => {
20207
+ useEffect28(() => {
19179
20208
  let active = true;
19180
20209
  const objectUrls = [];
19181
20210
  async function resolveFiles() {
@@ -19288,12 +20317,12 @@ function FileDropInput({
19288
20317
  disabled,
19289
20318
  ...props
19290
20319
  }) {
19291
- const inputId = useId6();
19292
- const inputRef = useRef19(null);
19293
- const [internalFiles, setInternalFiles] = useState44(defaultFiles);
19294
- const [dragging, setDragging] = useState44(false);
19295
- const [pendingCropFile, setPendingCropFile] = useState44(null);
19296
- const [cropOpen, setCropOpen] = useState44(false);
20320
+ const inputId = useId7();
20321
+ const inputRef = useRef21(null);
20322
+ const [internalFiles, setInternalFiles] = useState45(defaultFiles);
20323
+ const [dragging, setDragging] = useState45(false);
20324
+ const [pendingCropFile, setPendingCropFile] = useState45(null);
20325
+ const [cropOpen, setCropOpen] = useState45(false);
19297
20326
  const files = filesProp ?? internalFiles;
19298
20327
  const items = useResolvedPreviewItems(files, previewItems);
19299
20328
  const singleItem = !multiple && items.length === 1 ? items[0] : null;
@@ -19553,7 +20582,7 @@ import {
19553
20582
  IconUpload as IconUpload2,
19554
20583
  IconX as IconX12
19555
20584
  } from "@tabler/icons-react";
19556
- import { useId as useId7, useRef as useRef20, useState as useState45 } from "react";
20585
+ import { useId as useId8, useRef as useRef22, useState as useState46 } from "react";
19557
20586
  import { Fragment as Fragment29, jsx as jsx155, jsxs as jsxs95 } from "react/jsx-runtime";
19558
20587
  function FileInput({
19559
20588
  className,
@@ -19582,12 +20611,12 @@ function FileInput({
19582
20611
  id: inputIdProp,
19583
20612
  ...props
19584
20613
  }) {
19585
- const inputRef = useRef20(null);
19586
- const generatedInputId = useId7();
20614
+ const inputRef = useRef22(null);
20615
+ const generatedInputId = useId8();
19587
20616
  const inputId = inputIdProp ?? generatedInputId;
19588
- const [internalFiles, setInternalFiles] = useState45(defaultFiles);
19589
- const [pendingCropFile, setPendingCropFile] = useState45(null);
19590
- const [cropOpen, setCropOpen] = useState45(false);
20617
+ const [internalFiles, setInternalFiles] = useState46(defaultFiles);
20618
+ const [pendingCropFile, setPendingCropFile] = useState46(null);
20619
+ const [cropOpen, setCropOpen] = useState46(false);
19591
20620
  const files = filesProp ?? internalFiles;
19592
20621
  const items = useResolvedPreviewItems(files, previewItems);
19593
20622
  const singleItem = !multiple && items.length === 1 ? items[0] : null;
@@ -19964,7 +20993,7 @@ function Flex({
19964
20993
  }
19965
20994
 
19966
20995
  // src/components/ui/floating-indicator.tsx
19967
- import { useEffect as useEffect27, useState as useState46 } from "react";
20996
+ import { useEffect as useEffect29, useState as useState47 } from "react";
19968
20997
  import { jsx as jsx157 } from "react/jsx-runtime";
19969
20998
  function FloatingIndicator({
19970
20999
  className,
@@ -19975,9 +21004,9 @@ function FloatingIndicator({
19975
21004
  style,
19976
21005
  ...props
19977
21006
  }) {
19978
- const [position, setPosition] = useState46({ x: 0, y: 0, width: 0, height: 0 });
19979
- const [isVisible, setIsVisible] = useState46(!displayAfterTransitionEnd);
19980
- useEffect27(() => {
21007
+ const [position, setPosition] = useState47({ x: 0, y: 0, width: 0, height: 0 });
21008
+ const [isVisible, setIsVisible] = useState47(!displayAfterTransitionEnd);
21009
+ useEffect29(() => {
19981
21010
  const hasTargetAndParent2 = target && parent;
19982
21011
  if (!hasTargetAndParent2) {
19983
21012
  return;
@@ -20032,7 +21061,7 @@ function FloatingIndicator({
20032
21061
  }
20033
21062
 
20034
21063
  // src/components/ui/focus-trap.tsx
20035
- import { cloneElement as cloneElement2, useEffect as useEffect28, useRef as useRef21 } from "react";
21064
+ import { cloneElement as cloneElement2, useEffect as useEffect30, useRef as useRef23 } from "react";
20036
21065
  import { jsx as jsx158 } from "react/jsx-runtime";
20037
21066
  var FOCUSABLE = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
20038
21067
  function getFocusableElements(container) {
@@ -20041,8 +21070,8 @@ function getFocusableElements(container) {
20041
21070
  );
20042
21071
  }
20043
21072
  function useFocusTrap(active) {
20044
- const ref = useRef21(null);
20045
- useEffect28(() => {
21073
+ const ref = useRef23(null);
21074
+ useEffect30(() => {
20046
21075
  if (!active) {
20047
21076
  return;
20048
21077
  }
@@ -20631,7 +21660,7 @@ function ItemFooter({ className, ...props }) {
20631
21660
  }
20632
21661
 
20633
21662
  // src/components/ui/json-input.tsx
20634
- import { useState as useState47 } from "react";
21663
+ import { useState as useState48 } from "react";
20635
21664
  import { jsx as jsx165, jsxs as jsxs97 } from "react/jsx-runtime";
20636
21665
  function JsonInput({
20637
21666
  className,
@@ -20653,10 +21682,10 @@ function JsonInput({
20653
21682
  }
20654
21683
  return "";
20655
21684
  };
20656
- const [internalValue, setInternalValue] = useState47(
21685
+ const [internalValue, setInternalValue] = useState48(
20657
21686
  stringifyValue(defaultValue) || "{}"
20658
21687
  );
20659
- const [error, setError] = useState47(null);
21688
+ const [error, setError] = useState48(null);
20660
21689
  const currentValue = value !== void 0 ? stringifyValue(value) : internalValue;
20661
21690
  const handleChange = (e) => {
20662
21691
  const newValue = e.target.value;
@@ -21087,7 +22116,7 @@ function MenubarSubContent({
21087
22116
  }
21088
22117
 
21089
22118
  // src/components/ui/money-input.tsx
21090
- import { forwardRef as forwardRef12, useCallback as useCallback23, useState as useState48 } from "react";
22119
+ import { forwardRef as forwardRef13, useCallback as useCallback23, useState as useState49 } from "react";
21091
22120
  import { jsx as jsx170, jsxs as jsxs99 } from "react/jsx-runtime";
21092
22121
  var defaultCurrencies = [
21093
22122
  { label: "ETB", value: "etb", symbol: "Br" },
@@ -21123,7 +22152,7 @@ var sizeClasses4 = {
21123
22152
  select: "w-[90px] text-base"
21124
22153
  }
21125
22154
  };
21126
- var MoneyInput = forwardRef12(
22155
+ var MoneyInput = forwardRef13(
21127
22156
  ({
21128
22157
  value = 0,
21129
22158
  currency = "etb",
@@ -21137,9 +22166,9 @@ var MoneyInput = forwardRef12(
21137
22166
  id
21138
22167
  }, ref) => {
21139
22168
  const placeholder = placeholderProp ?? (fractionDigits > 0 ? `0.${"0".repeat(fractionDigits)}` : "0");
21140
- const [internalValue, setInternalValue] = useState48(value);
21141
- const [internalCurrency, setInternalCurrency] = useState48(currency);
21142
- const [displayValue, setDisplayValue] = useState48(
22169
+ const [internalValue, setInternalValue] = useState49(value);
22170
+ const [internalCurrency, setInternalCurrency] = useState49(currency);
22171
+ const [displayValue, setDisplayValue] = useState49(
21143
22172
  () => formatNumber(value, fractionDigits)
21144
22173
  );
21145
22174
  const currentCurrency = currencies.find(
@@ -21233,7 +22262,7 @@ MoneyInput.displayName = "MoneyInput";
21233
22262
  // src/components/ui/multi-select.tsx
21234
22263
  import { Autocomplete as AutocompletePrimitive2 } from "@base-ui/react/autocomplete";
21235
22264
  import { IconCheck as IconCheck8, IconChevronDown as IconChevronDown11, IconX as IconX13 } from "@tabler/icons-react";
21236
- import { useState as useState49 } from "react";
22265
+ import { useState as useState50 } from "react";
21237
22266
  import { jsx as jsx171, jsxs as jsxs100 } from "react/jsx-runtime";
21238
22267
  function MultiSelect({
21239
22268
  options,
@@ -21245,8 +22274,8 @@ function MultiSelect({
21245
22274
  disabled,
21246
22275
  ...props
21247
22276
  }) {
21248
- const [open, setOpen] = useState49(false);
21249
- const [inputValue, setInputValue] = useState49("");
22277
+ const [open, setOpen] = useState50(false);
22278
+ const [inputValue, setInputValue] = useState50("");
21250
22279
  const selectedOptions = options.filter((opt) => value.includes(opt.value));
21251
22280
  const filteredOptions = inputValue === "" ? options : options.filter(
21252
22281
  (option) => option.label.toLowerCase().includes(inputValue.toLowerCase())
@@ -21363,7 +22392,7 @@ function MultiSelect({
21363
22392
 
21364
22393
  // src/components/ui/native-select.tsx
21365
22394
  import { IconChevronDown as IconChevronDown12 } from "@tabler/icons-react";
21366
- import { forwardRef as forwardRef13 } from "react";
22395
+ import { forwardRef as forwardRef14 } from "react";
21367
22396
  import { jsx as jsx172, jsxs as jsxs101 } from "react/jsx-runtime";
21368
22397
  function mapNativeSelectSize(size) {
21369
22398
  return size === "xs" || size === "sm" ? "sm" : "default";
@@ -21373,7 +22402,7 @@ function parseOptions(data) {
21373
22402
  (item) => typeof item === "string" ? { value: item, label: item } : item
21374
22403
  );
21375
22404
  }
21376
- var NativeSelectBase = forwardRef13(
22405
+ var NativeSelectBase = forwardRef14(
21377
22406
  ({ className, size = "md", data, children, rightSection, ...props }, ref) => {
21378
22407
  const options = data ? parseOptions(data) : null;
21379
22408
  const mappedSize = mapNativeSelectSize(size);
@@ -21415,7 +22444,7 @@ var NativeSelectBase = forwardRef13(
21415
22444
  }
21416
22445
  );
21417
22446
  NativeSelectBase.displayName = "NativeSelectBase";
21418
- var NativeSelect = forwardRef13(
22447
+ var NativeSelect = forwardRef14(
21419
22448
  ({
21420
22449
  label,
21421
22450
  description,
@@ -21692,7 +22721,7 @@ function NavigationMenuIndicator({
21692
22721
  }
21693
22722
 
21694
22723
  // src/components/ui/nprogress.tsx
21695
- import { useEffect as useEffect29, useSyncExternalStore } from "react";
22724
+ import { useEffect as useEffect31, useSyncExternalStore } from "react";
21696
22725
  import { jsx as jsx175 } from "react/jsx-runtime";
21697
22726
  var DEFAULT_STEP_INTERVAL = 450;
21698
22727
  var DEFAULT_INITIAL_PROGRESS = 8;
@@ -21856,13 +22885,13 @@ function NProgress({
21856
22885
  }) {
21857
22886
  const current = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
21858
22887
  const translateX = current.progress - MAX_PROGRESS;
21859
- useEffect29(() => {
22888
+ useEffect31(() => {
21860
22889
  if (!pathname) {
21861
22890
  return;
21862
22891
  }
21863
22892
  completeNProgress();
21864
22893
  }, [pathname]);
21865
- useEffect29(() => {
22894
+ useEffect31(() => {
21866
22895
  if (!withNavigation) {
21867
22896
  return;
21868
22897
  }
@@ -21970,7 +22999,7 @@ function NumberFormatter({
21970
22999
 
21971
23000
  // src/components/ui/number-input.tsx
21972
23001
  import { IconChevronDown as IconChevronDown14, IconChevronUp as IconChevronUp4 } from "@tabler/icons-react";
21973
- import { forwardRef as forwardRef14, useCallback as useCallback24 } from "react";
23002
+ import { forwardRef as forwardRef15, useCallback as useCallback24 } from "react";
21974
23003
 
21975
23004
  // src/components/ui/unstyled-button.tsx
21976
23005
  import { useRender as useRender9 } from "@base-ui/react/use-render";
@@ -22027,7 +23056,7 @@ function getDisplayValue({
22027
23056
  }
22028
23057
  return "";
22029
23058
  }
22030
- var NumberInput = forwardRef14(
23059
+ var NumberInput = forwardRef15(
22031
23060
  ({
22032
23061
  value,
22033
23062
  defaultValue,
@@ -22360,11 +23389,11 @@ function Paper({
22360
23389
 
22361
23390
  // src/components/ui/password-input.tsx
22362
23391
  import { IconEye, IconEyeOff } from "@tabler/icons-react";
22363
- import { forwardRef as forwardRef15, useState as useState50 } from "react";
23392
+ import { forwardRef as forwardRef16, useState as useState51 } from "react";
22364
23393
  import { jsx as jsx181, jsxs as jsxs106 } from "react/jsx-runtime";
22365
- var PasswordInput = forwardRef15(
23394
+ var PasswordInput = forwardRef16(
22366
23395
  ({ className, showToggle = true, size, ...props }, ref) => {
22367
- const [showPassword, setShowPassword] = useState50(false);
23396
+ const [showPassword, setShowPassword] = useState51(false);
22368
23397
  const groupSizeClasses = {
22369
23398
  xs: "h-7",
22370
23399
  sm: "h-8",
@@ -22408,7 +23437,7 @@ var PasswordInput = forwardRef15(
22408
23437
  }
22409
23438
  );
22410
23439
  PasswordInput.displayName = "PasswordInput";
22411
- var PasswordInputWithWrapper = forwardRef15(
23440
+ var PasswordInputWithWrapper = forwardRef16(
22412
23441
  ({
22413
23442
  label,
22414
23443
  description,
@@ -22594,7 +23623,7 @@ import {
22594
23623
  IconStarFilled,
22595
23624
  IconStarHalfFilled
22596
23625
  } from "@tabler/icons-react";
22597
- import { useState as useState51 } from "react";
23626
+ import { useState as useState52 } from "react";
22598
23627
  import { jsx as jsx184 } from "react/jsx-runtime";
22599
23628
  function Rating({
22600
23629
  count = 5,
@@ -22608,7 +23637,7 @@ function Rating({
22608
23637
  className,
22609
23638
  ...props
22610
23639
  }) {
22611
- const [hoverValue, setHoverValue] = useState51(null);
23640
+ const [hoverValue, setHoverValue] = useState52(null);
22612
23641
  const isDisabled = readOnly || disabled;
22613
23642
  const sizeClasses6 = {
22614
23643
  sm: "size-4",
@@ -22985,7 +24014,7 @@ function Space({ className, h, w, style, ...props }) {
22985
24014
 
22986
24015
  // src/components/ui/spoiler.tsx
22987
24016
  import { IconChevronDown as IconChevronDown15 } from "@tabler/icons-react";
22988
- import { useEffect as useEffect30, useRef as useRef22, useState as useState52 } from "react";
24017
+ import { useEffect as useEffect32, useRef as useRef24, useState as useState53 } from "react";
22989
24018
  import { jsx as jsx190, jsxs as jsxs110 } from "react/jsx-runtime";
22990
24019
  function Spoiler({
22991
24020
  maxHeight = 100,
@@ -22996,10 +24025,10 @@ function Spoiler({
22996
24025
  className,
22997
24026
  ...props
22998
24027
  }) {
22999
- const [isExpanded, setIsExpanded] = useState52(initialState);
23000
- const [shouldShowButton, setShouldShowButton] = useState52(false);
23001
- const contentRef = useRef22(null);
23002
- useEffect30(() => {
24028
+ const [isExpanded, setIsExpanded] = useState53(initialState);
24029
+ const [shouldShowButton, setShouldShowButton] = useState53(false);
24030
+ const contentRef = useRef24(null);
24031
+ useEffect32(() => {
23003
24032
  const el = contentRef.current;
23004
24033
  if (!el) {
23005
24034
  return;
@@ -23116,7 +24145,7 @@ function Stack({
23116
24145
  }
23117
24146
 
23118
24147
  // src/components/ui/status-dropdown-button.tsx
23119
- import { useCallback as useCallback25, useMemo as useMemo16, useState as useState53 } from "react";
24148
+ import { useCallback as useCallback25, useMemo as useMemo16, useState as useState54 } from "react";
23120
24149
  import { Fragment as Fragment30, jsx as jsx192, jsxs as jsxs111 } from "react/jsx-runtime";
23121
24150
  var STATUS_MENU_SEPARATOR = "separator";
23122
24151
  function resolveConfirmConfig(target, entityLabel) {
@@ -23188,7 +24217,7 @@ function StatusDropdownButton({
23188
24217
  variant,
23189
24218
  ...dropdownProps
23190
24219
  }) {
23191
- const [pending, setPending] = useState53(null);
24220
+ const [pending, setPending] = useState54(null);
23192
24221
  const onPick = useCallback25(
23193
24222
  (next) => {
23194
24223
  const target = states.find((s) => s.value === next);
@@ -23458,7 +24487,7 @@ function TableOfContents({
23458
24487
 
23459
24488
  // src/components/ui/tags-input.tsx
23460
24489
  import { IconX as IconX14 } from "@tabler/icons-react";
23461
- import { useState as useState54 } from "react";
24490
+ import { useState as useState55 } from "react";
23462
24491
  import { jsx as jsx196, jsxs as jsxs113 } from "react/jsx-runtime";
23463
24492
  function TagsInput({
23464
24493
  className,
@@ -23472,8 +24501,8 @@ function TagsInput({
23472
24501
  disabled = false,
23473
24502
  ...props
23474
24503
  }) {
23475
- const [internalValue, setInternalValue] = useState54(defaultValue);
23476
- const [inputValue, setInputValue] = useState54("");
24504
+ const [internalValue, setInternalValue] = useState55(defaultValue);
24505
+ const [inputValue, setInputValue] = useState55("");
23477
24506
  const tags = value ?? internalValue;
23478
24507
  const addTag = (tag) => {
23479
24508
  const trimmed = tag.trim();
@@ -23567,9 +24596,9 @@ function TagsInput({
23567
24596
  }
23568
24597
 
23569
24598
  // src/components/ui/text-input.tsx
23570
- import { forwardRef as forwardRef16 } from "react";
24599
+ import { forwardRef as forwardRef17 } from "react";
23571
24600
  import { jsx as jsx197, jsxs as jsxs114 } from "react/jsx-runtime";
23572
- var TextInput = forwardRef16(
24601
+ var TextInput = forwardRef17(
23573
24602
  ({
23574
24603
  label,
23575
24604
  description,
@@ -24068,7 +25097,7 @@ function ToggleGroupItem({
24068
25097
  }
24069
25098
 
24070
25099
  // src/components/ui/transition.tsx
24071
- import { useEffect as useEffect31, useState as useState55 } from "react";
25100
+ import { useEffect as useEffect33, useState as useState56 } from "react";
24072
25101
  import { Fragment as Fragment31, jsx as jsx203 } from "react/jsx-runtime";
24073
25102
  var TRANSITIONS = {
24074
25103
  fade: {
@@ -24123,11 +25152,11 @@ var TRANSITIONS = {
24123
25152
  }
24124
25153
  };
24125
25154
  function useTransitionState(mounted, duration, exitDuration, timingFunction, onEnter, onEntered, onExit, onExited, enterDelay, exitDelay) {
24126
- const [status, setStatus] = useState55(
25155
+ const [status, setStatus] = useState56(
24127
25156
  mounted ? "entered" : "exited"
24128
25157
  );
24129
- const [displayDuration, setDisplayDuration] = useState55(duration);
24130
- useEffect31(() => {
25158
+ const [displayDuration, setDisplayDuration] = useState56(duration);
25159
+ useEffect33(() => {
24131
25160
  if (mounted) {
24132
25161
  setDisplayDuration(duration);
24133
25162
  const t12 = setTimeout(() => {
@@ -24240,7 +25269,7 @@ function Transition({
24240
25269
 
24241
25270
  // src/components/ui/tree.tsx
24242
25271
  import { IconChevronRight as IconChevronRight11 } from "@tabler/icons-react";
24243
- import { useState as useState56 } from "react";
25272
+ import { useState as useState57 } from "react";
24244
25273
  import { jsx as jsx204, jsxs as jsxs115 } from "react/jsx-runtime";
24245
25274
  function Tree({
24246
25275
  className,
@@ -24255,7 +25284,7 @@ function Tree({
24255
25284
  renderNode,
24256
25285
  ...props
24257
25286
  }) {
24258
- const [internalExpanded, setInternalExpanded] = useState56(
25287
+ const [internalExpanded, setInternalExpanded] = useState57(
24259
25288
  /* @__PURE__ */ new Set()
24260
25289
  );
24261
25290
  const expanded = expandedProp !== void 0 ? expandedProp : internalExpanded;
@@ -24855,6 +25884,7 @@ export {
24855
25884
  containerVariants,
24856
25885
  dateToIsoDate,
24857
25886
  formatDateWithPattern,
25887
+ getTimeRange,
24858
25888
  gridColVariants,
24859
25889
  gridVariants,
24860
25890
  incrementNProgress,