@payglocal_ui/flux-ui 0.2.1 → 0.2.2

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
@@ -3605,6 +3605,7 @@ function DataTable({
3605
3605
  className,
3606
3606
  rowKey,
3607
3607
  rowCta,
3608
+ rowAction,
3608
3609
  density = "default",
3609
3610
  tableLayout = "fixed",
3610
3611
  theadClassName,
@@ -3617,6 +3618,8 @@ function DataTable({
3617
3618
  const [internalPage, setInternalPage] = useState6(1);
3618
3619
  const page = isControlled ? controlledPage : internalPage;
3619
3620
  const setPage = isControlled ? (p) => onPageChange?.(p) : (p) => setInternalPage(p);
3621
+ const hasAction = rowAction != null || rowCta != null;
3622
+ const hasSpacer = tableLayout === "content";
3620
3623
  const total = totalRows ?? data.length;
3621
3624
  const totalPages = Math.ceil(total / pageSize);
3622
3625
  const paginated = isControlled ? data : data.slice((page - 1) * pageSize, page * pageSize);
@@ -3634,7 +3637,7 @@ function DataTable({
3634
3637
  const headPad = comfortable ? "px-5 py-4" : compactCellPad;
3635
3638
  const footerPad = comfortable ? "px-5 py-4" : compact ? "px-4 py-2.5" : "px-4 py-3.5";
3636
3639
  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;
3640
+ const actionGutter = comfortable ? 20 : compact ? 12 : 16;
3638
3641
  return /* @__PURE__ */ jsxs30(
3639
3642
  "div",
3640
3643
  {
@@ -3657,7 +3660,13 @@ function DataTable({
3657
3660
  "table",
3658
3661
  {
3659
3662
  className: cn(tableLayout === "auto" && "min-w-[920px]"),
3660
- style: { tableLayout, width: "100%" },
3663
+ style: {
3664
+ // `content` uses the automatic algorithm but stays 100% wide; a
3665
+ // greedy spacer column (below) soaks up the slack so the data
3666
+ // columns collapse to their content width while the table fills.
3667
+ tableLayout: tableLayout === "fixed" ? "fixed" : "auto",
3668
+ width: "100%"
3669
+ },
3661
3670
  children: [
3662
3671
  tableLayout === "fixed" && /* @__PURE__ */ jsxs30("colgroup", { children: [
3663
3672
  columns.map((col) => /* @__PURE__ */ jsx49(
@@ -3671,7 +3680,7 @@ function DataTable({
3671
3680
  },
3672
3681
  col.key
3673
3682
  )),
3674
- rowCta ? /* @__PURE__ */ jsx49("col", { style: { width: rowCtaColWidth } }) : null
3683
+ hasAction ? /* @__PURE__ */ jsx49("col", { style: { width: 0 } }) : null
3675
3684
  ] }),
3676
3685
  /* @__PURE__ */ jsx49(
3677
3686
  "thead",
@@ -3703,7 +3712,8 @@ function DataTable({
3703
3712
  },
3704
3713
  col.key
3705
3714
  )),
3706
- rowCta ? /* @__PURE__ */ jsx49("th", { className: cn(headPad, "w-[1%]"), "aria-hidden": true }) : null
3715
+ hasSpacer ? /* @__PURE__ */ jsx49("th", { className: "w-full p-0", "aria-hidden": true }) : null,
3716
+ hasAction ? /* @__PURE__ */ jsx49("th", { className: "sticky right-0 z-[1] w-0 p-0", "aria-hidden": true }) : null
3707
3717
  ]
3708
3718
  }
3709
3719
  )
@@ -3712,12 +3722,12 @@ function DataTable({
3712
3722
  /* @__PURE__ */ jsx49("tbody", { children: isLoading ? Array.from({ length: skeletonRows }).map((_, i) => /* @__PURE__ */ jsx49(
3713
3723
  TableRowSkeleton,
3714
3724
  {
3715
- cols: columns.length + (rowCta ? 1 : 0),
3725
+ cols: columns.length,
3716
3726
  density,
3717
3727
  snug
3718
3728
  },
3719
3729
  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(
3730
+ )) : 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
3731
  "tr",
3722
3732
  {
3723
3733
  className: cn(
@@ -3725,7 +3735,7 @@ function DataTable({
3725
3735
  comfortable && "min-h-[56px]",
3726
3736
  compact && "min-h-[44px]",
3727
3737
  "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"
3738
+ hasAction && "hover:shadow-[0_1px_0_rgba(0,0,0,0.04)] dark:hover:shadow-none"
3729
3739
  ),
3730
3740
  children: [
3731
3741
  columns.map((col) => /* @__PURE__ */ jsx49(
@@ -3749,27 +3759,32 @@ function DataTable({
3749
3759
  },
3750
3760
  col.key
3751
3761
  )),
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
- }
3762
+ hasSpacer ? /* @__PURE__ */ jsx49("td", { className: "p-0", "aria-hidden": true }) : null,
3763
+ hasAction ? (
3764
+ // Zero-width sticky cell pinned to the right edge of the
3765
+ // viewport. Its children are positioned absolutely so they
3766
+ // float over the row (out of the 0-width cell) — the action
3767
+ // stays in view while scrolling and nothing trails the last
3768
+ // data column. Everything is revealed on hover only.
3769
+ /* @__PURE__ */ jsx49("td", { className: "sticky right-0 z-[1] w-0 p-0 align-middle", children: /* @__PURE__ */ jsx49(
3770
+ "span",
3771
+ {
3772
+ 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",
3773
+ style: { right: actionGutter },
3774
+ children: rowAction != null ? typeof rowAction === "function" ? rowAction(row, i) : rowAction : /* @__PURE__ */ jsx49(
3775
+ "button",
3776
+ {
3777
+ type: "button",
3778
+ onClick: () => rowCta?.onClick?.(row),
3779
+ className: cn(
3780
+ "inline-flex items-center font-medium text-foreground bg-card rounded-lg border border-border hover:border-muted-foreground/50 whitespace-nowrap shadow-sm",
3781
+ compact ? "px-2.5 py-1 text-[11px]" : "px-3 py-1.5 text-[12px]"
3782
+ ),
3783
+ children: rowCta?.label
3784
+ }
3785
+ )
3786
+ }
3787
+ ) })
3773
3788
  ) : null
3774
3789
  ]
3775
3790
  },