@open-mercato/ui 0.7.1-develop.7191.1.3c9346566b → 0.7.1-develop.7194.1.ab4fc81f82

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.
Files changed (58) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/backend/AppShell.js +66 -7
  3. package/dist/backend/AppShell.js.map +2 -2
  4. package/dist/backend/CrudForm.js +14 -8
  5. package/dist/backend/CrudForm.js.map +2 -2
  6. package/dist/backend/DataTable.js +167 -24
  7. package/dist/backend/DataTable.js.map +2 -2
  8. package/dist/backend/PerspectiveSidebar.js +60 -21
  9. package/dist/backend/PerspectiveSidebar.js.map +2 -2
  10. package/dist/backend/forms/ActionsDropdown.js +35 -5
  11. package/dist/backend/forms/ActionsDropdown.js.map +2 -2
  12. package/dist/backend/forms/index.js.map +2 -2
  13. package/dist/backend/icons/lucideRegistry.generated.js +6 -0
  14. package/dist/backend/icons/lucideRegistry.generated.js.map +2 -2
  15. package/dist/backend/injection/spotIds.js +2 -0
  16. package/dist/backend/injection/spotIds.js.map +2 -2
  17. package/dist/backend/inputs/DurationInput.js +182 -0
  18. package/dist/backend/inputs/DurationInput.js.map +7 -0
  19. package/dist/backend/inputs/EventSelect.js.map +2 -2
  20. package/dist/backend/inputs/index.js +1 -0
  21. package/dist/backend/inputs/index.js.map +2 -2
  22. package/dist/backend/nav/navBadges.js +38 -0
  23. package/dist/backend/nav/navBadges.js.map +7 -0
  24. package/dist/backend/views/NewViewForm.js +46 -38
  25. package/dist/backend/views/NewViewForm.js.map +2 -2
  26. package/dist/primitives/segmented-control.js +4 -4
  27. package/dist/primitives/segmented-control.js.map +1 -1
  28. package/dist/primitives/sheet.js +21 -11
  29. package/dist/primitives/sheet.js.map +2 -2
  30. package/dist/primitives/textarea.js +54 -4
  31. package/dist/primitives/textarea.js.map +2 -2
  32. package/package.json +3 -3
  33. package/src/backend/AppShell.tsx +106 -2
  34. package/src/backend/CrudForm.tsx +28 -9
  35. package/src/backend/DataTable.tsx +293 -36
  36. package/src/backend/PerspectiveSidebar.tsx +80 -21
  37. package/src/backend/__tests__/CrudForm.density.test.tsx +113 -0
  38. package/src/backend/__tests__/DataTable.exportSectionTitles.test.tsx +134 -0
  39. package/src/backend/__tests__/DataTable.perspectiveReconcile.test.tsx +312 -0
  40. package/src/backend/__tests__/DataTable.propBulkActions.test.tsx +200 -0
  41. package/src/backend/__tests__/DataTable.render.test.tsx +76 -0
  42. package/src/backend/__tests__/PerspectiveSidebar.roleAutosave.test.tsx +252 -0
  43. package/src/backend/__tests__/navBadges.test.ts +57 -0
  44. package/src/backend/forms/ActionsDropdown.tsx +73 -6
  45. package/src/backend/forms/index.ts +1 -1
  46. package/src/backend/icons/lucideRegistry.generated.tsx +6 -0
  47. package/src/backend/injection/spotIds.ts +8 -0
  48. package/src/backend/inputs/DurationInput.tsx +207 -0
  49. package/src/backend/inputs/EventSelect.tsx +2 -0
  50. package/src/backend/inputs/__tests__/DurationInput.test.tsx +220 -0
  51. package/src/backend/inputs/index.ts +1 -0
  52. package/src/backend/nav/navBadges.ts +61 -0
  53. package/src/backend/views/NewViewForm.tsx +46 -32
  54. package/src/primitives/__tests__/segmented-control.test.tsx +2 -2
  55. package/src/primitives/__tests__/textarea.test.tsx +50 -0
  56. package/src/primitives/segmented-control.tsx +7 -7
  57. package/src/primitives/sheet.tsx +7 -1
  58. package/src/primitives/textarea.tsx +77 -4
@@ -3,11 +3,12 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useRouter } from "next/navigation";
5
5
  import { flexRender } from "@tanstack/react-table";
