@imfusion/web-ui 0.10.1-dev.37.g9147f90f → 0.10.1-dev.45.ga6a3c86a
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 +20 -2
- package/README.md +4 -30
- package/dist/components/app-shell/app-shell.d.ts +35 -23
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/use-disclosure.d.ts +17 -0
- package/dist/icons.js +1 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1840 -1746
- package/dist/style.css +1 -1
- package/dist/vite/local-web-ui-link.d.ts +17 -4
- package/dist/vite.js +25 -20
- package/dist/web-ui-cli.js +11 -11
- package/package.json +9 -7
- package/src/docgen/doc.gen.json +18 -66
- package/src/llms/install-templates/hooks/baseline-staleness.sh +2 -0
- package/src/llms/install-templates/hooks/stop.sh +5 -2
- package/src/llms/skills/imf-web-ui-audit/SKILL.md +5 -1
- package/src/llms/skills/imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md +2 -1
- package/src/llms/skills/imf-web-ui-conventions/topics/tooling.md +31 -4
- package/src/llms/skills/imf-web-ui-setup/SKILL.md +9 -1
- package/src/llms/skills/imf-web-ui-update/SKILL.md +7 -0
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import { Plugin, UserConfig } from 'vite';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
interface LinkConfig extends UserConfig {
|
|
3
|
+
test?: {
|
|
4
|
+
server?: {
|
|
5
|
+
deps?: {
|
|
6
|
+
inline?: (string | RegExp)[];
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
}
|
|
4
11
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
12
|
+
* Returns `undefined` unless `node_modules/@imfusion/web-ui` under `root` is a symlink. A symlinked checkout resolves its
|
|
13
|
+
* own copy of every peer, so the peers are deduped for Vite and the checkout's dependencies are inlined for Vitest.
|
|
14
|
+
*/
|
|
15
|
+
export declare function localWebUILinkConfig(root: string): LinkConfig | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Lets a consumer keep `localWebUILink()` registered for good. It does nothing for an installed package. With a
|
|
18
|
+
* `file:` dependency on a Web UI checkout it makes the checkout share the app's React.
|
|
7
19
|
*/
|
|
8
20
|
export declare function localWebUILink(): Plugin;
|
|
21
|
+
export {};
|
package/dist/vite.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { n as e } from "./paths-B5Ht3ETc.js";
|
|
2
|
-
import {
|
|
3
|
-
import { dirname as
|
|
2
|
+
import { existsSync as t, readFileSync as n, readdirSync as r, realpathSync as i } from "node:fs";
|
|
3
|
+
import { dirname as a, join as o, resolve as s } from "node:path";
|
|
4
4
|
import { fileURLToPath as c } from "node:url";
|
|
5
5
|
//#region src/vite/brand-assets.ts
|
|
6
|
-
var l =
|
|
6
|
+
var l = a(c(import.meta.resolve("@imfusion/web-ui/assets/favicon/favicon.svg"))), u = r(l).map((e) => ({
|
|
7
7
|
name: e,
|
|
8
|
-
source:
|
|
8
|
+
source: n(o(l, e))
|
|
9
9
|
})), d = {
|
|
10
10
|
".ico": "image/x-icon",
|
|
11
11
|
".png": "image/png",
|
|
@@ -20,11 +20,7 @@ function p() {
|
|
|
20
20
|
configureServer(e) {
|
|
21
21
|
e.middlewares.use((e, t, n) => {
|
|
22
22
|
let r = u.find(({ name: t }) => e.url?.split("?")[0] === `/${t}`);
|
|
23
|
-
|
|
24
|
-
n();
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
t.setHeader("Content-Type", f(r.name)), t.end(r.source);
|
|
23
|
+
r ? (t.setHeader("Content-Type", f(r.name)), t.end(r.source)) : n();
|
|
28
24
|
});
|
|
29
25
|
},
|
|
30
26
|
generateBundle() {
|
|
@@ -38,33 +34,42 @@ function p() {
|
|
|
38
34
|
}
|
|
39
35
|
//#endregion
|
|
40
36
|
//#region src/vite/local-web-ui-link.ts
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
var m = [
|
|
38
|
+
"/@base-ui/",
|
|
39
|
+
"/@floating-ui/",
|
|
40
|
+
"/use-sync-external-store/"
|
|
41
|
+
];
|
|
42
|
+
function h(r) {
|
|
43
|
+
let a = s(i(r), "node_modules", "@imfusion", "web-ui");
|
|
44
|
+
if (!t(a) || i(a) === a) return;
|
|
45
|
+
let o = JSON.parse(n(s(e, "package.json"), "utf-8")), c = typeof o == "object" && o ? Reflect.get(o, "peerDependencies") : {};
|
|
46
|
+
if (typeof c != "object" || !c) throw Error(`${e}/package.json has no peerDependencies`);
|
|
47
|
+
return {
|
|
48
|
+
resolve: { dedupe: Object.keys(c) },
|
|
49
|
+
test: { server: { deps: { inline: m.map((e) => new RegExp(e)) } } }
|
|
50
|
+
};
|
|
46
51
|
}
|
|
47
|
-
function
|
|
52
|
+
function g() {
|
|
48
53
|
return {
|
|
49
54
|
name: "imf-ui:local-web-ui-link",
|
|
50
|
-
config: () =>
|
|
55
|
+
config: (e) => h(s(e.root ?? process.cwd()))
|
|
51
56
|
};
|
|
52
57
|
}
|
|
53
58
|
//#endregion
|
|
54
59
|
//#region src/vite/readable-css-module-names.ts
|
|
55
|
-
function
|
|
60
|
+
function _(e, t) {
|
|
56
61
|
let { lightningcss: n, modules: r, transformer: i } = e.css ?? {}, a = n?.cssModules;
|
|
57
62
|
if (typeof a != "boolean" && r !== !1 && !a?.pattern && !(typeof r == "object" && r.generateScopedName)) return i === "postcss" ? { css: { modules: { generateScopedName: t } } } : { css: {
|
|
58
63
|
transformer: "lightningcss",
|
|
59
64
|
lightningcss: { cssModules: { pattern: t } }
|
|
60
65
|
} };
|
|
61
66
|
}
|
|
62
|
-
function
|
|
67
|
+
function v({ prefix: e }) {
|
|
63
68
|
let t = `${e}-[name]-[local]`;
|
|
64
69
|
return {
|
|
65
70
|
name: "imf-ui:readable-css-module-names",
|
|
66
|
-
config: (e) =>
|
|
71
|
+
config: (e) => _(e, t)
|
|
67
72
|
};
|
|
68
73
|
}
|
|
69
74
|
//#endregion
|
|
70
|
-
export { p as imfusionBrandAssets,
|
|
75
|
+
export { p as imfusionBrandAssets, g as localWebUILink, v as readableCssModuleNames };
|
package/dist/web-ui-cli.js
CHANGED
|
@@ -278,19 +278,19 @@ function me(e) {
|
|
|
278
278
|
if (i.length > 0) {
|
|
279
279
|
for (let e of i) console.error(`No skills installed for ${e}. Run \`npx web-ui install skills --harness=${e}\` first.`);
|
|
280
280
|
process.exitCode = 1;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
281
|
+
} else {
|
|
282
|
+
v.intro("@imfusion/web-ui install hooks");
|
|
283
|
+
try {
|
|
284
|
+
de(r);
|
|
285
|
+
} catch (e) {
|
|
286
|
+
if (e instanceof U) {
|
|
287
|
+
console.error(e.message), process.exitCode = 1;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
throw e;
|
|
290
291
|
}
|
|
291
|
-
|
|
292
|
+
v.outro("Done — agent hooks installed.");
|
|
292
293
|
}
|
|
293
|
-
v.outro("Done — agent hooks installed.");
|
|
294
294
|
}
|
|
295
295
|
var Q = new ee();
|
|
296
296
|
Q.name("web-ui").description("Command-line tools for @imfusion/web-ui").version(P);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imfusion/web-ui",
|
|
3
|
-
"version": "0.10.1-dev.
|
|
3
|
+
"version": "0.10.1-dev.45.ga6a3c86a",
|
|
4
4
|
"description": "The official Web UI component library for ImFusion web apps",
|
|
5
5
|
"author": "ImFusion GmbH",
|
|
6
6
|
"homepage": "https://imfusion.com",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"@types/react": "19.2.14",
|
|
139
139
|
"@types/react-dom": "19.2.3",
|
|
140
140
|
"@vitejs/plugin-react": "6.0.1",
|
|
141
|
-
"@vitest/browser-playwright": "5.0.
|
|
141
|
+
"@vitest/browser-playwright": "5.0.4",
|
|
142
142
|
"concurrently": "9.2.1",
|
|
143
143
|
"culori": "4.0.2",
|
|
144
144
|
"fast-xml-parser": "5.11.2",
|
|
@@ -148,19 +148,21 @@
|
|
|
148
148
|
"mermaid": "12.0.0",
|
|
149
149
|
"playwright": "1.60.0",
|
|
150
150
|
"prettier": "3.8.3",
|
|
151
|
+
"react": "19.2.5",
|
|
151
152
|
"react-docgen-typescript": "2.4.0",
|
|
153
|
+
"react-dom": "19.2.5",
|
|
152
154
|
"remark-gfm": "4.0.1",
|
|
153
155
|
"storybook": "10.6.2",
|
|
154
156
|
"tsx": "4.21.0",
|
|
155
157
|
"typescript": "6.0.3",
|
|
156
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@1.
|
|
158
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.2.0",
|
|
157
159
|
"vite-plugin-dts": "5.0.0",
|
|
158
|
-
"vite-plus": "1.
|
|
159
|
-
"vitest": "5.0.
|
|
160
|
+
"vite-plus": "1.2.0",
|
|
161
|
+
"vitest": "5.0.4"
|
|
160
162
|
},
|
|
161
163
|
"overrides": {
|
|
162
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@1.
|
|
163
|
-
"vitest": "5.0.
|
|
164
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.2.0",
|
|
165
|
+
"vitest": "5.0.4",
|
|
164
166
|
"storybook": {
|
|
165
167
|
".": "$storybook",
|
|
166
168
|
"vite-plus": "$vite-plus"
|
package/src/docgen/doc.gen.json
CHANGED
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"app-shell": {
|
|
119
119
|
"root": {
|
|
120
120
|
"name": "AppShell.Root",
|
|
121
|
-
"description": "",
|
|
121
|
+
"description": "AppShell — application layout shell.\n\nThe classic dashboard frame: collapsible navbar/aside sidebars, a page\nheader, an optional footer, and a scrolling main content area. Also called\nan app layout, application frame, dashboard shell, or sidebar layout.\n\nComposed of eight sub-components used with dot-notation: `AppShell.Root` wraps\n`AppShell.Header`, `AppShell.Navbar`, `AppShell.Aside`, `AppShell.Footer`,\n`AppShell.Main`, and (inside a sidebar) `AppShell.Section` and `AppShell.NavItem`.\n\nSizing is CSS-driven — override the `--imf-ui-appshell-*` custom properties\nrather than passing dimension props. Below the responsive breakpoints the\nnavbar (`md`) and aside (`lg`) open as drawers, and the shell renders the\nnavbar's toggle itself.\n\nCopied and adapted from Mantine's AppShell; no upstream runtime dependency.\nMIT licensed (see Mantine repo).",
|
|
122
122
|
"props": [
|
|
123
123
|
{
|
|
124
124
|
"name": "ref",
|
|
@@ -141,6 +141,13 @@
|
|
|
141
141
|
"defaultValue": "Close panel",
|
|
142
142
|
"description": "Accessible name of the close button shown while the aside is a drawer."
|
|
143
143
|
},
|
|
144
|
+
{
|
|
145
|
+
"name": "defaultOpen",
|
|
146
|
+
"required": false,
|
|
147
|
+
"type": "boolean",
|
|
148
|
+
"defaultValue": null,
|
|
149
|
+
"description": "Whether the drawer starts open when `open` is omitted."
|
|
150
|
+
},
|
|
144
151
|
{
|
|
145
152
|
"name": "onOpenChange",
|
|
146
153
|
"required": false,
|
|
@@ -185,68 +192,6 @@
|
|
|
185
192
|
}
|
|
186
193
|
]
|
|
187
194
|
},
|
|
188
|
-
{
|
|
189
|
-
"name": "AppShell.Burger",
|
|
190
|
-
"description": "AppShell.Burger — the menu toggle: three sheared bands that cross while the navbar drawer is open. With no props it\nopens and closes that drawer. Takes its color from the surface and hides from `md` up, where the navbar is docked, and\nsteps back while the drawer is open, so the drawer's own close is the only one shown.",
|
|
191
|
-
"props": [
|
|
192
|
-
{
|
|
193
|
-
"name": "className",
|
|
194
|
-
"required": false,
|
|
195
|
-
"type": "string | ((state: ButtonState) => string)",
|
|
196
|
-
"defaultValue": null,
|
|
197
|
-
"description": "CSS class applied to the element, or a function that\nreturns a class based on the component's state."
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
"name": "focusableWhenDisabled",
|
|
201
|
-
"required": false,
|
|
202
|
-
"type": "boolean",
|
|
203
|
-
"defaultValue": "false",
|
|
204
|
-
"description": "Whether the button should be focusable when disabled."
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
"name": "label",
|
|
208
|
-
"required": false,
|
|
209
|
-
"type": "string",
|
|
210
|
-
"defaultValue": null,
|
|
211
|
-
"description": "Accessible name. Defaults to \"Open navigation\" or \"Close navigation\" from `opened`."
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
"name": "nativeButton",
|
|
215
|
-
"required": false,
|
|
216
|
-
"type": "boolean",
|
|
217
|
-
"defaultValue": "true",
|
|
218
|
-
"description": "Whether the component renders a native `<button>` element when replacing it\nvia the `render` prop.\nSet to `false` if the rendered element is not a button (for example, `<div>`)."
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
"name": "opened",
|
|
222
|
-
"required": false,
|
|
223
|
-
"type": "boolean",
|
|
224
|
-
"defaultValue": null,
|
|
225
|
-
"description": "Draws the cross and sets `aria-expanded`. Defaults to whether the navbar drawer is open."
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
"name": "ref",
|
|
229
|
-
"required": false,
|
|
230
|
-
"type": "Ref<HTMLDivElement>",
|
|
231
|
-
"defaultValue": null,
|
|
232
|
-
"description": "Allows getting a ref to the component instance.\nOnce the component unmounts, React will set `ref.current` to `null`\n(or call the ref with `null` if you passed a callback ref).\n@see {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}"
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
"name": "render",
|
|
236
|
-
"required": false,
|
|
237
|
-
"type": "| ReactElement<\n unknown,\n string | JSXElementConstructor<any>\n >\n| ComponentRenderFn<HTMLProps, ButtonState>",
|
|
238
|
-
"defaultValue": null,
|
|
239
|
-
"description": "Allows you to replace the component's HTML element\nwith a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
240
|
-
},
|
|
241
|
-
{
|
|
242
|
-
"name": "style",
|
|
243
|
-
"required": false,
|
|
244
|
-
"type": "| CSSProperties\n| ((state: ButtonState) => CSSProperties)",
|
|
245
|
-
"defaultValue": null,
|
|
246
|
-
"description": "Style applied to the element, or a function that\nreturns a style object based on the component's state."
|
|
247
|
-
}
|
|
248
|
-
]
|
|
249
|
-
},
|
|
250
195
|
{
|
|
251
196
|
"name": "AppShell.Footer",
|
|
252
197
|
"description": "",
|
|
@@ -262,7 +207,7 @@
|
|
|
262
207
|
},
|
|
263
208
|
{
|
|
264
209
|
"name": "AppShell.Header",
|
|
265
|
-
"description": "",
|
|
210
|
+
"description": "AppShell.Header — the page row: a title and actions at every width. Below `md` it sits under the shell's bar, and from\n`md` it sits beside the rail.",
|
|
266
211
|
"props": [
|
|
267
212
|
{
|
|
268
213
|
"name": "ref",
|
|
@@ -297,11 +242,18 @@
|
|
|
297
242
|
"defaultValue": null,
|
|
298
243
|
"description": "The signed-in account at the foot of the rail, usually an `AccountCard`. Without it the foot is omitted."
|
|
299
244
|
},
|
|
245
|
+
{
|
|
246
|
+
"name": "defaultOpen",
|
|
247
|
+
"required": false,
|
|
248
|
+
"type": "boolean",
|
|
249
|
+
"defaultValue": null,
|
|
250
|
+
"description": "Whether the drawer starts open when `open` is omitted."
|
|
251
|
+
},
|
|
300
252
|
{
|
|
301
253
|
"name": "logo",
|
|
302
254
|
"required": false,
|
|
303
255
|
"type": "ReactNode",
|
|
304
|
-
"defaultValue": "
|
|
256
|
+
"defaultValue": "variant === \"branded\" ? oncolorLogo : brandLogo",
|
|
305
257
|
"description": "The brand at the top of the rail. Defaults to the ImFusion logo; `null` leaves the row empty."
|
|
306
258
|
},
|
|
307
259
|
{
|
|
@@ -336,7 +288,7 @@
|
|
|
336
288
|
},
|
|
337
289
|
{
|
|
338
290
|
"name": "AppShell.NavItem",
|
|
339
|
-
"description": "AppShell.NavItem — a navbar link: icon, mono label, and an optional description. Takes its color from the navbar;\n`aria-current=\"page\"` underlines the label. Pass a router link through `render`.",
|
|
291
|
+
"description": "AppShell.NavItem — a navbar link: icon, mono label, and an optional description. Takes its color from the navbar;\n`aria-current=\"page\"` underlines the label. Pass a router link through `render`. Followed inside the navbar drawer,\nit closes the drawer.",
|
|
340
292
|
"props": [
|
|
341
293
|
{
|
|
342
294
|
"name": "description",
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
# and warns on drift. Always exits 0 — staleness never blocks a commit.
|
|
5
5
|
PKG=node_modules/@imfusion/web-ui/package.json
|
|
6
6
|
[ -f "$PKG" ] || exit 0
|
|
7
|
+
# A symlinked checkout reports its own dev version.
|
|
8
|
+
[ -L node_modules/@imfusion/web-ui ] && exit 0
|
|
7
9
|
CURRENT=$(node -p "require('./$PKG').version" 2>/dev/null) || exit 0
|
|
8
10
|
|
|
9
11
|
# .claude/skills may be a symlink to .agents/skills; skip markers already read.
|
|
@@ -10,9 +10,12 @@ git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0
|
|
|
10
10
|
[ -n "$(git status --porcelain -- '*.ts' '*.tsx' '*.js' '*.jsx' '*.css' 2>/dev/null)" ] || exit 0
|
|
11
11
|
# Gate only turns that actually edited files — a tree left dirty by an earlier
|
|
12
12
|
# session must not block a question-answering turn. Edit evidence: Write/Edit
|
|
13
|
-
# tool calls (Claude transcript) or apply_patch calls (Codex rollout)
|
|
13
|
+
# tool calls (Claude transcript) or apply_patch calls (Codex rollout), searched
|
|
14
|
+
# only after the turn's opening entry: the last real user prompt (not a tool
|
|
15
|
+
# result or injected meta message) or the last Codex task_started event.
|
|
14
16
|
TRANSCRIPT=$(printf '%s' "$PAYLOAD" | sed -n 's/.*"transcript_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)
|
|
15
17
|
[ -f "$TRANSCRIPT" ] || exit 0
|
|
16
|
-
grep -
|
|
18
|
+
TURN_START=$(grep -En '"type":"user"|"type":"task_started"' "$TRANSCRIPT" | grep -Ev '"type":"tool_result"|"isMeta":true' | tail -n 1 | cut -d: -f1)
|
|
19
|
+
tail -n +$(( ${TURN_START:-0} + 1 )) "$TRANSCRIPT" | grep -Eq '"name":"Write"|"name":"Edit"|"name":"MultiEdit"|"name":"NotebookEdit"|"name":"apply_patch"' || exit 0
|
|
17
20
|
printf '{"decision":"block","reason":"web-ui stop gate: this turn changed source files. Run the project verification (verify:typecheck, verify:lint, and verify:format at minimum), fix what it reports, then finish. If it already ran after the last change, say so and finish."}\n'
|
|
18
21
|
exit 0
|
|
@@ -60,7 +60,11 @@ Classify every result as one of these:
|
|
|
60
60
|
|
|
61
61
|
Use the report contract's severity, `path:line` evidence, concrete impact, and smallest next action. Unverified entries use
|
|
62
62
|
that same structure: unavailable runtime evidence, the impact of the unknown, and the check that resolves it. Do not promote
|
|
63
|
-
an optional tool or a working alternative to a missing finding.
|
|
63
|
+
an optional tool or a working alternative to a missing finding. A `vite.config.ts` without `localWebUILink()` registered from
|
|
64
|
+
`@imfusion/web-ui/vite` is Missing. A `tsconfig.json` without the `paths` block from the `tooling` topic is Missing too. Each
|
|
65
|
+
next action is the add from that topic. A major or minor mismatch between the project and Web UI on a package listed under
|
|
66
|
+
Aligned runtime packages in the `tooling` topic is a Deviation. Report both versions, with
|
|
67
|
+
`npm install <package>@<Web UI's version>` as the fix.
|
|
64
68
|
|
|
65
69
|
## Topics
|
|
66
70
|
|
|
@@ -109,7 +109,8 @@ sections one to one — change a topic's sections and this file follows in the s
|
|
|
109
109
|
- [ ] Oxfmt
|
|
110
110
|
- [ ] Oxlint and TypeScript
|
|
111
111
|
- [ ] Pre-commit checks
|
|
112
|
-
- [ ] Vite plugins
|
|
112
|
+
- [ ] Vite plugins, including `localWebUILink()`
|
|
113
|
+
- [ ] Aligned runtime packages
|
|
113
114
|
|
|
114
115
|
## npm project — `npm-project`
|
|
115
116
|
|
|
@@ -119,10 +119,10 @@ Register Web UI's Vite plugins in the application configuration:
|
|
|
119
119
|
```ts
|
|
120
120
|
import { defineConfig } from "vite-plus";
|
|
121
121
|
import react from "@vitejs/plugin-react";
|
|
122
|
-
import { imfusionBrandAssets, readableCssModuleNames } from "@imfusion/web-ui/vite";
|
|
122
|
+
import { imfusionBrandAssets, localWebUILink, readableCssModuleNames } from "@imfusion/web-ui/vite";
|
|
123
123
|
|
|
124
124
|
export default defineConfig({
|
|
125
|
-
plugins: [react(), imfusionBrandAssets(), readableCssModuleNames({ prefix: "app" })]
|
|
125
|
+
plugins: [react(), imfusionBrandAssets(), readableCssModuleNames({ prefix: "app" }), localWebUILink()]
|
|
126
126
|
});
|
|
127
127
|
```
|
|
128
128
|
|
|
@@ -130,5 +130,32 @@ export default defineConfig({
|
|
|
130
130
|
Register `readableCssModuleNames` in every compiler that processes the app's CSS, including development, Storybook, and
|
|
131
131
|
production. A compiler left out produces different class names and styles that appear to work only in some environments.
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
## Aligned runtime packages
|
|
134
|
+
|
|
135
|
+
Web UI and the app run the same versions of these packages. The `peerDependencies` of
|
|
136
|
+
`node_modules/@imfusion/web-ui/package.json` give the accepted ranges, and its `devDependencies` give the version Web UI
|
|
137
|
+
builds and tests with. A matching major and minor is the rule; a patch difference is fine.
|
|
138
|
+
|
|
139
|
+
- `react`, `react-dom`
|
|
140
|
+
- `@types/react`, `@types/react-dom`
|
|
141
|
+
- `@base-ui/react`, which brings `@floating-ui/*` with it
|
|
142
|
+
- `vite-plus`
|
|
143
|
+
- `vite`, the `npm:@voidzero-dev/vite-plus-core` alias that `vite-plus` provides
|
|
144
|
+
|
|
145
|
+
## Version drift
|
|
146
|
+
|
|
147
|
+
Aligned versions are the primary fix. The plugin and the `paths` block below catch the drift that slips through.
|
|
148
|
+
|
|
149
|
+
`localWebUILink` stays registered for good. It does nothing for an installed package. When `@imfusion/web-ui` is a symlinked
|
|
150
|
+
checkout, it keeps one React in dev, build, and Vitest.
|
|
151
|
+
|
|
152
|
+
Add this to `compilerOptions` in `tsconfig.json`, merged by hand into an existing `paths`. For a symlinked checkout it keeps
|
|
153
|
+
one set of React and Vite types for `tsc`, and it does nothing for an installed package:
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
"paths": {
|
|
157
|
+
"react": ["./node_modules/@types/react"],
|
|
158
|
+
"react/*": ["./node_modules/@types/react/*"],
|
|
159
|
+
"vite": ["./node_modules/vite"]
|
|
160
|
+
}
|
|
161
|
+
```
|
|
@@ -45,10 +45,18 @@ Include these pieces unless the existing project already has them or the user re
|
|
|
45
45
|
- one server-backed current-user query at the route boundary;
|
|
46
46
|
- a minimal `AppShell` in `_app/`, unless the user says the product has no persistent authenticated navigation;
|
|
47
47
|
- an API topic folder for data shown by the first screen;
|
|
48
|
-
- the root provider and library wiring
|
|
48
|
+
- the root provider and library wiring;
|
|
49
|
+
- the Vite plugins below.
|
|
49
50
|
|
|
50
51
|
The plan describes the exact starter files. It does not copy a generic starter project.
|
|
51
52
|
|
|
53
|
+
## Vite plugins
|
|
54
|
+
|
|
55
|
+
Propose a `vite.config.ts` that registers `imfusionBrandAssets()`, `readableCssModuleNames()`, and `localWebUILink()` from
|
|
56
|
+
`@imfusion/web-ui/vite`, next to the plugins the project already has. Register `localWebUILink()` in every project: without a
|
|
57
|
+
symlinked checkout it does nothing. Also propose the `tsconfig.json` `paths` block. Both keep one React and one set of types
|
|
58
|
+
when the package is a symlinked checkout. The `tooling` topic has the exact config.
|
|
59
|
+
|
|
52
60
|
## Installer steps
|
|
53
61
|
|
|
54
62
|
For `agent-tooling`, list the `npx web-ui install` commands as steps for the human. Read existing registrations first and do
|
|
@@ -96,6 +96,13 @@ changed. A diff shows what moved, not the step order you continue under, so it d
|
|
|
96
96
|
the current step using the updated guidance, keeping the original baseline, user choices, and completed changes in mind.
|
|
97
97
|
Check for newly required steps without repeating completed mutations or expanding the approved scope.
|
|
98
98
|
|
|
99
|
+
## Align the runtime packages
|
|
100
|
+
|
|
101
|
+
After the install, compare the app's installed versions of the packages listed under Aligned runtime packages in the
|
|
102
|
+
`tooling` topic with Web UI's own `package.json` in `node_modules/@imfusion/web-ui`. Report every major or minor mismatch and
|
|
103
|
+
propose `npm install <package>@<Web UI's version>` for each. Make the change as its own commit, in this same update, after
|
|
104
|
+
the base commit and with its own approval.
|
|
105
|
+
|
|
99
106
|
## Verify the base update
|
|
100
107
|
|
|
101
108
|
After every mutating command, compare the status with the preflight snapshot. Stop on an unexpected path or overlapping
|