@exxatdesignux/ui 0.5.2 → 0.5.4

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 (104) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/consumer-extras/cursor-rules/exxat-accessibility.mdc +1 -1
  4. package/consumer-extras/cursor-rules/exxat-data-tables.mdc +8 -6
  5. package/consumer-extras/cursor-rules/exxat-drawer-vs-dialog.mdc +4 -4
  6. package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +6 -1
  7. package/consumer-extras/cursor-rules/exxat-hub-supported-views.mdc +54 -0
  8. package/consumer-extras/cursor-rules/exxat-nav-single-active.mdc +31 -0
  9. package/consumer-extras/cursor-rules/exxat-no-vaul.mdc +25 -0
  10. package/consumer-extras/cursor-rules/exxat-page-header-actions.mdc +31 -0
  11. package/consumer-extras/cursor-rules/exxat-table-row-preview.mdc +24 -0
  12. package/consumer-extras/cursor-rules/exxat-tabs-chrome.mdc +31 -0
  13. package/consumer-extras/cursor-skills/exxat-drawer-vs-dialog/SKILL.md +5 -5
  14. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +10 -5
  15. package/consumer-extras/cursor-skills/exxat-ds-skill/references/accessibility.md +1 -1
  16. package/consumer-extras/cursor-skills/exxat-ds-skill/references/data-table-pattern.md +15 -5
  17. package/consumer-extras/cursor-skills/exxat-token-economy/SKILL.md +14 -5
  18. package/consumer-extras/handbook/HANDBOOK.md +1 -1
  19. package/consumer-extras/handbook/reference-implementations.md +2 -2
  20. package/consumer-extras/patterns/consumer-upgrade-checklist.md +14 -1
  21. package/consumer-extras/patterns/data-views-pattern.md +6 -0
  22. package/consumer-extras/patterns/drawer-vs-dialog-pattern.md +50 -0
  23. package/consumer-extras/patterns/hub-supported-views-pattern.md +53 -0
  24. package/dist/components/data-table/index.js +13 -9
  25. package/dist/components/data-table/index.js.map +1 -1
  26. package/dist/components/data-table/pagination.js +13 -9
  27. package/dist/components/data-table/pagination.js.map +1 -1
  28. package/dist/components/data-views/hub-table.d.ts +8 -4
  29. package/dist/components/data-views/hub-table.js +25 -10
  30. package/dist/components/data-views/hub-table.js.map +1 -1
  31. package/dist/components/data-views/index.d.ts +1 -1
  32. package/dist/components/data-views/index.js +25 -10
  33. package/dist/components/data-views/index.js.map +1 -1
  34. package/dist/components/data-views/list-page-connected-view-body.d.ts +1 -1
  35. package/dist/components/data-views/list-page-connected-view-body.js +1 -0
  36. package/dist/components/data-views/list-page-connected-view-body.js.map +1 -1
  37. package/dist/components/table-properties/drawer-button.js +1 -0
  38. package/dist/components/table-properties/drawer-button.js.map +1 -1
  39. package/dist/components/table-properties/drawer.js +1 -0
  40. package/dist/components/table-properties/drawer.js.map +1 -1
  41. package/dist/components/table-properties/index.d.ts +1 -1
  42. package/dist/components/table-properties/index.js +1 -0
  43. package/dist/components/table-properties/index.js.map +1 -1
  44. package/dist/components/templates/index.d.ts +1 -1
  45. package/dist/components/templates/index.js +12 -2
  46. package/dist/components/templates/index.js.map +1 -1
  47. package/dist/components/templates/list-page.d.ts +4 -2
  48. package/dist/components/templates/list-page.js +12 -2
  49. package/dist/components/templates/list-page.js.map +1 -1
  50. package/dist/{data-list-view-registry-CyBoBML4.d.ts → data-list-view-registry-BstmlfQ3.d.ts} +16 -1
  51. package/dist/index.d.ts +2 -3
  52. package/dist/index.js +135 -126
  53. package/dist/index.js.map +1 -1
  54. package/dist/lib/data-list-view-registry.d.ts +1 -1
  55. package/dist/lib/data-list-view-registry.js +17 -1
  56. package/dist/lib/data-list-view-registry.js.map +1 -1
  57. package/dist/lib/data-list-view-surface.d.ts +1 -1
  58. package/dist/lib/data-list-view-surface.js +1 -0
  59. package/dist/lib/data-list-view-surface.js.map +1 -1
  60. package/dist/lib/list-page-table-properties.d.ts +1 -1
  61. package/dist/lib/list-page-table-properties.js +1 -0
  62. package/dist/lib/list-page-table-properties.js.map +1 -1
  63. package/dist/lib/nav-active.d.ts +38 -0
  64. package/dist/lib/nav-active.js +104 -0
  65. package/dist/lib/nav-active.js.map +1 -0
  66. package/package.json +1 -2
  67. package/src/components/data-table/index.tsx +25 -17
  68. package/src/components/data-views/hub-table.tsx +9 -3
  69. package/src/components/templates/list-page.tsx +9 -3
  70. package/src/index.ts +1 -1
  71. package/src/lib/data-list-view-registry.ts +31 -0
  72. package/src/lib/nav-active.ts +162 -0
  73. package/template/.claude/skills/exxat-ds-skill/SKILL.md +2 -1
  74. package/template/.cursor/rules/exxat-accessibility.mdc +1 -1
  75. package/template/AGENTS.md +18 -3
  76. package/template/components/columns-client.tsx +3 -2
  77. package/template/components/columns-showcase.tsx +22 -18
  78. package/template/components/exxat-product-logo.tsx +1 -1
  79. package/template/components/library-table.tsx +62 -23
  80. package/template/components/new-library-item-form.tsx +0 -7
  81. package/template/components/product-wordmark.tsx +1 -1
  82. package/template/components/sidebar/app-sidebar.tsx +14 -106
  83. package/template/components/sidebar/secondary-nav.tsx +22 -4
  84. package/template/components/site-header.tsx +1 -1
  85. package/template/components/tokens-hub-auxiliary-views.tsx +301 -0
  86. package/template/components/tokens-themes-client.tsx +44 -16
  87. package/template/docs/HANDBOOK.md +2 -2
  88. package/template/docs/component-selection-guide.md +1 -1
  89. package/template/docs/consumer-upgrade-checklist.md +51 -0
  90. package/template/docs/data-views-pattern.md +6 -0
  91. package/template/docs/drawer-vs-dialog-pattern.md +8 -8
  92. package/template/docs/glossary.md +2 -1
  93. package/template/docs/hub-supported-views-pattern.md +53 -0
  94. package/template/docs/reference-implementations.md +2 -2
  95. package/template/lib/full-hub-supported-views.ts +8 -0
  96. package/template/lib/library-supported-views.ts +5 -12
  97. package/template/lib/motion-ui.ts +2 -2
  98. package/template/package.json +1 -1
  99. package/tokens/hooks-index.json +2 -2
  100. package/dist/components/ui/drawer.d.ts +0 -16
  101. package/dist/components/ui/drawer.js +0 -125
  102. package/dist/components/ui/drawer.js.map +0 -1
  103. package/src/components/ui/drawer.tsx +0 -134
  104. package/template/components/ui/drawer.tsx +0 -1
