@exxatdesignux/ui 0.4.1 → 0.5.0
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 +64 -0
- package/README.md +28 -11
- package/bin/init.mjs +42 -9
- package/bin/sync-extras.mjs +13 -5
- package/dist/components/data-views/hub-table.js +6 -5
- package/dist/components/data-views/hub-table.js.map +1 -1
- package/dist/components/data-views/index.js +6 -5
- package/dist/components/data-views/index.js.map +1 -1
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/data-views/hub-table.tsx +13 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- `create-exxat-app` now drops the full Cursor + Claude agent bundle into
|
|
8
|
+
the scaffolded repo **automatically** after the dependency install.
|
|
9
|
+
Before this change, a new app shipped with only the 11 binding rules
|
|
10
|
+
that happened to live under `apps/web/.cursor/rules/`; the full curated
|
|
11
|
+
set (29 rules · 16 Cursor skills · 16 Claude skills · 6 pattern docs ·
|
|
12
|
+
4 handbook files) required a second manual `exxat-ui sync-extras` step.
|
|
13
|
+
|
|
14
|
+
What's new for a fresh `pnpm create exxat-app my-app`:
|
|
15
|
+
- After `pnpm install` succeeds, `init.mjs` invokes `sync-extras` in
|
|
16
|
+
`--quiet` mode so the scaffolded repo is one step from "open in
|
|
17
|
+
Cursor and every rule + skill is live".
|
|
18
|
+
- The bundle is namespaced (`exxat-*` files only) so re-syncing on
|
|
19
|
+
upgrade never touches a consumer's own rules, skills, AGENTS.md, or
|
|
20
|
+
product code.
|
|
21
|
+
- Opt out with `create-exxat-app my-app --no-extras` (alias
|
|
22
|
+
`--skip-extras`) — print a "run sync-extras later" hint instead.
|
|
23
|
+
- Final "Done!" message no longer treats `sync-extras` as an optional
|
|
24
|
+
follow-up; it mentions the upgrade-time refresh command instead.
|
|
25
|
+
|
|
26
|
+
Smaller polish in the same release:
|
|
27
|
+
- `--help` now documents `--no-extras`.
|
|
28
|
+
- Project-name normalization handles absolute target paths cleanly
|
|
29
|
+
(no leading-hyphen package names; no `.//absolute/path/` in the
|
|
30
|
+
success message).
|
|
31
|
+
- The `cd <target>` hint is suppressed when the user scaffolded into
|
|
32
|
+
the current directory with `.`.
|
|
33
|
+
- `sync-extras.mjs` learned `--quiet` (and the
|
|
34
|
+
`EXXAT_SYNC_EXTRAS_QUIET=1` env override) so the scaffolder can
|
|
35
|
+
call it without flooding the user with 50+ per-file log lines; the
|
|
36
|
+
final summary line still prints.
|
|
37
|
+
- README updated to describe the auto-extras flow and to clarify the
|
|
38
|
+
`sync-extras` command is now an _upgrade_ refresh, not a required
|
|
39
|
+
first step.
|
|
40
|
+
|
|
41
|
+
## 0.4.2
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- ### `HubTable` — stop warning when the centralized default covers a supported view
|
|
46
|
+
|
|
47
|
+
The dev-time `Missing renderer for supported view …` warning in
|
|
48
|
+
`HubTable` only treated `data-table` as having a built-in fallback,
|
|
49
|
+
even though the same component synthesises centralized defaults for
|
|
50
|
+
`list-with-toolbar` (when the consumer passes `renderListRow`) and
|
|
51
|
+
`board-with-toolbar` (when the consumer passes `renderBoardCard` plus
|
|
52
|
+
`boardGroups`). Every consumer that wired list/board the happy-path
|
|
53
|
+
way saw a spurious console warning every time their hub mounted —
|
|
54
|
+
including the freshly-scaffolded Library hub in `create-exxat-app`,
|
|
55
|
+
where the first thing a new user saw was a repeating
|
|
56
|
+
`[HubTable: Library] Missing renderer for supported view "list"
|
|
57
|
+
(list-with-toolbar)` line, even though the view renders correctly.
|
|
58
|
+
|
|
59
|
+
The warning loop now also skips the two centralized-default cases
|
|
60
|
+
(it still fires for exotic surfaces that genuinely need an explicit
|
|
61
|
+
renderer entry, e.g. Placements' per-phase column-search board, or a
|
|
62
|
+
custom finder body the package doesn't synthesise).
|
|
63
|
+
|
|
64
|
+
No behavior change in production builds (the warning is already gated
|
|
65
|
+
on `process.env.NODE_ENV !== "production"`).
|
|
66
|
+
|
|
3
67
|
## 0.4.1
|
|
4
68
|
|
|
5
69
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -26,8 +26,23 @@ bun create exxat-app my-app
|
|
|
26
26
|
|
|
27
27
|
The scaffolder ships a complete Next.js 16 starter: the reference
|
|
28
28
|
**Library** hub at `/library/all`, the `/columns` cell-catalog showcase,
|
|
29
|
-
typed mock data, the full Cursor
|
|
30
|
-
|
|
29
|
+
typed mock data, plus the full Cursor + Claude agent bundle dropped into
|
|
30
|
+
the right paths **automatically**:
|
|
31
|
+
|
|
32
|
+
- `.cursor/rules/exxat-*.mdc` — 29 binding rules (Cursor reads these as
|
|
33
|
+
always-on / agent-requestable).
|
|
34
|
+
- `.cursor/skills/exxat-*/` and `.claude/skills/exxat-*/` — 16 skill
|
|
35
|
+
bundles (`SKILL.md` + references); same source written to both readers.
|
|
36
|
+
- `docs/exxat-ds/*.md` — 6 pattern docs (data views, command menu,
|
|
37
|
+
drawer-vs-dialog, KPI flat band, …) + the consumer upgrade checklist.
|
|
38
|
+
- `docs/exxat-ds/handbook/*.md` — HANDBOOK · glossary · voice-and-tone ·
|
|
39
|
+
reference-implementations.
|
|
40
|
+
- `AGENTS.md` (root) — the project's AI handbook from the reference app.
|
|
41
|
+
|
|
42
|
+
When you `cd my-app` and open Cursor for the first time, every binding
|
|
43
|
+
rule, skill, and pattern doc is already in place. To opt out, pass
|
|
44
|
+
`--no-extras` to the scaffolder; you can run it later with
|
|
45
|
+
`exxat-ui sync-extras` (see below).
|
|
31
46
|
|
|
32
47
|
## Adding to an existing Next.js app
|
|
33
48
|
|
|
@@ -55,19 +70,21 @@ Mount `KeyMetricsProvider` near the root if you want the "Ask Leo about
|
|
|
55
70
|
these metrics" CTA wired to your AI surface (otherwise the strip just
|
|
56
71
|
hides that button automatically).
|
|
57
72
|
|
|
58
|
-
## Refresh Cursor
|
|
73
|
+
## Refresh Cursor / Claude agent bundle in any consumer
|
|
59
74
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
`pnpm create exxat-app` drops the agent bundle for you on first scaffold.
|
|
76
|
+
When you upgrade `@exxatdesignux/ui` later — or when you want to seed the
|
|
77
|
+
bundle into an **existing** Next.js app that already depends on the DS —
|
|
78
|
+
run:
|
|
63
79
|
|
|
64
80
|
```bash
|
|
65
81
|
pnpm dlx --package=@exxatdesignux/ui@latest exxat-ui sync-extras
|
|
66
82
|
```
|
|
67
83
|
|
|
68
|
-
|
|
69
|
-
`
|
|
70
|
-
|
|
84
|
+
The command is **namespaced**: it only writes files starting with
|
|
85
|
+
`exxat-` (rules + skills) and only inside `.cursor/`, `.claude/skills/`,
|
|
86
|
+
and `docs/exxat-ds/`. Your own rules, skills, AGENTS.md, and product
|
|
87
|
+
code are never touched.
|
|
71
88
|
|
|
72
89
|
## What's inside
|
|
73
90
|
|
|
@@ -121,8 +138,8 @@ natively.
|
|
|
121
138
|
custom property the DS ships.
|
|
122
139
|
|
|
123
140
|
The full doc set is mirrored under `handbook/` and `patterns/` in this
|
|
124
|
-
package; `exxat-
|
|
125
|
-
|
|
141
|
+
package; `pnpm create exxat-app` drops them at `docs/exxat-ds/` on first
|
|
142
|
+
scaffold, and `exxat-ui sync-extras` re-syncs them in any later upgrade.
|
|
126
143
|
|
|
127
144
|
## Compatibility
|
|
128
145
|
|
package/bin/init.mjs
CHANGED
|
@@ -27,9 +27,17 @@ const flags = new Set(args.filter((a) => a.startsWith("--")))
|
|
|
27
27
|
const positional = args.filter((a) => !a.startsWith("--"))
|
|
28
28
|
const targetArg = positional[0] ?? "."
|
|
29
29
|
const targetDir = resolve(process.cwd(), targetArg)
|
|
30
|
-
|
|
30
|
+
// `displayName` is what we show in messages and use to derive package.json
|
|
31
|
+
// `name`. For "." or an absolute path we just use the basename; for a
|
|
32
|
+
// relative path the user typed (`my-app`, `apps/sandbox`) we keep it as-is.
|
|
33
|
+
const isAbsolute = targetArg.startsWith("/") || /^[a-zA-Z]:\\/.test(targetArg)
|
|
34
|
+
const displayName = targetArg === "." || isAbsolute ? basename(targetDir) : targetArg
|
|
35
|
+
// `cdHint` is what we tell the user to `cd` into. If they passed an
|
|
36
|
+
// absolute path, that's the literal path; otherwise the relative arg.
|
|
37
|
+
const cdHint = isAbsolute ? targetDir : displayName
|
|
31
38
|
const force = flags.has("--force")
|
|
32
39
|
const skipInstall = flags.has("--no-install") || flags.has("--skip-install")
|
|
40
|
+
const skipExtras = flags.has("--no-extras") || flags.has("--skip-extras")
|
|
33
41
|
|
|
34
42
|
if (flags.has("--help") || flags.has("-h")) {
|
|
35
43
|
console.log(`
|
|
@@ -47,6 +55,9 @@ Options:
|
|
|
47
55
|
files are NOT overwritten unless template ships the
|
|
48
56
|
same path).
|
|
49
57
|
--no-install Skip the dependency install step.
|
|
58
|
+
--no-extras Skip auto-syncing Cursor / Claude agent skills, binding
|
|
59
|
+
rules, and pattern docs. You can run them later with
|
|
60
|
+
\`exxat-ui sync-extras\`.
|
|
50
61
|
-h, --help Show this message.
|
|
51
62
|
|
|
52
63
|
Examples:
|
|
@@ -59,7 +70,7 @@ Examples:
|
|
|
59
70
|
|
|
60
71
|
if (!existsSync(targetDir)) {
|
|
61
72
|
mkdirSync(targetDir, { recursive: true })
|
|
62
|
-
console.log(`📁 Created ${
|
|
73
|
+
console.log(`📁 Created ${displayName}/`)
|
|
63
74
|
}
|
|
64
75
|
|
|
65
76
|
const targetStat = statSync(targetDir)
|
|
@@ -86,7 +97,7 @@ if (blockers.length > 0 && !force) {
|
|
|
86
97
|
process.exit(1)
|
|
87
98
|
}
|
|
88
99
|
|
|
89
|
-
console.log(`📦 Copying Exxat DS starter app into ${
|
|
100
|
+
console.log(`📦 Copying Exxat DS starter app into ${displayName}/ …`)
|
|
90
101
|
cpSync(templateDir, targetDir, { recursive: true })
|
|
91
102
|
|
|
92
103
|
// Pin DS to this CLI's published version so `latest` cache drift cannot
|
|
@@ -97,7 +108,7 @@ if (targetPkg.dependencies?.["@exxatdesignux/ui"]) {
|
|
|
97
108
|
targetPkg.dependencies["@exxatdesignux/ui"] = `^${selfPkg.version}`
|
|
98
109
|
}
|
|
99
110
|
// Name the project after the target dir for nicer dev-server / process titles.
|
|
100
|
-
targetPkg.name =
|
|
111
|
+
targetPkg.name = displayName.replace(/[^a-z0-9-_]/gi, "-").toLowerCase() || "my-exxat-app"
|
|
101
112
|
writeFileSync(targetPkgPath, `${JSON.stringify(targetPkg, null, 2)}\n`)
|
|
102
113
|
console.log(`📌 Pinned @exxatdesignux/ui to ^${selfPkg.version} and named the project "${targetPkg.name}".`)
|
|
103
114
|
|
|
@@ -111,19 +122,41 @@ if (skipInstall) {
|
|
|
111
122
|
} catch (err) {
|
|
112
123
|
console.error("")
|
|
113
124
|
console.error(`❌ ${pm.label} install failed. You can retry manually:`)
|
|
114
|
-
console.error(` cd ${
|
|
125
|
+
console.error(` cd ${cdHint} && ${pm.installCmd}`)
|
|
115
126
|
process.exit(1)
|
|
116
127
|
}
|
|
117
128
|
}
|
|
118
129
|
|
|
130
|
+
// Drop the full curated bundle (Cursor + Claude skills, binding rules,
|
|
131
|
+
// pattern docs, handbook) into the new repo so AI assistants light up on
|
|
132
|
+
// first open. The bundle replaces only `exxat-*` namespaced files — the
|
|
133
|
+
// consumer's own rules/skills/docs are preserved on every re-run.
|
|
134
|
+
if (skipExtras) {
|
|
135
|
+
console.log(`⏭ Skipped agent skills + rules (--no-extras).`)
|
|
136
|
+
} else {
|
|
137
|
+
const syncScript = resolve(__dirname, "sync-extras.mjs")
|
|
138
|
+
if (!existsSync(syncScript)) {
|
|
139
|
+
console.warn(`⚠️ Could not find sync-extras at ${syncScript} — skipping.`)
|
|
140
|
+
} else {
|
|
141
|
+
console.log(`🧠 Installing Cursor + Claude agent skills, binding rules, and pattern docs …`)
|
|
142
|
+
try {
|
|
143
|
+
execSync(`node "${syncScript}" --quiet`, { stdio: "inherit", cwd: targetDir })
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.warn(`⚠️ Agent extras step failed. You can retry manually:`)
|
|
146
|
+
console.warn(` cd ${cdHint} && ${pm.dlxCmd} --package=@exxatdesignux/ui@${selfPkg.version} exxat-ui sync-extras`)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
119
151
|
console.log("")
|
|
120
|
-
console.log(`✅ Done! Your Exxat DS app is ready in
|
|
152
|
+
console.log(`✅ Done! Your Exxat DS app is ready in ${isAbsolute ? targetDir : `./${displayName}/`}`)
|
|
121
153
|
console.log("")
|
|
122
|
-
console.log(` cd ${
|
|
154
|
+
if (targetArg !== ".") console.log(` cd ${cdHint}`)
|
|
123
155
|
console.log(` ${pm.runCmd} dev # start dev server`)
|
|
124
156
|
console.log("")
|
|
125
|
-
console.log("
|
|
126
|
-
console.log(
|
|
157
|
+
console.log(" Cursor / Claude skills, rules, and pattern docs are already in place.")
|
|
158
|
+
console.log(" When you upgrade @exxatdesignux/ui later, refresh them with:")
|
|
159
|
+
console.log(` ${pm.dlxCmd} --package=@exxatdesignux/ui@latest exxat-ui sync-extras`)
|
|
127
160
|
console.log("")
|
|
128
161
|
|
|
129
162
|
/**
|
package/bin/sync-extras.mjs
CHANGED
|
@@ -28,6 +28,14 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
28
28
|
const pkgRoot = resolve(__dirname, "..")
|
|
29
29
|
const cwd = process.cwd()
|
|
30
30
|
|
|
31
|
+
// `--quiet` suppresses the per-file "[sync-extras] wrote …" lines so the
|
|
32
|
+
// scaffolder (`create-exxat-app`) can call us inline without drowning the
|
|
33
|
+
// user in 50+ status lines. The final summary line still prints.
|
|
34
|
+
const QUIET = process.argv.includes("--quiet") || process.env.EXXAT_SYNC_EXTRAS_QUIET === "1"
|
|
35
|
+
function log(...m) {
|
|
36
|
+
if (!QUIET) console.log(...m)
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
const SOURCES = {
|
|
32
40
|
skills: join(pkgRoot, "consumer-extras", "cursor-skills"),
|
|
33
41
|
rules: join(pkgRoot, "consumer-extras", "cursor-rules"),
|
|
@@ -69,7 +77,7 @@ function syncSkillsTo(label, dest) {
|
|
|
69
77
|
if (!statSync(src).isDirectory()) continue
|
|
70
78
|
if (!name.startsWith("exxat-")) continue
|
|
71
79
|
replaceDir(src, join(dest, name))
|
|
72
|
-
|
|
80
|
+
log(`[sync-extras] wrote ${label}/${name}/`)
|
|
73
81
|
wrote++
|
|
74
82
|
}
|
|
75
83
|
}
|
|
@@ -91,7 +99,7 @@ function syncRules() {
|
|
|
91
99
|
if (!statSync(src).isFile()) continue
|
|
92
100
|
if (!name.startsWith("exxat-") || !name.endsWith(".mdc")) continue
|
|
93
101
|
cpSync(src, join(DESTINATIONS.cursorRules, name))
|
|
94
|
-
|
|
102
|
+
log(`[sync-extras] wrote .cursor/rules/${name}`)
|
|
95
103
|
wrote++
|
|
96
104
|
}
|
|
97
105
|
}
|
|
@@ -111,7 +119,7 @@ function syncPatterns() {
|
|
|
111
119
|
const src = join(SOURCES.patterns, name)
|
|
112
120
|
if (!statSync(src).isFile()) continue
|
|
113
121
|
cpSync(src, join(DESTINATIONS.patterns, name))
|
|
114
|
-
|
|
122
|
+
log(`[sync-extras] wrote docs/exxat-ds/${name}`)
|
|
115
123
|
wrote++
|
|
116
124
|
}
|
|
117
125
|
}
|
|
@@ -137,7 +145,7 @@ function syncHandbook() {
|
|
|
137
145
|
const src = join(SOURCES.handbook, name)
|
|
138
146
|
if (!statSync(src).isFile()) continue
|
|
139
147
|
cpSync(src, join(DESTINATIONS.handbook, name))
|
|
140
|
-
|
|
148
|
+
log(`[sync-extras] wrote docs/exxat-ds/handbook/${name}`)
|
|
141
149
|
wrote++
|
|
142
150
|
}
|
|
143
151
|
}
|
|
@@ -149,4 +157,4 @@ syncPatterns()
|
|
|
149
157
|
syncHandbook()
|
|
150
158
|
|
|
151
159
|
console.log(`[sync-extras] Done. ${wrote} files / dirs written; ${skipped} optional sources missing.`)
|
|
152
|
-
console.log("[sync-extras] Product routes and app content were not modified.")
|
|
160
|
+
if (!QUIET) console.log("[sync-extras] Product routes and app content were not modified.")
|
|
@@ -5687,11 +5687,12 @@ function HubTable({
|
|
|
5687
5687
|
for (const v of supportedViewTypes) {
|
|
5688
5688
|
const kind = getDataListViewRenderKind(v);
|
|
5689
5689
|
if (kind === "data-table") continue;
|
|
5690
|
-
if (renderers[kind]
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5690
|
+
if (renderers[kind] != null) continue;
|
|
5691
|
+
if (kind === "list-with-toolbar" && renderListRow != null) continue;
|
|
5692
|
+
if (kind === "board-with-toolbar" && renderBoardCard != null && boardGroups != null) continue;
|
|
5693
|
+
console.warn(
|
|
5694
|
+
`[Exxat DS][HubTable: ${hubLabel}] Missing renderer for supported view "${v}" (${kind}). Add a renderer entry, or remove the view from supportedViewTypes.`
|
|
5695
|
+
);
|
|
5695
5696
|
}
|
|
5696
5697
|
}
|
|
5697
5698
|
const composed = {
|