@exxatdesignux/ui 0.3.0 → 0.4.1
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.
- package/CHANGELOG.md +701 -6
- package/README.md +138 -0
- package/bin/init.mjs +134 -31
- package/consumer-extras/cursor-rules/exxat-board-cards.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +2 -2
- package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-data-tables.mdc +2 -0
- package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +3 -3
- package/consumer-extras/cursor-rules/exxat-library-hub-header.mdc +28 -0
- package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +1 -1
- package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +6 -6
- package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +1 -1
- package/consumer-extras/cursor-skills/exxat-board-cards/SKILL.md +2 -2
- package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-collaboration-access/SKILL.md +3 -3
- package/consumer-extras/cursor-skills/exxat-dedicated-search-surfaces/SKILL.md +2 -2
- package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +7 -7
- package/consumer-extras/cursor-skills/exxat-kpi-flat-band/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-list-page-view-shells/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-mono-ids/SKILL.md +4 -4
- package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +8 -8
- package/consumer-extras/cursor-skills/exxat-token-economy/SKILL.md +277 -0
- package/consumer-extras/handbook/HANDBOOK.md +2 -0
- package/consumer-extras/handbook/glossary.md +2 -1
- package/consumer-extras/handbook/reference-implementations.md +31 -4
- package/consumer-extras/patterns/collaboration-access-pattern.md +7 -7
- package/consumer-extras/patterns/data-views-pattern.md +18 -16
- package/consumer-extras/patterns/kpi-flat-band-pattern.md +2 -2
- package/dist/components/data-table/index.js +2 -2
- package/dist/components/data-table/index.js.map +1 -1
- package/dist/components/data-table/pagination.js +3 -3
- package/dist/components/data-table/pagination.js.map +1 -1
- package/dist/components/data-table/use-table-state.d.ts +1 -1
- package/dist/components/data-table/use-table-state.js.map +1 -1
- package/dist/components/data-views/data-row-list.js.map +1 -1
- package/dist/components/data-views/finder-panel-view.d.ts +1 -1
- package/dist/components/data-views/finder-panel-view.js.map +1 -1
- package/dist/components/data-views/hub-table.d.ts +9 -3
- package/dist/components/data-views/hub-table.js +262 -40
- package/dist/components/data-views/hub-table.js.map +1 -1
- package/dist/components/data-views/index.js +262 -40
- package/dist/components/data-views/index.js.map +1 -1
- package/dist/components/data-views/list-page-split-hub-tokens.d.ts +2 -2
- package/dist/components/data-views/list-page-split-hub-tokens.js.map +1 -1
- package/dist/components/data-views/list-page-tree-column-header.d.ts +1 -1
- package/dist/components/data-views/list-page-tree-column-header.js.map +1 -1
- package/dist/components/data-views/list-page-tree-panel-shell.js.map +1 -1
- package/dist/components/data-views/os-folder-glyph.d.ts +1 -1
- package/dist/components/data-views/os-folder-glyph.js.map +1 -1
- package/dist/components/ui/avatar.d.ts +1 -1
- package/dist/components/ui/key-metrics.js.map +1 -1
- package/dist/index.js +136 -39
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/components/data-table/index.tsx +2 -2
- package/src/components/data-table/pagination.tsx +5 -1
- package/src/components/data-table/use-table-state.ts +1 -1
- package/src/components/data-views/data-row-list.tsx +1 -1
- package/src/components/data-views/finder-panel-view.tsx +2 -2
- package/src/components/data-views/hub-table.tsx +149 -41
- package/src/components/data-views/list-page-split-hub-tokens.ts +2 -2
- package/src/components/data-views/list-page-tree-column-header.tsx +1 -1
- package/src/components/data-views/os-folder-glyph.tsx +1 -1
- package/src/components/ui/key-metrics.tsx +1 -1
- package/template/.claude/skills/exxat-ds-skill/SKILL.md +8 -7
- package/template/.cursor/rules/exxat-accessibility.mdc +1 -1
- package/template/.cursor/rules/exxat-command-menu.mdc +1 -1
- package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +6 -6
- package/template/.cursor/rules/exxat-data-tables.mdc +3 -3
- package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +5 -5
- package/template/.cursor/rules/exxat-mono-ids.mdc +1 -1
- package/template/.cursor/rules/exxat-page-vs-drawer.mdc +1 -1
- package/template/.cursor/rules/exxat-table-properties-drawer.mdc +1 -1
- package/template/AGENTS.md +43 -37
- package/template/app/(app)/columns/page.tsx +11 -0
- package/template/app/(app)/library/all/page.tsx +11 -0
- package/template/app/(app)/library/find/page.tsx +12 -0
- package/template/app/(app)/{question-bank → library}/layout.tsx +16 -16
- package/template/app/(app)/library/list/page.tsx +12 -0
- package/template/app/(app)/{question-bank → library}/new/page.tsx +10 -10
- package/template/app/(app)/library/page.tsx +11 -0
- package/template/app/(app)/tokens-themes/page.tsx +11 -0
- package/template/components/ask-leo-composer.tsx +2 -2
- package/template/components/columns-client.tsx +158 -0
- package/template/components/columns-showcase.tsx +541 -0
- package/template/components/data-views/index.ts +32 -6
- package/template/components/data-views/{question-bank-folder-tree-branch.tsx → library-folder-tree-branch.tsx} +19 -19
- package/template/components/data-views/table-cells.tsx +673 -0
- package/template/components/folder-details-shell.tsx +11 -11
- package/template/components/hub-tree-panel-view.tsx +24 -24
- package/template/components/{question-bank-board-view.tsx → library-board-view.tsx} +44 -44
- package/template/components/{question-bank-client.tsx → library-client.tsx} +82 -82
- package/template/components/{question-bank-dashboard-charts.tsx → library-dashboard-charts.tsx} +14 -14
- package/template/components/{question-bank-favorite-button.tsx → library-favorite-button.tsx} +7 -7
- package/template/components/{question-bank-hub-client.tsx → library-hub-client.tsx} +43 -43
- package/template/components/{question-bank-new-folder-sheet.tsx → library-new-folder-sheet.tsx} +14 -14
- package/template/components/{question-bank-os-folder-view.tsx → library-os-folder-view.tsx} +31 -31
- package/template/components/{question-bank-page-header.tsx → library-page-header.tsx} +6 -6
- package/template/components/library-panel-activator.tsx +8 -0
- package/template/components/{question-bank-secondary-nav.tsx → library-secondary-nav.tsx} +60 -60
- package/template/components/{question-bank-table.tsx → library-table.tsx} +97 -97
- package/template/components/list-hub-status-badge.tsx +2 -2
- package/template/components/{new-question-composer.tsx → new-library-item-form.tsx} +37 -37
- package/template/components/sidebar/app-sidebar.tsx +61 -5
- package/template/components/sidebar/secondary-panel.tsx +109 -56
- package/template/components/sidebar/sidebar-auto-collapse.tsx +2 -2
- package/template/components/sidebar/sidebar-auto-open.tsx +2 -1
- package/template/components/table-properties/types.ts +1 -1
- package/template/components/templates/discovery-hub-template.tsx +1 -1
- package/template/components/templates/new-focus-template.tsx +2 -2
- package/template/components/templates/secondary-panel-hub-template.tsx +1 -1
- package/template/components/tokens-secondary-nav.tsx +192 -0
- package/template/components/tokens-themes-client.tsx +476 -0
- package/template/components/tokens-themes-section.tsx +386 -0
- package/template/docs/HANDBOOK.md +187 -0
- package/template/docs/blueprints/README.md +1 -1
- package/template/docs/blueprints/board-card.md +1 -1
- package/template/docs/blueprints/data-table.md +2 -2
- package/template/docs/blueprints/list-page-template.md +3 -3
- package/template/docs/blueprints/page-header.md +4 -4
- package/template/docs/collaboration-access-pattern.md +7 -7
- package/template/docs/component-selection-guide.md +1 -1
- package/template/docs/data-views-pattern.md +18 -16
- package/template/docs/glossary.md +58 -0
- package/template/docs/kpi-flat-band-pattern.md +3 -3
- package/template/docs/kpi-trend-pattern.md +18 -3
- package/template/docs/large-dataset-strategy.md +155 -0
- package/template/docs/library-hub-header-pattern.md +25 -0
- package/template/docs/migrations/_template.md +1 -1
- package/template/docs/reference-implementations.md +151 -0
- package/template/docs/token-taxonomy.md +1 -1
- package/template/docs/voice-and-tone.md +262 -0
- package/template/eslint.config.mjs +9 -39
- package/template/hooks/use-secondary-panel-hub-nav.ts +10 -10
- package/template/lib/ask-leo-route-context.ts +6 -18
- package/template/lib/coach-mark-registry.ts +0 -16
- package/template/lib/command-menu-config.ts +5 -12
- package/template/lib/command-menu-search-data.ts +8 -39
- package/template/lib/{question-bank-authoring.ts → library-authoring.ts} +89 -88
- package/template/lib/library-dedicated-search.ts +19 -0
- package/template/lib/library-hub-search.ts +90 -0
- package/template/lib/library-nav.ts +477 -0
- package/template/lib/library-recent-searches.ts +22 -0
- package/template/lib/{placements-supported-views.ts → library-supported-views.ts} +2 -2
- package/template/lib/list-status-badges.ts +16 -104
- package/template/lib/mock/dashboard.ts +1 -1
- package/template/lib/mock/{question-bank-folders.ts → library-folders.ts} +30 -30
- package/template/lib/mock/library-header-collaborators.ts +54 -0
- package/template/lib/mock/{question-bank-inspector.ts → library-inspector.ts} +29 -29
- package/template/lib/mock/{question-bank-kpi.ts → library-kpi.ts} +20 -20
- package/template/lib/mock/library.ts +249 -0
- package/template/lib/mock/navigation.tsx +32 -26
- package/template/lib/table-state-lifecycle.ts +1 -1
- package/template/next.config.mjs +7 -4
- package/template/package.json +0 -1
- package/tokens/hooks-index.json +2874 -0
- package/consumer-extras/cursor-rules/exxat-question-bank-hub-header.mdc +0 -28
- package/template/app/(app)/examples/page.tsx +0 -41
- package/template/app/(app)/question-bank/find/page.tsx +0 -12
- package/template/app/(app)/question-bank/library/page.tsx +0 -11
- package/template/app/(app)/question-bank/list/page.tsx +0 -12
- package/template/app/(app)/question-bank/page.tsx +0 -11
- package/template/components/compliance-board-view.tsx +0 -142
- package/template/components/compliance-client.tsx +0 -92
- package/template/components/compliance-page-header.tsx +0 -89
- package/template/components/compliance-table.tsx +0 -468
- package/template/components/data-view-dashboard-charts-compliance.tsx +0 -963
- package/template/components/data-view-dashboard-charts-team.tsx +0 -971
- package/template/components/data-view-dashboard-charts.tsx +0 -1503
- package/template/components/new-placement-back-btn.tsx +0 -28
- package/template/components/new-placement-form.tsx +0 -942
- package/template/components/placement-board-card.tsx +0 -250
- package/template/components/placement-detail.tsx +0 -438
- package/template/components/placements-board-view.tsx +0 -397
- package/template/components/placements-client.tsx +0 -220
- package/template/components/placements-list-view.tsx +0 -124
- package/template/components/placements-page-header.tsx +0 -166
- package/template/components/placements-table-cells.test.tsx +0 -22
- package/template/components/placements-table-cells.tsx +0 -173
- package/template/components/placements-table-columns.tsx +0 -210
- package/template/components/placements-table.tsx +0 -934
- package/template/components/question-bank-panel-activator.tsx +0 -8
- package/template/components/rotations-empty-state.tsx +0 -50
- package/template/components/rotations-panel-activator.tsx +0 -8
- package/template/components/sites-board-view.tsx +0 -67
- package/template/components/sites-client.tsx +0 -154
- package/template/components/sites-table.tsx +0 -249
- package/template/components/team-board-view.tsx +0 -122
- package/template/components/team-client.tsx +0 -100
- package/template/components/team-page-header.tsx +0 -92
- package/template/components/team-table.tsx +0 -553
- package/template/docs/question-bank-hub-header-pattern.md +0 -25
- package/template/lib/compliance-supported-views.ts +0 -10
- package/template/lib/data-view-dashboard-placements-layout.ts +0 -215
- package/template/lib/mock/compliance-kpi.ts +0 -61
- package/template/lib/mock/compliance.ts +0 -146
- package/template/lib/mock/placements-kpi.ts +0 -134
- package/template/lib/mock/placements.ts +0 -176
- package/template/lib/mock/question-bank-header-collaborators.ts +0 -54
- package/template/lib/mock/question-bank.ts +0 -249
- package/template/lib/mock/sites-directory.ts +0 -16
- package/template/lib/mock/sites-kpi.ts +0 -25
- package/template/lib/mock/team-kpi.ts +0 -60
- package/template/lib/mock/team.ts +0 -118
- package/template/lib/placement-board-card-layout.ts +0 -79
- package/template/lib/question-bank-dedicated-search.ts +0 -19
- package/template/lib/question-bank-hub-search.ts +0 -90
- package/template/lib/question-bank-nav.ts +0 -477
- package/template/lib/question-bank-recent-searches.ts +0 -22
- package/template/lib/question-bank-supported-views.ts +0 -12
- package/template/lib/sites-supported-views.ts +0 -10
- package/template/lib/team-supported-views.ts +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,687 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- ### `@exxatdesignux/ui` — publish hygiene + smarter scaffolder
|
|
8
|
+
|
|
9
|
+
Three real bugs in the `0.4.0` tarball made first-run consumer installs
|
|
10
|
+
fail. All three are now fixed.
|
|
11
|
+
- **`tokens/hooks-index.json` ships.** The `exports` map declared
|
|
12
|
+
`"./tokens/hooks-index.json"` but the `files` array did not include
|
|
13
|
+
`tokens`, so the file was silently omitted from the published tarball.
|
|
14
|
+
Any `import "@exxatdesignux/ui/tokens/hooks-index.json"` (used by
|
|
15
|
+
`@exxatdesignux/eslint-plugin`'s `no-deprecated-tokens` rule and by
|
|
16
|
+
workspaces that read the token registry) blew up with
|
|
17
|
+
`MODULE_NOT_FOUND`. The `files` array now includes `tokens`.
|
|
18
|
+
- **No more `workspace:*` leaking into the published template.** The
|
|
19
|
+
scaffolder template was sync'd from `apps/web/package.json`, which
|
|
20
|
+
uses `workspace:*` for both `@exxatdesignux/ui` (correct, gets
|
|
21
|
+
rewritten to a real semver pin) and a handful of monorepo-internal
|
|
22
|
+
dev tools (`@exxatdesignux/eslint-plugin`, …) which are not published
|
|
23
|
+
on npm. The previous sync rewrote only the design-system line, so
|
|
24
|
+
every consumer install (`npm` / `pnpm` / `yarn`) crashed on the
|
|
25
|
+
leaked entries. The sync script now walks every dep map
|
|
26
|
+
(`dependencies` / `devDependencies` / `peerDependencies` /
|
|
27
|
+
`optionalDependencies`), pins `@exxatdesignux/ui`, deletes any
|
|
28
|
+
remaining `workspace:` value, and fails the build if any leaks
|
|
29
|
+
survive — so the bug surfaces here, not on a consumer's terminal.
|
|
30
|
+
- **Consumer-safe `eslint.config.mjs` in the template.** The repo's
|
|
31
|
+
own `apps/web/eslint.config.mjs` imports
|
|
32
|
+
`@exxatdesignux/eslint-plugin` for DS guardrails (no hex literals,
|
|
33
|
+
no deprecated tokens, no SLDS leakage, no Sonner toasts). Because
|
|
34
|
+
that plugin isn't published, `pnpm lint` in a freshly-scaffolded app
|
|
35
|
+
crashed with `Cannot find package '@exxatdesignux/eslint-plugin'`.
|
|
36
|
+
The sync script now overwrites `template/eslint.config.mjs` with a
|
|
37
|
+
clean `eslint-config-next + globalIgnores + unused-vars` setup that
|
|
38
|
+
every consumer can run. The DS guardrails graduate to this template
|
|
39
|
+
whenever the plugin lands on npm.
|
|
40
|
+
|
|
41
|
+
### Smarter `bin/init.mjs` scaffolder
|
|
42
|
+
|
|
43
|
+
The `create-exxat-app` binary now matches the conventions of
|
|
44
|
+
`create-next-app` and `create-vite`:
|
|
45
|
+
- **Positional target directory.** `create-exxat-app my-app` creates
|
|
46
|
+
`./my-app` and scaffolds into it. `create-exxat-app .` scaffolds
|
|
47
|
+
into the current directory. Missing directories are auto-created.
|
|
48
|
+
- **Package-manager auto-detection.** Reads `npm_config_user_agent`
|
|
49
|
+
and runs the matching install (`pnpm install` / `yarn install` /
|
|
50
|
+
`bun install` / `npm install`). The post-install hint prints the
|
|
51
|
+
matching `<pm> run dev` command.
|
|
52
|
+
- **`--force` flag.** Allow scaffolding into a non-empty directory
|
|
53
|
+
(existing files are not overwritten unless the template ships the
|
|
54
|
+
same path). The previous "directory must be empty" hard-error
|
|
55
|
+
blocked every "install the DS first, then scaffold" sequence.
|
|
56
|
+
- **`--no-install` flag.** Skip the install step (useful in CI or
|
|
57
|
+
sandboxed setups).
|
|
58
|
+
- **`--help` / `-h`.** Print usage.
|
|
59
|
+
- **Clearer blocked-directory error.** When the target is non-empty
|
|
60
|
+
without `--force`, the CLI lists which files are blocking and
|
|
61
|
+
suggests both options (`create-exxat-app my-new-app` or
|
|
62
|
+
`create-exxat-app . --force`) instead of failing silently.
|
|
63
|
+
|
|
64
|
+
### Real README on the npm package page
|
|
65
|
+
|
|
66
|
+
`packages/ui/` had no `README.md` — the npm landing page at
|
|
67
|
+
[npmjs.com/package/@exxatdesignux/ui](https://www.npmjs.com/package/@exxatdesignux/ui)
|
|
68
|
+
showed only the bare package.json description. The new README leads
|
|
69
|
+
with the 60-second start (`pnpm create exxat-app my-app`), covers
|
|
70
|
+
"adding to an existing Next.js app", documents `exxat-ui sync-extras`
|
|
71
|
+
for Cursor skill installation, and links the full doc set.
|
|
72
|
+
|
|
73
|
+
### `create-exxat-app@0.0.x` → new package
|
|
74
|
+
|
|
75
|
+
A new `create-exxat-app` discovery package now ships on npm so
|
|
76
|
+
`pnpm create exxat-app my-app` (and the npm / yarn / bun variants)
|
|
77
|
+
resolve natively without a `--package=` flag. The shim is intentionally
|
|
78
|
+
tiny — it depends on `@exxatdesignux/ui` (via `workspace:^`, pinned to
|
|
79
|
+
`^<version>` at publish) and delegates to
|
|
80
|
+
`@exxatdesignux/ui/bin/init.mjs`. All template, version-pinning, and
|
|
81
|
+
package-manager-detection logic stays in `@exxatdesignux/ui` so there
|
|
82
|
+
is exactly one source of truth.
|
|
83
|
+
|
|
84
|
+
### Migration
|
|
85
|
+
|
|
86
|
+
Consumers on `0.4.0` should bump to `0.4.1`:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pnpm up @exxatdesignux/ui@latest
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
If you scaffolded with `0.4.0` and edited `eslint.config.mjs` /
|
|
93
|
+
`package.json` to work around the workspace leak, you can either keep
|
|
94
|
+
your manual edits or re-scaffold with `0.4.1` for a clean baseline.
|
|
95
|
+
|
|
96
|
+
## 0.4.0
|
|
97
|
+
|
|
98
|
+
### Minor Changes
|
|
99
|
+
|
|
100
|
+
- ### Build and distribution overhaul
|
|
101
|
+
|
|
102
|
+
The package now ships a real compiled `dist/` (ESM + `.d.ts` + source
|
|
103
|
+
maps) produced by `tsup`, replacing the previous shadcn-style "ship raw
|
|
104
|
+
`.tsx` source" approach. Non-Next consumers (Vite, Remix, plain Node
|
|
105
|
+
tooling) can now install and import without configuring a TS/JSX
|
|
106
|
+
transform for `node_modules`.
|
|
107
|
+
- `exports`, `main`, `module`, `types` point at `./dist/*`.
|
|
108
|
+
- `"use client"` directives are preserved on emit via a post-build pass
|
|
109
|
+
in `tsup.config.ts`.
|
|
110
|
+
- `prepack` builds before publish so `dist/` is always current.
|
|
111
|
+
- Per-component subpath imports
|
|
112
|
+
(`@exxatdesignux/ui/components/<name>`) continue to work — they now
|
|
113
|
+
resolve to `dist/components/ui/<name>.js`.
|
|
114
|
+
|
|
115
|
+
### New primitives
|
|
116
|
+
- **`AlertDialog`** — blocking confirm dialog backed by Radix
|
|
117
|
+
`AlertDialog`. Ships `AlertDialogAction` + `AlertDialogCancel` that
|
|
118
|
+
wrap `Button` so consumers can pair destructive verbs without
|
|
119
|
+
re-styling. Read the new
|
|
120
|
+
`.cursor/rules/exxat-drawer-vs-dialog.mdc` for when to choose this
|
|
121
|
+
over the generic `Dialog`.
|
|
122
|
+
- **`Accordion`** — Radix-backed expandable section list with
|
|
123
|
+
chevron-flipping triggers. Use for FAQ-style or settings-grouping
|
|
124
|
+
surfaces where each panel toggles independently (`type="multiple"`)
|
|
125
|
+
or as a single-open group (`type="single"`).
|
|
126
|
+
- **`ContextMenu`** — right-click + long-press menu mirroring the
|
|
127
|
+
`DropdownMenu` surface (same item heights, tints, separators,
|
|
128
|
+
sub-menu chevron, checkbox / radio item indicators). Pair with a
|
|
129
|
+
visible `…` overflow `DropdownMenu` so keyboard-only users can reach
|
|
130
|
+
the same actions.
|
|
131
|
+
- **`HoverCard`** — richer hover surface for content too large or
|
|
132
|
+
interactive for a `Tooltip` (avatars, link previews, glossary
|
|
133
|
+
entries). Comes with the same animation tokens as `Popover`.
|
|
134
|
+
- **`ScrollArea`** — explicitly-bounded scroll container with
|
|
135
|
+
always-visible-on-hover scrollbars that respect platform conventions;
|
|
136
|
+
for sidebar trees, popover lists, long inspector panels.
|
|
137
|
+
- **`Slider`** — single- and dual-thumb numeric range backed by Radix
|
|
138
|
+
`Slider`. Thumbs render automatically based on `value` / `defaultValue`
|
|
139
|
+
cardinality.
|
|
140
|
+
|
|
141
|
+
Each primitive is exported from both the umbrella entry
|
|
142
|
+
(`@exxatdesignux/ui`) and a subpath
|
|
143
|
+
(`@exxatdesignux/ui/components/<name>`); matching `apps/web`
|
|
144
|
+
re-export shims live at `apps/web/components/ui/<name>.tsx`.
|
|
145
|
+
|
|
146
|
+
### Promoted patterns (no longer leaf-only)
|
|
147
|
+
|
|
148
|
+
The package now ships product patterns alongside primitives — the same
|
|
149
|
+
shape as SLDS, Adobe Spectrum, Primer, MUI, Chakra.
|
|
150
|
+
- **`PageHeader`** — full hub header (h1, subtitle, optional
|
|
151
|
+
collaboration variant with face row + access info). Moved from
|
|
152
|
+
`apps/web/components/page-header.tsx`. `apps/web` keeps a 1-line
|
|
153
|
+
re-export shim at the original path; every existing
|
|
154
|
+
`import … from "@/components/page-header"` site continues to work.
|
|
155
|
+
- **`ListPageViewFrame`** — shared horizontal gutter + optional
|
|
156
|
+
centered max-width for non-`DataTable` list-hub view bodies (folder
|
|
157
|
+
icon grid, finder panel, OS-style explorer). Moved from
|
|
158
|
+
`apps/web/components/data-views/list-page-view-frame.tsx`.
|
|
159
|
+
- **`KeyMetrics`** (with `KeyMetricsContent`, `MetricItem`,
|
|
160
|
+
`MetricInsight`, `metricTrendTone`, `metricTrendAriaQualifier`) —
|
|
161
|
+
the full ~1.1 k LOC KPI strip moved from
|
|
162
|
+
`apps/web/components/key-metrics.tsx`. Hard-wired references to the
|
|
163
|
+
host app's `useAskLeo()` hook and `<AskLeoShortcutKbds />` component
|
|
164
|
+
are gone; both flow through a new injectable context.
|
|
165
|
+
|
|
166
|
+
Consumers wire their assistant by mounting `KeyMetricsProvider`
|
|
167
|
+
near the root and passing two optional values:
|
|
168
|
+
- **`defaultInsightAction: () => void`** — fires when the user
|
|
169
|
+
clicks the default "Ask Leo about these metrics" header CTA.
|
|
170
|
+
When omitted, the CTA is hidden entirely so the strip stays
|
|
171
|
+
useful in apps without an AI surface.
|
|
172
|
+
- **`shortcutHint: React.ReactNode`** — inline kbd chord (or any
|
|
173
|
+
node) rendered next to the action label inside the tooltip.
|
|
174
|
+
When omitted, the tooltip shows just the label.
|
|
175
|
+
- **`defaultActionLabel: string`** — visible + accessible name
|
|
176
|
+
for the header CTA. Defaults to "Ask Leo".
|
|
177
|
+
|
|
178
|
+
This is the same injection shape Adobe Spectrum (`Provider`-based
|
|
179
|
+
services) and Material UI (`Theme` context) use, so design-system
|
|
180
|
+
patterns can ship without taking a hard dependency on the host
|
|
181
|
+
app's AI / shortcut wiring.
|
|
182
|
+
|
|
183
|
+
`apps/web` keeps a 1-line `key-metrics.tsx` re-export shim plus a
|
|
184
|
+
new `key-metrics-ask-leo-bridge.tsx` adapter that's mounted in
|
|
185
|
+
`(app)/layout.tsx` just inside `AskLeoProvider`. All 20 existing
|
|
186
|
+
`<KeyMetrics />` consumers continue to work with no source
|
|
187
|
+
changes.
|
|
188
|
+
|
|
189
|
+
### New shared utilities (`@exxatdesignux/ui/lib/*`)
|
|
190
|
+
|
|
191
|
+
Foundation modules promoted from `apps/web` so the upcoming
|
|
192
|
+
`DataTable`, `useTableState`, and `TablePropertiesDrawer` promotions
|
|
193
|
+
have a stable shared contract.
|
|
194
|
+
- **`row-height`** — `RowHeight` type + `ROW_HEIGHT_TILES` density
|
|
195
|
+
presets (compact / default / comfortable). Shared by the Properties
|
|
196
|
+
drawer tiles and `useTableState`.
|
|
197
|
+
- **`raf-throttle`** — coalesces high-frequency event handlers
|
|
198
|
+
(scroll, resize, ResizeObserver) into one call per animation frame
|
|
199
|
+
with a `.cancel()` for effect cleanup.
|
|
200
|
+
- **`editable-target`** — `isEditableTarget()` guard used by global
|
|
201
|
+
keyboard-shortcut handlers (Export `⌘⇧E`, rename `F2`, …) so
|
|
202
|
+
hotkeys don't steal keystrokes from text inputs / `contenteditable`
|
|
203
|
+
surfaces.
|
|
204
|
+
- **`conditional-rule-match`** — pure matchers
|
|
205
|
+
(`conditionalRuleMatchesRow`, `getConditionalRowBackground`,
|
|
206
|
+
`getConditionalCellBackground`) shared by `DataTable` cells,
|
|
207
|
+
`data-row-list` rows, and board card row tints so all three views
|
|
208
|
+
paint conditional formatting identically.
|
|
209
|
+
- **`table-properties-types`** — generic filter / sort /
|
|
210
|
+
conditional-rule type contracts (`FilterOperator`,
|
|
211
|
+
`FilterTextMask`, `FilterFieldDef`, `ActiveFilter`, `SortRule`,
|
|
212
|
+
`ColDef`, `ConditionalRule`) plus the design-system
|
|
213
|
+
`OPERATOR_LABELS` and `RULE_COLORS` palette. Product-specific seed
|
|
214
|
+
data (Placements `FILTER_FIELDS` + `COLUMNS` arrays) intentionally
|
|
215
|
+
stays in `apps/web/components/table-properties/types.ts`, which
|
|
216
|
+
now re-exports the types from the package.
|
|
217
|
+
|
|
218
|
+
`apps/web` keeps 1-line shims at the original `@/lib/*` paths
|
|
219
|
+
(`row-height.ts`, `raf-throttle.ts`, `editable-target.ts`,
|
|
220
|
+
`conditional-rule-match.ts`) so every existing import site continues
|
|
221
|
+
to work with no source change. The 12 files that import from
|
|
222
|
+
`@/components/table-properties/types` also keep working because the
|
|
223
|
+
file now re-exports the package types alongside the Placements
|
|
224
|
+
defaults.
|
|
225
|
+
|
|
226
|
+
### Promoted DataTable (the biggest one)
|
|
227
|
+
|
|
228
|
+
The full generic `DataTable<TData>` family moved into the package as
|
|
229
|
+
`@exxatdesignux/ui/components/data-table` — ~3 k LOC across six files:
|
|
230
|
+
- **`./components/data-table`** (the umbrella) — `DataTable`,
|
|
231
|
+
`DataTableExtendedProps`, the column header context menu, resizing,
|
|
232
|
+
drag-to-reorder, per-column quick search, pinned columns,
|
|
233
|
+
group-by + collapsible groups, hidden columns, bulk-action bar,
|
|
234
|
+
conditional cell tints, sticky group headers, the column auto-fit
|
|
235
|
+
algorithm, and the inline filter popovers. Imports from
|
|
236
|
+
`next-themes` (light/dark column resizers) and `react-dom`
|
|
237
|
+
(`createPortal` for the bulk-action bar) are passed through; everything
|
|
238
|
+
else routes to DS primitives or DS lib utilities.
|
|
239
|
+
- **`./components/data-table/use-table-state`** — the 758-LOC hook
|
|
240
|
+
that owns filtering, sorting, search, density, pinning, hidden
|
|
241
|
+
columns, group-by, and column ordering for any consumer table.
|
|
242
|
+
No app-specific coupling; takes a generic `TData[]` + column defs.
|
|
243
|
+
- **`./components/data-table/pagination`** — `PaginationBar`,
|
|
244
|
+
`DataTablePaginated`, and `CountSyncer`. Wraps the umbrella
|
|
245
|
+
`DataTable` with a page-size selector + page navigation.
|
|
246
|
+
- **`./components/data-table/types`** — `ColumnDef`, `CellContext`,
|
|
247
|
+
`DataTableProps`, `PaginationConfig`, `SortDir`. Re-exports
|
|
248
|
+
`ConditionalRule` and `FilterTextMask` from the package
|
|
249
|
+
`table-properties-types` so column-def authors only need one import.
|
|
250
|
+
- **`./components/data-table/filter-date-calendar`** — single-date
|
|
251
|
+
YYYY-MM-DD filter calendar shared by the inline filter popover and
|
|
252
|
+
the Properties drawer date inputs.
|
|
253
|
+
- **`./components/data-table/filter-text-value-input`** — masked /
|
|
254
|
+
unmasked text input router for filter values (`phone`, `zip`,
|
|
255
|
+
`dateMDY`, free text). Falls back to the package `Input` when no
|
|
256
|
+
mask is requested.
|
|
257
|
+
|
|
258
|
+
The promotion required **no decoupling work** — Wave 7's `KeyMetrics`
|
|
259
|
+
context refactor and Wave 8's lib promotions had already moved every
|
|
260
|
+
shared dependency into the package. The DataTable suite has no
|
|
261
|
+
`useAskLeo`-style app-runtime coupling; every `@/` import the original
|
|
262
|
+
files used now resolves inside `packages/ui`.
|
|
263
|
+
|
|
264
|
+
Package `exports` map adds two new entries so the umbrella + subpath
|
|
265
|
+
imports both work:
|
|
266
|
+
- `./components/data-table` → `dist/components/data-table/index.js`
|
|
267
|
+
- `./components/data-table/*` →
|
|
268
|
+
`dist/components/data-table/*.{js,d.ts}`
|
|
269
|
+
|
|
270
|
+
These are declared **before** the generic `./components/*` rule so
|
|
271
|
+
the literal key and longer pattern win specificity resolution.
|
|
272
|
+
|
|
273
|
+
`apps/web/components/data-table/*.{ts,tsx}` (all 6 files) become 1-line
|
|
274
|
+
re-export shims so every existing
|
|
275
|
+
`import { DataTable } from "@/components/data-table"` site (~12 hubs
|
|
276
|
+
plus `useTableState` consumers) continues to work with no source
|
|
277
|
+
change.
|
|
278
|
+
|
|
279
|
+
The package now publishes `dist/components/data-table/{index,
|
|
280
|
+
pagination, use-table-state, filter-date-calendar,
|
|
281
|
+
filter-text-value-input, types}.{js,d.ts,js.map}` with the leading
|
|
282
|
+
`"use client"` directive preserved on every client module.
|
|
283
|
+
|
|
284
|
+
### Linting
|
|
285
|
+
- Add `eslint-plugin-react-hooks` to `packages/ui` and register
|
|
286
|
+
`react-hooks/rules-of-hooks` (error) + `react-hooks/exhaustive-deps`
|
|
287
|
+
(warn). Required so the promoted `DataTable` and `useTableState`
|
|
288
|
+
files keep working — both carry targeted `eslint-disable-next-line
|
|
289
|
+
react-hooks/exhaustive-deps` comments that previously errored out
|
|
290
|
+
with "Definition for rule '…' was not found".
|
|
291
|
+
|
|
292
|
+
### Promoted Table Properties drawer + data-list view registry
|
|
293
|
+
|
|
294
|
+
The full Table Properties drawer family moved into the package as
|
|
295
|
+
`@exxatdesignux/ui/components/table-properties` — ~1.6 k LOC across six
|
|
296
|
+
files plus the five data-list-view lib modules that the drawer (and
|
|
297
|
+
`ListPageTemplate` view tabs) read for label / icon / render-kind
|
|
298
|
+
metadata.
|
|
299
|
+
- **`./components/table-properties`** (the umbrella):
|
|
300
|
+
- `drawer.tsx` (~1.1 k LOC) — Properties sheet with View type tiles,
|
|
301
|
+
Filters / Sort / Group / Columns panels, Conditional formatting
|
|
302
|
+
rules, and the Display sub-sheet (gridlines, row height,
|
|
303
|
+
pagination, board swimlane field, line count). Sheet uses `z-[90]`
|
|
304
|
+
so portaled menus from inside it stack on top of `z-50` dropdowns.
|
|
305
|
+
- `drawer-button.tsx` (~280 LOC) — Reusable Properties button + drawer
|
|
306
|
+
combo. Accepts any `useTableState<T>` return value as `state`
|
|
307
|
+
(structural typing reads only display-agnostic fields, so it works
|
|
308
|
+
for any row shape). Mutators are read via `stateRef.current.X`
|
|
309
|
+
inside the Sheet portal, so handler identities stay stable
|
|
310
|
+
across re-renders.
|
|
311
|
+
- `filter-card.tsx` (~250 LOC) — One filter row inside the drawer
|
|
312
|
+
(operator dropdown, value picker, remove button). Used by both
|
|
313
|
+
filter rules and conditional-formatting rules.
|
|
314
|
+
- `sort-card.tsx` (~60 LOC) — One sort rule in the Sort panel (label,
|
|
315
|
+
direction toggle, drag handle, remove).
|
|
316
|
+
- `column-row.tsx` (~90 LOC) — One row in the Columns panel
|
|
317
|
+
(visibility toggle, drag handle).
|
|
318
|
+
- `draggable-list.ts` (~50 LOC) — `useDraggableList` pointer-driven
|
|
319
|
+
reorder hook shared by sort cards, column rows, and conditional
|
|
320
|
+
rule lists.
|
|
321
|
+
|
|
322
|
+
Both `drawer.tsx` and `drawer-button.tsx` get cleaner contracts as
|
|
323
|
+
part of the move: **`fieldDefinitions` and `filterFields` are now
|
|
324
|
+
required props**, replacing the silent fallback to the Placements
|
|
325
|
+
`COLUMNS` / `FILTER_FIELDS` constants. Every real consumer was
|
|
326
|
+
already passing both through `drawerToolbarProps` from
|
|
327
|
+
`HubTable` (built once via `columnsToFieldDefinitions` /
|
|
328
|
+
`columnsToFilterFields`); the fallback path was unreachable and
|
|
329
|
+
leaked Placements column shapes into the design-system package.
|
|
330
|
+
`DrawerSortCard` similarly drops its `COLUMNS.find(…).label`
|
|
331
|
+
fallback — the drawer always passes a `fieldLabel`
|
|
332
|
+
(`resolveColumnLabel(rule.fieldKey)`).
|
|
333
|
+
|
|
334
|
+
- **`./lib/data-list-view`** — `DataListViewType` vocabulary
|
|
335
|
+
(`table | list | board | dashboard | calendar | folder | panel |
|
|
336
|
+
tree-panel`), `DATA_LIST_VIEW_TILES`, `dataListViewLabel`,
|
|
337
|
+
`dataListViewIcon`, `dataListViewAddShortcut`.
|
|
338
|
+
- **`./lib/data-list-view-registry`** — Registry that maps each view
|
|
339
|
+
type to its render kind + chrome rules (`hubMetricsStrip`,
|
|
340
|
+
`dataListViewTilesForHub`, `dataListViewSelectionTilesForHub`,
|
|
341
|
+
`DATA_LIST_SURFACE_VIEW_TYPES`, `isDataListSurfaceViewType`,
|
|
342
|
+
`isDataListViewTypeSupported`).
|
|
343
|
+
- **`./lib/data-list-view-surface`** — `DataListViewRenderKind` enum
|
|
344
|
+
- `getDataListViewRenderKind`, `usesDataTableComponent`,
|
|
345
|
+
`usesDashboardSurface`, `usesToolbarWithFilteredRows` predicates so
|
|
346
|
+
`view === "dashboard"` is never mistaken for `view === "board"` in
|
|
347
|
+
switch chains.
|
|
348
|
+
- **`./lib/data-list-display-options`** — `DataListDisplayOptions`
|
|
349
|
+
(board line count, board swimlane key, show titles / column labels /
|
|
350
|
+
search) + `DEFAULT_DATA_LIST_DISPLAY_OPTIONS`.
|
|
351
|
+
- **`./lib/list-page-table-properties`** —
|
|
352
|
+
`createListPageEditViewHandler` + `OpenTablePropertiesHandle` so
|
|
353
|
+
`ListPageTemplate`'s "View → Edit" callback opens the drawer (after
|
|
354
|
+
coercing the tab to `table` when the active view does not host
|
|
355
|
+
Properties).
|
|
356
|
+
|
|
357
|
+
Package `exports` map adds:
|
|
358
|
+
- `./components/table-properties` →
|
|
359
|
+
`dist/components/table-properties/index.js` (umbrella)
|
|
360
|
+
- `./components/table-properties/*` →
|
|
361
|
+
`dist/components/table-properties/*.{js,d.ts}` (subpath)
|
|
362
|
+
|
|
363
|
+
`apps/web` keeps 1-line shims at all the original paths:
|
|
364
|
+
- 6 drawer-family files at `apps/web/components/table-properties/*`
|
|
365
|
+
(`drawer`, `drawer-button`, `filter-card`, `sort-card`, `column-row`,
|
|
366
|
+
`draggable-list`) — all re-export from
|
|
367
|
+
`@exxatdesignux/ui/components/table-properties/*`.
|
|
368
|
+
- 5 lib files at `apps/web/lib/*` (`data-list-view`,
|
|
369
|
+
`data-list-view-registry`, `data-list-view-surface`,
|
|
370
|
+
`data-list-display-options`, `list-page-table-properties`).
|
|
371
|
+
|
|
372
|
+
`apps/web/components/table-properties/types.ts` keeps the
|
|
373
|
+
Placements-specific `FILTER_FIELDS` + `COLUMNS` seed data (those are
|
|
374
|
+
**product data**, not design-system primitives) and continues to
|
|
375
|
+
re-export the generic types from `@exxatdesignux/ui/lib/table-properties-types`,
|
|
376
|
+
so every existing `import … from "@/components/table-properties"`
|
|
377
|
+
site keeps working unchanged.
|
|
378
|
+
|
|
379
|
+
The package now ships
|
|
380
|
+
`dist/components/table-properties/{drawer, drawer-button, filter-card,
|
|
381
|
+
sort-card, column-row, draggable-list, index}.{js,d.ts,js.map}` with
|
|
382
|
+
the leading `"use client"` directive preserved on the 5 client modules
|
|
383
|
+
(`draggable-list` is a pure hook so the inheriting consumer's `"use
|
|
384
|
+
client"` boundary covers it).
|
|
385
|
+
|
|
386
|
+
### Promoted Data views — list-page binding layer
|
|
387
|
+
|
|
388
|
+
The list-page binding layer moved into the package as
|
|
389
|
+
`@exxatdesignux/ui/components/data-views` — ~1.15 k LOC across 9
|
|
390
|
+
files. `HubTable<TRow>` is now the canonical composition that ties
|
|
391
|
+
`DataTable` + `useTableState` + `TablePropertiesDrawerButton` + view
|
|
392
|
+
tabs into one generic component:
|
|
393
|
+
- **`./components/data-views/hub-table`** (~497 LOC) — `HubTable<TRow>`
|
|
394
|
+
- `columnsToFilterFields` + `columnsToFieldDefinitions` helpers +
|
|
395
|
+
`HubTableProps<TRow>` / `HubTableRendererArgs<TRow>` /
|
|
396
|
+
`HubDrawerToolbarProps`. Pass columns, rows, supported view types,
|
|
397
|
+
and a `renderers: { [renderKind]: ReactNode | () => ReactNode }` map.
|
|
398
|
+
The component owns `useTableState`, builds
|
|
399
|
+
`filterFields`/`fieldDefinitions` from your columns, mounts the
|
|
400
|
+
Properties button, and routes the active view tab through
|
|
401
|
+
`ListPageConnectedViewBody`.
|
|
402
|
+
- **`./components/data-views/list-page-connected-view-body`** —
|
|
403
|
+
`ListPageConnectedViewBody` + `ListPageViewNotConfigured` + the
|
|
404
|
+
`ListPageConnectedViewRenderers` type. Switches view bodies by
|
|
405
|
+
`DataListViewRenderKind` and shows a clear empty state when a
|
|
406
|
+
registered view is missing a renderer (never silently falls through
|
|
407
|
+
to dashboard).
|
|
408
|
+
- **`./components/data-views/data-row-list`** — virtualized list-view
|
|
409
|
+
body backed by `@tanstack/react-virtual` (new package dependency,
|
|
410
|
+
declared in `peerDependencies` shape; tree-shaken when only board
|
|
411
|
+
consumers import).
|
|
412
|
+
- **`./components/data-views/list-page-board-template`** — Reusable
|
|
413
|
+
kanban shell where columns are defined by predicates over each row.
|
|
414
|
+
- **`./components/data-views/list-page-board-card`** —
|
|
415
|
+
`ListPageBoardCard` shell with `stack` and `row` layouts, optional
|
|
416
|
+
`ListPageBoardCardAvatar`, `ListPageBoardCardTitleRow`,
|
|
417
|
+
`ListPageBoardCardBadgeRow`, `ListPageBoardCardBody`,
|
|
418
|
+
`ListPageBoardCardSecondary` slots. Matches placement-board card
|
|
419
|
+
visuals one-to-one.
|
|
420
|
+
- **`./components/data-views/board-card-primitives`** —
|
|
421
|
+
`BoardCardTwoLineBlock`, `BoardCardIconRow`,
|
|
422
|
+
`BoardNewCardPlaceholder` primitives shared between
|
|
423
|
+
`list-page-board-template` and consumer-built board cards. Reads
|
|
424
|
+
`BoardLineCount` from `data-list-display-options` to clamp text
|
|
425
|
+
lines.
|
|
426
|
+
- **`./components/data-views/list-page-tree-column-header`** /
|
|
427
|
+
**`list-page-split-details-placeholder`** /
|
|
428
|
+
**`list-page-split-hub-chrome`** — Pure-CSS shells used by the
|
|
429
|
+
finder / tree-panel / multi-column explorer views (centered card
|
|
430
|
+
- fixed viewport height; composes `ListPageViewFrame`).
|
|
431
|
+
|
|
432
|
+
Package `exports` map adds:
|
|
433
|
+
- `./components/data-views` →
|
|
434
|
+
`dist/components/data-views/index.js` (umbrella)
|
|
435
|
+
- `./components/data-views/*` →
|
|
436
|
+
`dist/components/data-views/*.{js,d.ts}` (subpath)
|
|
437
|
+
|
|
438
|
+
All 9 modules are exported from the main `@exxatdesignux/ui` barrel
|
|
439
|
+
and `apps/web/components/data-views/{hub-table, data-row-list,
|
|
440
|
+
list-page-connected-view-body, board-card-primitives,
|
|
441
|
+
list-page-board-card, list-page-board-template,
|
|
442
|
+
list-page-tree-column-header, list-page-split-details-placeholder,
|
|
443
|
+
list-page-split-hub-chrome}.tsx` are all 1-line re-export shims, so
|
|
444
|
+
every existing consumer (Placements, Team, Compliance, Question Bank,
|
|
445
|
+
plus every `HubTableRendererArgs<TRow>`-typed table renderer) keeps
|
|
446
|
+
working with no source change.
|
|
447
|
+
|
|
448
|
+
### Tooling
|
|
449
|
+
- Add `@tanstack/react-virtual` to `packages/ui` `dependencies` (the
|
|
450
|
+
virtualized `DataRowList` body needs it). External in `tsup` so the
|
|
451
|
+
consumer bundle dedupes against any pre-existing `apps/web` copy.
|
|
452
|
+
- Add `packages/ui/src/globals.d.ts` declaring a minimal
|
|
453
|
+
`process.env.NODE_ENV` ambient so `HubTable`'s dev-time
|
|
454
|
+
missing-renderer `console.warn` typechecks without taking on a
|
|
455
|
+
`@types/node` dependency. Both bundlers and Next.js's RSC compiler
|
|
456
|
+
statically replace `process.env.NODE_ENV` at build time, so the
|
|
457
|
+
declaration only affects type-checking.
|
|
458
|
+
- Clean up `useImperativeHandle` deps in `HubTable` to extract the
|
|
459
|
+
stable `setSheetOpen` setter from `useTableState` before the hook
|
|
460
|
+
call, removing the misplaced
|
|
461
|
+
`eslint-disable-next-line react-hooks/exhaustive-deps` comment.
|
|
462
|
+
|
|
463
|
+
### Promoted ExportDrawer + ListPageTemplate + small templates
|
|
464
|
+
|
|
465
|
+
The page-scale list-hub composition moved into the package as
|
|
466
|
+
`@exxatdesignux/ui/components/templates` so non-Next consumers (Vite,
|
|
467
|
+
Remix, plain CRA) can mount a complete hub without copying app source.
|
|
468
|
+
- **`./components/export-drawer`** — `ExportDrawer` (format + date range
|
|
469
|
+
- columns + active-filter toggle), single-file component composed from
|
|
470
|
+
in-package primitives only. App-specific `devLog` came along as
|
|
471
|
+
`./lib/dev-log` (`process.env.NODE_ENV` gated — bundlers strip the
|
|
472
|
+
call site in production).
|
|
473
|
+
- **`./components/templates/list-page`** — `ListPageTemplate` +
|
|
474
|
+
`ViewTab` / `ViewType` / `FilterOption` types + the canonical
|
|
475
|
+
`VIEW_TYPES` array derived from `DATA_LIST_VIEW_TILES`. The template
|
|
476
|
+
composes `PageHeader` slots (`header`, `metrics`,
|
|
477
|
+
`beforeSiteHeader`), the view-segmented control, and the now-promoted
|
|
478
|
+
`ExportDrawer` directly.
|
|
479
|
+
- **`./components/templates/nested-secondary-panel-shell`** — Single
|
|
480
|
+
responsive shell pairing a primary sidebar with a nested secondary
|
|
481
|
+
panel (used by Question bank).
|
|
482
|
+
- **`./components/templates/dedicated-search-landing-template`** —
|
|
483
|
+
Empty-`?q=` landing surface (`DotPattern` + lens + suggestions
|
|
484
|
+
slot) composed on `ListPageViewFrame`.
|
|
485
|
+
- **`./components/templates/dedicated-search-results-template`** —
|
|
486
|
+
`DedicatedSearchResultsHeaderChrome` + the
|
|
487
|
+
`DEDICATED_SEARCH_RESULTS_OUTER_CONTENT_CLASSNAME` shared classname
|
|
488
|
+
for the populated `?q=` branch.
|
|
489
|
+
|
|
490
|
+
App-side compositions that wrap product-specific shells
|
|
491
|
+
(`PrimaryPageTemplate`, `SecondaryPanelHubTemplate`,
|
|
492
|
+
`DiscoveryHubTemplate`, `NewFocusTemplate`) stay in
|
|
493
|
+
`apps/web/components/templates/` because they pull in `SiteHeader`,
|
|
494
|
+
`useAskLeo`, or per-route mock data — those will graduate when their
|
|
495
|
+
respective shells are decoupled.
|
|
496
|
+
|
|
497
|
+
Package `exports` map adds:
|
|
498
|
+
- `./components/templates` → `dist/components/templates/index.js`
|
|
499
|
+
- `./components/templates/*` →
|
|
500
|
+
`dist/components/templates/*.{js,d.ts}`
|
|
501
|
+
|
|
502
|
+
`apps/web` ships 1-line re-export shims at
|
|
503
|
+
`apps/web/components/export-drawer.tsx`,
|
|
504
|
+
`apps/web/lib/dev-log.ts`, and
|
|
505
|
+
`apps/web/components/templates/{list-page,
|
|
506
|
+
nested-secondary-panel-shell, dedicated-search-landing-template,
|
|
507
|
+
dedicated-search-results-template}.tsx` so every existing consumer
|
|
508
|
+
keeps working unchanged. All 15 Next.js routes still compile.
|
|
509
|
+
|
|
510
|
+
### Promoted Data view bodies — finder / folder grid / outline tree / tree-panel shell + folder glyph
|
|
511
|
+
|
|
512
|
+
Six view-body modules moved into
|
|
513
|
+
`@exxatdesignux/ui/components/data-views/`, finishing the data-views
|
|
514
|
+
surface graduation that started with `HubTable`:
|
|
515
|
+
- **`./components/data-views/list-page-split-hub-tokens`** — Shared
|
|
516
|
+
layout classnames (`LIST_PAGE_SPLIT_MILLER_COLUMN_PANEL_CLASS`,
|
|
517
|
+
`LIST_PAGE_SPLIT_MILLER_DETAIL_PANEL_CLASS`,
|
|
518
|
+
`LIST_PAGE_SPLIT_RESIZABLE_HANDLE_CLASS`) so finder / tree-panel /
|
|
519
|
+
multi-column hubs stay visually aligned.
|
|
520
|
+
- **`./components/data-views/outline-tree-menu`** — VS Code–style
|
|
521
|
+
outline chrome (`OutlineTreeMenu`, `OutlineTreeMenuItem`,
|
|
522
|
+
`OutlineTreeLeafButton`, `OutlineTreeSub`, `OutlineTreeSubItem`,
|
|
523
|
+
`OutlineTreeCollapsibleContentRail`) with the guide-spacer + sub-row
|
|
524
|
+
shift classnames consumers compose for inset rails.
|
|
525
|
+
- **`./components/data-views/folder-grid-view`** — Generic icon-grid
|
|
526
|
+
layout with empty state, `aria-label`-named list, `renderTile`
|
|
527
|
+
render-prop, and optional centered max-width (icon-grid frame).
|
|
528
|
+
- **`./components/data-views/finder-panel-view`** — Miller-style
|
|
529
|
+
3-column split for list hubs (`FinderPanelView`) reusing the split
|
|
530
|
+
hub tokens + `ListPageTreeColumnHeader` +
|
|
531
|
+
`ListPageSplitDetailsPlaceholder`.
|
|
532
|
+
- **`./components/data-views/list-page-tree-panel-shell`** — Generic
|
|
533
|
+
two-pane layout (tree column + details column) with persisted
|
|
534
|
+
`react-resizable-panels` group id and shared
|
|
535
|
+
`ListPageSplitHubChrome` chrome.
|
|
536
|
+
- **`./components/data-views/os-folder-glyph`** — Windows-11-style
|
|
537
|
+
folder art (Icons8) + FA glyph overlay, with a generic
|
|
538
|
+
`FolderGlyphColorKey` palette type. Product `QuestionBankFolderColorKey`
|
|
539
|
+
stays in app mock data (same string union — structurally compatible
|
|
540
|
+
with `FolderGlyphColorKey`, no source changes required at call sites).
|
|
541
|
+
|
|
542
|
+
Package `exports` map continues to route
|
|
543
|
+
`./components/data-views/*` to the new modules. The package barrel
|
|
544
|
+
re-exports them all. App-side 1-line shims continue to provide the
|
|
545
|
+
`@/components/data-views/<file>` import paths.
|
|
546
|
+
|
|
547
|
+
`apps/web/components/data-views/question-bank-folder-tree-branch.tsx`
|
|
548
|
+
stays in the app — it pulls product mock data
|
|
549
|
+
(`QuestionBankFolder` / `QUESTION_BANK_FOLDER_ICON_COLORS`) and is the
|
|
550
|
+
right boundary between "design-system primitive" and "product
|
|
551
|
+
composition".
|
|
552
|
+
|
|
553
|
+
### Tailwind L0 token namespace — verified
|
|
554
|
+
|
|
555
|
+
The `--exxat-color-*` / `--exxat-radius-*` / `--exxat-spacing-*` L0
|
|
556
|
+
canonical namespace (migration `0002-exxat-token-namespace.md`) is live
|
|
557
|
+
in the package's `src/globals.css` with Tailwind bridges (`bg-surface-1`,
|
|
558
|
+
`text-ink-1`, `rounded-2`, …) wired through `@theme inline`. The hooks
|
|
559
|
+
index (`packages/ui/tokens/hooks-index.json`) is regenerated to 197
|
|
560
|
+
tokens and passes `tokens:check`. `apps/web/app/globals.css` imports
|
|
561
|
+
the package CSS, so consumers inherit every L0 alias automatically. No
|
|
562
|
+
existing token was renamed; opportunistic per-file migration to L0
|
|
563
|
+
forms is non-breaking and continues as devs touch the code.
|
|
564
|
+
|
|
565
|
+
### Documentation — three new blueprints
|
|
566
|
+
|
|
567
|
+
Added SLDS-style spec docs for the most-touched compositions, completing
|
|
568
|
+
the patterns the blueprints README itself flagged as "future":
|
|
569
|
+
- **`apps/web/docs/blueprints/list-page-template.md`** — view tabs +
|
|
570
|
+
metrics slot + properties drawer wiring, with WCAG mapping and
|
|
571
|
+
Do / Don't table.
|
|
572
|
+
- **`apps/web/docs/blueprints/board-card.md`** — `ListPageBoardCard`
|
|
573
|
+
shell + status badge + body primitives, including the list-row
|
|
574
|
+
counterpart (`layout="row"`).
|
|
575
|
+
- **`apps/web/docs/blueprints/key-metrics.md`** — flat vs card
|
|
576
|
+
variant, KPI count cap, trend polarity, and the service-injection
|
|
577
|
+
bridge for app-specific actions like Ask Leo.
|
|
578
|
+
|
|
579
|
+
The blueprints README links each new doc to its narrative + cursor
|
|
580
|
+
rules + React component. (Storybook / Ladle catalog is intentionally
|
|
581
|
+
not adopted in this pass: the Next.js demo routes plus blueprints
|
|
582
|
+
already cover the documentation surface, and adopting Storybook would
|
|
583
|
+
add infra without immediate signal for this DS.)
|
|
584
|
+
|
|
585
|
+
### Hygiene
|
|
586
|
+
- Add `license: "UNLICENSED"` + `author` fields to `package.json`.
|
|
587
|
+
- Add `--exxat-color-wordmark-ink-light` / `-dark` tokens (used by the
|
|
588
|
+
Exxat product logo SVG + HTML wordmark prefix; replaces five `[#273441](https://github.com/ExxatDesign/Exxat-DS-Workspace/issues/273441)`
|
|
589
|
+
/ `#A8B2BA` literals in `apps/web/components/exxat-product-logo.tsx`
|
|
590
|
+
- `product-wordmark.tsx`).
|
|
591
|
+
- ESLint config landed alongside source. Runs in PR CI with the
|
|
592
|
+
workspace `@exxatdesignux/eslint-plugin` rules (no hex literals, no
|
|
593
|
+
deprecated tokens, no SLDS / Lightning leakage, no Sonner toasts).
|
|
594
|
+
- `npm publish` runs with Sigstore `--provenance` from the
|
|
595
|
+
`.github/workflows/publish-ui.yml` workflow + creates an automated
|
|
596
|
+
GitHub Release.
|
|
597
|
+
- New PR-time CI workflow gates every PR on install → lint → typecheck
|
|
598
|
+
→ tokens drift check → vitest → build, plus the Changesets release
|
|
599
|
+
flow on `main`.
|
|
600
|
+
- Scope the `brace-expansion` security override (GHSA-v6h2-p8h4-qcjw)
|
|
601
|
+
to per-major lines so `minimatch@3.1.5` keeps its compatible 1.x
|
|
602
|
+
branch and ESLint config loading no longer crashes with
|
|
603
|
+
`expand is not a function`.
|
|
604
|
+
- Prune unused mutator destructures in
|
|
605
|
+
`apps/web/components/table-properties/drawer-button.tsx` (left behind
|
|
606
|
+
by the earlier `react-hooks/refs` refactor). Setters are now read
|
|
607
|
+
exclusively via `stateRef.current.X` so handler identities stay
|
|
608
|
+
stable while the Sheet is portaled.
|
|
609
|
+
|
|
610
|
+
- ### Demo / template hub renamed from "Question bank" → "Library"
|
|
611
|
+
|
|
612
|
+
The reference hub that ships in `packages/ui/template/**` and the
|
|
613
|
+
consumer-side mirrors in `packages/ui/consumer-extras/**` were renamed
|
|
614
|
+
from a domain-specific "Question bank" to a generic, placeholder-labeled
|
|
615
|
+
**Library** hub. This affects three surfaces consumers see:
|
|
616
|
+
1. **Template route + components** (used by `exxat-ui scaffold-app`):
|
|
617
|
+
- `app/(app)/question-bank/**` → `app/(app)/library/**`. The
|
|
618
|
+
`library/library` sub-route was simultaneously renamed to
|
|
619
|
+
`library/all` so the canonical "list everything" path reads
|
|
620
|
+
`/library/all`.
|
|
621
|
+
- `components/question-bank-*.tsx` (13 files) →
|
|
622
|
+
`components/library-*.tsx`. `components/new-question-composer.tsx`
|
|
623
|
+
→ `components/new-library-item-form.tsx`.
|
|
624
|
+
- `components/data-views/question-bank-folder-tree-branch.tsx` →
|
|
625
|
+
`components/data-views/library-folder-tree-branch.tsx`.
|
|
626
|
+
- `lib/mock/question-bank{,-folders,-inspector,-kpi,-header-collaborators}.ts`
|
|
627
|
+
→ `lib/mock/library-*.ts`.
|
|
628
|
+
- `lib/question-bank-{nav,supported-views,authoring,recent-searches,hub-search,dedicated-search}.ts`
|
|
629
|
+
→ `lib/library-*.ts`.
|
|
630
|
+
2. **TypeScript surface (template only — package itself ships
|
|
631
|
+
generic shells):** `QuestionBankItem` → `LibraryItem`,
|
|
632
|
+
`QuestionBankFolder` → `LibraryFolder`, `QuestionBankNavState` →
|
|
633
|
+
`LibraryNavState`, `QuestionBankTable` → `LibraryTable`, etc. The
|
|
634
|
+
nested secondary-panel id flipped from `"question-bank"` to
|
|
635
|
+
`"library"`; consumers wiring `useAutoPanel` or the `secondaryPanel`
|
|
636
|
+
prop on a nav row must update the literal.
|
|
637
|
+
3. **Consumer docs + agent rules** (`packages/ui/consumer-extras/`):
|
|
638
|
+
`cursor-rules/exxat-question-bank-hub-header.mdc` →
|
|
639
|
+
`cursor-rules/exxat-library-hub-header.mdc`. The skill and
|
|
640
|
+
handbook entries that cited "Question bank" as the reference
|
|
641
|
+
implementation now cite the **Library** hub instead.
|
|
642
|
+
|
|
643
|
+
Mock content was also abstracted from clinical/medical strings (Bloom
|
|
644
|
+
taxonomy, NBME, anatomy, clinical decks) to neutral placeholders:
|
|
645
|
+
`Item 01..12`, `Owner A..E`, `Category 1..4`, `Type 1..3`,
|
|
646
|
+
`Low / Normal / High`, `Tier 1..6`, `Folder 1..6`, `LIB-2026-###` ids.
|
|
647
|
+
This makes the template usable as a starter for any domain — clinical,
|
|
648
|
+
education, retail, ops, etc. — without rewriting demo data first.
|
|
649
|
+
|
|
650
|
+
### Migration for consumer apps
|
|
651
|
+
|
|
652
|
+
Run `pnpm exxat-ui sync-extras` (or whatever wrapper your repo uses)
|
|
653
|
+
to refresh `cursor-rules/`, `cursor-skills/`, `patterns/`, and
|
|
654
|
+
`handbook/` from the new mirror. The two breaking edges to check
|
|
655
|
+
manually inside your own app code:
|
|
656
|
+
- Any nav row that pinned `secondaryPanel: "question-bank"` →
|
|
657
|
+
`secondaryPanel: "library"`.
|
|
658
|
+
- Any direct import from
|
|
659
|
+
`@/components/question-bank-*` / `@/lib/question-bank-*` /
|
|
660
|
+
`@/lib/mock/question-bank-*` (likely only if you forked the demo
|
|
661
|
+
hub) → rename to the matching `library-*` path.
|
|
662
|
+
|
|
663
|
+
The `DataTable`, `useTableState`, `HubTable`, `ListPageTemplate`,
|
|
664
|
+
`TablePropertiesDrawer`, `KeyMetrics`, and `PageHeader` APIs are
|
|
665
|
+
unchanged — only the demo hub naming flipped.
|
|
666
|
+
|
|
667
|
+
### Pagination chrome regression fixed
|
|
668
|
+
|
|
669
|
+
Independent of the rename, `HubTable.defaultTableRenderer` and the
|
|
670
|
+
`list-with-toolbar` default block now embed `<PaginationBar>` inside
|
|
671
|
+
the table card with `sticky bottom-0` instead of floating it below the
|
|
672
|
+
border. The new layout passes `hasFooter` through to `<DataTable>` so
|
|
673
|
+
the table's top corners stay `rounded-t-lg` and the bottom corners go
|
|
674
|
+
square, then anchors the pagination slab to the page scroll container
|
|
675
|
+
(`PrimaryPageTemplate.bodyClassName`). The shipped `PaginationBar`
|
|
676
|
+
component itself is unchanged.
|
|
677
|
+
|
|
678
|
+
### Docs
|
|
679
|
+
- `apps/web/docs/large-dataset-strategy.md` — new doc covering today's
|
|
680
|
+
client-mode behavior, when to enable pagination, the server-mode
|
|
681
|
+
upgrade path via `paginationOverride`, and the row-virtualization
|
|
682
|
+
follow-up. Cross-linked from `apps/web/AGENTS.md` and
|
|
683
|
+
`apps/web/docs/data-views-pattern.md`.
|
|
684
|
+
|
|
3
685
|
All notable changes to `@exxatdesignux/ui` are documented here. The file ships in the npm tarball at `node_modules/@exxatdesignux/ui/CHANGELOG.md`.
|
|
4
686
|
|
|
5
687
|
## For AI assistants (upgrade handoff)
|
|
@@ -17,12 +699,25 @@ After the user bumps `@exxatdesignux/ui`, do this in order:
|
|
|
17
699
|
|
|
18
700
|
## [Unreleased]
|
|
19
701
|
|
|
702
|
+
## [0.3.1] – 2026-05-21
|
|
703
|
+
|
|
704
|
+
### Fixed
|
|
705
|
+
|
|
706
|
+
- **Customer demo `template/` was stale.** Re-ran `sync-template-from-web` and confirmed the npm `template/` payload now matches what the monorepo runs (`/columns`, `/tokens-themes`, `/question-bank`, `/dashboard`, settings) byte-for-byte. Previously the published `template/` still carried deleted entity-domain files (`placements-*`, `sites-*`, `team-*`, `compliance-*`, `rotation-*`) — they're gone now.
|
|
707
|
+
|
|
708
|
+
### Changed
|
|
709
|
+
|
|
710
|
+
- **`prepack` now auto-syncs template + consumer-extras before `tsup`.** New chain: `sync-template-from-web && vendor-consumer-extras && tsup`. Every `npm publish` (and every `npm pack`) guarantees the shipped `template/` mirrors `apps/web` and the AI bundle under `consumer-extras/` mirrors the latest skills + patterns. No more "I bumped the version but the template is stale" mode — drift is now impossible at publish time.
|
|
711
|
+
- **Handbook + skills refreshed for the post-cleanup canonical refs.** `apps/web/AGENTS.md`, `apps/web/docs/HANDBOOK.md`, `apps/web/docs/data-views-pattern.md`, `apps/web/docs/glossary.md`, `apps/web/docs/reference-implementations.md`, `apps/web/docs/blueprints/{data-table,page-header}.md`, `apps/web/docs/kpi-flat-band-pattern.md`, and `apps/web/docs/component-selection-guide.md` (and the matching `.cursor/skills/exxat-ds-skill/SKILL.md`) all stop citing the deleted Placements / Sites / Team / Compliance components. New canonical references: `columns-showcase.tsx` (smallest single-view hub), `tokens-themes-client.tsx` (smallest secondary-panel + URL-driven scope hub with built-in pagination chrome), `question-bank-table.tsx` + `question-bank-hub-client.tsx` (full multi-view hub: table, board, dashboard).
|
|
712
|
+
|
|
20
713
|
## [0.3.0] – 2026-05-21
|
|
21
714
|
|
|
22
715
|
### Added
|
|
23
716
|
|
|
717
|
+
- **`exxat-token-economy` skill** (`.cursor/skills/exxat-token-economy/SKILL.md` + Claude mirror) — the new "read this first" entry for any AI working with the design system. Targets **~50% fewer input tokens per design turn** by giving the assistant: a task → minimum-file-set table (so it doesn't reflexively open `AGENTS.md`), a five-question pre-flight that catches the top rule violations before generation, canonical primitive aliases (no `grep` needed), tiny copy-verbatim scaffolds for hub client / column def / KPI item, a deny-list of expensive files, an ask-vs-assume heuristic, and an output-discipline section that keeps the assistant's own response lean. `HANDBOOK.md` now opens with a callout pointing to it.
|
|
718
|
+
- **Importable cell primitives** — every SaaS-grid cell pattern demoed in `columns-showcase.tsx` (progress, currency, numeric, rating, signal bars, boolean toggle, attachment count, external link, relative time, face rail with `+N`, type pill, tag list with `+N`, generic `RowActionsCell<TRow>`) is now a named export from `@/components/data-views` (`apps/web/components/data-views/table-cells.tsx`). The showcase becomes a thin orchestrator that imports these — proving they're production-ready, not demo-only. The token-economy skill's §3 ("primitive aliases") and §4 ("`ColumnDef` scaffolds") both name the cells so the AI imports them on the first try instead of re-deriving `Intl.NumberFormat`, star loops, or `<a target="_blank">` inline. `.cursor/rules/exxat-data-tables.mdc` adds a MUST-USE clause; `reference-implementations.md` gains a "Cell primitives (importable)" table; `glossary.md` adds a "Cell primitive" entry.
|
|
24
719
|
- **`exxat-ui sync-extras` now installs the full AI bundle in one command.** Previously the CLI shipped only Cursor skills + pattern docs; consumers had to `degit` Cursor rules and handbook tier docs separately. The CLI now writes, in one pass:
|
|
25
|
-
1. **Skills to both clients** — `.cursor/skills/exxat-*/` **and** `.claude/skills/exxat-*/` (same `SKILL.md` shape, two readers, one source of truth — no more `ln -s` step).
|
|
720
|
+
1. **Skills to both clients** — `.cursor/skills/exxat-*/` **and** `.claude/skills/exxat-*/` (16 folders including the new **`exxat-token-economy`**; same `SKILL.md` shape, two readers, one source of truth — no more `ln -s` step).
|
|
26
721
|
2. **Cursor rules** — `.cursor/rules/exxat-*.mdc` (29 binding `MUST` / `MUST NOT` files: data-tables, accessibility, kbd shortcuts, KPI trends/flat-band/max-four, board cards, list-page-view-shells, centralized-list-dataset, reuse-before-custom, no-toast, drawer-vs-dialog, page-vs-drawer, no-slds-leakage, token-discipline, mono-ids, fontawesome-icons, dashboard-view-charts, …).
|
|
27
722
|
3. **Handbook tier** — `docs/exxat-ds/handbook/{HANDBOOK,glossary,voice-and-tone,reference-implementations}.md`. These are stage-rewritten copies of `apps/web/docs/*.md` — links to shipped patterns use `../`, links to unshipped neighbours (blueprints, token-taxonomy, root `AGENTS.md`, `lib/*`) are rewritten to absolute GitHub URLs at bundle time so every link in the consumer's repo resolves.
|
|
28
723
|
4. **Patterns + checklist** — unchanged from prior releases (`docs/exxat-ds/*-pattern.md`, `consumer-upgrade-checklist.md`).
|
|
@@ -76,11 +771,11 @@ After the user bumps `@exxatdesignux/ui`, do this in order:
|
|
|
76
771
|
### Fixed
|
|
77
772
|
|
|
78
773
|
- **Dark mode surface elevation ladder — popover / card split, secondary panel nestled** (`globals.css`):
|
|
79
|
-
1. **`--popover` lifted to L=0.275** (was 0.225). Sharing the card's subtle 0.225 value made floating dropdowns blend straight into the canvas (only +0.025 above L=0.20) — the dropdown chrome lost its boundary. Popover now sits +0.075 above canvas with a slightly elevated chroma (built-ins 0.022 / custom `max(0.018, c·0.16)`), giving dropdowns and menus the visible lift they need over content. `--card` stays at 0.225 — it's an
|
|
80
|
-
2. **`--secondary-panel-bg` rewired** from `var(--brand-tint)` (which resolved to L=0.30) down to **L=0.22**. The old value made the secondary nav panel
|
|
774
|
+
1. **`--popover` lifted to L=0.275** (was 0.225). Sharing the card's subtle 0.225 value made floating dropdowns blend straight into the canvas (only +0.025 above L=0.20) — the dropdown chrome lost its boundary. Popover now sits +0.075 above canvas with a slightly elevated chroma (built-ins 0.022 / custom `max(0.018, c·0.16)`), giving dropdowns and menus the visible lift they need over content. `--card` stays at 0.225 — it's an _inline_ surface, not a floating one, and the earlier "subtle wash" reading was correct for it.
|
|
775
|
+
2. **`--secondary-panel-bg` rewired** from `var(--brand-tint)` (which resolved to L=0.30) down to **L=0.22**. The old value made the secondary nav panel _brighter_ than the surrounding sidebar (L=0.245), so the Library / question-bank rail popped out as a bright tile instead of nesting in. The new value wedges it between sidebar (0.245) and canvas (0.20). Per-theme overrides carry the brand hue + chroma (Exxat One 0.025, Prism 0.030, Assessment 0.025, custom `max(0.020, c·0.20)`).
|
|
81
776
|
3. **Dark surface ladder is now** `--background` 0.20 → `--secondary-panel-bg` 0.22 → `--card` 0.225 → `--sidebar` / `--input-background` 0.245 → `--popover` 0.275 — clear, monotonic stepping with floating elements lifting further than inline ones.
|
|
82
|
-
- **Dark mode card / popover / input-background — softened to a subtle brand wash, not a tinted panel** (`globals.css`): The previous pass at `L=0.255 C=0.030` made cards read as a
|
|
83
|
-
- **Hydration warnings from the Cursor IDE browser preview** (`app/(app)/layout.tsx`, `components/templates/nested-secondary-panel-shell.tsx`, `components/ask-leo-sidebar.tsx`): The in-IDE browser MCP injects a `data-cursor-ref` attribute on top-level layout chrome
|
|
777
|
+
- **Dark mode card / popover / input-background — softened to a subtle brand wash, not a tinted panel** (`globals.css`): The previous pass at `L=0.255 C=0.030` made cards read as a _separate tinted surface_ floating above canvas. Pulled lightness down to `L=0.225` (only 0.025 above `--background` at L=0.20) and chroma down to `C=0.017` (built-ins) / `max(0.015, calc(c*0.13))` (custom). Cards now read as the same surface family as canvas with a small elevation step and a whisper of brand hue — the saturated brand expression remains on `--brand-tint` and `--sidebar` where it belongs. Input background follows the same shift (L 0.245 / C 0.010). Foreground contrast unchanged (≥ 12:1).
|
|
778
|
+
- **Hydration warnings from the Cursor IDE browser preview** (`app/(app)/layout.tsx`, `components/templates/nested-secondary-panel-shell.tsx`, `components/ask-leo-sidebar.tsx`): The in-IDE browser MCP injects a `data-cursor-ref` attribute on top-level layout chrome _before_ React hydrates so it can target those nodes for click automation. React then warned about an attribute it didn't render. Added `suppressHydrationWarning` on just the three SSR-rendered shell roots that the MCP tags. The flag is scoped to _each element's own attributes only_ — children still hydrate normally and any real mismatch inside the panel still surfaces. Has zero effect outside the Cursor IDE preview.
|
|
84
779
|
- **Dark mode brand surfaces — every product chrome surface now reads as the brand per product** (`globals.css`):
|
|
85
780
|
1. **`--brand-tint`** was never overridden in `.dark` or any `.theme-*.dark` block, so it cascaded down from the light-mode pale value (e.g. `oklch(0.97 0.02 343)` for Prism). Because the dark `--secondary-panel-bg` formula derived it as `color-mix(--card 32%, --brand-tint 68%)`, the question-bank Library secondary panel rendered as a pale rose / lavender pastel on dark canvas. Fixed by adding `--brand-tint` / `--brand-tint-light` / `--brand-tint-subtle` overrides at dark-mode lightness inside `.dark`, `.theme-one.dark`, `.theme-prism.dark`, `.theme-assessment.dark`, and `.theme-custom.dark`.
|
|
86
781
|
2. **`--secondary-panel-bg` formula in `.dark`** rewritten from `color-mix(--card 32%, --brand-tint 68%)` to plain `var(--brand-tint)`. The old mix folded in `--card`'s neutral hue 270 — never overridden per theme in dark mode — so every product's secondary panel was pulled toward the same purple-neutral. Now the panel renders as a fully brand-tinted dark surface that varies clearly per product: Exxat One `#2c2a46` (navy-lavender), Prism `#402235` (wine), Assessment `#143525` (forest green).
|
|
@@ -113,7 +808,7 @@ After the user bumps `@exxatdesignux/ui`, do this in order:
|
|
|
113
808
|
|
|
114
809
|
### Changed
|
|
115
810
|
|
|
116
|
-
- **Tokens**: `globals.css` refinements and starter **`template/`** parity with the web app (layout, Question bank hub chrome, navigation).
|
|
811
|
+
- **Tokens**: `globals.css` refinements and starter **`template/`** parity with the web app (layout, Question bank hub chrome, navigation). _(Note: `theme.css` was a duplicate of `globals.css` and has been removed — see [`0003-globals-css-canonical.md`](../../apps/web/docs/migrations/0003-globals-css-canonical.md).)_
|
|
117
812
|
- **Consumer extras**: Cursor skills + pattern docs refreshed for collaboration / Question bank hub header.
|
|
118
813
|
|
|
119
814
|
### Chore (monorepo)
|