@underverse-ui/underverse 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2262,7 +2262,7 @@ var sizeStyles3 = {
2262
2262
  md: "max-w-md",
2263
2263
  lg: "max-w-lg",
2264
2264
  xl: "max-w-xl",
2265
- full: "max-w-full mx-4"
2265
+ full: "max-w-full"
2266
2266
  };
2267
2267
  var Modal = ({
2268
2268
  isOpen,
@@ -2271,11 +2271,14 @@ var Modal = ({
2271
2271
  title,
2272
2272
  description,
2273
2273
  className,
2274
+ contentClassName,
2274
2275
  overlayClassName,
2275
2276
  showCloseButton = true,
2276
2277
  closeOnOverlayClick = true,
2277
2278
  closeOnEsc = true,
2278
- size = "md"
2279
+ size = "md",
2280
+ noPadding = false,
2281
+ fullWidth = false
2279
2282
  }) => {
2280
2283
  const [isMounted, setIsMounted] = React9.useState(false);
2281
2284
  const [isVisible, setIsVisible] = React9.useState(false);
@@ -2343,7 +2346,8 @@ var Modal = ({
2343
2346
  className: cn(
2344
2347
  "relative w-full rounded-lg bg-card text-card-foreground shadow-xl",
2345
2348
  "transition-all duration-200 ease-out",
2346
- sizeStyles3[size],
2349
+ fullWidth ? "max-w-full" : sizeStyles3[size],
2350
+ fullWidth && "mx-0",
2347
2351
  className
2348
2352
  ),
2349
2353
  style: {
@@ -2372,7 +2376,7 @@ var Modal = ({
2372
2376
  }
2373
2377
  )
2374
2378
  ] }),
2375
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "p-6", children })
2379
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("p-6", noPadding && "p-0", contentClassName), children })
2376
2380
  ]
2377
2381
  }
2378
2382
  )
@@ -4027,7 +4031,9 @@ var Combobox = ({
4027
4031
  usePortal = true,
4028
4032
  label,
4029
4033
  required,
4030
- fontBold = false
4034
+ fontBold = false,
4035
+ loading: loading2 = false,
4036
+ loadingText = "Loading..."
4031
4037
  }) => {
4032
4038
  const [open, setOpen] = React18.useState(false);
4033
4039
  const [query, setQuery] = React18.useState("");
@@ -4045,6 +4051,7 @@ var Combobox = ({
4045
4051
  );
4046
4052
  const [dropdownPosition, setDropdownPosition] = React18.useState(null);
4047
4053
  const triggerRef = React18.useRef(null);
4054
+ const dropdownRef = React18.useRef(null);
4048
4055
  const calculatePosition = React18.useCallback(() => {
4049
4056
  if (!triggerRef.current) return null;
4050
4057
  const rect = triggerRef.current.getBoundingClientRect();
@@ -4073,11 +4080,10 @@ var Combobox = ({
4073
4080
  if (!open) return;
4074
4081
  const handleClickOutside = (event) => {
4075
4082
  const target = event.target;
4076
- if (triggerRef.current && !triggerRef.current.contains(target)) {
4077
- const dropdown = document.querySelector("[data-combobox-dropdown]");
4078
- if (dropdown && !dropdown.contains(target)) {
4079
- setOpen(false);
4080
- }
4083
+ const triggerEl = triggerRef.current;
4084
+ const dropdownEl = dropdownRef.current;
4085
+ if (triggerEl && !triggerEl.contains(target) && dropdownEl && !dropdownEl.contains(target)) {
4086
+ setOpen(false);
4081
4087
  }
4082
4088
  };
4083
4089
  const handleEscape = (event) => {
@@ -4121,6 +4127,7 @@ var Combobox = ({
4121
4127
  "div",
4122
4128
  {
4123
4129
  "data-combobox-dropdown": true,
4130
+ ref: dropdownRef,
4124
4131
  style: {
4125
4132
  position: "absolute",
4126
4133
  top: dropdownPosition?.top || 0,
@@ -4178,7 +4185,10 @@ var Combobox = ({
4178
4185
  }
4179
4186
  )
4180
4187
  ] }),
4181
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "max-h-64 overflow-y-auto overscroll-contain", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ul", { className: "p-1 space-y-1", children: filteredOptions.length > 0 ? filteredOptions.map((item, index) => {
4188
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "max-h-64 overflow-y-auto overscroll-contain", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ul", { className: "p-1 space-y-1", children: loading2 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { className: "px-3 py-8 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col items-center gap-2 animate-in fade-in-0 zoom-in-95 duration-300", children: [
4189
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Loader2, { className: "h-6 w-6 animate-spin text-primary" }),
4190
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-sm text-muted-foreground", children: loadingText || "Loading..." })
4191
+ ] }) }) : filteredOptions.length > 0 ? filteredOptions.map((item, index) => {
4182
4192
  const itemValue = getOptionValue(item);
4183
4193
  const itemLabel = getOptionLabel(item);
4184
4194
  const isSelected = itemValue === value;
@@ -4212,9 +4222,18 @@ var Combobox = ({
4212
4222
  },
4213
4223
  `${itemValue}-${index}`
4214
4224
  );
4215
- }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { className: "px-3 py-8 text-center text-muted-foreground text-sm", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col items-center gap-2", children: [
4216
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Search, { className: "h-6 w-6 opacity-50" }),
4217
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: emptyText })
4225
+ }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { className: "px-3 py-8 text-center text-muted-foreground text-sm", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col items-center gap-2 animate-in fade-in-0 zoom-in-95 duration-300", children: [
4226
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.SearchX, { className: "h-8 w-8 opacity-40 text-muted-foreground" }),
4227
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-sm", children: emptyText }),
4228
+ query && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4229
+ "button",
4230
+ {
4231
+ type: "button",
4232
+ onClick: () => setQuery(""),
4233
+ className: "text-xs text-primary hover:underline",
4234
+ children: "Clear search"
4235
+ }
4236
+ )
4218
4237
  ] }) }) }) })
