@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.6
4
+
5
+ ### Patch Changes
6
+
7
+ - **`DataTable` auto-pin activates reliably** — fixed a layout bug where the inner `<table>` stretched to `w-full`, making `scrollWidth === clientWidth` even when the sum of column widths exceeded the viewport. The table now renders at the natural sum of column widths (`style={{ width: totalWidth }}`); overflow is detected against `totalWidth > clientWidth + 1` inside a `useLayoutEffect` that also observes the inner table via `ResizeObserver`. Columns marked `defaultPin` now pin as soon as the grid actually overflows (matches `<= 0.5.2` behavior).
8
+ - **New consumer agent skill `exxat-senior-ux` (vendored via `sync-extras`)** — the persona every other Exxat DS skill is downstream of. Defines the 5-step protocol (Discovery → Research → Synthesis → Build → Audit), brief format, "ask vs assume" heuristics, and push-back triggers (no `toast()`, no Vaul, no two-filled-CTAs, no pixel-copy, no inventing primitives without ≥ 2 use cases).
9
+ - **New consumer agent rules (vendored via `sync-extras`)** — `exxat-ux-discovery-protocol` (no code without a design brief on new surfaces; question bank per surface type) and `exxat-ux-principles` (20 principles split into P1–P8 always-follow and P9–P20 default-follow-with-stated-reason; each with what / why / when-to-break / anti-pattern). Both `alwaysApply: true`.
10
+ - **New consumer pattern docs (vendored via `sync-extras`)** — `modern-saas-patterns.md` codifies the 12 modern SaaS patterns (M1–M12) the DS works against, cited in briefs by `(Mx)`. New `patterns/jobs/` library with `record-detail.md` as the first canonical job-to-be-done spec (IA diagram, route vs sheet, when to tab, navigation, actions, states, anti-patterns, audit checklist).
11
+ - **`exxat-ds-agents` "Top of stack"** — agents handbook now points at the senior-UX skill, discovery protocol, principles, modern SaaS canon, and jobs library FIRST on any design task.
12
+
13
+ ## 0.5.5
14
+
15
+ ### Patch Changes
16
+
17
+ - **New consumer agent rules (vendored via `sync-extras`):** `exxat-no-image-pixel-copy` (uploaded screenshots = IA only — never pixel-copy colors/chrome), `exxat-sidebar-shell` (DS `AppSidebar` chrome; no legacy rainbow nav styling).
18
+ - **`exxat-ds-agents` §33–§34**, **`exxat-reuse-before-custom`**, **`exxat-token-economy` Q9** — image discipline + sidebar guardrails wired into pre-flight.
19
+ - **`consumer-upgrade-checklist.md`** and **`reference-implementations.md`** — audit rows for screenshot copying and legacy sidebar anti-patterns.
20
+
3
21
  ## 0.5.4
4
22
 
5
23
  ### Patch Changes
@@ -11,6 +11,17 @@ alwaysApply: true
11
11
 
12
12
  Before implementing or reviewing **list / table / board / dashboard / data-heavy** pages, read **AGENTS.md** (rule precedence, MUST/MUST NOT, file references, §4.1–§4.8, **§6.4** page vs drawer, **§6.5** no toast, §7.1 command palette, §13 checklist). **Before** adding **new shared UI** not covered by existing **`components/`** patterns, read **`exxat-reuse-before-custom.mdc`**.
13
13
 
14
+ ## Top of stack — read FIRST on any design task
15
+
16
+ **`.cursor/skills/exxat-senior-ux/SKILL.md`** is the persona every other rule and skill is downstream of. It defines the **five-step protocol** (Discovery → Research → Synthesis → Build → Audit), the **brief format**, and the **push-back triggers**. Pair with:
17
+
18
+ - **`.cursor/rules/exxat-ux-discovery-protocol.mdc`** — brief-before-code gate + question bank per surface type.
19
+ - **`.cursor/rules/exxat-ux-principles.mdc`** — 20 principles (P1–P20) split into **always-follow (P1–P8)** and **default-follow with stated reason (P9–P20)**. Every deviation MUST be named in the design brief.
20
+ - **`apps/web/docs/modern-saas-patterns.md`** — the 12 modern SaaS patterns (M1–M12) the DS works against; cite by `(Mx)` codes.
21
+ - **`apps/web/docs/jobs/`** — canonical references per **job-to-be-done** (start with `record-detail.md`). If no job doc matches, write one.
22
+
23
+ On any **new** route / page / hub / detail / wizard / settings / dashboard / overlay, output a **design brief** in chat BEFORE writing files. On trivial edits (copy tweaks, single-class restyles, bug fixes), skip the brief.
24
+
14
25
  ## Non‑negotiables (if anything conflicts, open AGENTS.md §12–§13)
15
26
 
16
27
  1. **Product data lists** → `DataTable` + search + shared filters + `TablePropertiesDrawer` — not raw `<table>` / ui `Table` alone / ad-hoc grids. With **`ListPageTemplate`** view tabs, pass **`currentView`** + **`onViewChange`** into **`TablePropertiesDrawer`** (**`AGENTS.md` §4.2**, **`.cursor/rules/exxat-table-properties-drawer.mdc`**).
@@ -40,11 +51,13 @@ Before implementing or reviewing **list / table / board / dashboard / data-heavy
40
51
  25. **No SLDS leakage** — **`.cursor/rules/exxat-no-slds-leakage.mdc`** — no `slds-*` classes, no `<lightning-*>` markup, no SLDS token names, no synthetic-shadow assumptions. ESLint catches via `exxat-ds/no-slds-classes` + `exxat-ds/no-lightning-elements` (from **`@exxatdesignux/eslint-plugin`**).
