@exxatdesignux/ui 0.5.5 → 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 (28) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +16 -5
  3. package/consumer-extras/cursor-rules/exxat-ux-discovery-protocol.mdc +122 -0
  4. package/consumer-extras/cursor-rules/exxat-ux-principles.mdc +186 -0
  5. package/consumer-extras/cursor-skills/exxat-senior-ux/SKILL.md +145 -0
  6. package/consumer-extras/patterns/jobs/README.md +59 -0
  7. package/consumer-extras/patterns/jobs/record-detail.md +177 -0
  8. package/consumer-extras/patterns/modern-saas-patterns.md +165 -0
  9. package/dist/components/data-table/index.js +28 -22
  10. package/dist/components/data-table/index.js.map +1 -1
  11. package/dist/components/data-table/pagination.js +28 -22
  12. package/dist/components/data-table/pagination.js.map +1 -1
  13. package/dist/components/data-table/use-table-state.js +20 -17
  14. package/dist/components/data-table/use-table-state.js.map +1 -1
  15. package/dist/components/data-views/hub-table.js +28 -22
  16. package/dist/components/data-views/hub-table.js.map +1 -1
  17. package/dist/components/data-views/index.js +28 -22
  18. package/dist/components/data-views/index.js.map +1 -1
  19. package/dist/hooks/use-app-theme.d.ts +1 -1
  20. package/dist/index.js +28 -22
  21. package/dist/index.js.map +1 -1
  22. package/package.json +1 -1
  23. package/src/components/data-table/index.tsx +10 -6
  24. package/src/components/data-table/use-table-state.ts +33 -26
  25. package/template/docs/jobs/README.md +59 -0
  26. package/template/docs/jobs/record-detail.md +177 -0
  27. package/template/docs/modern-saas-patterns.md +165 -0
  28. package/tokens/hooks-index.json +2 -2
@@ -1470,15 +1470,6 @@ function useTableState(data, columns, defaultSort, paginationOverride, syncedSea
1470
1470
  });
1471
1471
  return [...groups.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([key, groupRows]) => ({ groupKey: key, groupLabel: key, rows: groupRows }));
1472
1472
  }, [rows, groupBy]);
1473
- const LOCKED_KEYS = React10.useMemo(() => new Set(Object.keys(lockedPins)), [lockedPins]);
1474
- const effectivePins = React10.useMemo(() => {
1475
- if (isReflowViewport || !isOverflowing) return {};
1476
- const result = {};
1477
- for (const [key, pin] of Object.entries(colPins)) {
1478
- result[key] = pin;
1479
- }
1480
- return result;
1481
- }, [colPins, isOverflowing, isReflowViewport]);
1482
1473
  const displayCols = React10.useMemo(() => {
1483
1474
  const leftPinned = [];
1484
1475
  const free = [];
@@ -1498,6 +1489,19 @@ function useTableState(data, columns, defaultSort, paginationOverride, syncedSea
1498
1489
  }
1499
1490
  return out;
1500
1491
  }, [colOrder, colPins, hiddenCols, columnsByKey]);
