@dimaan/ui 0.0.30 → 0.0.31

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
@@ -905,7 +905,7 @@ var badgeDotSizeClass = {
905
905
  md: "size-2"
906
906
  };
907
907
  var badgeBaseClass = "inline-flex shrink-0 items-center rounded-full border font-medium leading-none whitespace-nowrap select-none transition-colors";
908
- var Badge = react.forwardRef(function Badge2({ variant = "default", size = "md", tone = "solid", dot = false, className, children, ...props }, ref) {
908
+ var Badge = react.forwardRef(function Badge2({ variant = "default", size = "md", tone = "soft", dot = false, className, children, ...props }, ref) {
909
909
  const variantClass = tone === "soft" ? badgeSoftVariantClass[variant] : badgeVariantClass[variant];
910
910
  return /* @__PURE__ */ jsxRuntime.jsxs(
911
911
  "span",
@@ -2321,9 +2321,9 @@ function Pagination({
2321
2321
  children: isRtl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { "aria-hidden": "true", className: "size-3.5" })
2322
2322
  }
2323
2323
  ),
2324
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 text-foreground", children: [
2325
- pageIndex + 1,
2326
- " / ",
2324
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex min-w-7 items-center justify-center rounded-lg bg-gradient-table px-2.5 py-0.5 text-xs font-semibold text-white", children: pageIndex + 1 }),
2325
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-0.5 text-muted-foreground", children: [
2326
+ "/ ",
2327
2327
  pageCount
2328
2328
  ] }),
2329
2329
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2348,7 +2348,7 @@ function Toolbar({ count, onClear, renderLabel, clearLabel, children }) {
2348
2348
  {
2349
2349
  role: "toolbar",
2350
2350
  "aria-label": "Bulk actions",
2351
- className: "flex flex-wrap items-center gap-3 rounded-md border border-border bg-muted/40 px-3 py-2 text-sm",
2351
+ className: "flex flex-wrap items-center gap-3 rounded-xl border border-border bg-muted/50 px-3.5 py-2.5 text-sm shadow-[var(--shadow-xs)]",
2352
2352
  children: [
2353
2353
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: renderLabel ? renderLabel(count) : `${count} selected` }),
2354
2354
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ms-auto flex flex-wrap items-center gap-2", children: [
@@ -2364,18 +2364,18 @@ function Toolbar({ count, onClear, renderLabel, clearLabel, children }) {
2364
2364
  var tableSizeClass = {
2365
2365
  sm: {
2366
2366
  row: "",
2367
- cell: "px-3 py-1.5 text-xs tabular-nums",
2368
- head: "whitespace-nowrap px-3 py-2 text-xs font-medium"
2367
+ cell: "px-3 py-2 text-xs tabular-nums",
2368
+ head: "whitespace-nowrap px-3 py-3 text-[11px] font-semibold uppercase tracking-wider"
2369
2369
  },
2370
2370
  md: {
2371
2371
  row: "",
2372
- cell: "px-4 py-2.5 text-sm tabular-nums",
2373
- head: "whitespace-nowrap px-4 py-2.5 text-xs font-medium uppercase tracking-wide"
2372
+ cell: "px-4 py-3.5 text-sm tabular-nums",
2373
+ head: "whitespace-nowrap px-4 py-4 text-xs font-semibold uppercase tracking-wider"
2374
2374
  },
2375
2375
  lg: {
2376
2376
  row: "",
2377
- cell: "px-5 py-3.5 text-sm tabular-nums",
2378
- head: "whitespace-nowrap px-5 py-3 text-sm font-medium"
2377
+ cell: "px-6 py-4 text-sm tabular-nums",
2378
+ head: "whitespace-nowrap px-6 py-5 text-[13px] font-semibold uppercase tracking-wider"
2379
2379
  }
2380
2380
  };
2381
2381
  var tableBaseClass = "w-full caption-bottom border-collapse";
@@ -2432,6 +2432,7 @@ function Table(props) {
2432
2432
  maxHeight,
2433
2433
  striped = false,
2434
2434
  onRowClick,
2435
+ getRowAccent,
2435
2436
  tableRef,
2436
2437
  pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,
2437
2438
  showPagination,
@@ -2503,166 +2504,198 @@ function Table(props) {
2503
2504
  children: bulkActions(selectedRowsInData)
2504
2505
  }
2505
2506
  ),
2506
- /* @__PURE__ */ jsxRuntime.jsx(
2507
- "div",
2508
- {
2509
- className: cn(
2510
- "overflow-x-auto rounded-xl border border-border bg-card shadow-[var(--shadow-card)]",
2511
- maxHeight !== void 0 && "overflow-y-auto"
2512
- ),
2513
- style: maxHeight !== void 0 ? { maxHeight } : void 0,
2514
- children: /* @__PURE__ */ jsxRuntime.jsxs(
2515
- "table",
2516
- {
2517
- ref: tableRef,
2518
- "aria-label": ariaLabel,
2519
- "aria-labelledby": ariaLabelledBy,
2520
- "aria-rowcount": totalRowCount,
2521
- className: cn(tableBaseClass, "text-sm text-foreground", tableClassName),
2522
- children: [
2523
- caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
2524
- /* @__PURE__ */ jsxRuntime.jsx(
2525
- "thead",
2526
- {
2527
- className: cn(
2528
- // Clean opaque header (so a sticky header fully hides the rows
2529
- // scrolling underneath it) with a hairline bottom rule drawn via an
2530
- // inset shadow — it stays attached to the sticky header instead of
2531
- // collapsing into the first row's border.
2532
- "bg-card text-muted-foreground shadow-[inset_0_-1px_0_var(--color-border)]",
2533
- maxHeight !== void 0 && "sticky top-0 z-10"
2534
- ),
2535
- children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2536
- enableRowSelection ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: cn("w-10", sizeClasses.head), children: /* @__PURE__ */ jsxRuntime.jsx(
2537
- Checkbox,
2538
- {
2539
- "aria-label": "Select all rows on this page",
2540
- checked: allOnPageSelected,
2541
- indeterminate: someOnPageSelected,
2542
- disabled: selectableRowIds.length === 0,
2543
- onCheckedChange: toggleHeader
2544
- }
2545
- ) }) : null,
2546
- columns.map((column) => {
2547
- const isSorted = effectiveSort.columnId === column.id;
2548
- const ariaSort = isSorted ? effectiveSort.direction === "asc" ? "ascending" : "descending" : "none";
2549
- return /* @__PURE__ */ jsxRuntime.jsx(
2550
- "th",
2551
- {
2552
- scope: "col",
2553
- "aria-sort": column.sortable ? ariaSort : void 0,
2554
- className: cn(
2555
- sizeClasses.head,
2556
- alignClass[column.align ?? "start"],
2557
- column.className
2558
- ),
2559
- children: column.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
2560
- "button",
2561
- {
2562
- type: "button",
2563
- onClick: () => handleSortClick(column.id),
2564
- className: "inline-flex items-center gap-1.5 font-inherit uppercase tracking-inherit text-inherit hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
2565
- "aria-label": sortAriaLabel(column, effectiveSort),
2566
- children: [
2567
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: renderHeader(column.header) }),
2568
- /* @__PURE__ */ jsxRuntime.jsx(
2569
- SortIndicator,
2570
- {
2571
- active: isSorted,
2572
- direction: isSorted ? effectiveSort.direction : null
2573
- }
2574
- )
2575
- ]
2576
- }
2577
- ) : renderHeader(column.header)
2578
- },
2579
- column.id
2580
- );
2581
- })
2582
- ] })
2583
- }
2584
- ),
2585
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: loading ? /* @__PURE__ */ jsxRuntime.jsx(
2586
- SkeletonRows,
2587
- {
2588
- rowCount: skeletonCount,
2589
- columnCount: totalColumnCount,
2590
- cellClassName: sizeClasses.cell
2591
- }
2592
- ) : data.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
2593
- "td",
2594
- {
2595
- colSpan: totalColumnCount,
2596
- className: cn(sizeClasses.cell, "py-10 text-center text-muted-foreground"),
2597
- children: emptyState ?? "No data"
2598
- }
2599
- ) }) : data.map((row, rowIndex) => {
2600
- const id = getRowId(row, rowIndex);
2601
- const isSelected = selected.has(id);
2602
- const rowSelectable = isRowSelectable ? isRowSelectable(row) : true;
2603
- return /* @__PURE__ */ jsxRuntime.jsxs(
2604
- "tr",
2507
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative overflow-hidden rounded-xl border border-border bg-card shadow-[var(--shadow-card)]", children: [
2508
+ /* @__PURE__ */ jsxRuntime.jsx(
2509
+ "span",
2510
+ {
2511
+ "aria-hidden": "true",
2512
+ "data-testid": "table-accent",
2513
+ className: "pointer-events-none absolute inset-x-0 top-0 z-20 h-[3px] bg-gradient-table"
2514
+ }
2515
+ ),
2516
+ /* @__PURE__ */ jsxRuntime.jsx(
2517
+ "div",
2518
+ {
2519
+ className: cn("overflow-x-auto", maxHeight !== void 0 && "overflow-y-auto"),
2520
+ style: maxHeight !== void 0 ? { maxHeight } : void 0,
2521
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
2522
+ "table",
2523
+ {
2524
+ ref: tableRef,
2525
+ "aria-label": ariaLabel,
2526
+ "aria-labelledby": ariaLabelledBy,
2527
+ "aria-rowcount": totalRowCount,
2528
+ className: cn(tableBaseClass, "text-sm text-foreground", tableClassName),
2529
+ children: [
2530
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
2531
+ /* @__PURE__ */ jsxRuntime.jsx(
2532
+ "thead",
2605
2533
  {
2606
- "data-selected": isSelected ? "true" : void 0,
2607
- "aria-selected": enableRowSelection ? isSelected : void 0,
2608
2534
  className: cn(
2609
- "border-t border-border/60 first:border-t-0 transition-colors",
2610
- "hover:bg-primary/5",
2611
- striped && rowIndex % 2 === 1 && "bg-muted/20",
2612
- isSelected && selectedRowClass,
2613
- onRowClick && "cursor-pointer"
2535
+ // Clean opaque header (so a sticky header fully hides the rows
2536
+ // scrolling underneath it) with a hairline bottom rule drawn via an
2537
+ // inset shadow it stays attached to the sticky header instead of
2538
+ // collapsing into the first row's border.
2539
+ // Opaque header background so a sticky header fully hides the rows
2540
+ // scrolling underneath it (a translucent tint would let them bleed through).
2541
+ "bg-muted text-muted-foreground shadow-[inset_0_-1px_0_var(--color-border)]",
2542
+ maxHeight !== void 0 && "sticky top-0 z-10"
2614
2543
  ),
2615
- onClick: onRowClick ? () => onRowClick(row, rowIndex) : void 0,
2616
- children: [
2617
- enableRowSelection ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: cn(sizeClasses.cell, "w-10"), children: /* @__PURE__ */ jsxRuntime.jsx(
2544
+ children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2545
+ enableRowSelection ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: cn("w-10", sizeClasses.head), children: /* @__PURE__ */ jsxRuntime.jsx(
2618
2546
  Checkbox,
2619
2547
  {
2620
- "aria-label": `Select row ${rowIndex + 1}`,
2621
- checked: isSelected,
2622
- disabled: !rowSelectable,
2623
- onCheckedChange: (next) => toggleRow(id, next),
2624
- onClick: stopRowClickPropagation
2548
+ "aria-label": "Select all rows on this page",
2549
+ checked: allOnPageSelected,
2550
+ indeterminate: someOnPageSelected,
2551
+ disabled: selectableRowIds.length === 0,
2552
+ onCheckedChange: toggleHeader
2625
2553
  }
2626
2554
  ) }) : null,
2627
- columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(
2628
- "td",
2629
- {
2630
- className: cn(
2631
- sizeClasses.cell,
2632
- alignClass[column.align ?? "start"],
2633
- column.className
2634
- ),
2635
- children: renderCell(column, row, rowIndex)
2636
- },
2637
- column.id
2638
- ))
2639
- ]
2640
- },
2641
- id
2642
- );
2643
- }) })
2644
- ]
2645
- }
2646
- )
2647
- }
2648
- ),
2649
- paginationVisible ? /* @__PURE__ */ jsxRuntime.jsx(
2650
- Pagination,
2651
- {
2652
- pageIndex,
2653
- pageSize,
2654
- pageCount,
2655
- totalRowCount,
2656
- pageSizeOptions,
2657
- onChange: handlePaginationChange,
2658
- labels
2659
- }
2660
- ) : null
2555
+ columns.map((column) => {
2556
+ const isSorted = effectiveSort.columnId === column.id;
2557
+ const ariaSort = isSorted ? effectiveSort.direction === "asc" ? "ascending" : "descending" : "none";
2558
+ return /* @__PURE__ */ jsxRuntime.jsx(
2559
+ "th",
2560
+ {
2561
+ scope: "col",
2562
+ "aria-sort": column.sortable ? ariaSort : void 0,
2563
+ className: cn(
2564
+ sizeClasses.head,
2565
+ alignClass[column.align ?? "start"],
2566
+ column.className,
2567
+ isSorted && "text-primary"
2568
+ ),
2569
+ children: column.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
2570
+ "button",
2571
+ {
2572
+ type: "button",
2573
+ onClick: () => handleSortClick(column.id),
2574
+ className: "inline-flex items-center gap-1.5 font-inherit uppercase tracking-inherit text-inherit hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
2575
+ "aria-label": sortAriaLabel(column, effectiveSort),
2576
+ children: [
2577
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: renderHeader(column.header) }),
2578
+ /* @__PURE__ */ jsxRuntime.jsx(
2579
+ SortIndicator,
2580
+ {
2581
+ active: isSorted,
2582
+ direction: isSorted ? effectiveSort.direction : null
2583
+ }
2584
+ )
2585
+ ]
2586
+ }
2587
+ ) : renderHeader(column.header)
2588
+ },
2589
+ column.id
2590
+ );
2591
+ })
2592
+ ] })
2593
+ }
2594
+ ),
2595
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: loading ? /* @__PURE__ */ jsxRuntime.jsx(
2596
+ SkeletonRows,
2597
+ {
2598
+ rowCount: skeletonCount,
2599
+ columnCount: totalColumnCount,
2600
+ cellClassName: sizeClasses.cell
2601
+ }
2602
+ ) : data.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
2603
+ "td",
2604
+ {
2605
+ colSpan: totalColumnCount,
2606
+ className: cn(sizeClasses.cell, "py-10 text-center text-muted-foreground"),
2607
+ children: emptyState ?? "No data"
2608
+ }
2609
+ ) }) : data.map((row, rowIndex) => {
2610
+ const id = getRowId(row, rowIndex);
2611
+ const isSelected = selected.has(id);
2612
+ const rowSelectable = isRowSelectable ? isRowSelectable(row) : true;
2613
+ const accent = getRowAccent?.(row, rowIndex);
2614
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2615
+ "tr",
2616
+ {
2617
+ "data-selected": isSelected ? "true" : void 0,
2618
+ "aria-selected": enableRowSelection ? isSelected : void 0,
2619
+ className: cn(
2620
+ "border-b border-border/60 last:border-b-0 transition-colors",
2621
+ "hover:bg-muted/60",
2622
+ striped && rowIndex % 2 === 1 && "bg-muted/20",
2623
+ isSelected && selectedRowClass,
2624
+ onRowClick && "cursor-pointer"
2625
+ ),
2626
+ onClick: onRowClick ? () => onRowClick(row, rowIndex) : void 0,
2627
+ children: [
2628
+ enableRowSelection ? /* @__PURE__ */ jsxRuntime.jsxs("td", { className: cn(sizeClasses.cell, "relative w-10"), children: [
2629
+ accent ? /* @__PURE__ */ jsxRuntime.jsx(RowAccent, { color: accent }) : null,
2630
+ /* @__PURE__ */ jsxRuntime.jsx(
2631
+ Checkbox,
2632
+ {
2633
+ "aria-label": `Select row ${rowIndex + 1}`,
2634
+ checked: isSelected,
2635
+ disabled: !rowSelectable,
2636
+ onCheckedChange: (next) => toggleRow(id, next),
2637
+ onClick: stopRowClickPropagation
2638
+ }
2639
+ )
2640
+ ] }) : null,
2641
+ columns.map((column, colIndex) => {
2642
+ const isFirst = colIndex === 0 && !enableRowSelection;
2643
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2644
+ "td",
2645
+ {
2646
+ className: cn(
2647
+ sizeClasses.cell,
2648
+ alignClass[column.align ?? "start"],
2649
+ column.className,
2650
+ isFirst && "relative"
2651
+ ),
2652
+ children: [
2653
+ isFirst && accent ? /* @__PURE__ */ jsxRuntime.jsx(RowAccent, { color: accent }) : null,
2654
+ renderCell(column, row, rowIndex)
2655
+ ]
2656
+ },
2657
+ column.id
2658
+ );
2659
+ })
2660
+ ]
2661
+ },
2662
+ id
2663
+ );
2664
+ }) })
2665
+ ]
2666
+ }
2667
+ )
2668
+ }
2669
+ ),
2670
+ paginationVisible ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
2671
+ Pagination,
2672
+ {
2673
+ pageIndex,
2674
+ pageSize,
2675
+ pageCount,
2676
+ totalRowCount,
2677
+ pageSizeOptions,
2678
+ onChange: handlePaginationChange,
2679
+ labels
2680
+ }
2681
+ ) }) : null
2682
+ ] })
2661
2683
  ] });
