@payglocal_ui/flux-ui 0.2.1 → 0.2.3

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.d.cts CHANGED
@@ -777,10 +777,31 @@ interface DataTableProps<T> {
777
777
  label: string;
778
778
  onClick?: (row: T) => void;
779
779
  };
780
+ /**
781
+ * Custom action revealed on row hover — typically a `<Button>` or
782
+ * `<ButtonGroup>`, but any `ReactNode` is accepted. Pass a **function** to
783
+ * render per-row: it receives `(row, index)`, so the action always has the
784
+ * record for its row (e.g. to navigate or open a drawer for that row).
785
+ *
786
+ * It is not a real column: it floats as an overlay **pinned to the right edge
787
+ * of the viewport**, so it stays in view as the table scrolls horizontally
788
+ * (no scrolling to the end to reach it) while the last data column stays
789
+ * flush with nothing trailing it. Takes precedence over `rowCta`.
790
+ */
791
+ rowAction?: ReactNode | ((row: T, index: number) => ReactNode);
780
792
  /** Row / cell vertical rhythm and horizontal gutters */
781
793
  density?: DataTableDensity;
782
- /** `auto` lets columns breathe; `fixed` uses `colgroup` hints */
783
- tableLayout?: "auto" | "fixed";
794
+ /**
795
+ * Column-sizing strategy:
796
+ * - `fixed` — widths come only from `colgroup` hints (`width`/`minWidth`/
797
+ * `maxWidth`); content is ignored and overflow is clipped. Table fills 100%.
798
+ * - `auto` — columns size to content but the table still fills 100%, so any
799
+ * leftover space is distributed into the columns (they stretch).
800
+ * - `content` — columns size to their content's intrinsic width and the table
801
+ * shrinks to fit. Leftover space stays empty to the right of the last
802
+ * column; it scrolls horizontally only once content exceeds the container.
803
+ */
804
+ tableLayout?: "auto" | "fixed" | "content";
784
805
  theadClassName?: string;
785
806
  headerStyle?: DataTableHeaderStyle;
786
807
  /** Footer: paginated range vs simple `n items` */
@@ -793,7 +814,7 @@ interface DataTableProps<T> {
793
814
  /** With `density="compact"`, use tighter cell gutters (`pl-1.5 pr-2.5` vs `px-3`). Footer keeps normal horizontal padding. */
794
815
  snug?: boolean;
795
816
  }
796
- declare function DataTable<T>({ columns, data, isLoading, skeletonRows, emptyTitle, emptyDescription, pageSize, page: controlledPage, onPageChange, totalRows, className, rowKey, rowCta, density, tableLayout, theadClassName, headerStyle, footerSummary, footerCountLabels, snug, }: DataTableProps<T>): React$1.JSX.Element;
817
+ declare function DataTable<T>({ columns, data, isLoading, skeletonRows, emptyTitle, emptyDescription, pageSize, page: controlledPage, onPageChange, totalRows, className, rowKey, rowCta, rowAction, density, tableLayout, theadClassName, headerStyle, footerSummary, footerCountLabels, snug, }: DataTableProps<T>): React$1.JSX.Element;
797
818
 