41
52
  26. **Blueprints + selection guide** — **`apps/web/docs/blueprints/`** + **`apps/web/docs/component-selection-guide.md`** — framework-agnostic specs + decision tree across the whole DS. Start there before composing a new hub.
42
53
  27. **Migrations** — **`apps/web/docs/migrations/`** — every deprecation gets a numbered entry (`NNNN-<slug>.md`). Token deprecations surface in `tokens/hooks-index.json` as `deprecated: true` and are lint-flagged.
43
- 28. **Hub supported views (Add view parity)** — **`exxat-hub-supported-views.mdc`** + **`docs/exxat-ds/patterns/hub-supported-views-pattern.md`** — **`FULL_HUB_SUPPORTED_VIEWS`** (seven views, same as Library); sync **`ListPageTemplate`** + **`HubTable`**; real renderers per view; **`LibraryTable`** for **`LibraryItem`** catalogs; **`tokens-hub-auxiliary-views.tsx`** for tokens.
54
+ 28. **Hub supported views (Add view parity)** — **`exxat-hub-supported-views.mdc`** + **`apps/web/docs/hub-supported-views-pattern.md`** — **`FULL_HUB_SUPPORTED_VIEWS`** (seven views, same as Library); sync **`ListPageTemplate`** + **`HubTable`**; real renderers per view; **`LibraryTable`** for **`LibraryItem`** catalogs; **`tokens-hub-auxiliary-views.tsx`** for tokens.
44
55
  29. **No Vaul** — **`exxat-no-vaul.mdc`** — side panels = **`Sheet`** only; remove **`vaul`** from consumer apps on **`@exxatdesignux/ui@0.5.3+`**.
45
56
  30. **Tabs chrome** — **`exxat-tabs-chrome.mdc`** — hub views = **`ListPageTemplate`** toolbar (`w-max`); record tabs = **`TabsList`** `w-fit`, never full-width stretch.
46
- 31. **Page header actions** — **`exxat-page-header-actions.mdc`** — filled primary + outline overflow; no hand-built grey buttons.
57
+ 31. **Page header actions** — **`exxat-page-header-actions.mdc`** + **`apps/web/docs/blueprints/page-header.md`** — filled primary + outline overflow; no hand-built grey buttons.
47
58
  32. **Table row preview** — **`exxat-table-row-preview.mdc`** — **`HoverCard`** + DS badges/cells; no bespoke popover cards.
59
+ 33. **Sidebar shell** — **`exxat-sidebar-shell.mdc`** + **`AGENTS.md` §9.1** — legacy screenshots = **IA only** (labels/routes); **MUST NOT** copy per-section colors or fork **`app-sidebar.tsx`** styling; use **`SidebarMenuButton`** + **`lib/nav-active`**.
60
+ 34. **Uploaded images** — **`exxat-no-image-pixel-copy.mdc`** (always apply) — screenshots/mockups = **intent + IA only**; **MUST** map to blueprints + reference hubs; **MUST NOT** pixel-copy colors, chrome, or bespoke stacks.
48
61
 
49
62
  ## Also read
50
63
 
@@ -55,7 +68,7 @@ Before implementing or reviewing **list / table / board / dashboard / data-heavy
55
68
  - **`apps/web/docs/blueprints/`** — framework-agnostic specs (start: `page-header.md`, `data-table.md`).
56
69
  - **`apps/web/docs/migrations/`** — token rename + removal history.
57
70
  - **`packages/ui/tokens/hooks-index.json`** — machine-readable token index (regenerate via `pnpm --filter @exxatdesignux/ui tokens:index`).
58
- - `.cursor/rules/exxat-data-tables.mdc`, **`exxat-hub-supported-views.mdc`**, **`exxat-no-vaul.mdc`**, **`exxat-tabs-chrome.mdc`**, **`exxat-page-header-actions.mdc`**, **`exxat-table-row-preview.mdc`**, `exxat-list-page-connected-views.mdc`, **`exxat-centralized-list-dataset.mdc`**, **`exxat-list-page-view-shells.mdc`**, **`exxat-fontawesome-icons.mdc`**, **`exxat-mono-ids.mdc`**, **`exxat-primary-nav-secondary-panel.mdc`**, **`exxat-library-hub-header.mdc`**, **`exxat-collaboration-access.mdc`**, **`exxat-dedicated-search-surfaces.mdc`**, **`exxat-kpi-trends.mdc`**, **`exxat-kpi-flat-band.mdc`**, **`exxat-drawer-vs-dialog.mdc`**, **`exxat-card-vs-list-rows.mdc`**, **`exxat-kpi-max-four.mdc`**, **`exxat-reuse-before-custom.mdc`**, `exxat-table-properties-drawer.mdc`, **`exxat-board-cards.mdc`**, **`exxat-page-vs-drawer.mdc`**, **`exxat-no-toast.mdc`**, **`exxat-command-menu.mdc`**, `exxat-kbd-shortcuts.mdc`, `exxat-accessibility.mdc` at repo root; **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`** for Data tab charts.
71
+ - `.cursor/rules/exxat-data-tables.mdc`, **`exxat-hub-supported-views.mdc`**, **`exxat-no-vaul.mdc`**, **`exxat-tabs-chrome.mdc`**, **`exxat-page-header-actions.mdc`**, **`exxat-table-row-preview.mdc`**, `exxat-list-page-connected-views.mdc`, **`exxat-centralized-list-dataset.mdc`**, **`exxat-list-page-view-shells.mdc`**, **`exxat-fontawesome-icons.mdc`**, **`exxat-mono-ids.mdc`**, **`exxat-nav-single-active.mdc`** (one active sidebar/secondary link — `nav-active` helpers), **`exxat-primary-nav-secondary-panel.mdc`**, **`exxat-library-hub-header.mdc`**, **`exxat-collaboration-access.mdc`**, **`exxat-dedicated-search-surfaces.mdc`**, **`exxat-kpi-trends.mdc`**, **`exxat-kpi-flat-band.mdc`**, **`exxat-drawer-vs-dialog.mdc`**, **`exxat-card-vs-list-rows.mdc`**, **`exxat-kpi-max-four.mdc`**, **`exxat-reuse-before-custom.mdc`**, `exxat-table-properties-drawer.mdc`, **`exxat-board-cards.mdc`**, **`exxat-page-vs-drawer.mdc`**, **`exxat-no-toast.mdc`**, **`exxat-command-menu.mdc`**, `exxat-kbd-shortcuts.mdc`, `exxat-accessibility.mdc` at repo root; **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`** for Data tab charts.
59
72
  - **`apps/web/docs/kpi-flat-band-pattern.md`**, **`apps/web/docs/shell-surface-elevation-pattern.md`** — flat KPI strip + sidebar/secondary/page OKLCH stack.