6
- import { useLegacyTable, getCoreRowModel, getSortedRowModel } from "@tanstack/react-table/legacy";
6
+ import { useLegacyTable, getCoreRowModel, getSortedRowModel, getExpandedRowModel } from "@tanstack/react-table/legacy";
7
7
  import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
8
- import { RefreshCw, Loader2, SlidersHorizontal, MoreHorizontal, Circle, Filter, ChevronUp, ChevronDown, ChevronsUpDown, Check, Inbox, Save } from "lucide-react";
8
+ import { RefreshCw, Loader2, SlidersHorizontal, MoreHorizontal, Circle, Filter, ChevronUp, ChevronDown, ChevronRight, ChevronsUpDown, Check, Inbox, Save } from "lucide-react";
9
9
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../primitives/table.js";
10
10
  import { Button } from "../primitives/button.js";
11
+ import { IconButton } from "../primitives/icon-button.js";
11
12
  import { Checkbox } from "../primitives/checkbox.js";
12
13
  import {
13
14
  Select,
@@ -161,13 +162,17 @@ function collectUniqueById(entries, warningScope) {
161
162
  }
162
163
  return Array.from(byId.values());
163
164
  }
164
- function resolveExportSections(config) {
165
+ const DEFAULT_VIEW_EXPORT_TITLE = "Export what you view";
166
+ const DEFAULT_FULL_EXPORT_TITLE = "Full data export";
167
+ function resolveExportSections(config, t) {
165
168
  if (!config) return [];
166
169
  const sections = [];
167
170
  const baseFormats = config.formats && config.formats.length > 0 ? config.formats : DEFAULT_EXPORT_FORMATS;
168
- const addSection = (key, section, fallbackTitle) => {
171
+ const addSection = (key, section, fallbackTitle, fallbackFilenameBase) => {
169
172
  if (!section || !section.getUrl && !section.prepare) return;
170
- const title = section.title?.trim().length ? section.title.trim() : fallbackTitle;
173
+ const explicitTitle = section.title?.trim().length ? section.title.trim() : null;
174
+ const title = explicitTitle ?? fallbackTitle;
175
+ const filenameBase = explicitTitle ?? fallbackFilenameBase;
171
176
  const seen = /* @__PURE__ */ new Set();
172
177
  const formatsSource = section.formats && section.formats.length > 0 ? section.formats : baseFormats;
173
178
  const formats = formatsSource.filter((format) => {
@@ -179,6 +184,7 @@ function resolveExportSections(config) {
179
184
  sections.push({
180
185
  key,
181
186
  title,
187
+ filenameBase,
182
188
  description: section.description,
183
189
  formats,
184
190
  getUrl: section.getUrl,
@@ -193,17 +199,19 @@ function resolveExportSections(config) {
193
199
  });
194
200
  };
195
201
  const hasExplicitSections = Array.isArray(config.sections) && config.sections.length > 0;
202
+ const viewTitle = t("ui.dataTable.export.viewTitle", DEFAULT_VIEW_EXPORT_TITLE);
196
203
  if (!config.view && !config.full && !hasExplicitSections && config.getUrl) {
197
- addSection("view", { getUrl: config.getUrl, formats: config.formats }, "Export what you view");
204
+ addSection("view", { getUrl: config.getUrl, formats: config.formats }, viewTitle, DEFAULT_VIEW_EXPORT_TITLE);
198
205
  } else {
199
- addSection("view", config.view, "Export what you view");
206
+ addSection("view", config.view, viewTitle, DEFAULT_VIEW_EXPORT_TITLE);
200
207
  }
201
208
  if (hasExplicitSections) {
202
209
  config.sections.forEach((section, idx) => {
203
- addSection(`section-${idx}`, section, section.title?.trim().length ? section.title : `Export ${idx + 1}`);
210
+ const numberedTitle = t("ui.dataTable.export.sectionTitle", "Export {index}", { index: idx + 1 });
211
+ addSection(`section-${idx}`, section, numberedTitle, `Export ${idx + 1}`);
204
212
  });
205
213
  }
206
- addSection("full", config.full, "Full data export");
214
+ addSection("full", config.full, t("ui.dataTable.export.fullTitle", DEFAULT_FULL_EXPORT_TITLE), DEFAULT_FULL_EXPORT_TITLE);
207
215
  return sections;
208
216
  }
209
217
  const COLUMN_MIN_WIDTH = 60;
@@ -426,7 +434,7 @@ function ExportMenu({ config, sections }) {
426
434
  if (!preparedResult) return;
427
435
  const prepared = preparedResult.prepared;
428
436
  const serialized = serializeExport(prepared, format);
429
- const filename = preparedResult.filename ?? section.filename?.(format) ?? config.filename?.(format) ?? defaultExportFilename(section.title, format);
437
+ const filename = preparedResult.filename ?? section.filename?.(format) ?? config.filename?.(format) ?? defaultExportFilename(section.filenameBase, format);
430
438
  if (typeof window !== "undefined") {
431
439
  const blob = new Blob([serialized.body], { type: serialized.contentType });
432
440
  const href = URL.createObjectURL(blob);
@@ -782,7 +790,11 @@ function DataTable({
782
790
  advancedFilter: advancedFilterInput,
783
791
  columnChooser,
784
792
  activeFilterChips,
785
- filterAwareEmptyState
793
+ filterAwareEmptyState,
794
+ getSubRows,
795
+ expandable,
796
+ expanded: expandedProp,
797
+ onExpandedChange
786
798
  }) {
787
799
  const t = useT();
788
800
  const { confirm, ConfirmDialogElement } = useConfirmDialog();
@@ -828,9 +840,12 @@ function DataTable({
828
840
  const queryClient = useQueryClient();
829
841
  const perspectiveConfig = perspective ?? null;
830
842
  const perspectiveTableId = perspectiveConfig?.tableId ?? null;
843
+ const perspectiveAlign = perspectiveConfig?.align ?? "left";
831
844
  const perspectiveEnabled = Boolean(perspectiveTableId);
832
845
  const initialSnapshotRef = React.useRef(null);
833
846
  const snapshotHydratedTableRef = React.useRef(null);
847
+ const serverReconciledTableRef = React.useRef(null);
848
+ const hydratedSnapshotRef = React.useRef(null);
834
849
  const initialSettingsSource = perspectiveConfig?.initialState?.initialSettings ?? null;
835
850
  const mergedInitialSettings = React.useMemo(
836
851
  () => sanitizePerspectiveSettings(initialSettingsSource),
@@ -1183,14 +1198,34 @@ function DataTable({
1183
1198
  const [rowSelection, setRowSelection] = React.useState({});
1184
1199
  const selectionScopeKeyRef = React.useRef(selectionScopeKey);
1185
1200
  const enableClientSorting = sortable && !manualSorting;
1201
+ const expansionEnabled = getSubRows !== void 0 || expandable !== void 0;
1202
+ const [internalExpanded, setInternalExpanded] = React.useState({});
1203
+ const expandedState = expandedProp !== void 0 ? expandedProp : internalExpanded;
1204
+ const handleExpandedChange = React.useCallback((updater) => {
1205
+ if (onExpandedChange) {
1206
+ onExpandedChange(updater);
1207
+ return;
1208
+ }
1209
+ setInternalExpanded((prev) => typeof updater === "function" ? updater(prev) : updater);
1210
+ }, [onExpandedChange]);
1186
1211
  const table = useLegacyTable({
1187
1212
  data: clientFilteredData,
1188
1213
  columns: mergedColumns,
1189
1214
  getCoreRowModel: getCoreRowModel(),
1190
1215
  ...enableClientSorting ? { getSortedRowModel: getSortedRowModel() } : {},
1216
+ ...expansionEnabled ? {
1217
+ getSubRows,
1218
+ getExpandedRowModel: getExpandedRowModel(),
1219
+ getRowCanExpand: (row) => {
1220
+ if (typeof expandable === "function") return expandable(row.original);
1221
+ if (expandable === true) return true;
1222
+ return (row.subRows?.length ?? 0) > 0;
1223
+ },
1224
+ onExpandedChange: handleExpandedChange
1225
+ } : {},
1191
1226
  manualSorting: manualSorting === true,
1192
1227
  getRowId: resolveDataTableRowId,
1193
- state: { sorting, columnVisibility, columnOrder, rowSelection },
1228
+ state: { sorting, columnVisibility, columnOrder, rowSelection, ...expansionEnabled ? { expanded: expandedState } : {} },
1194
1229
  enableRowSelection: hasInjectedBulkActions,
1195
1230
  onSortingChange: (updater) => {
1196
1231
  const next = typeof updater === "function" ? updater(sorting) : updater;
@@ -1399,6 +1434,7 @@ function DataTable({
1399
1434
  const snapshot = readPerspectiveSnapshot(perspectiveTableId);
1400
1435
  if (!snapshot) return;
1401
1436
  initialSnapshotRef.current = snapshot;
1437
+ hydratedSnapshotRef.current = snapshot;
1402
1438
  const preserveAdvancedFilter = !!advancedFilter?.onApplyTree;
1403
1439
  applyPerspectiveSettings(
1404
1440
  snapshot.settings,
@@ -1818,14 +1854,42 @@ function DataTable({
1818
1854
  React.useLayoutEffect(() => {
1819
1855
  if (!canUsePerspectives) return;
1820
1856
  if (!perspectiveTableId) return;
1821
- if (initialSnapshotRef.current) return;
1822
- if (initialPerspectiveAppliedRef.current) return;
1823
1857
  const source = perspectiveData ?? perspectiveConfig?.initialState?.response;
1824
1858
  if (!source) return;
1859
+ let orphanedSnapshotDropped = false;
1825
1860
  const tryResolve = (id) => {
1826
1861
  if (!id) return void 0;
1827
1862
  return source.perspectives.find((p) => p.id === id) ?? source.rolePerspectives.find((p) => p.id === id);
1828
1863
  };
1864
+ if (initialSnapshotRef.current || initialPerspectiveAppliedRef.current) {
1865
+ if (serverReconciledTableRef.current === perspectiveTableId) return;
1866
+ serverReconciledTableRef.current = perspectiveTableId;
1867
+ const hydrated = hydratedSnapshotRef.current;
1868
+ const snapshot = hydrated && (!activePerspectiveId || activePerspectiveId === hydrated.perspectiveId) ? hydrated : null;
1869
+ const localId = snapshot?.perspectiveId ?? activePerspectiveId;
1870
+ if (!localId) return;
1871
+ const local = tryResolve(localId);
1872
+ if (local) {
1873
+ const serverUpdatedAt = local.updatedAt ? Date.parse(local.updatedAt) : NaN;
1874
+ const serverIsNewer = snapshot != null && Number.isFinite(serverUpdatedAt) && serverUpdatedAt > snapshot.updatedAt;
1875
+ const settingsDiffer = snapshot != null && diffPerspectiveSettings(
1876
+ sanitizePerspectiveSettings(local.settings) ?? {},
1877
+ sanitizePerspectiveSettings(snapshot.settings) ?? {}
1878
+ ).length > 0;
1879
+ if (serverIsNewer && settingsDiffer) {
1880
+ applyPerspectiveSettings(local.settings, local.id, {
1881
+ preserveAdvancedFilter: !!advancedFilter?.onApplyTree
1882
+ });
1883
+ initialPerspectiveAppliedRef.current = true;
1884
+ }
1885
+ return;
1886
+ }
1887
+ writePerspectiveSnapshot(perspectiveTableId, null);
1888
+ initialSnapshotRef.current = null;
1889
+ hydratedSnapshotRef.current = null;
1890
+ initialPerspectiveAppliedRef.current = false;
1891
+ orphanedSnapshotDropped = true;
1892
+ }
1829
1893
  let target;
1830
1894
  if (activePerspectiveId) {
1831
1895
  target = tryResolve(activePerspectiveId);
@@ -1842,10 +1906,18 @@ function DataTable({
1842
1906
  target = source.perspectives[0];
1843
1907
  }
1844
1908
  if (target) {
1845
- applyPerspectiveSettings(target.settings, target.id);
1909
+ applyPerspectiveSettings(
1910
+ target.settings,
1911
+ target.id,
1912
+ orphanedSnapshotDropped ? { preserveAdvancedFilter: !!advancedFilter?.onApplyTree } : void 0
1913
+ );
1914
+ } else if (orphanedSnapshotDropped) {
1915
+ applyPerspectiveSettings({}, null, {
1916
+ preserveAdvancedFilter: !!advancedFilter?.onApplyTree
1917
+ });
1846
1918
  }
1847
1919
  initialPerspectiveAppliedRef.current = true;
1848
- }, [canUsePerspectives, perspectiveData, perspectiveTableId, perspectiveConfig, applyPerspectiveSettings, activePerspectiveId]);
1920
+ }, [canUsePerspectives, perspectiveData, perspectiveTableId, perspectiveConfig, applyPerspectiveSettings, activePerspectiveId, advancedFilter?.onApplyTree]);
1849
1921
  const scrollTableIntoView = React.useCallback(() => {
1850
1922
  const rect = containerRef.current?.getBoundingClientRect();
1851
1923
  if (!rect || rect.top >= 0) return;
@@ -2154,12 +2226,44 @@ function DataTable({
2154
2226
  );
2155
2227
  const runPropBulkAction = React.useCallback(
2156
2228
  async (action) => {
2157
- const result = await action.onExecute(selectedRows);
2158
- if (result !== false) {
2229
+ try {
2230
+ const result = await action.onExecute(selectedRows);
2231
+ if (result === false) return;
2232
+ if (!result || typeof result !== "object") {
2233
+ setRowSelection({});
2234
+ return;
2235
+ }
2236
+ if (result.ok === false) {
2237
+ if (result.message === void 0) return;
2238
+ flash(result.message, "error");
2239
+ return;
2240
+ }
2159
2241
  setRowSelection({});
2242
+ if (result.progressJobId) {
2243
+ trackedBulkProgressJobIdsRef.current.add(result.progressJobId);
2244
+ flash(
2245
+ result.message ?? t("ui.dataTable.bulkAction.started", "Bulk action started. Track progress in the top bar."),
2246
+ "success"
2247
+ );
2248
+ return;
2249
+ }
2250
+ flash(
2251
+ result.message ?? t("ui.dataTable.bulkAction.success", "Bulk action completed."),
2252
+ "success"
2253
+ );
2254
+ if (refreshButton?.onRefresh) {
2255
+ refreshButton.onRefresh();
2256
+ } else {
2257
+ scheduleRouterRefresh(router);
2258
+ }
2259
+ } catch (error2) {
2260
+ flash(
2261
+ error2 instanceof Error ? error2.message : t("ui.dataTable.bulkAction.error", "Bulk action failed."),
2262
+ "error"
2263
+ );
2160
2264
  }
2161
2265
  },
2162
- [selectedRows]
2266
+ [refreshButton, router, selectedRows, t]
2163
2267
  );
2164
2268
  const builtToolbar = React.useMemo(() => {
2165
2269
  if (toolbar) return toolbar;
@@ -2240,6 +2344,7 @@ function DataTable({
2240
2344
  }
2241
2345
  )
2242
2346
  ] }) : null;
2347
+ const perspectiveButtonLeading = perspectiveAlign === "right" ? null : perspectiveButton;
2243
2348
  const saveViewButton = showSaveViewButton && canUsePerspectives ? /* @__PURE__ */ jsxs(
2244
2349
  Button,
2245
2350
  {
@@ -2259,9 +2364,9 @@ function DataTable({
2259
2364
  ]
2260
2365
  }
2261
2366
  ) : null;
2262
- const leadingItems = advancedFilterButton || perspectiveButton || saveViewButton ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2367
+ const leadingItems = advancedFilterButton || perspectiveButtonLeading || saveViewButton ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2263
2368
  advancedFilterButton,
2264
- perspectiveButton,
2369
+ perspectiveButtonLeading,
2265
2370
  saveViewButton
2266
2371
  ] }) : null;
2267
2372
  const trailingItems = hasBulkButtons ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
@@ -2305,6 +2410,7 @@ function DataTable({
2305
2410
  }) : null
2306
2411
  ] }) : null;
2307
2412
  const searchTrailingNode = searchTrailingInjectionSpotId && onSearchChange ? /* @__PURE__ */ jsx(InjectionSpot, { spotId: searchTrailingInjectionSpotId, context: resolvedInjectionContext }) : null;
2413
+ if (perspectiveAlign === "right" && !anySearch && combined.length === 0 && !advancedFilterButton && !saveViewButton && !trailingItems && !fieldsetSelector) return null;
2308
2414
  return /* @__PURE__ */ jsx(
2309
2415
  FilterBar,
2310
2416
  {
@@ -2337,6 +2443,7 @@ function DataTable({
2337
2443
  onFiltersApply,
2338
2444
  onFiltersClear,
2339
2445
  canUsePerspectives,
2446
+ perspectiveAlign,
2340
2447
  embedded,
2341
2448
  supportsCustomFieldFilterFieldsets,
2342
2449
  resolvedEntityIds,
@@ -2367,7 +2474,7 @@ function DataTable({
2367
2474
  const hasActions = actions !== void 0 && actions !== null && actions !== false;
2368
2475
  const shouldReserveActionsSpace = actions === null || actions === false;
2369
2476
  const exportConfig = exporter === false ? null : exporter || null;
2370
- const resolvedExportSections = React.useMemo(() => resolveExportSections(exportConfig), [exportConfig]);
2477
+ const resolvedExportSections = React.useMemo(() => resolveExportSections(exportConfig, t), [exportConfig, t]);
2371
2478
  const hasExport = resolvedExportSections.length > 0;
2372
2479
  const refreshButtonConfig = refreshButton;
2373
2480
  const hasRefreshButton = Boolean(refreshButtonConfig);
@@ -2432,7 +2539,18 @@ function DataTable({
2432
2539
  ]
2433
2540
  }
2434
2541
  ) : null,
2435
- canUsePerspectives ? /* @__PURE__ */ jsxs(
2542
+ canUsePerspectives ? perspectiveAlign === "right" ? /* @__PURE__ */ jsx(
2543
+ ViewSwitcherDropdown,
2544
+ {
2545
+ activePerspectiveId,
2546
+ perspectives: perspectiveData?.perspectives ?? [],
2547
+ rolePerspectives: perspectiveData?.rolePerspectives ?? [],
2548
+ onClear: () => applyPerspectiveSettings({}, null),
2549
+ onActivate: handlePerspectiveActivate,
2550
+ onOpenSidebar: () => setPerspectiveOpen(true),
2551
+ t
2552
+ }
2553
+ ) : /* @__PURE__ */ jsxs(
2436
2554
  Button,
2437
2555
  {
2438
2556
  type: "button",
@@ -2633,12 +2751,37 @@ function DataTable({
2633
2751
  const sizedWidth = enableColumnResize && columnId ? columnSizing[columnId] : void 0;
2634
2752
  const effectiveMaxWidth = typeof sizedWidth === "number" ? `${sizedWidth}px` : maxWidth;
2635
2753
  const wrappedContent = shouldTruncate ? /* @__PURE__ */ jsx(TruncatedCell, { maxWidth: effectiveMaxWidth, tooltipContent: tooltipText, children: content }) : content;
2754
+ const expandAffordance = expansionEnabled && cellIndex === 0 ? /* @__PURE__ */ jsx(
2755
+ "span",
2756
+ {
2757
+ className: "inline-flex shrink-0 items-center",
2758
+ style: { paddingLeft: `${row.depth * 1.25}rem` },
2759
+ children: row.getCanExpand() ? /* @__PURE__ */ jsx(
2760
+ IconButton,
2761
+ {
2762
+ type: "button",
2763
+ variant: "ghost",
2764
+ size: "xs",
2765
+ "aria-label": row.getIsExpanded() ? t("ui.dataTable.expand.collapseRow", "Collapse row") : t("ui.dataTable.expand.expandRow", "Expand row"),
2766
+ "aria-expanded": row.getIsExpanded(),
2767
+ onClick: (event) => {
2768
+ event.stopPropagation();
2769
+ row.toggleExpanded();
2770
+ },
2771
+ children: row.getIsExpanded() ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-4", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-4", "aria-hidden": "true" })
2772
+ }
2773
+ ) : /* @__PURE__ */ jsx("span", { className: "inline-block size-6", "aria-hidden": "true" })
2774
+ }
2775
+ ) : null;
2636
2776
  return /* @__PURE__ */ jsx(
2637
2777
  TableCell,
2638
2778
  {
2639
2779
  className: responsiveClass(priority, columnMeta?.hidden) + (isStickyCell ? ` md:sticky md:left-0 md:z-10 md:bg-background ${STICKY_LEFT_SHADOW_CLASS}` : ""),
2640
2780
  style: typeof sizedWidth === "number" ? { width: sizedWidth, minWidth: sizedWidth, maxWidth: sizedWidth } : void 0,
2641
- children: wrappedContent
2781
+ children: expandAffordance ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
2782
+ expandAffordance,
2783
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children: wrappedContent })
2784
+ ] }) : wrappedContent
2642
2785
  },
2643
2786
  cell.id
2644
2787
  );