4219
4238
  ] })
4220
4239
  }
@@ -4290,7 +4309,15 @@ var Combobox = ({
4290
4309
  children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.X, { className: "h-3 w-3" })
4291
4310
  }
4292
4311
  ),
4293
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.ChevronDown, { className: cn("h-4 w-4 text-muted-foreground transition-transform duration-200", open && "rotate-180") })
4312
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4313
+ import_lucide_react12.ChevronDown,
4314
+ {
4315
+ className: cn(
4316
+ "h-4 w-4 text-muted-foreground transition-all duration-200",
4317
+ open && "rotate-180 scale-110 text-primary"
4318
+ )
4319
+ }
4320
+ )
4294
4321
  ] })
4295
4322
  ]
4296
4323
  }
@@ -6217,7 +6244,10 @@ var MultiCombobox = ({
6217
6244
  label,
6218
6245
  title,
6219
6246
  required,
6220
- displayFormat = (option) => option.label
6247
+ displayFormat = (option) => option.label,
6248
+ loading: loading2 = false,
6249
+ loadingText = "Loading...",
6250
+ emptyText = "No results found"
6221
6251
  }) => {
6222
6252
  const [query, setQuery] = React24.useState("");
6223
6253
  const [open, setOpen] = React24.useState(false);
@@ -6226,6 +6256,7 @@ var MultiCombobox = ({
6226
6256
  const listRef = React24.useRef([]);
6227
6257
  const [dropdownPosition, setDropdownPosition] = React24.useState(null);
6228
6258
  const triggerRef = React24.useRef(null);
6259
+ const dropdownRef = React24.useRef(null);
6229
6260
  useShadCNAnimations();
6230
6261
  const calculatePosition = React24.useCallback(() => {
6231
6262
  if (!triggerRef.current) return null;
@@ -6255,11 +6286,10 @@ var MultiCombobox = ({
6255
6286
  if (!open) return;
6256
6287
  const handleClickOutside = (event) => {
6257
6288
  const target = event.target;
6258
- if (triggerRef.current && !triggerRef.current.contains(target)) {
6259
- const dropdown = document.querySelector('[data-dropdown="multicombobox"]');
6260
- if (dropdown && !dropdown.contains(target)) {
6261
- setOpen(false);
6262
- }
6289
+ const triggerEl = triggerRef.current;
6290
+ const dropdownEl = dropdownRef.current;
6291
+ if (triggerEl && !triggerEl.contains(target) && dropdownEl && !dropdownEl.contains(target)) {
6292
+ setOpen(false);
6263
6293
  }
6264
6294
  };
6265
6295
  const handleEscape = (event) => {
@@ -6428,7 +6458,12 @@ var MultiCombobox = ({
6428
6458
  value.length,
6429
6459
  " selected"
6430
6460
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "text-muted-foreground", children: placeholder || "Select..." }) }),
6431
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react17.ChevronDown, { className: cn("opacity-50 transition-transform", sizeStyles8[size].icon, open && "rotate-180") })
6461
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
6462
+ import_lucide_react17.ChevronDown,
6463
+ {
6464
+ className: cn("opacity-50 transition-all duration-200", sizeStyles8[size].icon, open && "rotate-180 scale-110 text-primary opacity-100")
6465
+ }
6466
+ )
6432
6467
  ]
6433
6468
  }
6434
6469
  ),
@@ -6436,6 +6471,7 @@ var MultiCombobox = ({
6436
6471
  /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
6437
6472
  "div",
6438
6473
  {
6474
+ ref: dropdownRef,
6439
6475
  "data-dropdown": "multicombobox",
6440
6476
  style: {
6441
6477
  position: "absolute",
@@ -6453,10 +6489,7 @@ var MultiCombobox = ({
6453
6489
  children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
6454
6490
  "div",
6455
6491
  {
6456
- className: cn(
6457
- "rounded-md border bg-popover text-popover-foreground shadow-md",
6458
- "backdrop-blur-sm bg-popover/95 border-border/60"
6459
- ),
6492
+ className: cn("rounded-md border bg-popover text-popover-foreground shadow-md", "backdrop-blur-sm bg-popover/95 border-border/60"),
6460
6493
  children: [
6461
6494
  showClear && value.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-3 py-2 border-b border-border/60 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
6462
6495
  "button",
@@ -6488,7 +6521,10 @@ var MultiCombobox = ({
6488
6521
  }
6489
6522
  )
6490
6523
  ] }),
6491
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { className: cn("max-h-60 overflow-y-auto p-1", size === "lg" ? "text-base" : size === "sm" ? "text-xs" : "text-sm"), children: filtered.length ? filtered.map((item, index) => {
6524
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { className: cn("max-h-60 overflow-y-auto p-1", size === "lg" ? "text-base" : size === "sm" ? "text-xs" : "text-sm"), children: loading2 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("li", { className: "px-3 py-8 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col items-center gap-2 animate-in fade-in-0 zoom-in-95 duration-300", children: [
6525
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react17.Loader2, { className: "h-6 w-6 animate-spin text-primary" }),
6526
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "text-muted-foreground", children: loadingText })
6527
+ ] }) }) : filtered.length ? filtered.map((item, index) => {
6492
6528
  const isSelected = value.includes(item.value);
6493
6529
  const isDisabled = disabledOptions.includes(item.value);
6494
6530
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
@@ -6520,7 +6556,20 @@ var MultiCombobox = ({
6520
6556
  },
6521
6557
  item.value
6522
6558
  );
6523
- }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("li", { className: cn("px-3 py-2 text-muted-foreground", size === "lg" ? "text-base" : size === "sm" ? "text-xs" : "text-sm"), children: "No result." }) })
6559
+ }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
6560
+ "li",
6561
+ {
6562
+ className: cn(
6563
+ "px-3 py-8 text-center text-muted-foreground",
6564
+ size === "lg" ? "text-base" : size === "sm" ? "text-xs" : "text-sm"
6565
+ ),
6566
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col items-center gap-2 animate-in fade-in-0 zoom-in-95 duration-300", children: [
6567
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react17.SearchX, { className: "h-8 w-8 opacity-40 text-muted-foreground" }),
6568
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: emptyText }),
6569
+ query && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { type: "button", onClick: () => setQuery(""), className: "text-xs text-primary hover:underline", children: "Clear search" })
6570
+ ] })
6571
+ }
6572
+ ) })
6524
6573
  ]