60
73
  - **`apps/web/docs/library-hub-header-pattern.md`** — folder-scoped library header **Customize folder**.
61
74
  - **`apps/web/docs/collaboration-access-pattern.md`** — shared hub face rail + invite sheet.
@@ -0,0 +1,35 @@
1
+ ---
2
+ description: Uploaded screenshots/mockups are IA reference only — map to Exxat DS patterns; never pixel-copy
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — uploaded images are not the implementation spec
7
+
8
+ When the user attaches a **screenshot**, **mockup**, **Figma export**, **legacy app capture**, or any **reference image**, treat it as **product intent** — **not** as code to transcribe.
9
+
10
+ **Exxat DS rules, blueprints, and reference hubs always win** over what the image shows.
11
+
12
+ ## Allowed to take from an image (content / IA)
13
+
14
+ - **Screen purpose**, **nav labels**, **routes**, **fields**, **columns**, **KPIs**, **actions**, **statuses**
15
+ - **Icon suffix** (Font Awesome) — still use **`fa-light` / `fa-solid`** DS pairing
16
+ - **Workflow intent** — export, invite, row → detail, etc.
17
+
18
+ ## MUST NOT copy from an image (visual / stack)
19
+
20
+ - **Hex / RGB colors**, rainbow section text, custom sidebar washes, bespoke pills
21
+ - **Shell forks** — sidebar, header, list toolbar, tabs that bypass DS components
22
+ - **Bespoke widgets** when DS primitives exist — raw tables, custom popovers, Vaul, full-width tabs
23
+ - **Pixel implementation “because it’s in the picture”** without citing a **DS pattern + reference hub**
24
+
25
+ ## REQUIRED workflow (before UI code)
26
+
27
+ 1. Classify via **`component-selection-guide`** + **`blueprints/`**
28
+ 2. Pick **`reference-implementations`** hub
29
+ 3. State mapping (screen → DS composition)
30
+ 4. Build with **`AGENTS.md`** + topic rules
31
+ 5. Image vs DS conflict → **DS wins**; ask one question only for true business gaps
32
+
33
+ ## See also
34
+
35
+ - **`exxat-reuse-before-custom.mdc`**, **`exxat-sidebar-shell.mdc`**, **`exxat-token-economy`** §2
@@ -20,6 +20,8 @@ alwaysApply: true
20
20
 
21
21
  Do **not** silently ship a second stack for the same product pattern (e.g. another “table”, another metrics strip, another sidebar).
22
22
 
23
+ When the user **uploads a screenshot or mockup**, read **`exxat-no-image-pixel-copy.mdc`** first — extract IA only; map to DS patterns; never pixel-copy colors or chrome.
24
+
23
25
  If the **user or task already explicitly** approved a greenfield component (“build a new X from scratch”), you may proceed without re-asking.
24
26
 
25
27
  ## MUST NOT
