@mesob/ui 0.5.7 → 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.
@@ -5019,10 +5019,12 @@ function EntityFormActions({
5019
5019
  isSubmitting = false,
5020
5020
  isDeleting = false,
5021
5021
  disabled = false,
5022
+ deleteDisabled,
5022
5023
  submitLabel,
5023
5024
  deleteLabel = "Delete",
5024
5025
  itemName = "item"
5025
5026
  }) {
5027
+ const deleteTriggerDisabled = deleteDisabled ?? disabled;
5026
5028
  const defaultSubmitLabel = mode === "new" ? "Create" : "Update";
5027
5029
  const label = submitLabel || defaultSubmitLabel;
5028
5030
  return /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2", children: [
@@ -5058,7 +5060,7 @@ function EntityFormActions({
5058
5060
  Button,
5059
5061
  {
5060
5062
  variant: "destructive",
5061
- disabled,
5063
+ disabled: deleteTriggerDisabled,
5062
5064
  loading: isDeleting,
5063
5065
  className: "cursor-pointer",
5064
5066
  leftIcon: /* @__PURE__ */ jsx44(IconTrash3, { className: "size-4" })
@@ -8384,7 +8386,7 @@ function DatePickerContent({
8384
8386
  }
8385
8387
  )
8386
8388
  ] }),
8387
- view === "days" && /* @__PURE__ */ jsx76(Fragment14, { children: (() => {
8389
+ view === "days" && (() => {
8388
8390
  const dayGridClass = withWeekNumbers ? "grid grid-cols-[2rem_repeat(7,minmax(0,1fr))]" : "grid grid-cols-7";
8389
8391
  const rowCount = cells.length / 7;
8390
8392
  const labels = weekdayHeaderLabels(firstDayOfWeek);
@@ -8510,7 +8512,7 @@ function DatePickerContent({
8510
8512
  }
8511
8513
  )
8512
8514
  ] });
8513
- })() }),
8515
+ })(),
8514
8516
  view === "months" && /* @__PURE__ */ jsx76("div", { className: "grid grid-cols-3 gap-1 py-2", children: monthShortList.map((m, i) => {
8515
8517
  const sel = calendarType === "EC" ? (() => {
8516
8518
  if (!primaryDate) {
@@ -11849,7 +11851,8 @@ var DateTimeTriggerButton = forwardRef5(function DateTimeTriggerButton2({
11849
11851
  variant = "default",
11850
11852
  leftSection,
11851
11853
  leftSectionPointerEvents = "auto",
11852
- "aria-label": ariaLabel
11854
+ "aria-label": ariaLabel,
11855
+ rightSection
11853
11856
  }, ref) {
11854
11857
  const filled = variant === "filled";
11855
11858
  return /* @__PURE__ */ jsxs68(
@@ -11861,7 +11864,7 @@ var DateTimeTriggerButton = forwardRef5(function DateTimeTriggerButton2({
11861
11864
  "aria-label": ariaLabel,
11862
11865
  "aria-invalid": !!error || void 0,
11863
11866
  className: cn(
11864
- "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",
11865
11868
  TRIGGER_SIZE_CLASSES[size],
11866
11869
  leftSection && "pl-10",
11867
11870
  TRIGGER_RADIUS_CLASSES[radius],
@@ -11882,7 +11885,17 @@ var DateTimeTriggerButton = forwardRef5(function DateTimeTriggerButton2({
11882
11885
  children: leftSection
11883
11886
  }
11884
11887
  ) : null,
11885
- 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
11886
11899
  ]
11887
11900
  }
11888
11901
  );
@@ -11915,6 +11928,8 @@ function DateInputShell({
11915
11928
  triggerRef,
11916
11929
  onClear,
11917
11930
  dropdownClassName,
11931
+ popoverProps,
11932
+ rightSection,
11918
11933
  children,
11919
11934
  buttonRef
11920
11935
  }) {
@@ -11933,7 +11948,8 @@ function DateInputShell({
11933
11948
  variant,
11934
11949
  leftSection,
11935
11950
  leftSectionPointerEvents,
11936
- "aria-label": ariaLabel
11951
+ "aria-label": ariaLabel,
11952
+ rightSection
11937
11953
  }
11938
11954
  );
11939
11955
  const wrapper = /* @__PURE__ */ jsxs69("div", { className: cn("relative inline-block w-full", className), children: [
@@ -12009,14 +12025,16 @@ function DateInputShell({
12009
12025
  PopoverContent,
12010
12026
  {
12011
12027
  anchor: triggerRef,
12012
- side: contentSide,
12028
+ side: popoverProps?.side ?? contentSide,
12013
12029
  sideOffset: 8,
12014
- align: "center",
12030
+ align: popoverProps?.align ?? "center",
12015
12031
  alignOffset: 0,
12016
12032
  className: cn(
12017
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)]",
12018
12035
  dropdownClassName
12019
12036
  ),
12037
+ style: popoverProps?.width && popoverProps.width !== "target" ? { width: popoverProps.width } : void 0,
12020
12038
  children
12021
12039
  }
12022
12040
  )
@@ -12587,6 +12605,25 @@ function formatDateTimeDisplay(d, calendarType, withSeconds) {
12587
12605
  }
12588
12606
 
12589
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
+ }
12590
12627
  function clampAndPad(raw, max) {
12591
12628
  if (!raw) {
12592
12629
  return "";
@@ -13105,213 +13142,584 @@ function TextDateInput({
13105
13142
  }
13106
13143
 
13107
13144
  // src/components/date-time/datetime-picker/time-grid.tsx
13108
- import { jsx as jsx107 } from "react/jsx-runtime";
13109
- function buildSlots(stepMinutes, minHour, maxHour) {
13110
- const slots = [];
13111
- const d = new Date(0, 0, 1, 0, 0, 0);
13112
- for (let h = minHour; h < maxHour; h++) {
13113
- for (let m = 0; m < 60; m += stepMinutes) {
13114
- d.setHours(h, m, 0, 0);
13115
- slots.push(new Date(d.getTime()));
13116
- }
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;
13117
13181
  }
13118
- 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
+ });
13119
13258
  }
13120
13259
  function TimeGrid({
13121
- value,
13260
+ data: dataProp,
13261
+ value: controlledValue,
13122
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 = {},
13123
13275
  stepMinutes = 30,
13124
13276
  minHour = 0,
13125
13277
  maxHour = 24,
13126
- baseDate = /* @__PURE__ */ new Date(),
13127
13278
  className
13128
13279
  }) {
13129
- const base = new Date(
13130
- baseDate.getFullYear(),
13131
- baseDate.getMonth(),
13132
- baseDate.getDate()
13133
- );
13134
- const slots = buildSlots(stepMinutes, minHour, maxHour);
13135
- const valueMinutes = value != null ? value.getHours() * 60 + value.getMinutes() : null;
13136
- 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(
13137
13331
  "div",
13138
13332
  {
13139
13333
  className: cn(
13140
- "grid grid-cols-4 gap-1 overflow-y-auto rounded-md border border-border bg-background p-2 max-h-[200px]",
13141
- 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]"
13142
13338
  ),
13143
- children: slots.map((slot) => {
13144
- const slotMinutes = slot.getHours() * 60 + slot.getMinutes();
13145
- const selected = valueMinutes === slotMinutes;
13146
- const date = new Date(base);
13147
- date.setHours(slot.getHours(), slot.getMinutes(), 0, 0);
13148
- 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;
13149
13344
  return /* @__PURE__ */ jsx107(
13150
13345
  "button",
13151
13346
  {
13152
13347
  type: "button",
13153
- 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
+ },
13154
13359
  className: cn(
13155
- "rounded px-2 py-1.5 text-center text-sm transition-colors",
13156
- 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")
13157
13365
  ),
13158
- children: label
13366
+ children: formatTimeForDisplay(
13367
+ normalized,
13368
+ format,
13369
+ withSeconds,
13370
+ amPmLabels
13371
+ )
13159
13372
  },
13160
- label
13373
+ normalized
13161
13374
  );
13162
13375
  })
13163
13376
  }
13164
- );
13377
+ ) });
13165
13378
  }
13166
13379
 
13167
13380
  // src/components/date-time/datetime-picker/time-input.tsx
13168
- 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";
13169
13390
  import { Fragment as Fragment19, jsx as jsx108, jsxs as jsxs71 } from "react/jsx-runtime";
13170
- function TimeInput({
13171
- value,
13172
- onChange,
13173
- withSeconds = false,
13174
- disabled = false,
13175
- baseDate = /* @__PURE__ */ new Date(),
13176
- className,
13177
- "aria-label": ariaLabel
13178
- }) {
13179
- const base = new Date(
13180
- baseDate.getFullYear(),
13181
- baseDate.getMonth(),
13182
- baseDate.getDate()
13183
- );
13184
- const [h, setH] = useState30(value ? pad2(value.getHours()) : "");
13185
- const [m, setM] = useState30(value ? pad2(value.getMinutes()) : "");
13186
- const [s, setS] = useState30(value ? pad2(value.getSeconds()) : "");
13187
- const [focus, setFocus] = useState30(null);
13188
- 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 = "";
13189
13498
  if (value) {
13190
- setH(pad2(value.getHours()));
13191
- setM(pad2(value.getMinutes()));
13192
- setS(pad2(value.getSeconds()));
13193
- } else {
13194
- setH("");
13195
- setM("");
13196
- 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
+ }
13197
13504
  }
13198
- }, [value]);
13199
- const commit = useCallback13(
13200
- (hh, mm, ss) => {
13201
- const nh = clampAndPad(hh, 23);
13202
- const nm = clampAndPad(mm, 59);
13203
- const ns = withSeconds ? clampAndPad(ss, 59) : "00";
13204
- 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"));
13205
13513
  const d = new Date(base);
13206
13514
  d.setHours(
13207
- Number.parseInt(nh, 10),
13208
- Number.parseInt(nm, 10),
13209
- Number.parseInt(ns, 10),
13515
+ Number.parseInt(hh, 10),
13516
+ Number.parseInt(mm, 10),
13517
+ Number.parseInt(ss, 10),
13210
13518
  0
13211
13519
  );
13212
13520
  onChange?.(d);
13213
- } else {
13214
- onChange?.(null);
13215
- }
13216
- },
13217
- [base, onChange, withSeconds]
13218
- );
13219
- const handleBlur = useCallback13(() => {
13220
- setFocus(null);
13221
- const nh = clampAndPad(h, 23);
13222
- const nm = clampAndPad(m, 59);
13223
- const ns = withSeconds ? clampAndPad(s, 59) : "00";
13224
- if (nh) {
13225
- setH(nh);
13226
- }
13227
- if (nm) {
13228
- setM(nm);
13229
- }
13230
- if (withSeconds && ns) {
13231
- setS(ns);
13232
- }
13233
- commit(nh || h, nm || m, withSeconds ? ns || s : "00");
13234
- }, [h, m, s, commit, withSeconds]);
13235
- return /* @__PURE__ */ jsxs71(
13236
- "fieldset",
13237
- {
13238
- className: cn(
13239
- "flex flex-row items-center gap-0.5 rounded border border-input bg-background px-2.5 py-1.5",
13240
- disabled && "opacity-50 cursor-not-allowed",
13241
- className
13242
- ),
13243
- "aria-label": ariaLabel ?? "Time",
13244
- children: [
13245
- /* @__PURE__ */ jsx108("legend", { className: "sr-only", children: "Time" }),
13246
- /* @__PURE__ */ jsx108(
13247
- "input",
13248
- {
13249
- type: "text",
13250
- inputMode: "numeric",
13251
- value: focus === "h" ? h : h || "--",
13252
- placeholder: "--",
13253
- "aria-label": "Hours",
13254
- disabled,
13255
- onFocus: () => setFocus("h"),
13256
- onBlur: handleBlur,
13257
- onChange: (e) => setH(e.target.value.replace(/\D/g, "").slice(0, 2)),
13258
- className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
13259
- }
13260
- ),
13261
- /* @__PURE__ */ jsx108("span", { className: "select-none text-sm text-muted-foreground", children: ":" }),
13262
- /* @__PURE__ */ jsx108(
13263
- "input",
13264
- {
13265
- type: "text",
13266
- inputMode: "numeric",
13267
- value: focus === "m" ? m : m || "--",
13268
- placeholder: "--",
13269
- "aria-label": "Minutes",
13270
- disabled,
13271
- onFocus: () => setFocus("m"),
13272
- onBlur: handleBlur,
13273
- onChange: (e) => setM(e.target.value.replace(/\D/g, "").slice(0, 2)),
13274
- className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
13275
- }
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
13276
13533
  ),
13277
- 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
+ ),
13278
13577
  /* @__PURE__ */ jsx108("span", { className: "select-none text-sm text-muted-foreground", children: ":" }),
13279
13578
  /* @__PURE__ */ jsx108(
13280
13579
  "input",
13281
13580
  {
13282
13581
  type: "text",
13283
13582
  inputMode: "numeric",
13284
- value: focus === "s" ? s : s || "--",
13583
+ value: focus === "m" ? m : m || "--",
13285
13584
  placeholder: "--",
13286
- "aria-label": "Seconds",
13585
+ "aria-label": "Minutes",
13287
13586
  disabled,
13288
- onFocus: () => setFocus("s"),
13587
+ onFocus: () => setFocus("m"),
13289
13588
  onBlur: handleBlur,
13290
- 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)),
13291
13590
  className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
13292
13591
  }
13293
- )
13294
- ] })
13295
- ]
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
+ ] });
13296
13655
  }