1492
+ const totalWidth = React10.useMemo(
1493
+ () => displayCols.reduce((s, c) => s + (colWidths[c.key] ?? c.width ?? 100), 0),
1494
+ [displayCols, colWidths]
1495
+ );
1496
+ const LOCKED_KEYS = React10.useMemo(() => new Set(Object.keys(lockedPins)), [lockedPins]);
1497
+ const effectivePins = React10.useMemo(() => {
1498
+ if (isReflowViewport || !isOverflowing) return {};
1499
+ const result = {};
1500
+ for (const [key, pin] of Object.entries(colPins)) {
1501
+ result[key] = pin;
1502
+ }
1503
+ return result;
1504
+ }, [colPins, isOverflowing, isReflowViewport]);
1501
1505
  function startResize(key, e) {
1502
1506
  e.preventDefault();
1503
1507
  e.stopPropagation();
@@ -1558,18 +1562,21 @@ function useTableState(data, columns, defaultSort, paginationOverride, syncedSea
1558
1562
  function toggleWrap(key) {
1559
1563
  setColWrap((p) => ({ ...p, [key]: !p[key] }));
1560
1564
  }
1561
- function checkOverflow() {
1565
+ const checkOverflow = React10.useCallback(() => {
1562
1566
  const el = scrollRef.current;
1563
1567
  if (!el) return;
1564
- setIsOverflowing(el.scrollWidth > el.clientWidth + 1);
1565
- }
1568
+ setIsOverflowing(totalWidth > el.clientWidth + 1);
1569
+ }, [totalWidth]);
1566
1570
  function handleScroll() {
1567
1571
  const el = scrollRef.current;
1568
1572
  if (!el) return;
1569
1573
  setScrolled(el.scrollLeft > 1);
1570
1574
  setScrollEnd(el.scrollLeft >= el.scrollWidth - el.clientWidth - 1);
1571
- setIsOverflowing(el.scrollWidth > el.clientWidth + 1);
1575
+ setIsOverflowing(totalWidth > el.clientWidth + 1);
1572
1576
  }
1577
+ React10.useLayoutEffect(() => {
1578
+ checkOverflow();
1579
+ }, [checkOverflow]);
1573
1580
  function getRowId(row, index, getIdFn) {
1574
1581
  return getIdFn ? getIdFn(row, index) : row.id ?? index;
1575
1582
  }
@@ -1622,10 +1629,6 @@ function useTableState(data, columns, defaultSort, paginationOverride, syncedSea
1622
1629
  },
1623
1630
  [effectivePins, isReflowViewport, stickyOffsets]
1624
1631
  );
1625
- const totalWidth = React10.useMemo(
1626
- () => displayCols.reduce((s, c) => s + (colWidths[c.key] ?? c.width ?? 100), 0),
1627
- [displayCols, colWidths]
1628
- );
1629
1632
  return {
1630
1633
  // Sort
1631
1634
  sortRules,
@@ -2365,7 +2368,7 @@ function DataTableInner({
2365
2368
  setSheetOpen,
2366
2369
  setSheetInitialPanel
2367
2370
  } = state;
2368
- React10.useEffect(() => {
2371
+ React10.useLayoutEffect(() => {
2369
2372
  const syncScrollport = () => {
2370
2373
  const el2 = scrollRef.current;
2371
2374
  if (el2) {
@@ -2378,8 +2381,10 @@ function DataTableInner({
2378
2381
  if (!el) return;
2379
2382
  const ro = new ResizeObserver(syncScrollport);
2380
2383
  ro.observe(el);
2384
+ const table = el.querySelector("table");
2385
+ if (table) ro.observe(table);
2381
2386
  return () => ro.disconnect();
2382
- }, []);
2387
+ }, [totalWidth, displayCols.length, checkOverflow]);
2383
2388
  const columnMenuPendingActionRef = React10.useRef(null);
2384
2389
  const pinnedScrollHintDoneRef = React10.useRef(false);
2385
2390
  React10.useEffect(() => {
@@ -2616,11 +2621,12 @@ function DataTableInner({
2616
2621
  children: /* @__PURE__ */ jsxs(
2617
2622
  "table",
2618
2623
  {
2619
- className: "w-full text-sm border-separate border-spacing-0",
2624
+ className: "text-sm border-separate border-spacing-0",
2620
2625
  style: {
2621
2626
  tableLayout: "fixed",
2622
- minWidth: totalWidth,
2623
- width: headerIsStuck ? floatingHeaderTableWidth : void 0
2627
+ // Explicit column-sum width — `w-full` made the grid stretch to the scrollport
2628
+ // so scrollWidth === clientWidth and the overflow-gated pin rule never fired.
2629
+ width: totalWidth
2624
2630
  },
2625
2631
  children: [
2626
2632
  /* @__PURE__ */ jsx("colgroup", { children: displayCols.map((col) => /* @__PURE__ */ jsx("col", { style: { width: colWidths[col.key] ?? col.width ?? 100 } }, col.key)) }),