2662
2684
  }
2663
2685
  function renderHeader(header) {
2664
2686
  return typeof header === "function" ? header() : header;
2665
2687
  }
2688
+ function RowAccent({ color }) {
2689
+ return /* @__PURE__ */ jsxRuntime.jsx(
2690
+ "span",
2691
+ {
2692
+ "aria-hidden": "true",
2693
+ "data-testid": "row-accent",
2694
+ className: "pointer-events-none absolute inset-y-1 start-0 w-[3px] rounded-full",
2695
+ style: { background: color }
2696
+ }
2697
+ );
2698
+ }
2666
2699
  function renderCell(column, row, rowIndex) {
2667
2700
  if (column.render) return column.render(row, rowIndex);
2668
2701
  if (column.accessor !== void 0) {
@@ -2687,10 +2720,18 @@ function stopRowClickPropagation(event) {
2687
2720
  function SkeletonRows({ rowCount, columnCount, cellClassName }) {
2688
2721
  const rowKeys = Array.from({ length: Math.max(0, rowCount) }, (_, i) => `skeleton-row-${i}`);
2689
2722
  const colKeys = Array.from({ length: Math.max(1, columnCount) }, (_, i) => `skeleton-col-${i}`);
2690
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: rowKeys.map((rowKey) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "border-t border-border", "data-testid": "table-skeleton-row", children: colKeys.map((colKey) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: cellClassName, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block h-3 w-full animate-pulse rounded bg-muted" }) }, `${rowKey}-${colKey}`)) }, rowKey)) });
2723
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: rowKeys.map((rowKey) => /* @__PURE__ */ jsxRuntime.jsx(
2724
+ "tr",
2725
+ {
2726
+ className: "border-b border-border/60 last:border-b-0",
2727
+ "data-testid": "table-skeleton-row",
2728
+ children: colKeys.map((colKey) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: cellClassName, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block h-3 w-full animate-pulse rounded bg-muted" }) }, `${rowKey}-${colKey}`))
2729
+ },
2730
+ rowKey
2731
+ )) });
2691
2732
  }
2692
2733
  function SortIndicator({ active, direction }) {
2693
- const className = cn("size-3.5 shrink-0", active ? "text-foreground" : "text-muted-foreground");
2734
+ const className = cn("size-3.5 shrink-0", active ? "text-primary" : "text-muted-foreground");
2694
2735
  if (!active) return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { "aria-hidden": "true", className });
2695
2736
  return direction === "asc" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { "aria-hidden": "true", className }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": "true", className });
2696
2737
  }