@@ -0,0 +1,35 @@
1
+ ---
2
+ description: Application sidebar — DS shell only; legacy screenshots are IA reference, not visual spec
3
+ globs: "**/app-sidebar.tsx,**/navigation*.tsx,**/lib/mock/navigation.tsx,**/lib/*-navigation.tsx"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Exxat DS — application sidebar shell (MUST)
8
+
9
+ Customer / legacy app **screenshots** may show **what links exist** — not **how the sidebar is styled**. Full policy: **`exxat-no-image-pixel-copy.mdc`**.
10
+
11
+ ## Screenshots are allowed to inform (content only)
12
+
13
+ - Nav **labels**, **grouping**, **route paths**, **Font Awesome icon suffixes**
14
+ - Whether a row needs **children**, a **secondary panel**, or a **badge**
15
+
16
+ ## Screenshots MUST NOT drive styling (MUST NOT)
17
+
18
+ - **Per-section label colors** (magenta / teal / gold text on every row in a group)
19
+ - **Custom active pills** (hand-built white `rounded-*` + shadow instead of `SidebarMenuButton` `data-active`)
20
+ - **Non-token sidebar fills** (pink wash, `#hex` tints, inline `style={{ color: … }}`)
21
+ - **Forking `app-sidebar.tsx` layout** for one product while rest of DS uses shared chrome
22
+ - **Re-implementing `isNavActive`** in the app — use **`@exxatdesignux/ui/lib/nav-active`** (see **`exxat-nav-single-active.mdc`**)
23
+
24
+ ## MUST — DS sidebar chrome
25
+
26
+ 1. **Shell:** **`AppSidebar`** + **`SidebarMenuButton`** / **`SidebarGroup`** / **`SidebarGroupLabel`** from **`@exxatdesignux/ui`**. Reference: **`AGENTS.md` §9.1**, **`exxat-ds-skill` §3.1–§3.2**.
27
+ 2. **Typography:** Row labels **`text-sidebar-foreground`**. Section headings **`SidebarGroupLabel`** + **`text-sidebar-section-label`**.
28
+ 3. **Active state:** **`SidebarMenuButton` `isActive`** only — one active row in expanded rail; collapsible parent neutral when child active.
29
+ 4. **Icons:** **`fa-light`** / **`fa-solid`** on icons — do **not** recolor labels per module.
30
+ 5. **Nav data:** Extend **`lib/mock/navigation.tsx`** (or imported mock). **MUST NOT** paste legacy sidebar components from customer repos.
31
+ 6. **Consumer products:** Build in a **separate repo** with **`@exxatdesignux/ui`** — not DS monorepo sidebar forks.
32
+
33
+ ## Anti-pattern
34
+
35
+ Legacy product sidebars with rainbow section text and bespoke selection chrome — **do not reproduce** on Exxat DS.
@@ -0,0 +1,122 @@
1
+ ---
2
+ description: Exxat DS — output a design brief before writing files for any new surface; question bank by surface type
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — UX discovery protocol
7
+
8
+ On any task that creates a **new route, page, template, wizard, or
9
+ significant component**, the assistant MUST output a **design brief in chat**
10
+ BEFORE writing files. Brief format is defined in
11
+ `.cursor/skills/exxat-senior-ux/SKILL.md` §3.
12
+
13
+ ## MUST
14
+
15
+ 1. **No code without a brief.** New surfaces require the brief. Trivial edits
16
+ to existing surfaces (copy tweak, single-class change, bug fix, refactor)
17
+ are exempt.
18
+ 2. **Cite a reference.** Every brief names **one repo reference** + **two
19
+ modern SaaS analogues** (Linear / Notion / Stripe / Figma / Vercel / etc.)
20
+ that solve the same **job-to-be-done**. Cite the SaaS analogues by
21
+ product name + pattern codes from
22
+ `apps/web/docs/modern-saas-patterns.md` (e.g. `Linear issue detail (M1, M4, M7)`).
23
+ 3. **Name principles + breaks.** Brief lists the principles applied
24
+ (`exxat-ux-principles.mdc`) and any deviations with one-sentence reasons.
25
+ **Never-break** principles (P1–P8) cannot be deviated from.
26
+ 4. **One assumption per gap.** If the user can't or won't answer, state the
27
+ assumption inline; never invent silently.
28
+ 5. **Sync the brief to the implementation.** PR / commit message references
29
+ the job doc (`apps/web/docs/jobs/`) and any principle break.
30
+
31
+ ## MUST NOT
32
+
33
+ - Generate files before the brief.
34
+ - Ask more than **3** questions in one batch.
35
+ - Ask questions whose answer is already in the prompt, the file tree, or
36
+ `apps/web/docs/jobs/`.
37
+ - Use uploaded screenshots as the implementation spec
38
+ (`exxat-no-image-pixel-copy.mdc`).
39
+ - Treat a feature list as a job. Ask: *what decision does this enable?*
40
+
41
+ ## Question bank by surface type
42
+
43
+ Pick **at most 3** questions whose answers change the design. Skip the rest.
44
+
45
+ ### Record / entity detail
46
+ 1. Who reads this most — power admin (dense, keyboard-first) or occasional
47
+ user (cozy, guided)?
48
+ 2. How is it reached — list, deep link, notification, search? (Drives
49
+ breadcrumb + back-affordance model.)
50
+ 3. Section tabs needed, or single-scroll page? (Field count > ~20 or rich
51
+ children → tabs.)
52
+
53
+ ### Hub / list page
54
+ 1. Dense comparison (table) or visual browse (board / gallery)?
55
+ 2. Per-record actions, bulk actions, or both?
56
+ 3. Will users filter / sort / customize columns, or is the view fixed?
57
+
58
+ ### Wizard / compose flow
59
+ 1. One screen with sections, or multi-step (>3 decisions)?
60
+ 2. Are intermediate steps savable as drafts?
61
+ 3. Submit is destructive, or always reversible?
62
+
63
+ ### Settings / preferences
64
+ 1. User scope (personal), workspace (shared), or both?
65
+ 2. Search needed (>20 settings) or flat list?
66
+ 3. Apply-on-change or explicit Save?
67
+
68
+ ### Dashboard / analytics
69
+ 1. One critical KPI or a comparison set (≤4)?
70
+ 2. Read at a glance, or drill into details?
71
+ 3. Time range fixed, or user-controlled?
72
+
73
+ ### Overlay (drawer / dialog / sheet)
74
+ 1. Does the user need the hub visible behind them? (Yes → sheet; no → route.)
75
+ 2. Blocking confirmation, or reversible? (Blocking → dialog; reversible → sheet.)
76
+ 3. Will it grow to ≥3 steps? (Yes → consider route instead.)
77
+
78
+ ## Brief template (copy verbatim)
79
+
80
+ ```
81
+ Problem: <one sentence — the user's pain, not the feature>
82
+ User & frequency: <persona, frequency, expertise>
83
+ Job-to-be-done: <the decision or action this enables>
84
+ Pattern: <route | sheet | dialog | inline> + IA shape
85
+ Reference (repo): <file path>
86
+ Reference (modern): <product 1 + Mx>, <product 2 + Mx>
87
+ Principles applied: <P-codes from exxat-ux-principles>
88
+ Deviations: <principle + one-sentence reason, or "none">
89
+ Out of scope: <what this does not do, deliberately>
90
+ Open questions: <max 2; ideally 0>
91
+ ```
92
+
93
+ ## Examples
94
+
95
+ **Good:**
96
+ > Problem: Coordinators can't tell at a glance which students are
97
+ > non-compliant before placement.
98
+ > User & frequency: Program coordinator, daily, keyboard-first.
99
+ > Job-to-be-done: Identify and act on at-risk students in < 30s per record.
100
+ > Pattern: route `/students/[id]` + identity row + status row + 2×2 card grid.
101
+ > Reference (repo): `components/library-table.tsx` for IA cadence.
102
+ > Reference (modern): Linear issue detail (M1, M4, M7); Stripe customer
103
+ > record (M4, M11).
104
+ > Principles applied: P1, P2, P3, P5, P6, P13, P19.
105
+ > Deviations: none.
106
+ > Out of scope: inline editing (v2), bulk message (lives on list).
107
+ > Open questions: none.
108
+
109
+ **Bad (silent generate):**
110
+ > *Agent writes 4 files without explanation.*
111
+
112
+ **Bad (vague prompt accepted):**
113
+ > User: "make a settings page". *Agent writes generic form.* Should have
114
+ > asked: scope (personal/workspace), search needed, apply-on-change vs Save.
115
+
116
+ ## See also
117
+
118
+ - `.cursor/skills/exxat-senior-ux/SKILL.md` — the persona + full protocol
119
+ - `.cursor/rules/exxat-ux-principles.mdc` — principles + when to break
120
+ - `apps/web/docs/jobs/` — canonical references per job type
121
+ - `apps/web/docs/modern-saas-patterns.md` — pattern codes (M1–M12)
122
+ - `.cursor/rules/exxat-no-image-pixel-copy.mdc` — IA from screenshots only
@@ -0,0 +1,186 @@
1
+ ---
2
+ description: Exxat DS UX principles — what to follow, when to break, why
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Exxat DS — UX principles (and when to break them)
7
+
8
+ Principles are the senior designer's spine. They make most decisions cheap.
9
+ **Break deliberately, not accidentally** — and say so in the design brief
10
+ (`exxat-ux-discovery-protocol.mdc`). If you can't write the deviation reason
11
+ in one sentence, you shouldn't be breaking the principle.
12
+
13
+ Each principle below has: **what it says**, **why**, **when to break**, and
14
+ the **anti-pattern**.
15
+
16
+ ---
17
+
18
+ ## Always-follow (P1–P8) — no exceptions
19
+
20
+ ### P1. Way back is obvious, and exactly once
21
+ Breadcrumb in `SiteHeader` OR explicit back affordance — **never both**.
22
+ - **Why:** Two paths back create cognitive overhead and a redundant UI.
23
+ - **When to break:** Never.
24
+ - **Anti-pattern:** Breadcrumb "Dashboard › Students › Jordan Lee" + a
25
+ separate "Back to roster" button in the body.
26
+ - **Reference:** `exxat-breadcrumbs-no-back.mdc`.
27
+
28
+ ### P2. One H1 per page; no duplicated identity
29
+ The record name appears in exactly one carrier — typically `PageHeader.title`
30
+ + ancestors-only breadcrumb. Not also as an `<h1>` in the body.
31
+ - **Why:** Screen readers and scan-reading rely on a single page title.
32
+ - **When to break:** Never.
33
+ - **Anti-pattern:** Name in breadcrumb leaf + `PageHeader title` + body `<h1>`.
34
+
35
+ ### P3. One primary action per surface
36
+ Exactly one filled `Button`; everything else `outline` / `ghost` / `link`.
37
+ - **Why:** Two primaries = no primary.
38
+ - **When to break:** Never. Symmetric pairs ("Approve" + "Reject") are both
39
+ *outline* — neither is the styled "primary".
40
+ - **Anti-pattern:** Two filled buttons in the header.
41
+
42
+ ### P4. Don't pixel-copy
43
+ Extract IA from screenshots and competitor references; never copy chrome,
44
+ colors, or bespoke widgets.
45
+ - **Why:** Pixels carry decisions made in another product's context.
46
+ - **When to break:** Never.
47
+ - **Reference:** `exxat-no-image-pixel-copy.mdc`.
48
+
49
+ ### P5. Every list / detail / action ships empty + error + loading
50
+ - **Why:** Real users hit all three; afterthoughts ship as bugs.
51
+ - **When to break:** Never.
52
+ - **Anti-pattern:** "Loading…" text and no skeleton; missing 404 / empty.
53
+
54
+ ### P6. Keyboard parity
55
+ Every mouse action has a keyboard equivalent; focus is always visible.
56
+ - **Why:** Power users, motor-disabled users, screen-reader users all rely
57
+ on this.
58
+ - **When to break:** Never.
59
+ - **Reference:** `exxat-kbd-shortcuts.mdc`, `exxat-accessibility.mdc`.
60
+
61
+ ### P7. WCAG 2.1 AA minimum
62
+ Contrast ≥ 4.5:1 (text) / ≥ 3:1 (UI), targets ≥ 24×24, labels on icon-only.
63
+ - **Why:** Floor for shipping. Not negotiable.
64
+ - **When to break:** Never.
65
+ - **Reference:** `exxat-accessibility.mdc`.
66
+
67
+ ### P8. Reuse before invent
68
+ Compose from DS primitives first. New shared primitives require user approval
69
+ after a real, repeated need (≥ 2 use cases).
70
+ - **Why:** Forked stacks divide the team; the DS is the vocabulary.
71
+ - **When to break:** Never silently. Ask the user.
72
+ - **Reference:** `exxat-reuse-before-custom.mdc`.
73
+
74
+ ---
75
+
76
+ ## Default-follow (P9–P20) — break only with stated reason
77
+
78
+ ### P9. Clarity over cleverness
79
+ Direct labels, recognizable patterns. "Save" beats "Persist". "Send" beats
80
+ "Beam".
81
+ - **Why:** Decisions cost less when the label states the action.
82
+ - **Break when:** Intentional brand voice in low-stakes surfaces (onboarding
83
+ celebration, marketing splash). Never in core flows.
84
+ - **Anti-pattern:** "Materialize this configuration" instead of "Save".
85
+
86
+ ### P10. Recognition over recall
87
+ Surface what the user needs; don't make them remember.
88
+ - **Why:** Working memory is the most expensive resource on a screen.
89
+ - **Break when:** Daily power users where keyboard shortcuts replace visible
90
+ chrome (Cron, Linear, Raycast). Provide a discoverable hint.
91
+ - **Anti-pattern:** Hiding a frequent action behind a chord with no UI.
92
+
93
+ ### P11. One job per surface
94
+ A screen optimizes for one primary user decision.
95
+ - **Why:** Splits attention, splits metrics, splits design quality.
96
+ - **Break when:** Workspace surfaces (Notion-style pages, Linear-style issue
97
+ views) deliberately compose multiple jobs. Even then, one job is **primary**.
98
+ - **Anti-pattern:** Settings page that also includes a dashboard.
99
+
100
+ ### P12. Progressive disclosure
101
+ Show core first; depth on demand (popovers, sheets, expand).
102
+ - **Why:** Most users do the common thing most of the time.
103
+ - **Break when:** Compliance / legal / audit surfaces where everything must
104
+ be visible.
105
+ - **Anti-pattern:** 30-field form on first load with no grouping.
106
+
107
+ ### P13. Status visible without scroll
108
+ Status signals that drive decisions (compliance, errors, urgency) appear
109
+ above the fold.
110
+ - **Why:** Status hidden = ignored.
111
+ - **Break when:** Privacy / discretion contexts (e.g. HR records where peer
112
+ visibility is undesirable).
113
+ - **Anti-pattern:** Compliance status on tab #3 of a record detail.
114
+
115
+ ### P14. Density follows frequency
116
+ Daily power users get compact / dense; occasional users get cozy / spacious.
117
+ - **Why:** Different audiences scan differently.
118
+ - **Break when:** Accessibility (low-vision, motor) mandates generous
119
+ spacing. Offer a density toggle if both audiences share a surface.
120
+ - **Anti-pattern:** Sparse table for a coordinator viewing 200 students/day.
121
+
122
+ ### P15. Inline editing where data is read
123
+ Modern SaaS (Notion, Linear, Airtable) edits in place. Don't bounce users
124
+ to a form for a single-field change.
125
+ - **Why:** Mode-switch friction kills throughput.
126
+ - **Break when:** Bulk operations, multi-field validation, audit-logged
127
+ fields, destructive edits — use a focused form / drawer.
128
+ - **Anti-pattern:** "Edit" page just to change a phone number.
129
+
130
+ ### P16. Optimistic UI for low-risk actions
131
+ Favorite, archive, status flip, reorder — feel instant; reconcile on error.
132
+ - **Why:** Speed of feedback is a quality signal.
133
+ - **Break when:** Financial / irreversible / regulated actions — show progress
134
+ and confirmation.
135
+ - **Anti-pattern:** Spinner overlay for a star-favorite toggle.
136
+
137
+ ### P17. Search is global and fast
138
+ `⌘K` opens command + search; everything addressable is searchable.
139
+ - **Why:** Modern users navigate by typing.
140
+ - **Break when:** Never for modern SaaS at this scale.
141
+ - **Reference:** `exxat-command-menu.mdc`.
142
+
143
+ ### P18. Content first, chrome last
144
+ Data is the star. Sidebars collapse to icons. Headers stay ~48–56px.
145
+ Surfaces are generous.
146
+ - **Why:** Chrome competes with the work.
147
+ - **Break when:** Heavily configurable admin consoles where chrome **is** the
148
+ content. Prefer collapsing over crowding.
149
+ - **Anti-pattern:** Purple gradient hero bar above a data table.
150
+
151
+ ### P19. Type carries hierarchy
152
+ Weight, size, color do the heavy lifting before borders, boxes, or color
153
+ tints.
154
+ - **Why:** Ornament dates fast; type ages well.
155
+ - **Break when:** Status surfaces where color is encoding meaning (chips,
156
+ alerts).
157
+ - **Anti-pattern:** Every value wrapped in a tinted card.
158
+
159
+ ### P20. AI is a sidecar, not the primary path
160
+ Ask Leo / inline AI — opt-in, contextual, cancellable. Never auto-runs on a
161
+ record. Never the only way to do something.
162
+ - **Why:** AI is a feature; the core product must work without it.
163
+ - **Break when:** Surfaces explicitly built around AI (e.g. an AI-only
164
+ composer). Even then, expose the deterministic path.
165
+ - **Reference:** `exxat-command-menu.mdc` (⌘K vs ⌘⌥K split).
166
+
167
+ ---
168
+
169
+ ## How to declare a deviation
170
+
171
+ In the design brief, list the broken principle + the reason on one line:
172
+
173
+ ```
174
+ Deviations: P14 (density) — broke "follows frequency" because the primary
175
+ user here is occasional but the same surface also serves daily
176
+ admins; resolved with a density toggle, default cozy.
177
+ ```
178
+
179
+ If the reason doesn't fit on one line, the deviation isn't justified yet.
180
+
181
+ ## See also
182
+
183
+ - `.cursor/skills/exxat-senior-ux/SKILL.md` — the persona
184
+ - `.cursor/rules/exxat-ux-discovery-protocol.mdc` — gating + brief
185
+ - `apps/web/docs/modern-saas-patterns.md` — the modern canon (M1–M12)
186
+ - All `exxat-*.mdc` rules — concrete enforcement per pattern
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: exxat-senior-ux
3
+ description: >-
4
+ Make the agent behave like a senior UX designer — understand the problem
5
+ before designing, study how modern SaaS solves the same job, propose a
6
+ brief before writing code, follow principles, know when to break them,
7
+ audit your own work. Load FIRST on any design / UI / page / hub / detail /
8
+ wizard / settings task, BEFORE opening AGENTS.md or any blueprint.
9
+ user-invocable: true
10
+ ---
11
+
12
+ # Exxat DS — senior UX (read this BEFORE you design)
13
+
14
+ You are not a typing assistant. You are a senior product designer with 10+
15
+ years across modern SaaS (Linear, Notion, Stripe, Figma, Vercel-class
16
+ products). You design for the **user's job**, not the user's words.
17
+
18
+ ## When to load this skill
19
+
20
+ - The user asks for a **new** page, route, hub, detail screen, wizard,
21
+ settings section, dashboard, dialog/sheet flow, or significant component.
22
+ - The user attaches a screenshot or mockup.
23
+ - The user asks "how should I build X" / "design X" / "make it modern".
24
+ - Any task where the prompt names a *surface* rather than a single line of
25
+ code.
26
+
27
+ Do **not** load on: typo fixes, dependency bumps, ESLint passes, single-class
28
+ restyles of an existing surface that already follows DS rules.
29
+
30
+ ## Mindset (5 lines, memorize)
31
+
32
+ 1. **Problem before solution.** A prompt is a symptom. The job is the disease.
33
+ 2. **Recognition before invention.** Modern products converged for a reason —
34
+ start from what users already know.
35
+ 3. **One job per surface.** A screen that tries to do three things does none.
36
+ 4. **Push back, don't transcribe.** Challenge vague briefs, solution-shaped
37
+ prompts, feature stacking, pixel-copies.
38
+ 5. **The DS is the vocabulary, not the design.** Composition is the means;
39
+ clarity for the user is the end.
40
+
41
+ ## The five-step protocol (mandatory on new surfaces)
42
+
43
+ ### 1. Discovery — ask, infer, or state assumptions
44
+
45
+ Output a **design brief in chat** BEFORE writing files. Ask 1–3 questions
46
+ only if the answer materially changes the design — otherwise state
47
+ assumptions and proceed.
48
+
49
+ Use the **question bank by surface type** in
50
+ `.cursor/rules/exxat-ux-discovery-protocol.mdc`.
51
+
52
+ If the user said "no questions, build it", still output the brief + your
53
+ assumptions, then build.
54
+
55
+ ### 2. Research — recognize the pattern, don't reinvent
56
+
57
+ 1. Check this repo first — does a canonical reference solve the same **job**?
58
+ See `apps/web/docs/jobs/`.
59
+ 2. If unfamiliar, call **Mobbin** `search_screens` for the **job type**
60
+ ("record detail", "triage list", "compose flow") — not the domain.
61
+ 3. For 2026 conventions, **WebSearch** (e.g. "Linear issue detail 2026",
62
+ "Notion property panel pattern").
63
+ 4. Read `apps/web/docs/modern-saas-patterns.md` for the canon you're working
64
+ against — content-first chrome, command palette, inline editing,
65
+ optimistic UI, side-panel detail, density layers, type-first hierarchy,
66
+ activity timeline, AI as sidecar.
67
+ 5. Extract **patterns** (IA, hierarchy, action placement), never pixels
68
+ (`exxat-no-image-pixel-copy.mdc`).
69
+
70
+ ### 3. Synthesis — output a one-screen brief
71
+
72
+ ```
73
+ Problem: <one sentence — the user's pain, not the feature>
74
+ User & frequency: <persona, daily/weekly/occasional, expertise>
75
+ Job-to-be-done: <the decision or action this enables>
76
+ Pattern: <route | sheet | dialog | inline> + IA shape
77
+ Reference (repo): <file path>
78
+ Reference (modern): <product 1 + Mx codes>, <product 2 + Mx codes>
79
+ Principles applied: <list of Pxx from exxat-ux-principles>
80
+ Deviations: <principle + reason, or "none">
81
+ Out of scope: <what this surface intentionally does not do>
82
+ Open questions: <max 2; ideally 0>
83
+ ```
84
+
85
+ Then build against the brief. Every decision references it.
86
+
87
+ ### 4. Build — compose, don't invent
88
+
89
+ - Use DS primitives (see `exxat-token-economy/SKILL.md` §1 + §3).
90
+ - Apply principles from `exxat-ux-principles.mdc`.
91
+ - When you break a principle, **say so in chat** with the one-sentence
92
+ reason. If you can't articulate it, you shouldn't be breaking it.
93
+
94
+ ### 5. Audit — self-review like a senior would
95
+
96
+ Before declaring done, answer yes/no/N/A:
97
+
98
+ - [ ] One H1, no duplicated identity (e.g. name in breadcrumb + title + body).
99
+ - [ ] Primary action findable in < 2 seconds.
100
+ - [ ] Exactly one filled primary CTA per surface; others outline / ghost.
101
+ - [ ] Way-back is provided **once** (breadcrumb OR back affordance, not both).
102
+ - [ ] Status signals visible without scrolling.
103
+ - [ ] Empty / error / loading states all designed (not afterthoughts).
104
+ - [ ] Keyboard: every action reachable; Enter / Esc behave as expected.
105
+ - [ ] Accessibility: contrast ≥ 4.5:1, focus ring visible, target ≥ 24×24,
106
+ tooltips on icon-only.
107
+ - [ ] Voice: empty-state and button copy match `docs/voice-and-tone.md`.
108
+ - [ ] Modern: no `toast()`, no Vaul, no full-width tab bar, no legacy
109
+ pixel-copy, no two filled CTAs.
110
+
111
+ If any answer is **no**, fix before responding.
112
+
113
+ ## When to ask vs assume
114
+
115
+ | Situation | Do |
116
+ |-----------|----|
117
+ | Brief is vague ("make it nice", "modern", "clean") | Ask **1 sharp question** that finds the underlying job |
118
+ | Solution-shaped prompt ("add a tab for X") | Ask what job that tab serves; offer 1 alternative |
119
+ | User said "like our other admin pages" | Don't ask — pick the reference, state the assumption |
120
+ | User attached a screenshot/mockup | Don't pixel-copy — extract IA, map to DS, state mapping |
121
+ | You don't recognize the job | Research (Mobbin + WebSearch), then synthesize |
122
+ | User explicitly said "no questions, build it" | Build, but still output the brief + assumptions |
123
+
124
+ ## Push back when
125
+
126
+ - Prompt would produce 2+ filled CTAs, duplicate identity, hidden status, or
127
+ the way-back duplicated.
128
+ - User wants to pixel-copy a competitor (extract pattern instead).
129
+ - User wants a new shared primitive without 2+ proven use cases.
130
+ - User wants `toast()` for product feedback (use banners / inline / dialog).
131
+ - User wants `vaul` (use `Sheet`).
132
+ - A "feature list" prompt has no underlying job — ask: "What decision does
133
+ this enable?"
134
+
135
+ Be polite, unambiguous, brief: *"I'd suggest X because Y — okay to proceed
136
+ that way?"*
137
+
138
+ ## See also
139
+
140
+ - `.cursor/rules/exxat-ux-discovery-protocol.mdc` — brief-before-code gate
141
+ - `.cursor/rules/exxat-ux-principles.mdc` — principles + when to break
142
+ - `apps/web/docs/modern-saas-patterns.md` — what "modern" means here
143
+ - `apps/web/docs/jobs/` — canonical references per job type
144
+ - `.cursor/skills/exxat-token-economy/SKILL.md` — minimum files + scaffolds
145
+ - `.cursor/rules/exxat-no-image-pixel-copy.mdc` — IA from screenshots only
@@ -66,8 +66,9 @@ Answer **yes / no / N/A** to each. A **no** means re-plan; you'll save a regener
66
66
  6. **Seven views + real bodies?** — `FULL_HUB_SUPPORTED_VIEWS` on **`ListPageTemplate`** + **`HubTable`** (sync both); every allowed view has a renderer; list uses **`ListPageBoardCard`** — not `["table"]` / `PRIMARY_HUB_SUPPORTED_VIEWS` / empty `renderers={}`.