6525
6574
  }
6526
6575
  )
@@ -10190,11 +10239,44 @@ function DataTable({
10190
10239
  col.key
10191
10240
  )) });
10192
10241
  const isServerMode = Boolean(onQueryChange);
10242
+ const processedData = import_react23.default.useMemo(() => {
10243
+ if (isServerMode) return data;
10244
+ let result = [...data];
10245
+ if (Object.keys(filters).length > 0) {
10246
+ result = result.filter((row) => {
10247
+ return Object.entries(filters).every(([key, value]) => {
10248
+ if (value === void 0 || value === null || value === "") return true;
10249
+ const col = columns.find((c) => c.key === key);
10250
+ const rowValue = col?.dataIndex ? row[col.dataIndex] : row[key];
10251
+ if (col?.filter?.type === "date" && value instanceof Date) {
10252
+ return new Date(rowValue).toDateString() === value.toDateString();
10253
+ }
10254
+ return String(rowValue ?? "").toLowerCase().includes(String(value).toLowerCase());
10255
+ });
10256
+ });
10257
+ }
10258
+ if (sort) {
10259
+ result.sort((a, b) => {
10260
+ const col = columns.find((c) => c.key === sort.key);
10261
+ const aValue = col?.dataIndex ? a[col.dataIndex] : a[sort.key];
10262
+ const bValue = col?.dataIndex ? b[col.dataIndex] : b[sort.key];
10263
+ if (aValue === bValue) return 0;
10264
+ if (typeof aValue === "number" && typeof bValue === "number") {
10265
+ return sort.order === "asc" ? aValue - bValue : bValue - aValue;
10266
+ }
10267
+ const compare = String(aValue).localeCompare(String(bValue));
10268
+ return sort.order === "asc" ? compare : -compare;
10269
+ });
10270
+ }
10271
+ return result;
10272
+ }, [data, isServerMode, filters, sort, columns]);
10273
+ const totalItems = isServerMode ? total : processedData.length;
10193
10274
  const displayedData = isServerMode ? data : import_react23.default.useMemo(() => {
10194
10275
  const start = (curPage - 1) * curPageSize;
10195
- return data.slice(start, start + curPageSize);
10196
- }, [data, curPage, curPageSize]);
10197
- const totalItems = isServerMode ? total : data.length;
10276
+ if (start >= processedData.length && curPage > 1) {
10277
+ }
10278
+ return processedData.slice(start, start + curPageSize);
10279
+ }, [processedData, curPage, curPageSize]);
10198
10280
  return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: cn("space-y-2", className), children: [
10199
10281
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex items-center justify-between gap-4 mb-1", children: [
10200
10282
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "text-sm text-muted-foreground", children: caption }),
@@ -10266,24 +10348,27 @@ function DataTable({
10266
10348
  )
10267
10349
  ] }),