798
819
  interface EmptyStateProps {
799
820
  icon?: LucideIcon;
package/dist/index.d.ts CHANGED
@@ -777,10 +777,31 @@ interface DataTableProps<T> {
777
777
  label: string;
778
778
  onClick?: (row: T) => void;
779
779
  };
780
+ /**
781
+ * Custom action revealed on row hover — typically a `<Button>` or
782
+ * `<ButtonGroup>`, but any `ReactNode` is accepted. Pass a **function** to
783
+ * render per-row: it receives `(row, index)`, so the action always has the
784
+ * record for its row (e.g. to navigate or open a drawer for that row).
785
+ *
786
+ * It is not a real column: it floats as an overlay **pinned to the right edge
787
+ * of the viewport**, so it stays in view as the table scrolls horizontally
788
+ * (no scrolling to the end to reach it) while the last data column stays
789
+ * flush with nothing trailing it. Takes precedence over `rowCta`.
790
+ */
791
+ rowAction?: ReactNode | ((row: T, index: number) => ReactNode);
780
792
  /** Row / cell vertical rhythm and horizontal gutters */
781
793
  density?: DataTableDensity;
782
- /** `auto` lets columns breathe; `fixed` uses `colgroup` hints */
783
- tableLayout?: "auto" | "fixed";
794
+ /**
795
+ * Column-sizing strategy:
796
+ * - `fixed` — widths come only from `colgroup` hints (`width`/`minWidth`/
797
+ * `maxWidth`); content is ignored and overflow is clipped. Table fills 100%.
798
+ * - `auto` — columns size to content but the table still fills 100%, so any
799
+ * leftover space is distributed into the columns (they stretch).
800
+ * - `content` — columns size to their content's intrinsic width and the table
801
+ * shrinks to fit. Leftover space stays empty to the right of the last
802
+ * column; it scrolls horizontally only once content exceeds the container.
803
+ */
804
+ tableLayout?: "auto" | "fixed" | "content";
784
805
  theadClassName?: string;
785
806
  headerStyle?: DataTableHeaderStyle;
786
807
  /** Footer: paginated range vs simple `n items` */
@@ -793,7 +814,7 @@ interface DataTableProps<T> {
793
814
  /** With `density="compact"`, use tighter cell gutters (`pl-1.5 pr-2.5` vs `px-3`). Footer keeps normal horizontal padding. */
794
815
  snug?: boolean;
795
816
  }
796
- declare function DataTable<T>({ columns, data, isLoading, skeletonRows, emptyTitle, emptyDescription, pageSize, page: controlledPage, onPageChange, totalRows, className, rowKey, rowCta, density, tableLayout, theadClassName, headerStyle, footerSummary, footerCountLabels, snug, }: DataTableProps<T>): React$1.JSX.Element;
817
+ declare function DataTable<T>({ columns, data, isLoading, skeletonRows, emptyTitle, emptyDescription, pageSize, page: controlledPage, onPageChange, totalRows, className, rowKey, rowCta, rowAction, density, tableLayout, theadClassName, headerStyle, footerSummary, footerCountLabels, snug, }: DataTableProps<T>): React$1.JSX.Element;
797
818
 
798
819
  interface EmptyStateProps {
799
820
  icon?: LucideIcon;
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  // src/utils.ts
2
4
  import { clsx } from "clsx";
3
5
  import { twMerge } from "tailwind-merge";
@@ -3605,6 +3607,7 @@ function DataTable({
3605
3607
  className,
3606
3608
  rowKey,
3607
3609
  rowCta,
3610
+ rowAction,
3608
3611
  density = "default",
3609
3612
  tableLayout = "fixed",
3610
3613
  theadClassName,
@@ -3617,6 +3620,8 @@ function DataTable({
3617
3620
  const [internalPage, setInternalPage] = useState6(1);
3618
3621
  const page = isControlled ? controlledPage : internalPage;
3619
3622
  const setPage = isControlled ? (p) => onPageChange?.(p) : (p) => setInternalPage(p);
3623
+ const hasAction = rowAction != null || rowCta != null;
3624
+ const hasSpacer = tableLayout === "content";
3620
3625
  const total = totalRows ?? data.length;
3621
3626
  const totalPages = Math.ceil(total / pageSize);
3622
3627
  const paginated = isControlled ? data : data.slice((page - 1) * pageSize, page * pageSize);
@@ -3634,7 +3639,7 @@ function DataTable({
3634
3639
  const headPad = comfortable ? "px-5 py-4" : compactCellPad;
3635
3640
  const footerPad = comfortable ? "px-5 py-4" : compact ? "px-4 py-2.5" : "px-4 py-3.5";
3636
3641
  const headText = comfortable ? "text-[12px] font-medium text-muted-foreground tracking-normal" : compact ? "text-[11px] font-semibold text-muted-foreground" : "text-[11px] font-semibold text-foreground/75 dark:text-foreground/85";
3637
- const rowCtaColWidth = compact ? 108 : 130;
3642
+ const actionGutter = comfortable ? 20 : compact ? 12 : 16;
3638
3643
  return /* @__PURE__ */ jsxs30(
3639
3644
  "div",
3640
3645
  {
@@ -3657,7 +3662,13 @@ function DataTable({
3657
3662
  "table",
3658
3663
  {
3659
3664
  className: cn(tableLayout === "auto" && "min-w-[920px]"),
3660
- style: { tableLayout, width: "100%" },
3665
+ style: {
3666
+ // `content` uses the automatic algorithm but stays 100% wide; a
3667
+ // greedy spacer column (below) soaks up the slack so the data
3668
+ // columns collapse to their content width while the table fills.
3669
+ tableLayout: tableLayout === "fixed" ? "fixed" : "auto",
3670
+ width: "100%"
3671
+ },
3661
3672
  children: [
3662
3673
  tableLayout === "fixed" && /* @__PURE__ */ jsxs30("colgroup", { children: [
3663
3674
  columns.map((col) => /* @__PURE__ */ jsx49(
@@ -3671,7 +3682,7 @@ function DataTable({
3671
3682
  },
3672
3683
  col.key
3673
3684
  )),
3674
- rowCta ? /* @__PURE__ */ jsx49("col", { style: { width: rowCtaColWidth } }) : null
3685
+ hasAction ? /* @__PURE__ */ jsx49("col", { style: { width: 0 } }) : null
3675
3686
  ] }),
3676
3687
  /* @__PURE__ */ jsx49(
3677
3688
  "thead",
@@ -3703,7 +3714,8 @@ function DataTable({
3703
3714
  },
3704
3715
  col.key
3705
3716
  )),
3706
- rowCta ? /* @__PURE__ */ jsx49("th", { className: cn(headPad, "w-[1%]"), "aria-hidden": true }) : null
3717
+ hasSpacer ? /* @__PURE__ */ jsx49("th", { className: "w-full p-0", "aria-hidden": true }) : null,
3718
+ hasAction ? /* @__PURE__ */ jsx49("th", { className: "sticky right-0 z-[1] w-0 p-0", "aria-hidden": true }) : null
3707
3719
  ]
3708
3720
  }
3709
3721
  )
@@ -3712,12 +3724,12 @@ function DataTable({
3712
3724
  /* @__PURE__ */ jsx49("tbody", { children: isLoading ? Array.from({ length: skeletonRows }).map((_, i) => /* @__PURE__ */ jsx49(
3713
3725
  TableRowSkeleton,
3714
3726
  {
3715
- cols: columns.length + (rowCta ? 1 : 0),
3727
+ cols: columns.length,
3716
3728
  density,
3717
3729
  snug
3718
3730
  },
3719
3731
  i
3720
- )) : paginated.length === 0 ? /* @__PURE__ */ jsx49("tr", { children: /* @__PURE__ */ jsx49("td", { colSpan: columns.length + (rowCta ? 1 : 0), children: /* @__PURE__ */ jsx49(EmptyState, { title: emptyTitle, description: emptyDescription }) }) }) : paginated.map((row, i) => /* @__PURE__ */ jsxs30(
3732
+ )) : paginated.length === 0 ? /* @__PURE__ */ jsx49("tr", { children: /* @__PURE__ */ jsx49("td", { colSpan: columns.length + (hasSpacer ? 1 : 0) + (hasAction ? 1 : 0), children: /* @__PURE__ */ jsx49(EmptyState, { title: emptyTitle, description: emptyDescription }) }) }) : paginated.map((row, i) => /* @__PURE__ */ jsxs30(
3721
3733
  "tr",
3722
3734
  {
3723
3735
  className: cn(
@@ -3725,7 +3737,7 @@ function DataTable({
3725
3737
  comfortable && "min-h-[56px]",
3726
3738
  compact && "min-h-[44px]",
3727
3739
  "hover:bg-muted/40 dark:hover:bg-muted/25",
3728
- rowCta && "hover:shadow-[0_1px_0_rgba(0,0,0,0.04)] dark:hover:shadow-none"
3740
+ hasAction && "hover:shadow-[0_1px_0_rgba(0,0,0,0.04)] dark:hover:shadow-none"
3729
3741
  ),
3730
3742
  children: [
3731
3743
  columns.map((col) => /* @__PURE__ */ jsx49(
@@ -3749,27 +3761,32 @@ function DataTable({
3749
3761
  },
3750
3762
  col.key
3751
3763
  )),
3752
- rowCta ? /* @__PURE__ */ jsx49(
3753
- "td",
3754
- {
3755
- className: cn(
3756
- cellPad,
3757
- "text-left align-middle whitespace-nowrap",
3758
- comfortable ? "pl-2 pr-5" : compact ? snug ? "pl-1.5 pr-2" : "pl-1.5 pr-3" : "pl-3 pr-4"
3759
- ),
3760
- children: /* @__PURE__ */ jsx49(
3761
- "button",
3762
- {
3763
- type: "button",
3764
- onClick: () => rowCta.onClick?.(row),
3765
- className: cn(
3766
- "opacity-0 group-hover:opacity-100 transition-opacity duration-150 inline-flex items-center font-medium text-foreground bg-card rounded-lg border border-border hover:border-muted-foreground/50 whitespace-nowrap shadow-sm",
3767
- compact ? "px-2.5 py-1 text-[11px]" : "px-3 py-1.5 text-[12px]"
3768
- ),
3769
- children: rowCta.label
3770
- }
3771
- )
3772
- }
3764
+ hasSpacer ? /* @__PURE__ */ jsx49("td", { className: "p-0", "aria-hidden": true }) : null,
3765
+ hasAction ? (
3766
+ // Zero-width sticky cell pinned to the right edge of the
3767
+ // viewport. Its children are positioned absolutely so they
3768
+ // float over the row (out of the 0-width cell) — the action
3769
+ // stays in view while scrolling and nothing trails the last
3770
+ // data column. Everything is revealed on hover only.
3771
+ /* @__PURE__ */ jsx49("td", { className: "sticky right-0 z-[1] w-0 p-0 align-middle", children: /* @__PURE__ */ jsx49(
3772
+ "span",
3773
+ {
3774
+ className: "absolute top-1/2 -translate-y-1/2 z-[1] inline-flex items-center opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100",
3775
+ style: { right: actionGutter },
3776
+ children: rowAction != null ? typeof rowAction === "function" ? rowAction(row, i) : rowAction : /* @__PURE__ */ jsx49(
3777
+ "button",
3778
+ {
3779
+ type: "button",
3780
+ onClick: () => rowCta?.onClick?.(row),
3781
+ className: cn(
3782
+ "inline-flex items-center font-medium text-foreground bg-card rounded-lg border border-border hover:border-muted-foreground/50 whitespace-nowrap shadow-sm",
3783
+ compact ? "px-2.5 py-1 text-[11px]" : "px-3 py-1.5 text-[12px]"
3784
+ ),
3785
+ children: rowCta?.label
3786
+ }
3787
+ )
3788
+ }
3789
+ ) })
3773
3790
  ) : null
3774
3791
  ]
3775
3792
  },