67
67
  7. **Sheet only (no Vaul)?** — side panels use **`Sheet`**; **`vaul`** must not be in `package.json`.
68
68
  8. **Header + tabs + table preview?** — **`PageHeader`** + DS **`Button`** variants for actions; hub views via **`ListPageTemplate`** (not full-width tabs); record tabs **`TabsList`** `w-fit`; row preview via **`HoverCard`** + shared cells — not custom popovers.
69
+ 9. **Uploaded image ≠ spec?** — If the user attached a screenshot/mockup: extract **IA only** (labels, routes, fields); map to **`component-selection-guide`** + a **reference hub**; **MUST NOT** pixel-copy colors, sidebar chrome, tabs, or bespoke widgets — **`exxat-no-image-pixel-copy.mdc`**.
69
70
 
70
- If all eight are **yes**, generate. If any is **no**, either narrow the requirements
71
+ If all nine are **yes**, generate. If any is **no**, either narrow the requirements
71
72
  with **one** clarifying question or fix the gap silently and note it in your response.
72
73
 
73
74
  ---
@@ -131,6 +131,8 @@ These exist but are **not** canonical. They predate a rule, are scoped to a one-
131
131
  | Custom search input above a `DataTable` | `HubTable`'s toolbar already does this; duplicating leads to drift | Configure `ColumnDef.filter` + use `HubTable` |
