@exxatdesignux/ui 0.5.4 → 0.5.6

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 (36) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +16 -3
  3. package/consumer-extras/cursor-rules/exxat-no-image-pixel-copy.mdc +35 -0
  4. package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +2 -0
  5. package/consumer-extras/cursor-rules/exxat-sidebar-shell.mdc +35 -0
  6. package/consumer-extras/cursor-rules/exxat-ux-discovery-protocol.mdc +122 -0
  7. package/consumer-extras/cursor-rules/exxat-ux-principles.mdc +186 -0
  8. package/consumer-extras/cursor-skills/exxat-senior-ux/SKILL.md +145 -0
  9. package/consumer-extras/cursor-skills/exxat-token-economy/SKILL.md +2 -1
  10. package/consumer-extras/handbook/reference-implementations.md +2 -0
  11. package/consumer-extras/patterns/consumer-upgrade-checklist.md +1 -0
  12. package/consumer-extras/patterns/jobs/README.md +59 -0
  13. package/consumer-extras/patterns/jobs/record-detail.md +177 -0
  14. package/consumer-extras/patterns/modern-saas-patterns.md +165 -0
  15. package/dist/components/data-table/index.js +28 -22
  16. package/dist/components/data-table/index.js.map +1 -1
  17. package/dist/components/data-table/pagination.js +28 -22
  18. package/dist/components/data-table/pagination.js.map +1 -1
  19. package/dist/components/data-table/use-table-state.js +20 -17
  20. package/dist/components/data-table/use-table-state.js.map +1 -1
  21. package/dist/components/data-views/hub-table.js +28 -22
  22. package/dist/components/data-views/hub-table.js.map +1 -1
  23. package/dist/components/data-views/index.js +28 -22
  24. package/dist/components/data-views/index.js.map +1 -1
  25. package/dist/index.js +28 -22
  26. package/dist/index.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/data-table/index.tsx +10 -6
  29. package/src/components/data-table/use-table-state.ts +33 -26
  30. package/template/docs/consumer-upgrade-checklist.md +1 -0
  31. package/template/docs/jobs/README.md +59 -0
  32. package/template/docs/jobs/record-detail.md +177 -0
  33. package/template/docs/modern-saas-patterns.md +165 -0
  34. package/template/docs/reference-implementations.md +2 -0
  35. package/template/lib/mock/navigation.tsx +1 -1
  36. package/tokens/hooks-index.json +2 -2
@@ -1443,15 +1443,6 @@ function useTableState(data, columns, defaultSort, paginationOverride, syncedSea
1443
1443
  });
1444
1444
  return [...groups.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([key, groupRows]) => ({ groupKey: key, groupLabel: key, rows: groupRows }));
1445
1445
  }, [rows, groupBy]);
1446
- const LOCKED_KEYS = React9.useMemo(() => new Set(Object.keys(lockedPins)), [lockedPins]);
1447
- const effectivePins = React9.useMemo(() => {
1448
- if (isReflowViewport || !isOverflowing) return {};
1449
- const result = {};
1450
- for (const [key, pin] of Object.entries(colPins)) {
1451
- result[key] = pin;
1452
- }
1453
- return result;
1454
- }, [colPins, isOverflowing, isReflowViewport]);
1455
1446
  const displayCols = React9.useMemo(() => {
1456
1447
  const leftPinned = [];
1457
1448
  const free = [];
@@ -1471,6 +1462,19 @@ function useTableState(data, columns, defaultSort, paginationOverride, syncedSea
1471
1462
  }
1472
1463
  return out;
1473
1464
  }, [colOrder, colPins, hiddenCols, columnsByKey]);