13297
- );
13298
- }
13656
+ return wrapper;
13657
+ }
13658
+ );
13299
13659
 
13300
13660
  // src/components/date-time/datetime-picker/time-value.tsx
13301
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
+ }
13302
13687
  function TimeValue({
13303
13688
  value,
13304
- format,
13689
+ format = "24h",
13305
13690
  withSeconds = false,
13691
+ amPmLabels = { am: "AM", pm: "PM" },
13306
13692
  className
13307
13693
  }) {
13308
- const defaultFormat2 = (d) => `${pad2(d.getHours())}:${pad2(d.getMinutes())}${withSeconds ? `:${pad2(d.getSeconds())}` : ""}`;
13309
- 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
+ }
13310
13718
  return /* @__PURE__ */ jsx109("span", { className, children: str });
13311
13719
  }
13312
13720
 
13313
13721
  // src/components/date-time/mini-calendar/use-mini-calendar.ts
13314
- 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";
13315
13723
  function dayInWindow(day, windowStart, numberOfDays) {
13316
13724
  const end = addDays(windowStart, numberOfDays - 1);
13317
13725
  const t = stripTime2(day).getTime();
@@ -13328,7 +13736,7 @@ function useMiniCalendar(props) {
13328
13736
  maxDate
13329
13737
  } = props;
13330
13738
  const isControlled = valueProp !== void 0;
13331
- const [internalValue, setInternalValue] = useState31(
13739
+ const [internalValue, setInternalValue] = useState32(
13332
13740
  defaultValue
13333
13741
  );
13334
13742
  const selectedIso = valueProp !== void 0 ? valueProp : internalValue;
@@ -13348,7 +13756,7 @@ function useMiniCalendar(props) {
13348
13756
  }
13349
13757
  return parseAnchorDate(defaultDate, today);
13350
13758
  })();