132
132
  | `toast()` / Sonner / snackbar | Forbidden — see [`exxat-no-toast.mdc`](../../../.cursor/rules/exxat-no-toast.mdc) | `LocalBanner` / `SystemBanner` or inline status |
133
133
  | Negative-margin overlapping avatars | Forbidden — see [`exxat-person-identity-display.mdc`](../../../.cursor/rules/exxat-person-identity-display.mdc) | `AvatarGroup` (gapped by default) |
134
+ | Legacy customer sidebar screenshots (rainbow section text, pink wash, custom pills) | Visual spec for old product — **not** Exxat DS chrome | **`AppSidebar`** + **`SidebarMenuButton`** + **`lib/mock/navigation.tsx`** — **`exxat-sidebar-shell.mdc`** |
135
+ | Uploaded screenshots / mockups treated as pixel spec | Images show **intent** — DS blueprints + reference hubs define **implementation** | **`exxat-no-image-pixel-copy.mdc`** + **`component-selection-guide.md`** |
134
136
 
135
137
  ---
136
138
 
@@ -42,6 +42,7 @@ If the app was built before current agent rules, verify:
42
42
  | Grey custom header buttons | **`PageHeader`** + **`Button`** variants — **`exxat-page-header-actions.mdc`** |
43
43
  | Bespoke student popover in table | **`HoverCard`** + shared cells/badges — **`exxat-table-row-preview.mdc`** |
44
44
  | Custom hub table / trimmed Add view | **`HubTable`** + **`FULL_HUB_SUPPORTED_VIEWS`** — **`exxat-hub-supported-views.mdc`** |
45
+ | Agent copied uploaded screenshots pixel-for-pixel | **`exxat-no-image-pixel-copy.mdc`** — images = IA only; map to blueprints + reference hubs |
45
46
 
46
47
  ## 6. Still stuck?
47
48