1465
+ const totalWidth = React9.useMemo(
1466
+ () => displayCols.reduce((s, c) => s + (colWidths[c.key] ?? c.width ?? 100), 0),
1467
+ [displayCols, colWidths]
1468
+ );
1469
+ const LOCKED_KEYS = React9.useMemo(() => new Set(Object.keys(lockedPins)), [lockedPins]);
1470
+ const effectivePins = React9.useMemo(() => {
1471
+ if (isReflowViewport || !isOverflowing) return {};
1472
+ const result = {};
1473
+ for (const [key, pin] of Object.entries(colPins)) {
1474
+ result[key] = pin;
1475
+ }
1476
+ return result;
1477
+ }, [colPins, isOverflowing, isReflowViewport]);
1474
1478
  function startResize(key, e) {
1475
1479
  e.preventDefault();
1476
1480
  e.stopPropagation();
@@ -1531,18 +1535,21 @@ function useTableState(data, columns, defaultSort, paginationOverride, syncedSea
1531
1535
  function toggleWrap(key) {
1532
1536
  setColWrap((p) => ({ ...p, [key]: !p[key] }));
1533
1537
  }
1534
- function checkOverflow() {
1538
+ const checkOverflow = React9.useCallback(() => {
1535
1539
  const el = scrollRef.current;
1536
1540
  if (!el) return;
1537
- setIsOverflowing(el.scrollWidth > el.clientWidth + 1);
1538
- }
1541
+ setIsOverflowing(totalWidth > el.clientWidth + 1);
1542
+ }, [totalWidth]);
1539
1543
  function handleScroll() {
1540
1544
  const el = scrollRef.current;
1541
1545
  if (!el) return;
1542
1546
  setScrolled(el.scrollLeft > 1);
1543
1547
  setScrollEnd(el.scrollLeft >= el.scrollWidth - el.clientWidth - 1);
1544
- setIsOverflowing(el.scrollWidth > el.clientWidth + 1);
1548
+ setIsOverflowing(totalWidth > el.clientWidth + 1);
1545
1549
  }
1550
+ React9.useLayoutEffect(() => {
1551
+ checkOverflow();
1552
+ }, [checkOverflow]);
1546
1553
  function getRowId(row, index, getIdFn) {
1547
1554
  return getIdFn ? getIdFn(row, index) : row.id ?? index;
1548
1555
  }
@@ -1595,10 +1602,6 @@ function useTableState(data, columns, defaultSort, paginationOverride, syncedSea
1595
1602
  },
1596
1603
  [effectivePins, isReflowViewport, stickyOffsets]
1597
1604
  );
1598
- const totalWidth = React9.useMemo(
1599
- () => displayCols.reduce((s, c) => s + (colWidths[c.key] ?? c.width ?? 100), 0),
1600
- [displayCols, colWidths]
1601
- );
1602
1605
  return {
1603
1606
  // Sort
1604
1607
  sortRules,
@@ -2338,7 +2341,7 @@ function DataTableInner({
2338
2341
  setSheetOpen,
2339
2342
  setSheetInitialPanel
2340
2343
  } = state;
2341
- React9.useEffect(() => {
2344
+ React9.useLayoutEffect(() => {
2342
2345
  const syncScrollport = () => {
2343
2346
  const el2 = scrollRef.current;
2344
2347
  if (el2) {
@@ -2351,8 +2354,10 @@ function DataTableInner({
2351
2354
  if (!el) return;
2352
2355
  const ro = new ResizeObserver(syncScrollport);
2353
2356
  ro.observe(el);
2357
+ const table = el.querySelector("table");
2358
+ if (table) ro.observe(table);
2354
2359
  return () => ro.disconnect();
2355
- }, []);
2360
+ }, [totalWidth, displayCols.length, checkOverflow]);
2356
2361
  const columnMenuPendingActionRef = React9.useRef(null);
2357
2362
  const pinnedScrollHintDoneRef = React9.useRef(false);
2358
2363
  React9.useEffect(() => {
@@ -2589,11 +2594,12 @@ function DataTableInner({
2589
2594
  children: /* @__PURE__ */ jsxs(
2590
2595
  "table",
2591
2596
  {
2592
- className: "w-full text-sm border-separate border-spacing-0",
2597
+ className: "text-sm border-separate border-spacing-0",
2593
2598
  style: {
2594
2599
  tableLayout: "fixed",
2595
- minWidth: totalWidth,
2596
- width: headerIsStuck ? floatingHeaderTableWidth : void 0
2600
+ // Explicit column-sum width — `w-full` made the grid stretch to the scrollport
2601
+ // so scrollWidth === clientWidth and the overflow-gated pin rule never fired.
2602
+ width: totalWidth
2597
2603
  },
2598
2604
  children: [
2599
2605
  /* @__PURE__ */ jsx("colgroup", { children: displayCols.map((col) => /* @__PURE__ */ jsx("col", { style: { width: colWidths[col.key] ?? col.width ?? 100 } }, col.key)) }),