13351
- const [windowStart, setWindowStart] = useState31(() => stripTime2(initialStart));
13759
+ const [windowStart, setWindowStart] = useState32(() => stripTime2(initialStart));
13352
13760
  const setSelected = useCallback14(
13353
13761
  (iso) => {
13354
13762
  if (!isControlled) {
@@ -13776,7 +14184,7 @@ function MonthPickerContent({
13776
14184
  }
13777
14185
 
13778
14186
  // src/components/date-time/month-picker/use-month-picker.ts
13779
- 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";
13780
14188
  function useMonthPicker(props) {
13781
14189
  const {
13782
14190
  defaultCalendarType = "GC",
@@ -13789,13 +14197,13 @@ function useMonthPicker(props) {
13789
14197
  const type = props.type ?? "default";
13790
14198
  const isControlled = props.value !== void 0;
13791
14199
  const isDateControlled = controlledDate !== void 0;
13792
- const [_single, _setSingle] = useState32(
14200
+ const [_single, _setSingle] = useState33(
13793
14201
  type === "default" ? props.defaultValue ?? null : null
13794
14202
  );
13795
- const [_multi, _setMulti] = useState32(
14203
+ const [_multi, _setMulti] = useState33(
13796
14204
  type === "multiple" ? props.defaultValue ?? [] : []
13797
14205
  );
13798
- const [_range, _setRange] = useState32(
14206
+ const [_range, _setRange] = useState33(
13799
14207
  type === "range" ? props.defaultValue ?? [
13800
14208
  null,
13801
14209
  null
@@ -13817,7 +14225,7 @@ function useMonthPicker(props) {
13817
14225
  multiValue = [];
13818
14226
  rangeValue = isControlled ? props.value : _range;
13819
14227
  }
13820
- const [hoveredMonth, setHoveredMonth] = useState32(null);
14228
+ const [hoveredMonth, setHoveredMonth] = useState33(null);
13821
14229
  let hasValue;
13822
14230
  if (type === "default") {
13823
14231
  hasValue = !!singleValue;
@@ -13834,17 +14242,17 @@ function useMonthPicker(props) {
13834
14242
  } else {
13835
14243
  primaryDate = rangeValue[0];
13836
14244
  }
13837
- const [view, setView] = useState32("months");
13838
- const [calendarType, setCalendarType] = useState32(defaultCalendarType);
14245
+ const [view, setView] = useState33("months");
14246
+ const [calendarType, setCalendarType] = useState33(defaultCalendarType);
13839
14247
  const now = /* @__PURE__ */ new Date();
13840
14248
  const initDate = controlledDate ?? defaultDate ?? primaryDate ?? now;
13841
- const [gcViewYear, setGcViewYear] = useState32(initDate.getFullYear());
14249
+ const [gcViewYear, setGcViewYear] = useState33(initDate.getFullYear());
13842
14250
  const initEC = toEC(
13843
14251
  initDate.getFullYear(),
13844
14252
  initDate.getMonth() + 1,
13845
14253
  initDate.getDate()
13846
14254
  );
13847
- const [ecViewYear, setEcViewYear] = useState32(initEC[0]);
14255
+ const [ecViewYear, setEcViewYear] = useState33(initEC[0]);
13848
14256
  useEffect20(() => {
13849
14257
  if (!(isDateControlled && controlledDate)) {
13850
14258
  return;
@@ -14128,7 +14536,7 @@ function MonthPicker(props) {
14128
14536
  }
14129
14537
 
14130
14538
  // src/components/date-time/month-picker-input/month-picker-input.tsx
14131
- import { forwardRef as forwardRef8 } from "react";
14539
+ import { forwardRef as forwardRef9 } from "react";
14132
14540
 
14133
14541
  // src/components/date-time/month-picker-input/use-month-picker-input.ts
14134
14542
  import { useCallback as useCallback16 } from "react";
@@ -14238,7 +14646,7 @@ function useMonthPickerInput(props) {
14238
14646
 
14239
14647
  // src/components/date-time/month-picker-input/month-picker-input.tsx
14240
14648
  import { jsx as jsx113 } from "react/jsx-runtime";
14241
- var MonthPickerInput = forwardRef8(function MonthPickerInput2(props, ref) {
14649
+ var MonthPickerInput = forwardRef9(function MonthPickerInput2(props, ref) {
14242
14650
  const {
14243
14651
  label,
14244
14652
  placeholder = "Pick month",
@@ -14308,9 +14716,10 @@ var MonthPickerInput = forwardRef8(function MonthPickerInput2(props, ref) {
14308
14716
  });
14309
14717
 
14310
14718
  // src/components/date-time/time-picker/time-picker.tsx
14311
- import { forwardRef as forwardRef9 } from "react";
14719
+ import { forwardRef as forwardRef10 } from "react";
14312
14720
 
14313
14721
  // src/components/date-time/time-picker/time-picker-content.tsx
14722
+ import { useEffect as useEffect21, useRef as useRef14 } from "react";
14314
14723
  import { Fragment as Fragment20, jsx as jsx114, jsxs as jsxs74 } from "react/jsx-runtime";
14315
14724
  var CheckIcon = /* @__PURE__ */ jsxs74(
14316
14725
  "svg",
@@ -14327,12 +14736,82 @@ var CheckIcon = /* @__PURE__ */ jsxs74(
14327
14736
  ]
14328
14737
  }
14329
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
+ }
14330
14794
  function TimePickerContent({
14331
14795
  timeH,
14332
14796
  timeM,
14333
14797
  timeS,
14334
14798
  timeFocus,
14335
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,
14336
14815
  onTimeFocus,
14337
14816
  onTimeBlur,
14338
14817
  onTimeHChange,
@@ -14340,96 +14819,309 @@ function TimePickerContent({
14340
14819
  onTimeSChange,
14341
14820
  onConfirm
14342
14821
  }) {
14343
- return /* @__PURE__ */ jsx114("div", { className: "p-3", children: /* @__PURE__ */ jsxs74("div", { className: "flex items-center gap-2", children: [
14344
- /* @__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: [
14345
- /* @__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: [
14346
14839
  /* @__PURE__ */ jsx114(
14347
- "input",
14840
+ TimeColumn,
14348
14841
  {
14349
- type: "text",
14350
- inputMode: "numeric",
14351
- value: timeFocus === "h" ? timeH : timeH || "--",
14352
- placeholder: "--",
14353
- "aria-label": "Hours",
14354
- onFocus: (e) => {
14355
- onTimeFocus("h");
14356
- e.target.select();
14357
- },
14358
- onBlur: () => onTimeBlur("h"),
14359
- onChange: (e) => onTimeHChange(e.target.value.replace(/\D/g, "").slice(0, 2)),
14360
- 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"
14361
14846
  }
14362
14847
  ),
14363
- /* @__PURE__ */ jsx114("span", { className: "select-none px-1 text-sm text-muted-foreground", children: ":" }),
14364
14848
  /* @__PURE__ */ jsx114(
14365
- "input",
14849
+ TimeColumn,
14366
14850
  {
14367
- type: "text",
14368
- inputMode: "numeric",
14369
- value: timeFocus === "m" ? timeM : timeM || "--",
14370
- placeholder: "--",
14371
- "aria-label": "Minutes",
14372
- onFocus: (e) => {
14373
- onTimeFocus("m");
14374
- e.target.select();
14375
- },
14376
- onBlur: () => onTimeBlur("m"),
14377
- onChange: (e) => onTimeMChange(e.target.value.replace(/\D/g, "").slice(0, 2)),
14378
- 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"
14379
14864
  }
14380
14865
  ),
14381
- 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
+ ),
14382
14922
  /* @__PURE__ */ jsx114("span", { className: "select-none px-1 text-sm text-muted-foreground", children: ":" }),
14383
14923
  /* @__PURE__ */ jsx114(
14384
14924
  "input",
14385
14925
  {
14386
14926
  type: "text",
14387
14927
  inputMode: "numeric",
14388
- value: timeFocus === "s" ? timeS : timeS || "--",
14928
+ value: timeFocus === "m" ? timeM : timeM || "--",
14389
14929
  placeholder: "--",
14390
- "aria-label": "Seconds",
14930
+ "aria-label": "Minutes",
14391
14931
  onFocus: (e) => {
14392
- onTimeFocus("s");
14932
+ onTimeFocus("m");
14393
14933
  e.target.select();
14394
14934
  },
14395
- onBlur: () => onTimeBlur("s"),
14396
- 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)),
14397
14939
  className: "w-7 shrink-0 border-0 bg-transparent text-center text-sm text-foreground outline-none placeholder:text-muted-foreground"
14398
14940
  }
14399
- )
14400
- ] })
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
+ )
14401
14991
  ] }),
14402
- /* @__PURE__ */ jsx114(
14403
- "button",
14404
- {
14405
- type: "button",
14406
- onClick: onConfirm,
14407
- "aria-label": "Apply time",
14408
- className: "flex size-8 shrink-0 items-center justify-center rounded border border-border text-muted-foreground transition-colors hover:bg-muted",
14409
- children: CheckIcon
14410
- }
14411
- )
14412
- ] }) });
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
+ ] });
14413
15017
  }
14414
15018
 
14415
15019
  // src/components/date-time/time-picker/use-time-picker.ts
14416
- 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
+ }
14417
15052
  function useTimePicker(props) {
14418
15053
  const {
14419
15054
  value: controlledValue,
14420
15055
  defaultValue = null,
14421
15056
  onChange,
14422
- 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
14423
15070
  } = props;
14424
15071
  const isControlled = controlledValue !== void 0;
14425
- const [internal, setInternal] = useState33(defaultValue);
15072
+ const isOpenControlled = controlledOpen !== void 0 || popoverProps?.opened !== void 0;
15073
+ const [internal, setInternal] = useState34(defaultValue);
14426
15074
  const value = isControlled ? controlledValue : internal;
14427
- 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;
14428
15092
  const now = /* @__PURE__ */ new Date();
14429
- const [timeH, setTimeH] = useState33(value ? pad2(value.getHours()) : "");
14430
- const [timeM, setTimeM] = useState33(value ? pad2(value.getMinutes()) : "");
14431
- const [timeS, setTimeS] = useState33(value ? pad2(value.getSeconds()) : "");
14432
- 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]);
14433
15125
  const updateValue = useCallback17(
14434
15126
  (d) => {
14435
15127
  if (!isControlled) {
@@ -14442,8 +15134,8 @@ function useTimePicker(props) {
14442
15134
  function handleTimeBlur(field) {
14443
15135
  setTimeFocus(null);
14444
15136
  const raw = { h: timeH, m: timeM, s: timeS }[field];
14445
- const max = field === "h" ? 23 : 59;
14446
- const padded = clampAndPad(raw, max);
15137
+ const maxVal = field === "h" ? hourMax : 59;
15138
+ const padded = clampAndPad(raw, maxVal);
14447
15139
  if (field === "h") {
14448
15140
  setTimeH(padded);
14449
15141
  } else if (field === "m") {
@@ -14453,8 +15145,9 @@ function useTimePicker(props) {
14453
15145
  }
14454
15146
  if (value && padded) {
14455
15147
  const d = new Date(value);
15148
+ const h24 = field === "h" && is12h ? to24h2(Number.parseInt(padded, 10) || 12, amPm) : Number.parseInt(padded, 10);
14456
15149
  if (field === "h") {
14457
- d.setHours(Number.parseInt(padded, 10));
15150
+ d.setHours(is12h ? h24 : Number.parseInt(padded, 10));
14458
15151
  } else if (field === "m") {
14459
15152
  d.setMinutes(Number.parseInt(padded, 10));
14460
15153
  } else {
@@ -14463,8 +15156,33 @@ function useTimePicker(props) {
14463
15156
  updateValue(d);
14464
15157
  }
14465
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
+ }
14466
15184
  function handleConfirm() {
14467
- const h = clampAndPad(timeH, 23);
15185
+ const h = clampAndPad(timeH, hourMax);
14468
15186
  const m = clampAndPad(timeM, 59);
14469
15187
  const s = clampAndPad(timeS, 59);
14470
15188
  if (h) {
@@ -14476,25 +15194,32 @@ function useTimePicker(props) {
14476
15194
  if (withSeconds && s) {
14477
15195
  setTimeS(s);
14478
15196
  }
15197
+ const h24 = is12h ? to24h2(Number.parseInt(clampAndPad(h, 12), 10) || 12, amPm) : Number.parseInt(h || "0", 10);
14479
15198
  const base = value ?? new Date(now.getFullYear(), now.getMonth(), now.getDate());
14480
15199
  const d = new Date(base);
14481
15200
  d.setHours(
14482
- h ? Number.parseInt(h, 10) : 0,
15201
+ h24,
14483
15202
  m ? Number.parseInt(m, 10) : 0,
14484
15203
  withSeconds && s ? Number.parseInt(s, 10) : 0,
14485
15204
  0
14486
15205
  );
14487
- if (value || h || m || withSeconds && s) {
15206
+ if ((value || h || m || withSeconds && s) && isWithinRange(d)) {
14488
15207
  updateValue(d);
15208
+ setOpen(false);
15209
+ setTimeFocus(null);
14489
15210
  }
14490
- setOpen(false);
14491
- setTimeFocus(null);
14492
15211
  }
14493
15212
  const handleOpenChange = useCallback17(
14494
15213
  (next) => {
14495
15214
  if (next) {
14496
15215
  if (value) {
14497
- 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
+ }
14498
15223
  setTimeM(pad2(value.getMinutes()));
14499
15224
  setTimeS(pad2(value.getSeconds()));
14500
15225
  }
@@ -14504,7 +15229,7 @@ function useTimePicker(props) {
14504
15229
  }
14505
15230
  setOpen(next);
14506
15231
  },
14507
- [updatePreferredSide, value, setOpen]
15232
+ [updatePreferredSide, value, setOpen, is12h]
14508
15233
  );
14509
15234
  function handleClear() {
14510
15235
  updateValue(null);
@@ -14512,10 +15237,125 @@ function useTimePicker(props) {
14512
15237
  setTimeM("");
14513
15238
  setTimeS("");
14514
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
+ }
14515
15350
  let displayValue = null;
14516
15351
  if (value) {
14517
15352
  if (props.valueFormat) {
14518
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}`;
14519
15359
  } else {
14520
15360
  const suffix = withSeconds ? `:${pad2(value.getSeconds())}` : "";
14521
15361
  displayValue = `${pad2(value.getHours())}:${pad2(value.getMinutes())}${suffix}`;
@@ -14540,13 +15380,28 @@ function useTimePicker(props) {
14540
15380
  handleTimeBlur,
14541
15381
  handleConfirm,
14542
15382
  handleOpenChange,
14543
- 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
14544
15399
  };
14545
15400
  }
14546
15401
 
14547
15402
  // src/components/date-time/time-picker/time-picker.tsx
14548
15403
  import { jsx as jsx115 } from "react/jsx-runtime";
14549
- var TimePicker = forwardRef9(
15404
+ var TimePicker = forwardRef10(
14550
15405
  function TimePicker2(props, ref) {
14551
15406
  const {
14552
15407
  label,
@@ -14554,9 +15409,11 @@ var TimePicker = forwardRef9(
14554
15409
  disabled = false,
14555
15410
  clearable = false,
14556
15411
  withSeconds = false,
15412
+ withDropdown = false,
14557
15413
  size = "md",
14558
15414
  radius = "md",
14559
15415
  dropdownType = "popover",
15416
+ rightSection,
14560
15417
  "aria-label": ariaLabel,
14561
15418
  className
14562
15419
  } = props;
@@ -14569,7 +15426,7 @@ var TimePicker = forwardRef9(
14569
15426
  description: void 0,
14570
15427
  error: void 0,
14571
15428
  required: false,
14572
- disabled,
15429
+ disabled: disabled || props.readOnly,
14573
15430
  clearable,
14574
15431
  size,
14575
15432
  radius,
@@ -14578,13 +15435,17 @@ var TimePicker = forwardRef9(
14578
15435
  className,
14579
15436
  displayValue: state2.displayValue,
14580
15437
  hasValue: !!state2.value,
14581
- open: state2.open,
14582
- 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,
14583
15443
  contentSide: state2.contentSide,
14584
15444
  triggerRef: state2.triggerRef,
14585
15445
  onClear: state2.handleClear,
14586
- dropdownClassName: "w-[200px]",
15446
+ dropdownClassName: cn(!props.popoverProps?.width && "w-[200px]"),
14587
15447
  buttonRef: ref,
15448
+ rightSection,
14588
15449
  children: /* @__PURE__ */ jsx115(
14589
15450
  TimePickerContent,
14590
15451
  {
@@ -14593,12 +15454,27 @@ var TimePicker = forwardRef9(
14593
15454
  timeS: state2.timeS,
14594
15455
  timeFocus: state2.timeFocus,
14595
15456
  withSeconds,
15457
+ is12h: state2.is12h,
15458
+ amPm: state2.amPm,
15459
+ setAmPm: state2.setAmPm,
15460
+ amPmLabels: state2.amPmLabels,
15461
+ isWithinRange: state2.isWithinRange,
14596
15462
  onTimeFocus: state2.setTimeFocus,
14597
15463
  onTimeBlur: state2.handleTimeBlur,
14598
15464
  onTimeHChange: state2.setTimeH,
14599
15465
  onTimeMChange: state2.setTimeM,
14600
15466
  onTimeSChange: state2.setTimeS,
14601
- 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
14602
15478
  }
14603
15479
  )
14604
15480
  }
@@ -14630,11 +15506,15 @@ var ChevronRight5 = /* @__PURE__ */ jsx116(
14630
15506
  children: /* @__PURE__ */ jsx116("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" })
14631
15507
  }
14632
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
+ };
14633
15515
  function YearPickerContent({
14634
15516
  calendarType,
14635
- years,
14636
- decadeStart,
14637
- headerLabel,
15517
+ views,
14638
15518
  onPrev,
14639
15519
  onNext,
14640
15520
  onYearClick,
@@ -14644,28 +15524,103 @@ function YearPickerContent({
14644
15524
  isYearSelected,
14645
15525
  isYearInRange,
14646
15526
  isRangeStart,
14647
- isRangeEnd
14648
- }) {
14649
- return /* @__PURE__ */ jsxs75("div", { className: "min-w-[22rem] p-3", children: [
14650
- /* @__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: [
14651
15591
  /* @__PURE__ */ jsx116(
14652
15592
  "button",
14653
15593
  {
14654
15594
  type: "button",
14655
15595
  onClick: onPrev,
14656
15596
  "aria-label": "Previous decade",
14657
- 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
+ ),
14658
15602
  children: ChevronLeft5
14659
15603
  }
14660
15604
  ),
14661
- /* @__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
+ )) }),
14662
15613
  /* @__PURE__ */ jsx116(
14663
15614
  "button",
14664
15615
  {
14665
15616
  type: "button",
14666
15617
  onClick: onNext,
14667
15618
  "aria-label": "Next decade",
14668
- 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
+ ),
14669
15624
  children: ChevronRight5
14670
15625
  }
14671
15626
  )
@@ -14673,38 +15628,11 @@ function YearPickerContent({
14673
15628
  /* @__PURE__ */ jsx116(
14674
15629
  "div",
14675
15630
  {
14676
- className: "grid grid-cols-3 gap-1 py-2",
14677
- onMouseLeave: onGridMouseLeave,
14678
- children: years.map((y) => {
14679
- const inRange = y >= decadeStart && y <= decadeStart + 9;
14680
- const sel = isYearSelected(y);
14681
- const inR = isYearInRange(y);
14682
- const start = isRangeStart(y);
14683
- const end = isRangeEnd(y);
14684
- const unselected = !(sel || inR);
14685
- const inRangeOnly = inR && !sel;
14686
- const unselectedInRange = unselected && inRange;
14687
- const unselectedOutRange = unselected && !inRange;
14688
- return /* @__PURE__ */ jsx116(
14689
- "button",
14690
- {
14691
- type: "button",
14692
- onClick: () => onYearClick(y),
14693
- onMouseEnter: () => onYearHover(y),
14694
- className: cn(
14695
- "rounded py-3 text-sm transition-colors",
14696
- sel && "bg-primary font-medium text-primary-foreground",
14697
- inRangeOnly && "bg-primary/20 text-foreground",
14698
- start && "rounded-e-none",
14699
- end && "rounded-s-none",
14700
- unselectedInRange && "text-foreground hover:bg-muted",
14701
- unselectedOutRange && "text-muted-foreground hover:bg-muted/50"
14702
- ),
14703
- children: y
14704
- },
14705
- y
14706
- );
14707
- })
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))
14708
15636
  }
14709
15637
  ),
14710
15638
  /* @__PURE__ */ jsxs75("div", { className: "mt-2 flex justify-end gap-1 border-t border-border pt-2", children: [
@@ -14741,42 +15669,53 @@ function YearPickerContent({
14741
15669
  }
14742
15670
 
14743
15671
  // src/components/date-time/year-picker/use-year-picker.ts
14744
- 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";
14745
15673
  function useYearPicker(props) {
14746
15674
  const {
14747
15675
  defaultCalendarType = "GC",
14748
15676
  allowDeselect = false,
14749
15677
  defaultDate,
14750
15678
  date: controlledDate,
14751
- onDateChange
15679
+ onDateChange,
15680
+ minDate,
15681
+ maxDate,
15682
+ getYearControlProps,
15683
+ numberOfColumns = 1,
15684
+ yearsListFormat = "YYYY",
15685
+ decadeLabelFormat = "YYYY"
14752
15686
  } = props;
14753
15687
  const type = props.type ?? "default";
14754
15688
  const isControlled = props.value !== void 0;
14755
15689
  const isDateControlled = controlledDate !== void 0;
14756
- const [_single, _setSingle] = useState34(
15690
+ const [_single, _setSingle] = useState35(
14757
15691
  type === "default" ? props.defaultValue ?? null : null
14758
15692
  );
14759
- const [_range, _setRange] = useState34(
15693
+ const [_range, _setRange] = useState35(
14760
15694
  type === "range" ? props.defaultValue ?? [
14761
15695
  null,
14762
15696
  null
14763
15697
  ] : [null, null]
14764
15698
  );
15699
+ const [_multi, _setMulti] = useState35(
15700
+ type === "multiple" ? props.defaultValue ?? [] : []
15701
+ );
14765
15702
  const singleValue = type === "default" ? isControlled ? props.value : _single : null;
14766
15703
  const rangeValue = type === "range" ? isControlled ? props.value : _range : [null, null];
14767
- const [hoveredYear, setHoveredYear] = useState34(null);
14768
- 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);
14769
15707
  const now = /* @__PURE__ */ new Date();
14770
- const initDate = controlledDate ?? defaultDate ?? (type === "default" ? singleValue : rangeValue[0]) ?? now;
14771
- const [gcViewYear, setGcViewYear] = useState34(initDate.getFullYear());
14772
- 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(
14773
15712
  toEC(
14774
15713
  initDate.getFullYear(),
14775
15714
  initDate.getMonth() + 1,
14776
15715
  initDate.getDate()
14777
15716
  )[0]
14778
15717
  );
14779
- useEffect21(() => {
15718
+ useEffect23(() => {
14780
15719
  if (!(isDateControlled && controlledDate)) {
14781
15720
  return;
14782
15721
  }
@@ -14798,7 +15737,18 @@ function useYearPicker(props) {
14798
15737
  const activeViewYear = calendarType === "EC" ? ecViewYear : gcViewYear;
14799
15738
  const decadeStart = getDecadeStart(activeViewYear);
14800
15739
  const years = buildYears(activeViewYear);
14801
- 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;
14802
15752
  const hasRange = type === "range" && !!rangeValue[0] && !!(rangeValue[1] ?? hoveredYear);
14803
15753
  function yearToDate(y) {
14804
15754
  if (calendarType === "EC") {
@@ -14813,9 +15763,6 @@ function useYearPicker(props) {
14813
15763
  }
14814
15764
  return d.getFullYear();
14815
15765
  }
14816
- function headerLabel() {
14817
- return `${decadeStart} \u2013 ${decadeStart + 9}`;
14818
- }
14819
15766
  function callOnChange(next) {
14820
15767
  if (props.onChange) {
14821
15768
  props.onChange(next);
@@ -14825,6 +15772,9 @@ function useYearPicker(props) {
14825
15772
  if (type === "default") {
14826
15773
  return !!singleValue && getViewYear(singleValue) === y;
14827
15774
  }
15775
+ if (type === "multiple") {
15776
+ return multiValue.some((d) => getViewYear(d) === y);
15777
+ }
14828
15778
  const y0 = rangeValue[0] ? getViewYear(rangeValue[0]) : null;
14829
15779
  const y1 = rangeValue[1] ? getViewYear(rangeValue[1]) : null;
14830
15780
  return y0 !== null && y0 === y || y1 !== null && y1 === y;
@@ -14849,7 +15799,32 @@ function useYearPicker(props) {
14849
15799
  const end = rangeValue[1] ?? (hoveredYear != null ? yearToDate(hoveredYear) : null);
14850
15800
  return !!(type === "range" && end && getViewYear(end) === y);
14851
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;
14852
15824
  function handleYearClick(y) {
15825
+ if (isYearDisabled(y)) {
15826
+ return;
15827
+ }
14853
15828
  const clicked = yearToDate(y);
14854
15829
  if (type === "default") {
14855
15830
  if (allowDeselect && singleValue && getViewYear(singleValue) === y) {
@@ -14863,6 +15838,16 @@ function useYearPicker(props) {
14863
15838
  }
14864
15839
  callOnChange(clicked);
14865
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);
14866
15851
  } else {
14867
15852
  const [start, end] = rangeValue;
14868
15853
  if (!start || start && end) {
@@ -14897,6 +15882,9 @@ function useYearPicker(props) {
14897
15882
  }
14898
15883
  }
14899
15884
  function handlePrev() {
15885
+ if (!canPrev) {
15886
+ return;
15887
+ }
14900
15888
  if (calendarType === "EC") {
14901
15889
  setEcViewYear((y) => y - 10);
14902
15890
  } else {
@@ -14905,6 +15893,9 @@ function useYearPicker(props) {
14905
15893
  }
14906
15894
  }
14907
15895
  function handleNext() {
15896
+ if (!canNext) {
15897
+ return;
15898
+ }
14908
15899
  if (calendarType === "EC") {
14909
15900
  setEcViewYear((y) => y + 10);
14910
15901
  } else {
@@ -14912,6 +15903,24 @@ function useYearPicker(props) {
14912
15903
  notifyDateChange(gcViewYear + 10);
14913
15904
  }
14914
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
+ }
14915
15924
  function handleCalendarTypeChange(nextType) {
14916
15925
  if (nextType === calendarType) {
14917
15926
  return;
@@ -14933,23 +15942,32 @@ function useYearPicker(props) {
14933
15942
  calendarType,
14934
15943
  years,
14935
15944
  decadeStart,
15945
+ decadeViews,
14936
15946
  ecViewYear,
14937
15947
  gcViewYear,
14938
15948
  primaryDate,
14939
15949
  hasRange,
14940
15950
  singleValue,
14941
15951
  rangeValue,
14942
- headerLabel,
15952
+ multiValue,
15953
+ formatYear,
15954
+ formatDecadeLabel,
15955
+ getYearControlProps,
15956
+ yearToDate,
14943
15957
  handlePrev,
14944
15958
  handleNext,
14945
15959
  handleYearClick,
14946
15960
  handleYearHover,
15961
+ handleClear,
14947
15962
  handleGridMouseLeave,
14948
15963
  handleCalendarTypeChange,
14949
15964
  isYearSelected,
14950
15965
  isYearInRange,
14951
15966
  isRangeStart,
14952
- isRangeEnd
15967
+ isRangeEnd,
15968
+ canPrev,
15969
+ canNext,
15970
+ isYearDisabled
14953
15971
  };
14954
15972
  }
14955
15973
 
@@ -14962,9 +15980,7 @@ function YearPicker(props) {
14962
15980
  YearPickerContent,
14963
15981
  {
14964
15982
  calendarType: state2.calendarType,
14965
- years: state2.years,
14966
- decadeStart: state2.decadeStart,
14967
- headerLabel: state2.headerLabel(),
15983
+ views: state2.decadeViews,
14968
15984
  onPrev: state2.handlePrev,
14969
15985
  onNext: state2.handleNext,
14970
15986
  onYearClick: state2.handleYearClick,
@@ -14974,13 +15990,20 @@ function YearPicker(props) {
14974
15990
  isYearSelected: state2.isYearSelected,
14975
15991
  isYearInRange: state2.isYearInRange,
14976
15992
  isRangeStart: state2.isRangeStart,
14977
- 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"
14978
16001
  }
14979
16002
  ) });
14980
16003
  }
14981
16004
 
14982
16005
  // src/components/date-time/year-picker-input/year-picker-input.tsx
14983
- import { forwardRef as forwardRef10 } from "react";
16006
+ import { forwardRef as forwardRef11 } from "react";
14984
16007
 
14985
16008
  // src/components/date-time/year-picker-input/use-year-picker-input.ts
14986
16009
  import { useCallback as useCallback19 } from "react";
@@ -15017,12 +16040,21 @@ function useYearPickerInput(props) {
15017
16040
  if (type === "default") {
15018
16041
  return picker.singleValue ? valueFormatter({ type: "default", date: picker.singleValue }) : null;
15019
16042
  }
16043
+ if (type === "multiple") {
16044
+ return valueFormatter({ type: "multiple", date: picker.multiValue });
16045
+ }
15020
16046
  return picker.rangeValue[0] ? valueFormatter({ type: "range", date: picker.rangeValue }) : null;
15021
16047
  }
15022
16048
  function formatWithFmt() {
15023
16049
  if (type === "default") {
15024
16050
  return picker.singleValue ? fmt(picker.singleValue) : null;
15025
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
+ }
15026
16058
  if (!picker.rangeValue[0]) {
15027
16059
  return null;
15028
16060
  }
@@ -15030,21 +16062,14 @@ function useYearPickerInput(props) {
15030
16062
  if (!b) {
15031
16063
  return a ? fmt(a) : null;
15032
16064
  }
15033
- const start = picker.rangeValue[0];
15034
- 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)}`;
15035
16069
  }
15036
16070
  const displayValue = formatWithFormatter() ?? formatWithFmt();
15037
16071
  function handleClear() {
15038
- if (props.onChange) {
15039
- if (type === "default") {
15040
- props.onChange(null);
15041
- } else {
15042
- props.onChange([
15043
- null,
15044
- null
15045
- ]);
15046
- }
15047
- }
16072
+ picker.handleClear();
15048
16073
  }
15049
16074
  return {
15050
16075
  displayValue,
@@ -15060,7 +16085,7 @@ function useYearPickerInput(props) {
15060
16085
 
15061
16086
  // src/components/date-time/year-picker-input/year-picker-input.tsx
15062
16087
  import { jsx as jsx118 } from "react/jsx-runtime";
15063
- var YearPickerInput = forwardRef10(function YearPickerInput2(props, ref) {
16088
+ var YearPickerInput = forwardRef11(function YearPickerInput2(props, ref) {
15064
16089
  const {
15065
16090
  label,
15066
16091
  placeholder = "Pick year",
@@ -15104,9 +16129,7 @@ var YearPickerInput = forwardRef10(function YearPickerInput2(props, ref) {
15104
16129
  YearPickerContent,
15105
16130
  {
15106
16131
  calendarType: p.calendarType,
15107
- years: p.years,
15108
- decadeStart: p.decadeStart,
15109
- headerLabel: p.headerLabel(),
16132
+ views: p.decadeViews,
15110
16133
  onPrev: p.handlePrev,
15111
16134
  onNext: p.handleNext,
15112
16135
  onYearClick: p.handleYearClick,
@@ -15116,7 +16139,14 @@ var YearPickerInput = forwardRef10(function YearPickerInput2(props, ref) {
15116
16139
  isYearSelected: p.isYearSelected,
15117
16140
  isYearInRange: p.isYearInRange,
15118
16141
  isRangeStart: p.isRangeStart,
15119
- 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"
15120
16150
  }
15121
16151
  )
15122
16152
  }
@@ -15537,7 +16567,7 @@ function Anchor({
15537
16567
  }
15538
16568
 
15539
16569
  // src/components/ui/angle-slider.tsx
15540
- 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";
15541
16571
  import { jsx as jsx124, jsxs as jsxs78 } from "react/jsx-runtime";
15542
16572
  var TAU = 2 * Math.PI;
15543
16573
  var px = (n) => `${Math.round(n * 1e4) / 1e4}px`;
@@ -15554,7 +16584,7 @@ function AngleSlider({
15554
16584
  disabled = false,
15555
16585
  ...props
15556
16586
  }) {
15557
- const [internalValue, setInternalValue] = useState35(defaultValue);
16587
+ const [internalValue, setInternalValue] = useState36(defaultValue);
15558
16588
  const value = valueProp ?? internalValue;
15559
16589
  const isControlled = valueProp !== void 0;
15560
16590
  const setValue = useCallback20(
@@ -15567,8 +16597,8 @@ function AngleSlider({
15567
16597
  },
15568
16598
  [isControlled, onChange]
15569
16599
  );
15570
- const ref = useRef13(null);
15571
- const angleRef = useRef13(value);
16600
+ const ref = useRef15(null);
16601
+ const angleRef = useRef15(value);
15572
16602
  const getAngle = useCallback20(
15573
16603
  (clientX, clientY) => {
15574
16604
  const el = ref.current;
@@ -15709,7 +16739,7 @@ function AngleSlider({
15709
16739
  import { useMesob as useMesob8 } from "@mesob/ui/providers";
15710
16740
  import { IconChevronDown as IconChevronDown7 } from "@tabler/icons-react";
15711
16741
  import { motion } from "motion/react";
15712
- 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";
15713
16743
  import { jsx as jsx125, jsxs as jsxs79 } from "react/jsx-runtime";
15714
16744
  function AnimatedTabs({
15715
16745
  tabs,
@@ -15722,17 +16752,17 @@ function AnimatedTabs({
15722
16752
  const mesob = useMesob8();
15723
16753
  const LinkComponent = linkProp ?? mesob?.navigation?.Link;
15724
16754
  const locale = mesob?.locale;
15725
- const [internalActiveTab, setInternalActiveTab] = useState36(
16755
+ const [internalActiveTab, setInternalActiveTab] = useState37(
15726
16756
  defaultTab ?? tabs[0]?.value ?? ""
15727
16757
  );
15728
16758
  const activeTab = controlledActiveTab ?? internalActiveTab;
15729
- const [visibleTabs, setVisibleTabs] = useState36(tabs);
15730
- const [overflowTabs, setOverflowTabs] = useState36([]);
15731
- const containerRef = useRef14(null);
15732
- const tabsListRef = useRef14(null);
15733
- const dropdownTriggerRef = useRef14(null);
15734
- const tabRefs = useRef14([]);
15735
- 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 });
15736
16766
  const handleTabChange = (newValue) => {
15737
16767
  if (!controlledActiveTab) {
15738
16768
  setInternalActiveTab(newValue);
@@ -16710,6 +17740,7 @@ var ChartStyle = ({ id, config }) => {
16710
17740
  "style",
16711
17741
  {
16712
17742
  dangerouslySetInnerHTML: {
17743
+ // biome-ignore lint/style/useNamingConvention: React requires `__html` on innerHTML object
16713
17744
  __html: Object.entries(THEMES).map(
16714
17745
  ([theme, prefix]) => `
16715
17746
  ${prefix} [data-chart=${id}] {
@@ -17006,7 +18037,7 @@ function CollapsibleContent({
17006
18037
  // src/components/ui/color-input.tsx
17007
18038
  import { IconColorPicker } from "@tabler/icons-react";
17008
18039
  import * as React14 from "react";
17009
- 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";
17010
18041
 
17011
18042
  // src/lib/color-utils.ts
17012
18043
  function hex2rgb(hex) {
@@ -17208,7 +18239,7 @@ function hasAlpha(format) {
17208
18239
  }
17209
18240
 
17210
18241
  // src/components/ui/color-picker.tsx
17211
- 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";
17212
18243
 
17213
18244
  // src/components/ui/color-swatch.tsx
17214
18245
  import { jsx as jsx139, jsxs as jsxs83 } from "react/jsx-runtime";
@@ -17300,8 +18331,8 @@ function HueAlphaSlider({
17300
18331
  ariaLabel,
17301
18332
  className
17302
18333
  }) {
17303
- const ref = useRef16(null);
17304
- const lastRef = useRef16(value);
18334
+ const ref = useRef18(null);
18335
+ const lastRef = useRef18(value);
17305
18336
  const handleMove = useCallback21(
17306
18337
  (clientX) => {
17307
18338
  const el = ref.current;
@@ -17396,15 +18427,15 @@ function ColorPicker({
17396
18427
  alphaLabel,
17397
18428
  ...inputProps
17398
18429
  }) {
17399
- const [hsva, setHsva] = useState38(
18430
+ const [hsva, setHsva] = useState39(
17400
18431
  () => parseColor(String(value ?? inputProps.defaultValue ?? "#000000"))
17401
18432
  );
17402
18433
  const isControlled = value !== void 0;
17403
- const valueRef = useRef16(value);
17404
- const saturationRef = useRef16(null);
17405
- const lastHsvaRef = useRef16(hsva);
18434
+ const valueRef = useRef18(value);
18435
+ const saturationRef = useRef18(null);
18436
+ const lastHsvaRef = useRef18(hsva);
17406
18437
  lastHsvaRef.current = hsva;
17407
- useEffect24(() => {
18438
+ useEffect26(() => {
17408
18439
  if (value === valueRef.current) {
17409
18440
  return;
17410
18441
  }
@@ -17745,9 +18776,9 @@ var ColorInput = React14.forwardRef(
17745
18776
  placeholder,
17746
18777
  ...inputProps
17747
18778
  }, ref) => {
17748
- const [dropdownOpened, setDropdownOpened] = useState39(false);
17749
- const [lastValidValue, setLastValidValue] = useState39("");
17750
- const [internalValue, setInternalValue] = useState39(
18779
+ const [dropdownOpened, setDropdownOpened] = useState40(false);
18780
+ const [lastValidValue, setLastValidValue] = useState40("");
18781
+ const [internalValue, setInternalValue] = useState40(
17751
18782
  defaultValue ?? valueProp ?? ""
17752
18783
  );
17753
18784
  const isControlled = valueProp !== void 0;
@@ -17764,18 +18795,18 @@ var ColorInput = React14.forwardRef(
17764
18795
  );
17765
18796
  const { supported: eyeDropperSupported, open: openEyeDropper } = useEyeDropper();
17766
18797
  const _withEyeDropper = withEyeDropperProp && eyeDropperSupported;
17767
- const inputRef = useRef17(null);
17768
- const anchorRef = useRef17(null);
17769
- const popoverContentRef = useRef17(null);
17770
- const openTimestampRef = useRef17(0);
17771
- const pointerDownInPopoverRef = useRef17(false);
17772
- 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(() => {
17773
18804
  if (isColorValid(value) || value.trim() === "") {
17774
18805
  setLastValidValue(value);
17775
18806
  }
17776
18807
  }, [value]);
17777
- const prevFormatRef = useRef17(format);
17778
- useEffect25(() => {
18808
+ const prevFormatRef = useRef19(format);
18809
+ useEffect27(() => {
17779
18810
  if (prevFormatRef.current !== format && isColorValid(value)) {
17780
18811
  setValue(formatColor(parseColor(value), format));
17781
18812
  prevFormatRef.current = format;
@@ -18008,7 +19039,7 @@ ColorInput.displayName = "ColorInput";
18008
19039
  // src/components/ui/combobox.tsx
18009
19040
  import { Combobox as ComboboxPrimitive } from "@base-ui/react/combobox";
18010
19041
  import { IconCheck as IconCheck4, IconChevronDown as IconChevronDown9 } from "@tabler/icons-react";
18011
- import { useMemo as useMemo13, useState as useState40 } from "react";
19042
+ import { useMemo as useMemo13, useState as useState41 } from "react";
18012
19043
  import { jsx as jsx142, jsxs as jsxs86 } from "react/jsx-runtime";
18013
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)]";
18014
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";
@@ -18023,7 +19054,7 @@ function Combobox({
18023
19054
  className,
18024
19055
  ...props
18025
19056
  }) {
18026
- const [inputValue, setInputValue] = useState40("");
19057
+ const [inputValue, setInputValue] = useState41("");
18027
19058
  const selectedOption = useMemo13(
18028
19059
  () => options.find((opt) => opt.value === value) ?? null,
18029
19060
  [options, value]
@@ -18475,7 +19506,7 @@ function ContextMenuShortcut({
18475
19506
 
18476
19507
  // src/components/ui/copy-button.tsx
18477
19508
  import { IconCheck as IconCheck6, IconCopy } from "@tabler/icons-react";
18478
- import { useState as useState41 } from "react";
19509
+ import { useState as useState42 } from "react";
18479
19510
  import { jsx as jsx145 } from "react/jsx-runtime";
18480
19511
  function CopyButton({
18481
19512
  value,
@@ -18486,7 +19517,7 @@ function CopyButton({
18486
19517
  className,
18487
19518
  ...props
18488
19519
  }) {
18489
- const [copied, setCopied] = useState41(false);
19520
+ const [copied, setCopied] = useState42(false);
18490
19521
  const handleCopy = async () => {
18491
19522
  try {
18492
19523
  await navigator.clipboard.writeText(value);
@@ -19073,7 +20104,7 @@ function DropdownButton({
19073
20104
  }
19074
20105
 
19075
20106
  // src/components/ui/file-button.tsx
19076
- import { useRef as useRef18 } from "react";
20107
+ import { useRef as useRef20 } from "react";
19077
20108
  import { Fragment as Fragment27, jsx as jsx152, jsxs as jsxs93 } from "react/jsx-runtime";
19078
20109
  function FileButton({
19079
20110
  onChange,
@@ -19085,7 +20116,7 @@ function FileButton({
19085
20116
  className,
19086
20117
  ...props
19087
20118
  }) {
19088
- const inputRef = useRef18(null);
20119
+ const inputRef = useRef20(null);
19089
20120
  const handleClick = () => {
19090
20121
  inputRef.current?.click();
19091
20122
  };
@@ -19122,7 +20153,7 @@ function FileButton({
19122
20153
 
19123
20154
  // src/components/ui/file-drop-input.tsx
19124
20155
  import { IconPencil as IconPencil2, IconPhoto as IconPhoto4, IconTrash as IconTrash6 } from "@tabler/icons-react";
19125
- 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";
19126
20157
 
19127
20158
  // src/components/files/file-preview.tsx
19128
20159
  import {
@@ -19132,7 +20163,7 @@ import {
19132
20163
  IconPhoto as IconPhoto3,
19133
20164
  IconVideo as IconVideo2
19134
20165
  } from "@tabler/icons-react";
19135
- 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";
19136
20167
  import { jsx as jsx153 } from "react/jsx-runtime";
19137
20168
  function formatBytes2(size) {
19138
20169
  if (!size) {
@@ -19168,12 +20199,12 @@ function buildPreviewKey(item) {
19168
20199
  return item.id ?? `${item.source}-${item.name}-${item.fileIndex ?? item.url}`;
19169
20200
  }
19170
20201
  function useResolvedPreviewItems(files, previewItems = []) {
19171
- const [localItems, setLocalItems] = useState43([]);
20202
+ const [localItems, setLocalItems] = useState44([]);
19172
20203
  const remoteItems = useMemo15(
19173
20204
  () => previewItems.map((item) => ({ ...item, source: "remote" })),
19174
20205
  [previewItems]
19175
20206
  );
19176
- useEffect26(() => {
20207
+ useEffect28(() => {
19177
20208
  let active = true;
19178
20209
  const objectUrls = [];
19179
20210
  async function resolveFiles() {
@@ -19286,12 +20317,12 @@ function FileDropInput({
19286
20317
  disabled,
19287
20318
  ...props
19288
20319
  }) {
19289
- const inputId = useId6();
19290
- const inputRef = useRef19(null);
19291
- const [internalFiles, setInternalFiles] = useState44(defaultFiles);
19292
- const [dragging, setDragging] = useState44(false);
19293
- const [pendingCropFile, setPendingCropFile] = useState44(null);
19294
- 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);
19295
20326
  const files = filesProp ?? internalFiles;
19296
20327
  const items = useResolvedPreviewItems(files, previewItems);
19297
20328
  const singleItem = !multiple && items.length === 1 ? items[0] : null;
@@ -19551,7 +20582,7 @@ import {
19551
20582
  IconUpload as IconUpload2,
19552
20583
  IconX as IconX12
19553
20584
  } from "@tabler/icons-react";
19554
- 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";
19555
20586
  import { Fragment as Fragment29, jsx as jsx155, jsxs as jsxs95 } from "react/jsx-runtime";
19556
20587
  function FileInput({
19557
20588
  className,
@@ -19577,13 +20608,15 @@ function FileInput({
19577
20608
  errorProps,
19578
20609
  inputContainer,
19579
20610
  disabled,
20611
+ id: inputIdProp,
19580
20612
  ...props
19581
20613
  }) {
19582
- const inputRef = useRef20(null);
19583
- const inputId = useId7();
19584
- const [internalFiles, setInternalFiles] = useState45(defaultFiles);
19585
- const [pendingCropFile, setPendingCropFile] = useState45(null);
19586
- const [cropOpen, setCropOpen] = useState45(false);
20614
+ const inputRef = useRef22(null);
20615
+ const generatedInputId = useId8();
20616
+ const inputId = inputIdProp ?? generatedInputId;
20617
+ const [internalFiles, setInternalFiles] = useState46(defaultFiles);
20618
+ const [pendingCropFile, setPendingCropFile] = useState46(null);
20619
+ const [cropOpen, setCropOpen] = useState46(false);
19587
20620
  const files = filesProp ?? internalFiles;
19588
20621
  const items = useResolvedPreviewItems(files, previewItems);
19589
20622
  const singleItem = !multiple && items.length === 1 ? items[0] : null;
@@ -19632,7 +20665,14 @@ function FileInput({
19632
20665
  const hasWrapper = label || description || error || required || withAsterisk;
19633
20666
  const RootIcon = singleItem ? getFileIcon2(singleItem.type) : IconPaperclip;
19634
20667
  let metaContent = null;
19635
- if (items.length > 1) {
20668
+ if (multiple && items.length > 0) {
20669
+ metaContent = /* @__PURE__ */ jsxs95("div", { "data-slot": "file-input-meta", className: "cn-file-input-meta", children: [
20670
+ items.length,
20671
+ " file",
20672
+ items.length === 1 ? "" : "s",
20673
+ " selected"
20674
+ ] });
20675
+ } else if (!multiple && items.length > 1) {
19636
20676
  metaContent = /* @__PURE__ */ jsxs95("div", { "data-slot": "file-input-meta", className: "cn-file-input-meta", children: [
19637
20677
  items.length,
19638
20678
  " files selected"
@@ -19666,13 +20706,11 @@ function FileInput({
19666
20706
  }
19667
20707
  ),
19668
20708
  /* @__PURE__ */ jsx155(
19669
- "button",
20709
+ "label",
19670
20710
  {
19671
- type: "button",
20711
+ htmlFor: inputId,
19672
20712
  "data-slot": "file-input-root",
19673
20713
  className: "cn-file-input-root",
19674
- onClick: () => inputRef.current?.click(),
19675
- disabled,
19676
20714
  children: singleItem ? /* @__PURE__ */ jsxs95(Fragment29, { children: [
19677
20715
  /* @__PURE__ */ jsx155(
19678
20716
  "div",
@@ -19712,6 +20750,7 @@ function FileInput({
19712
20750
  variant: "ghost",
19713
20751
  size: "icon-sm",
19714
20752
  onClick: (event) => {
20753
+ event.preventDefault();
19715
20754
  event.stopPropagation();
19716
20755
  handleEdit();
19717
20756
  },
@@ -19727,6 +20766,7 @@ function FileInput({
19727
20766
  variant: "ghost",
19728
20767
  size: "icon-sm",
19729
20768
  onClick: (event) => {
20769
+ event.preventDefault();
19730
20770
  event.stopPropagation();
19731
20771
  handleClear();
19732
20772
  },
@@ -19769,7 +20809,7 @@ function FileInput({
19769
20809
  ] })
19770
20810
  }
19771
20811
  ),
19772
- !singleItem && items.length > 1 ? /* @__PURE__ */ jsx155("div", { "data-slot": "file-input-list", className: "cn-file-input-list", children: items.map((item) => {
20812
+ !singleItem && (multiple ? items.length > 0 : items.length > 1) ? /* @__PURE__ */ jsx155("div", { "data-slot": "file-input-list", className: "cn-file-input-list", children: items.map((item) => {
19773
20813
  const ItemIcon = getFileIcon2(item.type);
19774
20814
  return /* @__PURE__ */ jsxs95(
19775
20815
  "div",
@@ -19953,7 +20993,7 @@ function Flex({
19953
20993
  }
19954
20994
 
19955
20995
  // src/components/ui/floating-indicator.tsx
19956
- import { useEffect as useEffect27, useState as useState46 } from "react";
20996
+ import { useEffect as useEffect29, useState as useState47 } from "react";
19957
20997
  import { jsx as jsx157 } from "react/jsx-runtime";
19958
20998
  function FloatingIndicator({
19959
20999
  className,
@@ -19964,9 +21004,9 @@ function FloatingIndicator({
19964
21004
  style,
19965
21005
  ...props
19966
21006
  }) {
19967
- const [position, setPosition] = useState46({ x: 0, y: 0, width: 0, height: 0 });
19968
- const [isVisible, setIsVisible] = useState46(!displayAfterTransitionEnd);
19969
- useEffect27(() => {
21007
+ const [position, setPosition] = useState47({ x: 0, y: 0, width: 0, height: 0 });
21008
+ const [isVisible, setIsVisible] = useState47(!displayAfterTransitionEnd);
21009
+ useEffect29(() => {
19970
21010
  const hasTargetAndParent2 = target && parent;
19971
21011
  if (!hasTargetAndParent2) {
19972
21012
  return;
@@ -20021,7 +21061,7 @@ function FloatingIndicator({
20021
21061
  }
20022
21062
 
20023
21063
  // src/components/ui/focus-trap.tsx
20024
- 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";
20025
21065
  import { jsx as jsx158 } from "react/jsx-runtime";
20026
21066
  var FOCUSABLE = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
20027
21067
  function getFocusableElements(container) {
@@ -20030,8 +21070,8 @@ function getFocusableElements(container) {
20030
21070
  );
20031
21071
  }
20032
21072
  function useFocusTrap(active) {
20033
- const ref = useRef21(null);
20034
- useEffect28(() => {
21073
+ const ref = useRef23(null);
21074
+ useEffect30(() => {
20035
21075
  if (!active) {
20036
21076
  return;
20037
21077
  }
@@ -20620,7 +21660,7 @@ function ItemFooter({ className, ...props }) {
20620
21660
  }
20621
21661
 
20622
21662
  // src/components/ui/json-input.tsx
20623
- import { useState as useState47 } from "react";
21663
+ import { useState as useState48 } from "react";
20624
21664
  import { jsx as jsx165, jsxs as jsxs97 } from "react/jsx-runtime";
20625
21665
  function JsonInput({
20626
21666
  className,
@@ -20642,10 +21682,10 @@ function JsonInput({
20642
21682
  }
20643
21683
  return "";
20644
21684
  };
20645
- const [internalValue, setInternalValue] = useState47(
21685
+ const [internalValue, setInternalValue] = useState48(
20646
21686
  stringifyValue(defaultValue) || "{}"
20647
21687
  );
20648
- const [error, setError] = useState47(null);
21688
+ const [error, setError] = useState48(null);
20649
21689
  const currentValue = value !== void 0 ? stringifyValue(value) : internalValue;
20650
21690
  const handleChange = (e) => {
20651
21691
  const newValue = e.target.value;
@@ -21076,7 +22116,7 @@ function MenubarSubContent({
21076
22116
  }
21077
22117
 
21078
22118
  // src/components/ui/money-input.tsx
21079
- 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";
21080
22120
  import { jsx as jsx170, jsxs as jsxs99 } from "react/jsx-runtime";
21081
22121
  var defaultCurrencies = [
21082
22122
  { label: "ETB", value: "etb", symbol: "Br" },
@@ -21112,7 +22152,7 @@ var sizeClasses4 = {
21112
22152
  select: "w-[90px] text-base"
21113
22153
  }
21114
22154
  };
21115
- var MoneyInput = forwardRef12(
22155
+ var MoneyInput = forwardRef13(
21116
22156
  ({
21117
22157
  value = 0,
21118
22158
  currency = "etb",
@@ -21126,9 +22166,9 @@ var MoneyInput = forwardRef12(
21126
22166
  id
21127
22167
  }, ref) => {
21128
22168
  const placeholder = placeholderProp ?? (fractionDigits > 0 ? `0.${"0".repeat(fractionDigits)}` : "0");
21129
- const [internalValue, setInternalValue] = useState48(value);
21130
- const [internalCurrency, setInternalCurrency] = useState48(currency);
21131
- const [displayValue, setDisplayValue] = useState48(
22169
+ const [internalValue, setInternalValue] = useState49(value);
22170
+ const [internalCurrency, setInternalCurrency] = useState49(currency);
22171
+ const [displayValue, setDisplayValue] = useState49(
21132
22172
  () => formatNumber(value, fractionDigits)
21133
22173
  );
21134
22174
  const currentCurrency = currencies.find(
@@ -21222,7 +22262,7 @@ MoneyInput.displayName = "MoneyInput";
21222
22262
  // src/components/ui/multi-select.tsx
21223
22263
  import { Autocomplete as AutocompletePrimitive2 } from "@base-ui/react/autocomplete";
21224
22264
  import { IconCheck as IconCheck8, IconChevronDown as IconChevronDown11, IconX as IconX13 } from "@tabler/icons-react";
21225
- import { useState as useState49 } from "react";
22265
+ import { useState as useState50 } from "react";
21226
22266
  import { jsx as jsx171, jsxs as jsxs100 } from "react/jsx-runtime";
21227
22267
  function MultiSelect({
21228
22268
  options,
@@ -21234,8 +22274,8 @@ function MultiSelect({
21234
22274
  disabled,
21235
22275
  ...props
21236
22276
  }) {
21237
- const [open, setOpen] = useState49(false);
21238
- const [inputValue, setInputValue] = useState49("");
22277
+ const [open, setOpen] = useState50(false);
22278
+ const [inputValue, setInputValue] = useState50("");
21239
22279
  const selectedOptions = options.filter((opt) => value.includes(opt.value));
21240
22280
  const filteredOptions = inputValue === "" ? options : options.filter(
21241
22281
  (option) => option.label.toLowerCase().includes(inputValue.toLowerCase())
@@ -21352,7 +22392,7 @@ function MultiSelect({
21352
22392
 
21353
22393
  // src/components/ui/native-select.tsx
21354
22394
  import { IconChevronDown as IconChevronDown12 } from "@tabler/icons-react";
21355
- import { forwardRef as forwardRef13 } from "react";
22395
+ import { forwardRef as forwardRef14 } from "react";
21356
22396
  import { jsx as jsx172, jsxs as jsxs101 } from "react/jsx-runtime";
21357
22397
  function mapNativeSelectSize(size) {
21358
22398
  return size === "xs" || size === "sm" ? "sm" : "default";
@@ -21362,7 +22402,7 @@ function parseOptions(data) {
21362
22402
  (item) => typeof item === "string" ? { value: item, label: item } : item
21363
22403
  );
21364
22404
  }
21365
- var NativeSelectBase = forwardRef13(
22405
+ var NativeSelectBase = forwardRef14(
21366
22406
  ({ className, size = "md", data, children, rightSection, ...props }, ref) => {
21367
22407
  const options = data ? parseOptions(data) : null;
21368
22408
  const mappedSize = mapNativeSelectSize(size);
@@ -21404,7 +22444,7 @@ var NativeSelectBase = forwardRef13(
21404
22444
  }
21405
22445
  );
21406
22446
  NativeSelectBase.displayName = "NativeSelectBase";
21407
- var NativeSelect = forwardRef13(
22447
+ var NativeSelect = forwardRef14(
21408
22448
  ({
21409
22449
  label,
21410
22450
  description,
@@ -21681,7 +22721,7 @@ function NavigationMenuIndicator({
21681
22721
  }
21682
22722
 
21683
22723
  // src/components/ui/nprogress.tsx
21684
- import { useEffect as useEffect29, useSyncExternalStore } from "react";
22724
+ import { useEffect as useEffect31, useSyncExternalStore } from "react";
21685
22725
  import { jsx as jsx175 } from "react/jsx-runtime";
21686
22726
  var DEFAULT_STEP_INTERVAL = 450;
21687
22727
  var DEFAULT_INITIAL_PROGRESS = 8;
@@ -21845,13 +22885,13 @@ function NProgress({
21845
22885
  }) {
21846
22886
  const current = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
21847
22887
  const translateX = current.progress - MAX_PROGRESS;
21848
- useEffect29(() => {
22888
+ useEffect31(() => {
21849
22889
  if (!pathname) {
21850
22890
  return;
21851
22891
  }
21852
22892
  completeNProgress();
21853
22893
  }, [pathname]);
21854
- useEffect29(() => {
22894
+ useEffect31(() => {
21855
22895
  if (!withNavigation) {
21856
22896
  return;
21857
22897
  }
@@ -21959,7 +22999,7 @@ function NumberFormatter({
21959
22999
 
21960
23000
  // src/components/ui/number-input.tsx
21961
23001
  import { IconChevronDown as IconChevronDown14, IconChevronUp as IconChevronUp4 } from "@tabler/icons-react";
21962
- import { forwardRef as forwardRef14, useCallback as useCallback24 } from "react";
23002
+ import { forwardRef as forwardRef15, useCallback as useCallback24 } from "react";
21963
23003
 
21964
23004
  // src/components/ui/unstyled-button.tsx
21965
23005
  import { useRender as useRender9 } from "@base-ui/react/use-render";
@@ -22016,7 +23056,7 @@ function getDisplayValue({
22016
23056
  }
22017
23057
  return "";
22018
23058
  }
22019
- var NumberInput = forwardRef14(
23059
+ var NumberInput = forwardRef15(
22020
23060
  ({
22021
23061
  value,
22022
23062
  defaultValue,
@@ -22349,11 +23389,11 @@ function Paper({
22349
23389
 
22350
23390
  // src/components/ui/password-input.tsx
22351
23391
  import { IconEye, IconEyeOff } from "@tabler/icons-react";
22352
- import { forwardRef as forwardRef15, useState as useState50 } from "react";
23392
+ import { forwardRef as forwardRef16, useState as useState51 } from "react";
22353
23393
  import { jsx as jsx181, jsxs as jsxs106 } from "react/jsx-runtime";
22354
- var PasswordInput = forwardRef15(
23394
+ var PasswordInput = forwardRef16(
22355
23395
  ({ className, showToggle = true, size, ...props }, ref) => {
22356
- const [showPassword, setShowPassword] = useState50(false);
23396
+ const [showPassword, setShowPassword] = useState51(false);
22357
23397
  const groupSizeClasses = {
22358
23398
  xs: "h-7",
22359
23399
  sm: "h-8",
@@ -22397,7 +23437,7 @@ var PasswordInput = forwardRef15(
22397
23437
  }
22398
23438
  );
22399
23439
  PasswordInput.displayName = "PasswordInput";
22400
- var PasswordInputWithWrapper = forwardRef15(
23440
+ var PasswordInputWithWrapper = forwardRef16(
22401
23441
  ({
22402
23442
  label,
22403
23443
  description,
@@ -22583,7 +23623,7 @@ import {
22583
23623
  IconStarFilled,
22584
23624
  IconStarHalfFilled
22585
23625
  } from "@tabler/icons-react";
22586
- import { useState as useState51 } from "react";
23626
+ import { useState as useState52 } from "react";
22587
23627
  import { jsx as jsx184 } from "react/jsx-runtime";
22588
23628
  function Rating({
22589
23629
  count = 5,
@@ -22597,7 +23637,7 @@ function Rating({
22597
23637
  className,
22598
23638
  ...props
22599
23639
  }) {
22600
- const [hoverValue, setHoverValue] = useState51(null);
23640
+ const [hoverValue, setHoverValue] = useState52(null);
22601
23641
  const isDisabled = readOnly || disabled;
22602
23642
  const sizeClasses6 = {
22603
23643
  sm: "size-4",
@@ -22974,7 +24014,7 @@ function Space({ className, h, w, style, ...props }) {
22974
24014
 
22975
24015
  // src/components/ui/spoiler.tsx
22976
24016
  import { IconChevronDown as IconChevronDown15 } from "@tabler/icons-react";
22977
- 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";
22978
24018
  import { jsx as jsx190, jsxs as jsxs110 } from "react/jsx-runtime";
22979
24019
  function Spoiler({
22980
24020
  maxHeight = 100,
@@ -22985,10 +24025,10 @@ function Spoiler({
22985
24025
  className,
22986
24026
  ...props
22987
24027
  }) {
22988
- const [isExpanded, setIsExpanded] = useState52(initialState);
22989
- const [shouldShowButton, setShouldShowButton] = useState52(false);
22990
- const contentRef = useRef22(null);
22991
- useEffect30(() => {
24028
+ const [isExpanded, setIsExpanded] = useState53(initialState);
24029
+ const [shouldShowButton, setShouldShowButton] = useState53(false);
24030
+ const contentRef = useRef24(null);
24031
+ useEffect32(() => {
22992
24032
  const el = contentRef.current;
22993
24033
  if (!el) {
22994
24034
  return;
@@ -23105,7 +24145,7 @@ function Stack({
23105
24145
  }
23106
24146
 
23107
24147
  // src/components/ui/status-dropdown-button.tsx
23108
- 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";
23109
24149
  import { Fragment as Fragment30, jsx as jsx192, jsxs as jsxs111 } from "react/jsx-runtime";
23110
24150
  var STATUS_MENU_SEPARATOR = "separator";
23111
24151
  function resolveConfirmConfig(target, entityLabel) {
@@ -23177,7 +24217,7 @@ function StatusDropdownButton({
23177
24217
  variant,
23178
24218
  ...dropdownProps
23179
24219
  }) {
23180
- const [pending, setPending] = useState53(null);
24220
+ const [pending, setPending] = useState54(null);
23181
24221
  const onPick = useCallback25(
23182
24222
  (next) => {
23183
24223
  const target = states.find((s) => s.value === next);
@@ -23447,7 +24487,7 @@ function TableOfContents({
23447
24487
 
23448
24488
  // src/components/ui/tags-input.tsx
23449
24489
  import { IconX as IconX14 } from "@tabler/icons-react";
23450
- import { useState as useState54 } from "react";
24490
+ import { useState as useState55 } from "react";
23451
24491
  import { jsx as jsx196, jsxs as jsxs113 } from "react/jsx-runtime";
23452
24492
  function TagsInput({
23453
24493
  className,
@@ -23461,8 +24501,8 @@ function TagsInput({
23461
24501
  disabled = false,
23462
24502
  ...props
23463
24503
  }) {
23464
- const [internalValue, setInternalValue] = useState54(defaultValue);
23465
- const [inputValue, setInputValue] = useState54("");
24504
+ const [internalValue, setInternalValue] = useState55(defaultValue);
24505
+ const [inputValue, setInputValue] = useState55("");
23466
24506
  const tags = value ?? internalValue;
23467
24507
  const addTag = (tag) => {
23468
24508
  const trimmed = tag.trim();
@@ -23556,9 +24596,9 @@ function TagsInput({
23556
24596
  }
23557
24597
 
23558
24598
  // src/components/ui/text-input.tsx
23559
- import { forwardRef as forwardRef16 } from "react";
24599
+ import { forwardRef as forwardRef17 } from "react";
23560
24600
  import { jsx as jsx197, jsxs as jsxs114 } from "react/jsx-runtime";
23561
- var TextInput = forwardRef16(
24601
+ var TextInput = forwardRef17(
23562
24602
  ({
23563
24603
  label,
23564
24604
  description,
@@ -24057,7 +25097,7 @@ function ToggleGroupItem({
24057
25097
  }
24058
25098
 
24059
25099
  // src/components/ui/transition.tsx
24060
- import { useEffect as useEffect31, useState as useState55 } from "react";
25100
+ import { useEffect as useEffect33, useState as useState56 } from "react";
24061
25101
  import { Fragment as Fragment31, jsx as jsx203 } from "react/jsx-runtime";
24062
25102
  var TRANSITIONS = {
24063
25103
  fade: {
@@ -24112,11 +25152,11 @@ var TRANSITIONS = {
24112
25152
  }
24113
25153
  };
24114
25154
  function useTransitionState(mounted, duration, exitDuration, timingFunction, onEnter, onEntered, onExit, onExited, enterDelay, exitDelay) {
24115
- const [status, setStatus] = useState55(
25155
+ const [status, setStatus] = useState56(
24116
25156
  mounted ? "entered" : "exited"
24117
25157
  );
24118
- const [displayDuration, setDisplayDuration] = useState55(duration);
24119
- useEffect31(() => {
25158
+ const [displayDuration, setDisplayDuration] = useState56(duration);
25159
+ useEffect33(() => {
24120
25160
  if (mounted) {
24121
25161
  setDisplayDuration(duration);
24122
25162
  const t12 = setTimeout(() => {
@@ -24229,7 +25269,7 @@ function Transition({
24229
25269
 
24230
25270
  // src/components/ui/tree.tsx
24231
25271
  import { IconChevronRight as IconChevronRight11 } from "@tabler/icons-react";
24232
- import { useState as useState56 } from "react";
25272
+ import { useState as useState57 } from "react";
24233
25273
  import { jsx as jsx204, jsxs as jsxs115 } from "react/jsx-runtime";
24234
25274
  function Tree({
24235
25275
  className,
@@ -24244,7 +25284,7 @@ function Tree({
24244
25284
  renderNode,
24245
25285
  ...props
24246
25286
  }) {
24247
- const [internalExpanded, setInternalExpanded] = useState56(
25287
+ const [internalExpanded, setInternalExpanded] = useState57(
24248
25288
  /* @__PURE__ */ new Set()
24249
25289
  );
24250
25290
  const expanded = expandedProp !== void 0 ? expandedProp : internalExpanded;
@@ -24844,6 +25884,7 @@ export {
24844
25884
  containerVariants,
24845
25885
  dateToIsoDate,
24846
25886
  formatDateWithPattern,
25887
+ getTimeRange,
24847
25888
  gridColVariants,
24848
25889
  gridVariants,
24849
25890
  incrementNProgress,