10268
10350
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-sm", children: "Loading..." })
10269
- ] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(TableCell, { colSpan: visibleColumns.length, className: "text-center py-6 text-muted-foreground", children: "No data" }) }) : displayedData.map((row, idx) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(TableRow, { className: cn(densityRowClass, striped && idx % 2 === 0 && "bg-muted/30"), children: visibleColumns.map((col, colIdx) => {
10270
- const value = col.dataIndex ? row[col.dataIndex] : void 0;
10271
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
10272
- TableCell,
10273
- {
10274
- className: cn(
10275
- cellPadding,
10276
- col.align === "right" && "text-right",
10277
- col.align === "center" && "text-center",
10278
- columnDividers && colIdx > 0 && "border-l border-border/60",
10279
- idx === data.length - 1 && col === visibleColumns[0] && "rounded-bl-md",
10280
- idx === data.length - 1 && col === visibleColumns[visibleColumns.length - 1] && "rounded-br-md"
10281
- ),
10282
- children: col.render ? col.render(value, row, idx) : String(value ?? "")
10283
- },
10284
- col.key
10285
- );
10286
- }) }, getRowKey(row, idx))) })
10351
+ ] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(TableCell, { colSpan: visibleColumns.length, className: "text-center py-6 text-muted-foreground", children: "No data" }) }) : displayedData.map((row, idx) => {
10352
+ const isLastRow = idx === displayedData.length - 1;
10353
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(TableRow, { className: cn(densityRowClass, striped && idx % 2 === 0 && "bg-muted/30"), children: visibleColumns.map((col, colIdx) => {
10354
+ const value = col.dataIndex ? row[col.dataIndex] : void 0;
10355
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
10356
+ TableCell,
10357
+ {
10358
+ className: cn(
10359
+ cellPadding,
10360
+ col.align === "right" && "text-right",
10361
+ col.align === "center" && "text-center",
10362
+ columnDividers && colIdx > 0 && "border-l border-border/60",
10363
+ isLastRow && col === visibleColumns[0] && "rounded-bl-md",
10364
+ isLastRow && col === visibleColumns[visibleColumns.length - 1] && "rounded-br-md"
10365
+ ),
10366
+ children: col.render ? col.render(value, row, idx) : String(value ?? "")
10367
+ },
10368
+ col.key
10369
+ );
10370
+ }) }, getRowKey(row, idx));
10371
+ }) })
10287
10372
  ]
10288
10373
  }
10289
10374
  ) }),