@underverse-ui/underverse 1.0.91 → 1.0.93

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "@underverse-ui/underverse",
3
- "version": "1.0.91",
3
+ "version": "1.0.93",
4
4
  "sourceEntry": "src/index.ts",
5
5
  "totalExports": 225,
6
6
  "exports": [
package/dist/index.cjs CHANGED
@@ -2064,6 +2064,8 @@ var DEFAULT_OVERLAY_SCROLLBAR_BEHAVIOR = {
2064
2064
  autoHideDelay: 600,
2065
2065
  dragScroll: true,
2066
2066
  clickScroll: false,
2067
+ overflowX: "scroll",
2068
+ overflowY: "scroll",
2067
2069
  exclude: DEFAULT_OVERLAY_SCROLLBAR_EXCLUDE
2068
2070
  };
2069
2071
  function resolveOverlayScrollbarBehavior(overrides = {}) {
@@ -2074,6 +2076,10 @@ function resolveOverlayScrollbarBehavior(overrides = {}) {
2074
2076
  }
2075
2077
  function buildOverlayScrollbarOptions(config) {
2076
2078
  return {
2079
+ overflow: {
2080
+ x: config.overflowX,
2081
+ y: config.overflowY
2082
+ },
2077
2083
  scrollbars: {
2078
2084
  theme: config.theme,
2079
2085
  visibility: config.visibility,
@@ -2218,6 +2224,8 @@ function OverlayScrollbarProvider({
2218
2224
  autoHideDelay = DEFAULT_OVERLAY_SCROLLBAR_BEHAVIOR.autoHideDelay,
2219
2225
  dragScroll = DEFAULT_OVERLAY_SCROLLBAR_BEHAVIOR.dragScroll,
2220
2226
  clickScroll = DEFAULT_OVERLAY_SCROLLBAR_BEHAVIOR.clickScroll,
2227
+ overflowX = DEFAULT_OVERLAY_SCROLLBAR_BEHAVIOR.overflowX,
2228
+ overflowY = DEFAULT_OVERLAY_SCROLLBAR_BEHAVIOR.overflowY,
2221
2229
  exclude = DEFAULT_OVERLAY_SCROLLBAR_BEHAVIOR.exclude,
2222
2230
  selector,
2223
2231
  children
@@ -2231,9 +2239,11 @@ function OverlayScrollbarProvider({
2231
2239
  autoHideDelay,
2232
2240
  dragScroll,
2233
2241
  clickScroll,
2242
+ overflowX,
2243
+ overflowY,
2234
2244
  exclude
2235
2245
  }),
2236
- [enabled, theme, visibility, autoHide, autoHideDelay, dragScroll, clickScroll, exclude]
2246
+ [enabled, theme, visibility, autoHide, autoHideDelay, dragScroll, clickScroll, overflowX, overflowY, exclude]
2237
2247
  );
2238
2248
  void selector;
2239
2249
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(OverlayScrollbarConfigContext.Provider, { value, children: children ?? null });
@@ -2247,6 +2257,8 @@ function useOverlayScrollbarTarget(targetRef, options = {}) {
2247
2257
  const autoHideDelay = options.autoHideDelay ?? inherited.autoHideDelay;
2248
2258
  const dragScroll = options.dragScroll ?? inherited.dragScroll;
2249
2259
  const clickScroll = options.clickScroll ?? inherited.clickScroll;
2260
+ const overflowX = options.overflowX ?? inherited.overflowX;
2261
+ const overflowY = options.overflowY ?? inherited.overflowY;
2250
2262
  const exclude = options.exclude ?? inherited.exclude;
2251
2263
  const resolved = (0, import_react3.useMemo)(
2252
2264
  () => resolveOverlayScrollbarBehavior({
@@ -2257,9 +2269,11 @@ function useOverlayScrollbarTarget(targetRef, options = {}) {
2257
2269
  autoHideDelay,
2258
2270
  dragScroll,
2259
2271
  clickScroll,
2272
+ overflowX,
2273
+ overflowY,
2260
2274
  exclude
2261
2275
  }),
2262
- [enabled, theme, visibility, autoHide, autoHideDelay, dragScroll, clickScroll, exclude]
2276
+ [enabled, theme, visibility, autoHide, autoHideDelay, dragScroll, clickScroll, overflowX, overflowY, exclude]
2263
2277
  );
2264
2278
  (0, import_react3.useEffect)(() => {
2265
2279
  if (typeof window === "undefined") return;
@@ -2284,6 +2298,8 @@ function useOverlayScrollbarTarget(targetRef, options = {}) {
2284
2298
  resolved.autoHideDelay,
2285
2299
  resolved.dragScroll,
2286
2300
  resolved.clickScroll,
2301
+ resolved.overflowX,
2302
+ resolved.overflowY,
2287
2303
  resolved.exclude
2288
2304
  ]);
2289
2305
  }
@@ -9738,7 +9754,7 @@ function WheelColumn({
9738
9754
  ref: scrollRef,
9739
9755
  className: cn(
9740
9756
  "h-full overflow-y-auto overscroll-contain snap-y snap-mandatory",
9741
- "select-none cursor-grab active:cursor-grabbing",
9757
+ "select-none",
9742
9758
  "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-xl",
9743
9759
  "[scrollbar-width:none] [-ms-overflow-style:none]",
9744
9760
  "[&::-webkit-scrollbar]:hidden"
@@ -9749,15 +9765,7 @@ function WheelColumn({
9749
9765
  tabIndex: focused ? 0 : -1,
9750
9766
  onKeyDown: (e) => onKeyDown(e, column),
9751
9767
  onFocus: () => setFocusedColumn(column),
9752
- onScroll: () => {
9753
- if (draggingRef.current) return;
9754
- if (inertialRef.current) return;
9755
- handleScroll();
9756
- },
9757
- onPointerDown,
9758
- onPointerMove,
9759
- onPointerUp: (e) => endDrag(e.pointerId),
9760
- onPointerCancel: (e) => endDrag(e.pointerId),
9768
+ onScroll: handleScroll,
9761
9769
  children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { children: extendedItems.map((n, index) => {
9762
9770
  const dist = Math.abs(index - currentVirtual);
9763
9771
  const distForVisual = Math.min(dist, 2);
@@ -11220,7 +11228,7 @@ function WheelColumn2({
11220
11228
  ref: scrollRef,
11221
11229
  className: cn(
11222
11230
  "h-full overflow-y-auto overscroll-contain snap-y snap-mandatory",
11223
- "select-none cursor-grab active:cursor-grabbing",
11231
+ "select-none",
11224
11232
  "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-xl",
11225
11233
  "[scrollbar-width:none] [-ms-overflow-style:none]",
11226
11234
  "[&::-webkit-scrollbar]:hidden"
@@ -11231,15 +11239,7 @@ function WheelColumn2({
11231
11239
  tabIndex: focused ? 0 : -1,
11232
11240
  onKeyDown: (e) => onKeyDown(e, column),
11233
11241
  onFocus: () => setFocusedColumn(column),
11234
- onScroll: () => {
11235
- if (draggingRef.current) return;
11236
- if (inertialRef.current) return;
11237
- handleScroll();
11238
- },
11239
- onPointerDown,
11240
- onPointerMove,
11241
- onPointerUp: (e) => endDrag(e.pointerId),
11242
- onPointerCancel: (e) => endDrag(e.pointerId),
11242
+ onScroll: handleScroll,
11243
11243
  children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { children: extendedItems.map((n, index) => {
11244
11244
  const dist = Math.abs(index - currentVirtual);
11245
11245
  const distForVisual = Math.min(dist, 2);
@@ -11314,6 +11314,14 @@ function formatTime2({ h, m, s, p }, fmt, includeSeconds) {
11314
11314
  const base2 = `${pad(h)}:${pad(m)}`;
11315
11315
  return includeSeconds ? `${base2}:${pad(s)}` : base2;
11316
11316
  }
11317
+ function isCompleteTimeInput(input, fmt, includeSeconds) {
11318
+ const trimmed = input.trim().toUpperCase();
11319
+ if (!trimmed) return false;
11320
+ if (fmt === "12") {
11321
+ return includeSeconds ? /^\d{1,2}:\d{2}:\d{2}\s?(AM|PM)$/.test(trimmed) : /^\d{1,2}:\d{2}\s?(AM|PM)$/.test(trimmed);
11322
+ }
11323
+ return includeSeconds ? /^\d{1,2}:\d{2}:\d{2}$/.test(trimmed) : /^\d{1,2}:\d{2}$/.test(trimmed);
11324
+ }
11317
11325
  var PRESETS = {
11318
11326
  morning: { h: 9, m: 0, s: 0, icon: import_lucide_react18.Coffee, label: "Morning", color: "from-amber-400 to-orange-400" },
11319
11327
  afternoon: { h: 14, m: 0, s: 0, icon: import_lucide_react18.Sun, label: "Afternoon", color: "from-yellow-400 to-amber-400" },
@@ -11355,24 +11363,38 @@ function TimePicker({
11355
11363
  ...rest
11356
11364
  }) {
11357
11365
  const tv = useSmartTranslations("ValidationInput");
11366
+ const autoId = React31.useId();
11358
11367
  const isControlled = value !== void 0;
11359
11368
  const now = /* @__PURE__ */ new Date();
11360
11369
  const initial = parseTime(isControlled ? value : defaultValue, format, includeSeconds) || (format === "12" ? { h: now.getHours() % 12 || 12, m: now.getMinutes(), s: now.getSeconds(), p: now.getHours() >= 12 ? "PM" : "AM" } : { h: now.getHours(), m: now.getMinutes(), s: now.getSeconds() });
11361
11370
  const [open, setOpen] = React31.useState(false);
11362
11371
  const [parts, setParts] = React31.useState(initial);
11363
- const [manualInput, setManualInput] = React31.useState("");
11372
+ const [manualInput, setManualInput] = React31.useState(formatTime2(initial, format, includeSeconds));
11373
+ const [isDirectEditing, setIsDirectEditing] = React31.useState(false);
11364
11374
  const [focusedColumn, setFocusedColumn] = React31.useState(null);
11365
11375
  const [localRequiredError, setLocalRequiredError] = React31.useState();
11366
11376
  const [hasCommittedValue, setHasCommittedValue] = React31.useState(Boolean(isControlled ? value : defaultValue));
11367
11377
  const hourScrollRef = React31.useRef(null);
11368
11378
  const minuteScrollRef = React31.useRef(null);
11369
11379
  const secondScrollRef = React31.useRef(null);
11380
+ const periodRef = React31.useRef(null);
11381
+ const directEditInputRef = React31.useRef(null);
11382
+ const triggerId = `time-picker-trigger-${autoId}`;
11383
+ const labelId = label ? `time-picker-label-${autoId}` : void 0;
11370
11384
  React31.useEffect(() => {
11371
11385
  if (isControlled) {
11372
11386
  const parsed = parseTime(value, format, includeSeconds);
11373
11387
  if (parsed) setParts(parsed);
11374
11388
  }
11375
11389
  }, [value, isControlled, format, includeSeconds]);
11390
+ React31.useEffect(() => {
11391
+ setManualInput(formatTime2(parts, format, includeSeconds));
11392
+ }, [format, includeSeconds, parts]);
11393
+ React31.useEffect(() => {
11394
+ if (!isDirectEditing) return;
11395
+ directEditInputRef.current?.focus();
11396
+ directEditInputRef.current?.select();
11397
+ }, [isDirectEditing]);
11376
11398
  React31.useEffect(() => {
11377
11399
  if (isControlled) {
11378
11400
  setHasCommittedValue(Boolean(value));
@@ -11463,6 +11485,15 @@ function TimePicker({
11463
11485
  setLocalRequiredError(void 0);
11464
11486
  }
11465
11487
  }, [disabled, hasCommittedValue, required]);
11488
+ const focusColumn = React31.useCallback((column) => {
11489
+ if (!column) return;
11490
+ const target = column === "hour" ? hourScrollRef.current : column === "minute" ? minuteScrollRef.current : column === "second" ? secondScrollRef.current : periodRef.current;
11491
+ target?.focus({ preventScroll: true });
11492
+ }, []);
11493
+ React31.useEffect(() => {
11494
+ if (variant !== "inline" && !open) return;
11495
+ focusColumn(focusedColumn);
11496
+ }, [focusColumn, focusedColumn, open, variant]);
11466
11497
  const handleKeyDown2 = (e, column) => {
11467
11498
  if (!["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End", "PageUp", "PageDown"].includes(e.key)) return;
11468
11499
  e.preventDefault();
@@ -11506,6 +11537,7 @@ function TimePicker({
11506
11537
  }
11507
11538
  tryUpdate(newParts);
11508
11539
  };
11540
+ const display = formatTime2(parts, format, includeSeconds);
11509
11541
  const setNow = () => {
11510
11542
  const now2 = /* @__PURE__ */ new Date();
11511
11543
  const h = now2.getHours();
@@ -11531,6 +11563,7 @@ function TimePicker({
11531
11563
  };
11532
11564
  const handleManualInput = (input) => {
11533
11565
  setManualInput(input);
11566
+ if (!isCompleteTimeInput(input, format, includeSeconds)) return;
11534
11567
  const parsed = parseTime(input, format, includeSeconds);
11535
11568
  if (parsed) {
11536
11569
  const timeStr = formatTime2(parsed, format, includeSeconds);
@@ -11539,6 +11572,53 @@ function TimePicker({
11539
11572
  }
11540
11573
  }
11541
11574
  };
11575
+ const commitManualInput = React31.useCallback(
11576
+ (input) => {
11577
+ const trimmed = input.trim();
11578
+ if (!trimmed) {
11579
+ setManualInput(display);
11580
+ return false;
11581
+ }
11582
+ if (!isCompleteTimeInput(trimmed, format, includeSeconds)) {
11583
+ setManualInput(display);
11584
+ return false;
11585
+ }
11586
+ const parsed = parseTime(trimmed, format, includeSeconds);
11587
+ if (!parsed) {
11588
+ setManualInput(display);
11589
+ return false;
11590
+ }
11591
+ const timeStr = formatTime2(parsed, format, includeSeconds);
11592
+ if (!isTimeInRange(timeStr) || isTimeDisabled(timeStr)) {
11593
+ setManualInput(display);
11594
+ return false;
11595
+ }
11596
+ const updated = tryUpdate(parsed);
11597
+ if (!updated) {
11598
+ setManualInput(display);
11599
+ return false;
11600
+ }
11601
+ setManualInput(timeStr);
11602
+ return true;
11603
+ },
11604
+ [display, format, includeSeconds, isTimeDisabled, isTimeInRange, tryUpdate]
11605
+ );
11606
+ const startDirectEdit = React31.useCallback(() => {
11607
+ if (disabled) return;
11608
+ setManualInput(display);
11609
+ setIsDirectEditing(true);
11610
+ }, [disabled, display]);
11611
+ const stopDirectEdit = React31.useCallback(
11612
+ (mode) => {
11613
+ if (mode === "commit") {
11614
+ commitManualInput(manualInput);
11615
+ } else {
11616
+ setManualInput(display);
11617
+ }
11618
+ setIsDirectEditing(false);
11619
+ },
11620
+ [commitManualInput, display, manualInput]
11621
+ );
11542
11622
  const handleCustomPreset = (time) => {
11543
11623
  const parsed = parseTime(time, format, includeSeconds);
11544
11624
  if (parsed) {
@@ -11606,13 +11686,14 @@ function TimePicker({
11606
11686
  const shouldMatchTriggerWidth = matchTriggerWidth ?? variant !== "compact";
11607
11687
  const compactPanel = variant === "compact";
11608
11688
  const effectiveError = error ?? localRequiredError;
11609
- const display = formatTime2(parts, format, includeSeconds);
11610
11689
  const trigger = variant === "inline" ? null : /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
11611
11690
  "button",
11612
11691
  {
11692
+ id: triggerId,
11613
11693
  type: "button",
11614
11694
  disabled,
11615
11695
  "aria-label": "Select time",
11696
+ "aria-labelledby": labelId,
11616
11697
  "aria-haspopup": "dialog",
11617
11698
  "aria-expanded": open,
11618
11699
  "aria-required": required,
@@ -11649,10 +11730,10 @@ function TimePicker({
11649
11730
  {
11650
11731
  className: cn(
11651
11732
  "truncate font-medium transition-colors duration-200",
11652
- !value && !defaultValue && "text-muted-foreground",
11653
- value || defaultValue ? "text-foreground" : ""
11733
+ !hasCommittedValue && "text-muted-foreground",
11734
+ hasCommittedValue ? "text-foreground" : ""
11654
11735
  ),
11655
- children: value || defaultValue ? display : placeholder
11736
+ children: hasCommittedValue ? display : placeholder
11656
11737
  }
11657
11738
  )
11658
11739
  ] }),
@@ -11672,13 +11753,51 @@ function TimePicker({
11672
11753
  tryUpdate(next);
11673
11754
  };
11674
11755
  const timePickerContent = /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: cn(panelSz.stackGap, compactPanel && "space-y-2.5"), children: [
11675
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: cn("flex items-center justify-center py-1", compactPanel && "py-0.5"), children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: cn(panelSz.timeText, "font-bold tabular-nums tracking-wide text-foreground underline underline-offset-8 decoration-primary/60"), children: display }) }),
11756
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: cn("flex items-center justify-center py-1", compactPanel && "py-0.5"), children: isDirectEditing ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
11757
+ "input",
11758
+ {
11759
+ ref: directEditInputRef,
11760
+ type: "text",
11761
+ value: manualInput,
11762
+ onChange: (e) => setManualInput(e.target.value),
11763
+ onBlur: () => stopDirectEdit("commit"),
11764
+ onKeyDown: (e) => {
11765
+ if (e.key === "Enter") {
11766
+ e.preventDefault();
11767
+ stopDirectEdit("commit");
11768
+ }
11769
+ if (e.key === "Escape") {
11770
+ e.preventDefault();
11771
+ stopDirectEdit("cancel");
11772
+ }
11773
+ },
11774
+ "aria-label": "Edit time value",
11775
+ className: cn(
11776
+ panelSz.timeText,
11777
+ "min-w-0 w-36 bg-transparent border-b border-primary/60 text-center font-bold tabular-nums tracking-wide text-foreground",
11778
+ "focus:outline-none focus:border-primary"
11779
+ )
11780
+ }
11781
+ ) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
11782
+ "button",
11783
+ {
11784
+ type: "button",
11785
+ onClick: startDirectEdit,
11786
+ className: cn(
11787
+ panelSz.timeText,
11788
+ "font-bold tabular-nums tracking-wide text-foreground underline underline-offset-8 decoration-primary/60",
11789
+ "rounded-md px-2 transition-colors hover:text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
11790
+ ),
11791
+ "aria-label": "Edit selected time",
11792
+ children: display
11793
+ }
11794
+ ) }),
11676
11795
  allowManualInput && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "relative", children: [
11677
11796
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
11678
11797
  Input_default,
11679
11798
  {
11680
11799
  placeholder: format === "12" ? "02:30 PM" : "14:30",
11681
- value: manualInput || display,
11800
+ value: manualInput,
11682
11801
  onChange: (e) => handleManualInput(e.target.value),
11683
11802
  size: panelSz.inputSize,
11684
11803
  variant: "outlined",
@@ -11828,9 +11947,11 @@ function TimePicker({
11828
11947
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
11829
11948
  "div",
11830
11949
  {
11950
+ ref: periodRef,
11831
11951
  className: cn("flex flex-col p-1 rounded-xl bg-muted/30", panelSz.periodGap),
11832
11952
  role: "radiogroup",
11833
11953
  "aria-label": "Select AM or PM",
11954
+ "aria-labelledby": labelId,
11834
11955
  tabIndex: focusedColumn === "period" ? 0 : -1,
11835
11956
  onKeyDown: (e) => handleKeyDown2(e, "period"),
11836
11957
  onFocus: () => setFocusedColumn("period"),
@@ -11926,10 +12047,17 @@ function TimePicker({
11926
12047
  ] });
11927
12048
  if (variant === "inline") {
11928
12049
  return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "w-fit max-w-full", ...rest, children: [
11929
- label && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("label", { className: cn(sz.label, "font-semibold", disabled ? "text-muted-foreground" : "text-foreground", effectiveError && "text-destructive"), children: [
11930
- label,
11931
- required && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-destructive ml-1", children: "*" })
11932
- ] }) }),
12050
+ label && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
12051
+ "label",
12052
+ {
12053
+ id: labelId,
12054
+ className: cn(sz.label, "font-semibold", disabled ? "text-muted-foreground" : "text-foreground", effectiveError && "text-destructive"),
12055
+ children: [
12056
+ label,
12057
+ required && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-destructive ml-1", children: "*" })
12058
+ ]
12059
+ }
12060
+ ) }),
11933
12061
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
11934
12062
  "input",
11935
12063
  {
@@ -11966,6 +12094,8 @@ function TimePicker({
11966
12094
  label && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
11967
12095
  "label",
11968
12096
  {
12097
+ id: labelId,
12098
+ htmlFor: triggerId,
11969
12099
  className: cn(
11970
12100
  sz.label,
11971
12101
  "font-semibold",
@@ -20962,7 +21092,7 @@ var LoadingBar = ({
20962
21092
  // src/components/Table.tsx
20963
21093
  var import_react28 = __toESM(require("react"), 1);
20964
21094
  var import_jsx_runtime62 = require("react/jsx-runtime");
20965
- var TABLE_BASE_CLASS = "w-full caption-bottom text-sm";
21095
+ var TABLE_BASE_CLASS = "w-full border-collapse caption-bottom text-sm";
20966
21096
  var TABLE_CONTAINER_BASE_CLASS = [
20967
21097
  "relative w-full overflow-auto",
20968
21098
  "rounded-2xl md:rounded-3xl border border-border/50",
@@ -21397,6 +21527,7 @@ function DataTableHeader({
21397
21527
  const prevCol = prevCell?.column;
21398
21528
  const isAfterFixedLeft = prevCol?.fixed === "left";
21399
21529
  const showBorderLeft = columnDividers && cellIndex > 0 && !isAfterFixedLeft && !col.fixed;
21530
+ const isLastCell = cellIndex === row.length - 1;
21400
21531
  return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
21401
21532
  TableHead,
21402
21533
  {
@@ -21436,7 +21567,8 @@ function DataTableHeader({
21436
21567
  onAutoFitColumn?.(col.key);
21437
21568
  },
21438
21569
  className: cn(
21439
- "absolute inset-y-0 right-0 z-10 w-3 -mr-1",
21570
+ "absolute inset-y-0 right-0 z-10 w-3",
21571
+ !isLastCell && "-mr-1",
21440
21572
  "cursor-col-resize select-none bg-transparent",
21441
21573
  "after:absolute after:inset-y-2 after:right-0.8 after:w-px after:bg-border/0 after:transition-colors",
21442
21574
  "hover:after:bg-primary/50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary"
@@ -22207,6 +22339,7 @@ function DataTable({
22207
22339
  storageKey,
22208
22340
  stickyHeader = true,
22209
22341
  maxHeight = 500,
22342
+ horizontalMode = "auto",
22210
22343
  overflowHidden = true,
22211
22344
  useOverlayScrollbar = false,
22212
22345
  enableHeaderAutoFit = true,
@@ -22280,6 +22413,10 @@ function DataTable({
22280
22413
  total
22281
22414
  });
22282
22415
  const { getStickyCellClass, getStickyColumnStyle, getStickyHeaderClass, getStickyHeaderCellStyle } = useStickyColumns(visibleColumns);
22416
+ const shouldForceHorizontalScroll = horizontalMode === "scroll";
22417
+ const shouldUseFixedLayout = horizontalMode !== "auto";
22418
+ const viewportOverflowXClass = horizontalMode === "fit" ? "overflow-x-hidden" : "overflow-x-auto";
22419
+ const overlayOverflowX = horizontalMode === "fit" ? "hidden" : "scroll";
22283
22420
  const getRowKey = (row, idx) => {
22284
22421
  if (!rowKey) return String(idx);
22285
22422
  if (typeof rowKey === "function") return String(rowKey(row));
@@ -22287,7 +22424,10 @@ function DataTable({
22287
22424
  };
22288
22425
  const viewportRef = import_react38.default.useRef(null);
22289
22426
  const tableRef = import_react38.default.useRef(null);
22290
- useOverlayScrollbarTarget(viewportRef, { enabled: useOverlayScrollbar });
22427
+ useOverlayScrollbarTarget(viewportRef, {
22428
+ enabled: useOverlayScrollbar,
22429
+ overflowX: overlayOverflowX
22430
+ });
22291
22431
  const autoFitColumn = import_react38.default.useCallback((columnKey) => {
22292
22432
  const tableElement = tableRef.current;
22293
22433
  if (!tableElement) return;
@@ -22349,7 +22489,7 @@ function DataTable({
22349
22489
  "div",
22350
22490
  {
22351
22491
  ref: viewportRef,
22352
- className: cn("w-full overflow-x-auto", stickyHeader && "overflow-y-auto"),
22492
+ className: cn("w-full", viewportOverflowXClass, stickyHeader && "overflow-y-auto"),
22353
22493
  style: stickyHeader ? { maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight } : void 0,
22354
22494
  children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
22355
22495
  Table,
@@ -22357,10 +22497,10 @@ function DataTable({
22357
22497
  ref: tableRef,
22358
22498
  disableContainer: true,
22359
22499
  className: cn(
22360
- "table-fixed",
22500
+ shouldUseFixedLayout ? "table-fixed" : "table-auto",
22361
22501
  stickyHeader && ["[&_thead]:sticky", "[&_thead]:top-0", "[&_thead]:z-20", "[&_thead]:shadow-[0_1px_3px_rgba(0,0,0,0.1)]"]
22362
22502
  ),
22363
- style: { minWidth: totalColumnsWidth > 0 ? `${totalColumnsWidth}px` : void 0 },
22503
+ style: { minWidth: shouldForceHorizontalScroll && totalColumnsWidth > 0 ? `${totalColumnsWidth}px` : void 0 },
22364
22504
  children: [
22365
22505
  /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
22366
22506
  DataTableHeader,