@@ -0,0 +1,50 @@
1
+ # Sheet panel vs dialog vs route
2
+
3
+ > **Related:** `docs/data-views-pattern.md` (Page vs drawer), **`AGENTS.md` §6.4**, **`.cursor/rules/exxat-page-vs-drawer.mdc`**. **This doc** splits **floating `Sheet` panels** vs **modal dialog** when both stay on the same route.
4
+
5
+ ## Sheet (side panel — product “drawers”)
6
+
7
+ **Use when:**
8
+
9
+ - The **list or hub behind the panel** still matters (user compares, copies, or dismisses and continues browsing).
10
+ - The flow is **medium length** — export options, table/column properties, invite collaborators, filters that mirror the grid.
11
+ - **Width** helps — tables of options, multi-field forms that would feel cramped in a narrow dialog.
12
+
13
+ **Implementation:** **`Sheet`** from `@exxatdesignux/ui/components/sheet` with the floating inset pattern (`showOverlay={false}`, `getFloatingSheetInsetProps`) — see `ExportDrawer`, `TablePropertiesDrawer`, `InviteCollaboratorsDrawer`, `LibraryNewFolderSheet`.
14
+
15
+ **Avoid when:** The task is the **only** thing the user should focus on and the parent would distract (prefer **dialog** for a sharp confirm, or **route** for a full wizard).
16
+
17
+ ## Dialog (modal)
18
+
19
+ **Use when:**
20
+
21
+ - You need a **hard stop** — user must answer or dismiss before interacting with the page again (confirm delete, acknowledge legal, pick a single blocking choice).
22
+ - The content is **short and focused** — one decision, one form step, or a compact message with primary/secondary actions.
23
+ - **Destructive or irreversible** actions — pair with clear copy; **Esc** / Cancel returns safely.
24
+
25
+ **Examples:** `AlertDialog`, confirm-before-remove, “Save changes?” when navigating away.
26
+
27
+ **Avoid when:** Users need to **reference** the grid or copy values from the page while the panel is open — use a **sheet panel** or **inline** pattern instead.
28
+
29
+ ## Route (new page)
30
+
31
+ Use when the work is **primary**, **long**, **multi-step**, or deserves its **own URL** — see **`exxat-page-vs-drawer.mdc`** and **`AGENTS.md` §6.4**.
32
+
33
+ ## Quick matrix
34
+
35
+ | Need | Sheet panel | Dialog | Route |
36
+ | --- | --- | --- | --- |
37
+ | Keep hub visible | Yes | No (blocks) | No |
38
+ | Short confirm / alert | Rare | Yes | Overkill |
39
+ | Long form / wizard | Cramped | No | Yes |
40
+ | Properties tied to a table | Yes | Too small | Optional |
41
+
42
+ ## Accessibility
43
+
44
+ - **Dialog / sheet:** Must expose a **title** (`DialogTitle`, `SheetTitle`) — use `sr-only` if visually hidden.
45
+ - **Focus trap** is expected in dialogs; sheet panels should still **restore focus** on close to the invoking control.
46
+
47
+ ## See also
48
+
49
+ - **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**, **`.cursor/skills/exxat-drawer-vs-dialog/SKILL.md`**
50
+ - **`exxat-no-toast.mdc`** — use dialog/banner/inline, not toasts, for outcomes that need acknowledgment.
@@ -0,0 +1,53 @@
1
+ # Hub supported views pattern (Add view parity)
2
+
3
+ > **Agents:** `.cursor/rules/exxat-hub-supported-views.mdc` (binding). **Reference hub:** Library / All questions (`library-table.tsx`, `library-client.tsx`).
4
+
5
+ ## Problem this solves
6
+
7
+ `ListPageTemplate` filters **Add view** and Properties view tiles from `supportedViewTypes`. If Column types passes four views but Library passes seven, users see inconsistent menus. If a hub allows Board but has no `board-with-toolbar` renderer, users see **“does not implement Board view”**.
8
+
9
+ ## Canonical allowlist
10
+
11
+ Import from the registry (single source of truth):
12
+
13
+ ```ts
14
+ import { FULL_HUB_SUPPORTED_VIEWS } from "@/lib/data-list-view-registry"
15
+ // or
16
+ import { LIBRARY_SUPPORTED_VIEWS } from "@/lib/library-supported-views" // alias of FULL
17
+ ```
18
+
19
+ Seven views: **table**, **list**, **board**, **dashboard**, **folder**, **panel**, **tree-panel**.
20
+
21
+ `HubTable` and `ListPageTemplate` use this list when `supportedViewTypes` is omitted.
22
+
23
+ `PRIMARY_HUB_SUPPORTED_VIEWS` (four views) remains for hubs that intentionally omit folder/panel/tree — document that in `lib/<entity>-supported-views.ts`.
24
+
25
+ ## Wiring checklist
26
+
27
+ 1. **`ListPageTemplate`** — `supportedViewTypes={FULL_HUB_SUPPORTED_VIEWS}` (or entity alias).
28
+ 2. **`HubTable`** — same allowlist (or omit on both).
29
+ 3. **List** — `renderListRow` returning **`ListPageBoardCard`** `layout="row"` (copy from `library-table.tsx`).
30
+ 4. **Board** — `renderBoardCard` + `boardGroups` and/or `renderers["board-with-toolbar"]`.
31
+ 5. **Dashboard** — `renderers["dashboard-with-toolbar"]` with **`KeyMetrics`** on filtered rows.
32
+ 6. **Folder / panel / tree** — explicit `renderers` entries (Library reference) or **`LibraryTable`** for `LibraryItem` rows.
33
+
34
+ ## Special cases in this app
35
+
36
+ | Hub | Pattern |
37
+ |-----|---------|
38
+ | **Library / All questions** | `LibraryTable` + `LIBRARY_SUPPORTED_VIEWS` — reference |
39
+ | **Column types** | `LibraryTable` with `columnDefs` + `hubLabels` + `DEFAULT_LIBRARY_FOLDERS` — custom table, shared other views |
40
+ | **Tokens & themes** | `FULL_HUB_SUPPORTED_VIEWS` + `tokens-hub-auxiliary-views.tsx` |
41
+ | **New entity hub** | Start from `library-table.tsx` or token/columns references; never table-only unless approved |
42
+
43
+ ## Anti-patterns
44
+
45
+ - `supportedViewTypes={["table"]}` on a `ListPageTemplate` hub.
46
+ - `COLUMNS_SUPPORTED_VIEWS = PRIMARY_HUB_SUPPORTED_VIEWS` without board/folder/panel/tree renderers.
47
+ - Minimal `renderListRow` with only stem + `questionId` (not product list UI).
48
+
49
+ ## See also
50
+
51
+ - `packages/ui/src/lib/data-list-view-registry.ts`
52
+ - `docs/exxat-ds/patterns/data-views-pattern.md`
53
+ - `apps/web/lib/hub-connected-view-renderers.ts` — `defineHubViewRenderers` dev warnings
@@ -2256,13 +2256,15 @@ function useBulkBarFixedToTableScrollEl(scrollRef, active, fullWidth) {
2256
2256
  const scheduled = rafThrottle(apply);
2257
2257
  const ro = new ResizeObserver(scheduled);
2258
2258
  ro.observe(el);
2259
+ el.addEventListener("scroll", scheduled, { passive: true });
2259
2260
  window.addEventListener("resize", scheduled, { passive: true });
2260
- window.addEventListener("scroll", scheduled, { passive: true, capture: true });
2261
+ window.addEventListener("scroll", scheduled, { passive: true });
2261
2262
  return () => {
2262
2263
  scheduled.cancel();
2263
2264
  ro.disconnect();
2265
+ el.removeEventListener("scroll", scheduled);
2264
2266
  window.removeEventListener("resize", scheduled);
2265
- window.removeEventListener("scroll", scheduled, { capture: true });
2267
+ window.removeEventListener("scroll", scheduled);
2266
2268
  };
2267
2269
  }, [active, fullWidth, scrollRef]);
