twico-ui 1.12.0 → 1.13.0

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
@@ -1946,8 +1946,12 @@ interface DatatableColumn<T = any> {
1946
1946
  headerName?: string;
1947
1947
  /** Data type. "actions" renders per-row action buttons via getActions. @default "string" */
1948
1948
  type?: "string" | "number" | "actions";
1949
- /** Column width in px. @default 160 (120 for actions) */
1950
- width?: number;
1949
+ /** Column width: a px number, or `"auto"` to size to the header's intrinsic width (chrome + label) so a short column fits without truncating or wasting the 160px default. @default 160 (120 for actions) */
1950
+ width?: number | "auto";
1951
+ /** Lower bound (px) for the resolved width, incl. `"auto"` and user resizes. */
1952
+ minWidth?: number;
1953
+ /** Upper bound (px) for the resolved width; `minWidth` wins if they conflict. */
1954
+ maxWidth?: number;
1951
1955
  /** Cell alignment; currently affects the actions column's button justification. @default "right" for number/actions columns, else "left" */
1952
1956
  align?: "left" | "right";
1953
1957
  /** Allow sorting this column. @default true */
@@ -1966,6 +1970,8 @@ interface DatatableColumn<T = any> {
1966
1970
  resizable?: boolean;
1967
1971
  /** Allow drag / menu / keyboard reorder of this column (independent of the table-wide `disableColumnReorder`). @default true */
1968
1972
  reorderable?: boolean;
1973
+ /** Offer the "Wrap text" / "Unwrap text" item in the ⋮ menu. Set `false` for a fixed single-token column (e.g. an ordinal) whose menu should show only Sort + Hide. @default true */
1974
+ wrappable?: boolean;
1969
1975
  /** Summary-footer aggregation: a preset, or a function over the column's values. */
1970
1976
  aggregation?: "sum" | "avg" | "min" | "max" | "count" | ((values: any[], rows: T[]) => React.ReactNode);
1971
1977
  /** Format an aggregation result for the footer (falls back to valueFormatter). */
@@ -2130,6 +2136,8 @@ interface CardGridProps<Row = any> extends Omit<React.HTMLAttributes<HTMLDivElem
2130
2136
  onSortChange?: (sort: CardGridSort | null) => void;
2131
2137
  /** Fields offered by the built-in sort control (renders it when provided). */
2132
2138
  sortOptions?: CardGridSortOption[];
2139
+ /** Min width (px or CSS length) for the built-in sort control's trigger, so long option labels aren't clipped. Defaults to an estimate from the longest label. */
2140
+ sortMinWidth?: string | number;
2133
2141
  /** Extra node rendered in the toolbar row (before the sort control). */
2134
2142
  toolbar?: React.ReactNode;
2135
2143
  /** Shown when there are no rows and not loading. @default "No results." */
package/dist/index.d.ts CHANGED
@@ -1946,8 +1946,12 @@ interface DatatableColumn<T = any> {
1946
1946
  headerName?: string;
1947
1947
  /** Data type. "actions" renders per-row action buttons via getActions. @default "string" */
1948
1948
  type?: "string" | "number" | "actions";
1949
- /** Column width in px. @default 160 (120 for actions) */
1950
- width?: number;
1949
+ /** Column width: a px number, or `"auto"` to size to the header's intrinsic width (chrome + label) so a short column fits without truncating or wasting the 160px default. @default 160 (120 for actions) */
1950
+ width?: number | "auto";
1951
+ /** Lower bound (px) for the resolved width, incl. `"auto"` and user resizes. */
1952
+ minWidth?: number;
1953
+ /** Upper bound (px) for the resolved width; `minWidth` wins if they conflict. */
1954
+ maxWidth?: number;
1951
1955
  /** Cell alignment; currently affects the actions column's button justification. @default "right" for number/actions columns, else "left" */
1952
1956
  align?: "left" | "right";
1953
1957
  /** Allow sorting this column. @default true */
@@ -1966,6 +1970,8 @@ interface DatatableColumn<T = any> {
1966
1970
  resizable?: boolean;
1967
1971
  /** Allow drag / menu / keyboard reorder of this column (independent of the table-wide `disableColumnReorder`). @default true */
1968
1972
  reorderable?: boolean;
1973
+ /** Offer the "Wrap text" / "Unwrap text" item in the ⋮ menu. Set `false` for a fixed single-token column (e.g. an ordinal) whose menu should show only Sort + Hide. @default true */
1974
+ wrappable?: boolean;
1969
1975
  /** Summary-footer aggregation: a preset, or a function over the column's values. */
1970
1976
  aggregation?: "sum" | "avg" | "min" | "max" | "count" | ((values: any[], rows: T[]) => React.ReactNode);
1971
1977
  /** Format an aggregation result for the footer (falls back to valueFormatter). */
@@ -2130,6 +2136,8 @@ interface CardGridProps<Row = any> extends Omit<React.HTMLAttributes<HTMLDivElem
2130
2136
  onSortChange?: (sort: CardGridSort | null) => void;
2131
2137
  /** Fields offered by the built-in sort control (renders it when provided). */
2132
2138
  sortOptions?: CardGridSortOption[];
2139
+ /** Min width (px or CSS length) for the built-in sort control's trigger, so long option labels aren't clipped. Defaults to an estimate from the longest label. */
2140
+ sortMinWidth?: string | number;
2133
2141
  /** Extra node rendered in the toolbar row (before the sort control). */
2134
2142
  toolbar?: React.ReactNode;
2135
2143
  /** Shown when there are no rows and not loading. @default "No results." */
package/dist/index.mjs CHANGED
@@ -9003,7 +9003,19 @@ function Datatable({
9003
9003
  rowGroupingKeyRef.current = rowGroupingKey;
9004
9004
  setGroupBy(rowGrouping || []);
9005
9005
  }, [rowGroupingKey]);
9006
- const widthOf = (c) => widths[c.field] ?? c.width ?? 160;
9006
+ const AUTO_CHROME = 74;
9007
+ const autoWidth = (c) => {
9008
+ const label = typeof c.headerName === "string" ? c.headerName : String(c.field ?? "");
9009
+ return AUTO_CHROME + Math.ceil(label.length * 8);
9010
+ };
9011
+ const clampWidth = (w, c) => {
9012
+ let x = w;
9013
+ if (typeof c.maxWidth === "number") x = Math.min(x, c.maxWidth);
9014
+ if (typeof c.minWidth === "number") x = Math.max(x, c.minWidth);
9015
+ return Math.max(40, x);
9016
+ };
9017
+ const intrinsicWidth = (c) => c.width === "auto" ? autoWidth(c) : typeof c.width === "number" ? c.width : 160;
9018
+ const widthOf = (c) => clampWidth(widths[c.field] ?? intrinsicWidth(c), c);
9007
9019
  const [colMenu, setColMenu] = React51__default.useState(null);
9008
9020
  const [menuPos, openMenu, closeMenu] = useFloating();
9009
9021
  const [panel, setPanel] = React51__default.useState(null);
@@ -10591,7 +10603,7 @@ function Datatable({
10591
10603
  e.preventDefault();
10592
10604
  e.stopPropagation();
10593
10605
  const delta = e.key === "ArrowRight" ? 10 : -10;
10594
- setWidths((m) => ({ ...m, [c.field]: Math.max(72, (m[c.field] ?? c.width ?? 160) + delta) }));
10606
+ setWidths((m) => ({ ...m, [c.field]: Math.max(72, (m[c.field] ?? intrinsicWidth(c)) + delta) }));
10595
10607
  },
10596
10608
  title: "Drag to resize \xB7 double-click to fit content"
10597
10609
  }
@@ -10834,10 +10846,10 @@ function Datatable({
10834
10846
  " ",
10835
10847
  groupBy.includes(c.field) ? "Stop grouping" : "Group by this column"
10836
10848
  ] }) : null,
10837
- !disableColumnReorder && c.type !== "actions" && !pins.left.includes(c.field) && !pins.right.includes(c.field) ? (() => {
10849
+ !disableColumnReorder && c.reorderable !== false && c.type !== "actions" && !pins.left.includes(c.field) && !pins.right.includes(c.field) && movableMidFields.length > 1 ? (() => {
10838
10850
  const midIdx = movableMidFields.indexOf(c.field);
10839
- const atFirst = midIdx <= 0;
10840
- const atLast = midIdx === -1 || midIdx >= movableMidFields.length - 1;
10851
+ const atFirst = midIdx === 0;
10852
+ const atLast = midIdx === movableMidFields.length - 1;
10841
10853
  return /* @__PURE__ */ jsxs(Fragment, { children: [
10842
10854
  /* @__PURE__ */ jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", disabled: atFirst, "aria-disabled": atFirst || void 0, onClick: () => {
10843
10855
  moveCol(c.field, -1);
@@ -10873,7 +10885,7 @@ function Datatable({
10873
10885
  pins.right.includes(c.field) ? "Unpin" : "Pin to right"
10874
10886
  ] })
10875
10887
  ] }) : null,
10876
- c.type !== "actions" ? /* @__PURE__ */ jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", "data-active": wrapped.has(c.field) || void 0, onClick: () => {
10888
+ c.type !== "actions" && c.wrappable !== false ? /* @__PURE__ */ jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", "data-active": wrapped.has(c.field) || void 0, onClick: () => {
10877
10889
  toggleWrap(c.field);
10878
10890
  close();
10879
10891
  }, children: [
@@ -11377,7 +11389,7 @@ var CARDGRID_CSS = `
11377
11389
  .twc-cardgrid__toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
11378
11390
  .twc-cardgrid__search { flex: 1 1 200px; min-width: 160px; }
11379
11391
  .twc-cardgrid__spacer { flex: 1 1 auto; }
11380
- .twc-cardgrid__sort { display: inline-flex; align-items: center; gap: var(--space-1); }
11392
+ .twc-cardgrid__sort { display: inline-flex; align-items: center; gap: var(--space-1); flex: none; }
11381
11393
  .twc-cardgrid__dir { display: inline-grid; place-items: center; width: 32px; height: 32px; border: var(--border-thin) solid var(--color-border); background: var(--color-surface); color: var(--color-text-muted); cursor: pointer; border-radius: var(--radius-md); transition: background-color var(--duration-fast), color var(--duration-fast); }
11382
11394
  .twc-cardgrid__dir:hover { background: var(--color-surface-sunken); color: var(--color-text); }
11383
11395
  .twc-cardgrid__dir svg { width: 16px; height: 16px; transition: transform var(--duration-fast) var(--ease-standard); }
@@ -11425,6 +11437,7 @@ function CardGrid({
11425
11437
  defaultSort = null,
11426
11438
  onSortChange,
11427
11439
  sortOptions,
11440
+ sortMinWidth,
11428
11441
  // slots / states
11429
11442
  toolbar,
11430
11443
  emptyState = "No results.",
@@ -11496,6 +11509,8 @@ function CardGrid({
11496
11509
  const to = paginated ? Math.min((pageVal + 1) * sizeVal, total) : total;
11497
11510
  const rppOptions = Array.from(new Set([...pageSizeOptions || [], pageSize].filter((n) => n > 0))).sort((a, b) => a - b).map((n) => ({ value: String(n), label: String(n) }));
11498
11511
  const sortSelectOptions = sortOptions ? [{ value: "", label: "Sort by\u2026" }, ...sortOptions.map((o) => ({ value: o.field, label: o.label || o.field }))] : null;
11512
+ const sortAutoWidth = sortSelectOptions ? Math.min(300, Math.max(120, Math.ceil(Math.max(...sortSelectOptions.map((o) => String(o.label).length)) * 7.2) + 46)) : void 0;
11513
+ const sortWidth = sortMinWidth != null ? sortMinWidth : sortAutoWidth;
11499
11514
  const hasToolbar = searchable || sortSelectOptions || toolbar;
11500
11515
  return /* @__PURE__ */ jsxs("div", { className: `twc-cardgrid ${className}`, id: fieldId, ...rest, children: [
11501
11516
  styles,
@@ -11523,6 +11538,7 @@ function CardGrid({
11523
11538
  value: sortVal?.field || "",
11524
11539
  options: sortSelectOptions,
11525
11540
  placeholder: "Sort by\u2026",
11541
+ style: { minWidth: sortWidth },
11526
11542
  "aria-label": "Sort by",
11527
11543
  onChange: (field) => commitSort(field ? { field, dir: sortVal?.dir || "asc" } : null)
11528
11544
  }