2268
2270
  return style;
@@ -2429,11 +2431,13 @@ function DataTableInner({
2429
2431
  };
2430
2432
  update();
2431
2433
  const scheduled = rafThrottle(update);
2432
- window.addEventListener("scroll", scheduled, { passive: true, capture: true });
2434
+ wrapEl.addEventListener("scroll", scheduled, { passive: true });
2435
+ window.addEventListener("scroll", scheduled, { passive: true });
2433
2436
  window.addEventListener("resize", scheduled, { passive: true });
2434
2437
  return () => {
2435
2438
  scheduled.cancel();
2436
- window.removeEventListener("scroll", scheduled, { capture: true });
2439
+ wrapEl.removeEventListener("scroll", scheduled);
2440
+ window.removeEventListener("scroll", scheduled);
2437
2441
  window.removeEventListener("resize", scheduled);
2438
2442
  };
2439
2443
  }, [showColumnHeaders, rows.length, displayCols.length]);
@@ -2870,11 +2874,11 @@ function DataTableInner({
2870
2874
  const rowPy = rowHeight === "compact" ? "py-1" : rowHeight === "comfortable" ? "py-4" : "py-2.5";
2871
2875
  const cs = cellStyle(col.key);
2872
2876
  const tdBase = cn(
2873
- `px-3 ${rowPy} align-middle`,
2877
+ `px-3 ${rowPy} align-middle max-w-0`,
2874
2878
  showGridlines && !isEdgePin && "border-e border-border last:border-e-0",
2875
2879
  "border-b border-border group-last/row:border-b-0",
2876
2880
  isPinned && [
2877
- "z-20 pinned-cell",
2881
+ "z-20 pinned-cell relative",
2878
2882
  "bg-dt-row-bg",
2879
2883
  "group-data-[state=selected]/row:bg-dt-row-selected",
2880
2884
  "group-hover/row:bg-dt-row-hover",
@@ -2924,17 +2928,17 @@ function DataTableInner({
2924
2928
  wrap && "[&_.truncate]:!whitespace-normal [&_.truncate]:!overflow-visible [&_.truncate]:!text-clip"
2925
2929
  ),
2926
2930
  style: tdStyle,
2927
- children: col.cell(row, {
2931
+ children: /* @__PURE__ */ jsx("div", { className: "min-w-0 overflow-hidden", children: col.cell(row, {
2928
2932
  rowIndex,
2929
2933
  selected: isSelected,
2930
2934
  onSelect: (checked) => checked ? setSelected((prev) => /* @__PURE__ */ new Set([...prev, rowId])) : toggleRow(rowId)
2931
- })
2935
+ }) })
2932
2936
  },
2933
2937
  col.key
2934
2938
  );
2935
2939
  }
2936
2940
  const rawVal = String(row[col.key] ?? "");
2937
- return /* @__PURE__ */ jsx("td", { className: cn(tdBase, "text-sm text-foreground/80"), style: tdStyle, children: /* @__PURE__ */ jsx("span", { className: wrap ? "whitespace-normal" : "block truncate", title: !wrap ? rawVal : void 0, children: rawVal }) }, col.key);
2941
+ return /* @__PURE__ */ jsx("td", { className: cn(tdBase, "text-sm text-foreground/80"), style: tdStyle, children: /* @__PURE__ */ jsx("div", { className: "min-w-0 overflow-hidden", children: /* @__PURE__ */ jsx("span", { className: wrap ? "whitespace-normal" : "block truncate", title: !wrap ? rawVal : void 0, children: rawVal }) }) }, col.key);
2938
2942
  })
2939
2943
  },
2940
2944
  String(rowId)