@imfusion/web-ui 0.8.1-dev.5.gee230289 → 0.8.1-dev.50.g91c115bb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +159 -0
  2. package/README.md +28 -18
  3. package/THIRD_PARTY_NOTICES.md +34 -0
  4. package/dist/{code-D2lwxHgd.js → code-GwkswukD.js} +5 -5
  5. package/dist/codegen/gen-icons.d.ts +29 -4
  6. package/dist/codegen/sharpen-icon.d.ts +11 -0
  7. package/dist/components/app-shell/app-shell.d.ts +55 -30
  8. package/dist/components/button/button.d.ts +5 -4
  9. package/dist/components/card/card.d.ts +15 -1
  10. package/dist/components/field/field.d.ts +5 -2
  11. package/dist/components/icon-button/icon-button.d.ts +19 -0
  12. package/dist/components/icon-button/icon-button.meta.d.ts +2 -0
  13. package/dist/components/icon-button/index.d.ts +2 -0
  14. package/dist/components/logo/logo.d.ts +1 -1
  15. package/dist/components/meter/index.d.ts +2 -0
  16. package/dist/components/meter/meter.d.ts +33 -0
  17. package/dist/components/meter/meter.meta.d.ts +2 -0
  18. package/dist/components/skeleton/index.d.ts +2 -0
  19. package/dist/components/skeleton/skeleton.d.ts +47 -0
  20. package/dist/components/skeleton/skeleton.meta.d.ts +2 -0
  21. package/dist/components/slider/slider.d.ts +11 -1
  22. package/dist/components/table/table.d.ts +9 -0
  23. package/dist/components/typo/typo.d.ts +20 -11
  24. package/dist/icons/catalog.gen.d.ts +3797 -0
  25. package/dist/icons/create-icon.d.ts +3 -0
  26. package/dist/icons/icon-config-context.d.ts +3 -0
  27. package/dist/icons/icon-config.d.ts +2 -2
  28. package/dist/icons/icons.gen.d.ts +1736 -1672
  29. package/dist/icons-DUxZcuf9.js +36339 -0
  30. package/dist/icons.js +2 -2
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.js +2059 -1613
  33. package/dist/integrations/code-highlight.js +6 -4
  34. package/dist/integrations/frame-selection/frame-selection-view.d.ts +24 -0
  35. package/dist/integrations/frame-selection/frame-selection.d.ts +21 -0
  36. package/dist/integrations/frame-selection/frame-selection.meta.d.ts +2 -0
  37. package/dist/integrations/frame-selection/index.d.ts +2 -0
  38. package/dist/integrations/frame-selection.js +121 -0
  39. package/dist/integrations/image-display-options.js +71 -70
  40. package/dist/llms/evals/runner/config.d.ts +1 -0
  41. package/dist/llms/gen-tokens.d.ts +1 -1
  42. package/dist/{paths-Oi0v8x-w.js → paths-B5Ht3ETc.js} +2 -2
  43. package/dist/separator-lzz4A3x_.js +26 -0
  44. package/dist/slider-Cqpreglu.js +116 -0
  45. package/dist/style.css +1 -1
  46. package/dist/tabs-Dsfp8Ogj.js +295 -0
  47. package/dist/utils/status-glyphs.d.ts +4 -0
  48. package/dist/vite.js +2 -2
  49. package/dist/web-ui-cli.js +1 -1
  50. package/docs/user-guide/AgentTooling.mdx +8 -3
  51. package/package.json +37 -38
  52. package/src/docgen/doc.gen.json +754 -12
  53. package/src/llms/icon-catalog.gen.json +5533 -1671
  54. package/src/llms/llms.gen.txt +24 -2
  55. package/src/llms/skills/imf-web-ui/SKILL.md +2 -0
  56. package/src/llms/skills/imf-web-ui-audit/SKILL.md +18 -4
  57. package/src/llms/skills/imf-web-ui-components/SKILL.md +3 -1
  58. package/src/llms/skills/imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md +4 -2
  59. package/src/llms/skills/imf-web-ui-conventions/topics/authentication.md +2 -1
  60. package/src/llms/skills/imf-web-ui-conventions/topics/data.md +5 -3
  61. package/src/llms/skills/imf-web-ui-conventions/topics/git.md +2 -3
  62. package/src/llms/skills/imf-web-ui-conventions/topics/npm-project.md +3 -4
  63. package/src/llms/skills/imf-web-ui-conventions/topics/styling.md +4 -2
  64. package/src/llms/skills/imf-web-ui-conventions/topics/tooling.md +66 -28
  65. package/src/llms/skills/imf-web-ui-conventions/topics/typescript.md +14 -0
  66. package/src/llms/skills/imf-web-ui-setup/SKILL.md +2 -0
  67. package/src/llms/skills/imf-web-ui-update/SKILL.md +42 -7
  68. package/src/llms/skills/imf-web-ui-user-profile/SKILL.md +95 -0
  69. package/src/llms/skills/imf-web-ui-ux/SKILL.md +2 -0
  70. package/src/llms/tokens.gen.json +3 -3
  71. package/dist/icons-CaGCCwG-.js +0 -78
  72. package/dist/tabs-BS6rqrrA.js +0 -398
  73. /package/dist/{meta-j-7HGrWv.js → meta-V_KyLeGn.js} +0 -0
  74. /package/dist/{chunk-DmhlhrBa.js → rolldown-runtime-Dy4uBu1J.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,13 +2,172 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ### Highlights
6
+
7
+ #### Built with Vite+
8
+
9
+ Web UI builds, tests, lints, and formats with [Vite+](https://viteplus.dev/), a single `vp` toolchain over Vite, Vitest,
10
+ Oxlint, and Oxfmt, configured in one `vite.config.ts`. The lint check drops from about 9 seconds to 1, and the format check
11
+ from 2 seconds to half a second. The pre-commit hook checks the staged state, every generated file included, and never
12
+ rewrites anything.
13
+
14
+ `imf-web-ui-conventions` recommends the same setup for ImFusion frontends, so `imf-web-ui-audit` reports a project that still
15
+ runs Vite, Vitest, ESLint, and Prettier as separate tools. `vp migrate --no-hooks` moves one over.
16
+
17
+ #### Skills that fit the person
18
+
19
+ On the first run, the agent asks a few short questions, one at a time: your name, your technical background, how much you
20
+ have built for the web, how comfortable you are with npm and the terminal, how much explanation you want, and how you like to work.
21
+ You can decline any question, and you see the result before anything is saved.
22
+
23
+ The answers go to `~/.config/imfusion/web-ui/consumer-profile.md`, outside the project. Every skill you run reads that file.
24
+ Someone new to npm gets a plain sentence before each command and a short gloss for a term like lockfile; a seasoned developer
25
+ gets the short version. You can ask for a pause after each step or after each finished piece, and the approvals the
26
+ workflows already ask for stay as they are. Say "change my profile" to answer again.
27
+
28
+ ### Breaking
29
+
30
+ - **Breaking:** The library supports Safari 17.5, Chrome 123, and Firefox 120 or newer. — Nikolaus Brunner <brunner@imfusion.com>
31
+ - The stylesheet ships native `light-dark()`; older browsers get no semantic colors.
32
+ - The JavaScript build targets the same versions.
33
+ - **Breaking:** AppShell sections draw no dividers, and the `--imf-ui-appshell-border-color`, `--imf-ui-appshell-border-width`, and `--imf-ui-appshell-border-style` properties are removed. ([WEBSDK-243](https://imfusion.atlassian.net/browse/WEBSDK-243)) — Nikolaus Brunner <brunner@imfusion.com>
34
+ - **Breaking:** `AppShell.Main` is the scroll container and the document does not scroll; window scroll listeners, scroll restoration, and `scrollTo` target `AppShell.Main`. ([WEBSDK-243](https://imfusion.atlassian.net/browse/WEBSDK-243)) — Nikolaus Brunner <brunner@imfusion.com>
35
+
5
36
  ### Added
6
37
 
38
+ - Agent skills — Nikolaus Brunner <brunner@imfusion.com>
39
+ - `web-ui-dev-user-profile` keeps a contributor's profile in `dev-profile.md` beside the consumer one;
40
+ `web-ui-dev-start` and `web-ui-dev-getting-started` read it before any other step.
41
+ - `web-ui-dev-new-integration` builds a component around a package only some apps install. It runs
42
+ `web-ui-dev-new-component` with the integration contract, which `docs/component-definition.md` now spells out.
43
+ - `web-ui-dev-design-system-sync` builds the design system and publishes it to its Claude Design System artifact, with
44
+ resolved light and dark tokens, a live preview per component, the design language and a cover
45
+ ([CP-202](https://imfusion.atlassian.net/browse/CP-202)).
46
+ - `web-ui-dev-new-icon` adds custom icons from an SVG, a Figma link, a Claude Design project, or a description. It checks the icon catalog
47
+ first, and codegen validates the SVGs in `src/icons/svg/` and exports them beside the Iconoir set ([WEBSDK-267](https://imfusion.atlassian.net/browse/WEBSDK-267)).
7
48
  - Components — Nikolaus Brunner <brunner@imfusion.com>
8
49
  - `Avatar` shows a person's photo, their initials, or a person glyph, in three sizes and an on-color context.
9
50
  - `AccountCard` links to the signed-in person's account: a large title over a quiet subtitle, then the organization and a
10
51
  mono role under a rule, with an action such as Log out in its top row. Emails wrap at the `@` and at dots, and
11
52
  `AccountCard.Group` lists several cards with the current one marked.
53
+ - `Typo.Eyebrow` sets a short mono, uppercase label above a heading, in the quiet `support` color by default.
54
+ - `Card.Status` marks a card's outcome with a tinted column or band and the `info`, `positive`, `warning`, or `negative`
55
+ glyph that `Callout` uses for the same status.
56
+ - `Typo` body members (`P`, `Lead`, `Detail`, `Small`, `Blockquote`, `Highlight`, `Link`, and the lists) take an
57
+ optional `weight` of `regular`, `medium`, or `strong`, for short body text on cards that reads thin at the regular weight.
58
+ - `Table.RowLink` links a row to its detail page from inside a cell. It reads as row text without an underline, wraps long
59
+ values such as emails anywhere, and takes a `render` prop for router links.
60
+ - `Skeleton` holds the place of loading data: `Skeleton.Text` is one line of its parent's font tall, `Skeleton.Block`
61
+ takes a size or a circle, and `Skeleton.Root` announces the load once and can hold its scan line still.
62
+ - `Button` has a `justify` prop: `center` or `spread`, which pins the icons to the edges of a stretched button.
63
+ - `Meter` shows a measured amount within a range, such as seats in use, as a read-only bar with an optional label and
64
+ value readout. ([WEBSDK-250](https://imfusion.atlassian.net/browse/WEBSDK-250))
65
+ - Components — Stephan Wenninger <wenninger@imfusion.com>
66
+ - `Slider.Root` has a `variant="position"` that draws a scrollbar-like trough and bar thumb for picking one position in a
67
+ range.
68
+ - `FrameSelection`, from `@imfusion/web-ui/integrations/frame-selection`, steps through the frames of ImFusion Web SDK
69
+ image sets with a position slider and a current-of-total readout.
70
+ - `IconButton` is a square `Button` that shows a single icon and no visible text. `label` sets its accessible name, the
71
+ glyph size follows the button size, and `iconProps` passes props such as `strokeWidth` to the icon.
72
+ - AppShell ([WEBSDK-243](https://imfusion.atlassian.net/browse/WEBSDK-243)) — Nikolaus Brunner <brunner@imfusion.com>
73
+ - `AppShell.Navbar` has a `variant` prop: `default` or `branded`, a rail filled with the primary color.
74
+ - `AppShell.Burger` toggles the navbar drawer with three sheared bands that align on hover and cross when open.
75
+ - `AppShell.NavItem` is a navbar link with icon, label, and description that follows the navbar's color.
76
+ - `AppShell.Navbar` and `AppShell.Aside` take `onOpenChange` for their drawers.
77
+ - `AppShell.Aside` has a drag handle that resizes it and resets on double-click or Home. It is on by default; `resizable`, `onWidthChange`, and `resizeLabel` configure it.
78
+ - `--imf-ui-appshell-aside-min-width` (`max(20rem, 20cqi)`) is the narrowest the docked aside gets, dragged or not.
79
+ - `--imf-ui-appshell-main-min-width` (`max(24rem, 45cqi)`) caps the docked aside so Main keeps at least 45% of the shell.
80
+ - `--imf-ui-appshell-main-max-width` caps Main's content at `100rem` on wide screens, aligned to the start.
81
+ - Storybook — Nikolaus Brunner <brunner@imfusion.com>
82
+ - The toolbar has Full HD, QHD, and Ultrawide viewports for previews past `xl`.
83
+ - The floating token button is hidden by default; `parameters.tokenDrawer.show` shows it for a story, and a toolbar toggle overrides either way.
84
+ - Sidebar labels stay in the sidebar text color when a story has test warnings or errors; the status icon carries the state.
85
+
86
+ - Icons ([WEBSDK-267](https://imfusion.atlassian.net/browse/WEBSDK-267)) — Nikolaus Brunner <brunner@imfusion.com>
87
+ - 65 Medical Imaging icons from the ImFusion design team, such as `ToolBrush`, `ToolWindowLevel`, and `DefineRoiAction`.
88
+
89
+ - Storybook ([WEBSDK-267](https://imfusion.atlassian.net/browse/WEBSDK-267)) — Nikolaus Brunner <brunner@imfusion.com>
90
+ - Every icon has its own Iconography page with a shareable link, and both the page and the catalog tile download the icon as
91
+ an SVG under its source file name.
92
+
93
+ ### Changed
94
+
95
+ - Icons ([WEBSDK-267](https://imfusion.atlassian.net/browse/WEBSDK-267)) — Nikolaus Brunner <brunner@imfusion.com>
96
+ - Icons from `@imfusion/web-ui/icons` have square corners, line caps, and line joins. Letters, digits, stars, and
97
+ badges keep Iconoir's round geometry.
98
+ - The package generates its icons from Iconoir's SVG source and has no `iconoir-react` dependency.
99
+ - `strokeWidth` set on `Icon` or through `WebUIProvider` reaches every part of an icon, circles and rectangles included.
100
+ - Every record in the icon catalog names its `origin`, `iconoir` or `imfusion`, and its source `file`. The Iconography
101
+ catalog filters by origin and badges every icon with it. While no category filter is set, each tile also names the
102
+ icon's category.
103
+
104
+ - Components — Nikolaus Brunner <brunner@imfusion.com>
105
+ - `Button` centers its icons and label when a container stretches it wider than its content; `justify="spread"`
106
+ keeps the icons at the edges.
107
+ - Documentation — Nikolaus Brunner <brunner@imfusion.com>
108
+ - The `CodeHighlight` install section names TanStack Highlight 0.1.x and the 0.1.0 build it is tested against.
109
+ - The consumer agent tooling diagram groups the skills you run in one lane, so the router and the profile each reach them
110
+ with a single edge.
111
+ - Agent skills — Nikolaus Brunner <brunner@imfusion.com>
112
+ - `imf-web-ui-update` proposes catalog icons for project-local icons they now cover, above all icons a release added
113
+ ([WEBSDK-267](https://imfusion.atlassian.net/browse/WEBSDK-267)).
114
+ - `imf-web-ui-conventions` declares named functions, local component helpers included, with `function`, and keeps
115
+ inline callbacks as arrows.
116
+ - `imf-web-ui-conventions` loads route data with `queryClient.query({ ...options, staleTime: "static" })` in place of the
117
+ deprecated `ensureQueryData`.
118
+ - `imf-web-ui-update` opens with the route and its decision points, and names the optional `imf-web-ui-audit full` in
119
+ the report and its closing offer.
120
+ - `web-ui-dev-teardown-worktree merge` rebases onto the fetched `origin` base, runs `verify:full`, fast-forwards, and
121
+ pushes; it never creates a merge commit. `web-ui-dev-commit` routes landing a worktree branch there.
122
+ - `web-ui-dev-changelog` gives every new component, and every visibly changed one, a light and a dark screenshot of its
123
+ story in the release highlights.
124
+ - `imf-web-ui-update` checks for a running npm process by PID and working directory, and shows a command line only for
125
+ a process in the package being updated.
126
+ - `web-ui-dev-eval-consumer-skills` records every run's benchmark, and skips the record only when the user asks for it.
127
+ - `web-ui-dev-claude-design-sync-legacy` uploads to the standalone Claude Design site until it closes on 2026-12-14
128
+ ([CP-202](https://imfusion.atlassian.net/browse/CP-202)).
129
+ - `imf-web-ui-conventions` recommends the Vite+ toolchain: `vp dev`, `vp build`, `vp test`, Oxfmt through `vp fmt`, Oxlint
130
+ through `vp lint`, and a pre-commit hook that runs `vp staged`.
131
+ - `web-ui install` formats the files it writes, skill version markers and hook settings, with the project's `vp fmt` when
132
+ the project has it, and with its Prettier otherwise.
133
+ - `imf-web-ui-audit` searches the frontend for `TODO`, `FIXME`, `HACK`, and similar markers. A marker that admits a
134
+ convention gap backs that topic's finding, and the rest go under `Suggestions`.
135
+ - CI and verification — Nikolaus Brunner <brunner@imfusion.com>
136
+ - The toolchain is Vite+: `vp build` and `vp test` replace the Vite and Vitest scripts, and Oxlint and Oxfmt replace ESLint and Prettier.
137
+ - The pre-commit hook runs `vp staged` against the staged state and never rewrites or stages files.
138
+ - `verify:generated` checks every committed `*.gen.*` file against the sources that produce it. It runs in the pre-commit hook, in `verify:full`, and as a TeamCity step.
139
+ - The pre-push hook runs `verify:fast`, the `verify:full` suite without the builds and tests.
140
+ - AppShell ([WEBSDK-243](https://imfusion.atlassian.net/browse/WEBSDK-243)) — Nikolaus Brunner <brunner@imfusion.com>
141
+ - The navbar sits on the support background by default.
142
+ - The navbar variants set the navbar's text color: `fg-main` by default, `fg-oncolor` when branded.
143
+ - The navbar runs the full height of the screen; Header and Footer start beside it.
144
+ - `AppShell.Main` scrolls with a thin scrollbar.
145
+ - Below their breakpoints the navbar opens as a drawer from the inline end and the aside as a bottom sheet on phones or a side drawer on tablets.
146
+ - `AppShell.Root` is an inline-size container; the navbar is `clamp(16rem, 18cqi, 20rem)` and the aside `clamp(20rem, 30cqi, 40rem)` wide.
147
+
148
+ ### Fixed
149
+
150
+ - Components — Nikolaus Brunner <brunner@imfusion.com>
151
+ - Screen readers announce `Field.Error` when its message appears; it has `role="alert"` by default.
152
+ - `WebUIProvider` and the components under it render on React 18, the runtime Claude's design canvases use.
153
+ - On-color `ghost` and `outline` Buttons invert to a white fill on hover instead of near-black.
154
+ - `Button`'s `startIcon` sits level with the label.
155
+ - Peer dependencies — Nikolaus Brunner <brunner@imfusion.com>
156
+ - The `@imfusion/sdk` and `@imfusion/sdk-react` peers accept any version, SDK dev builds included. The
157
+ `FrameSelection` and `ImageDisplayOptions` install sections name SDK 1.x and the 1.0.0 build they are tested against.
158
+ - CI and verification — Nikolaus Brunner <brunner@imfusion.com>
159
+ - The dev skill eval report scores the dev scenarios and lists only the `web-ui-dev-*` skills.
160
+ - `verify:icons` fails when a one-icon import bundles any other icon ([WEBSDK-267](https://imfusion.atlassian.net/browse/WEBSDK-267)).
161
+ - The dev skill eval builds its workspace from a checkout without uncommitted changes.
162
+ - The repository's Chrome DevTools MCP server runs with an isolated profile, so several agent sessions can drive Chrome
163
+ at once.
164
+ - The Iconography interaction test covers the catalog's core behavior and finishes well within the CI timeout.
165
+ - Storybook — Nikolaus Brunner <brunner@imfusion.com>
166
+ - The Iconography catalog shows solid icons as drawn, and its Copy JSX snippet adds no fill or stroke override.
167
+ - Long icon names in the Iconography catalog break between words instead of being cut off.
168
+ - Button's controls list `variant`, `size`, and its other variant props before the inherited Base UI props.
169
+ - Token defaults — Nikolaus Brunner <brunner@imfusion.com>
170
+ - `data-imf-ui-color-scheme` on a nested element switches the semantic colors for that element's subtree.
12
171
 
13
172
  ---
14
173
 
package/README.md CHANGED
@@ -65,28 +65,38 @@ npm install
65
65
  npm run git:config
66
66
  ```
67
67
 
68
- `git:config` sets the tracked hooks path, enables rebase pulls, and requires fast-forward merges. The
68
+ `git:config` sets the tracked hooks path, enables rebase pulls, and requires fast-forward merges. Every checkout and worktree
69
+ needs its own `node_modules`; the hooks stop with "run npm ci" without one.
70
+
71
+ The pre-commit hook runs `vp staged` against the staged state: it lints and format-checks the repository, checks that every
72
+ generated `*.gen.*` file matches its sources (`npm run verify:generated`), and runs the pinned-dependency, Knip, type-check,
73
+ and TeamCity DSL checks when their inputs are staged. It never rewrites or stages files; on failure it restores the working
74
+ tree and prints what to fix. The pre-push hook runs `npm run verify:fast`, the CI suite without the builds and tests; the
75
+ agent commit and landing skills run `npm run verify:full`. The
69
76
  [`web-ui-dev-getting-started`](./.agents/skills/web-ui-dev-getting-started/SKILL.md) skill can route a first task.
70
77
 
71
78
  The main development skills are:
72
79
 
73
- | Skill | Use it for |
74
- | ---------------------------------- | ------------------------------------------------ |
75
- | `/web-ui-dev-getting-started` | Route a first task based on experience and goal. |
76
- | `/web-ui-dev-start` | Establish task context and working location. |
77
- | `/web-ui-dev-new-component` | Add a primitive. |
78
- | `/web-ui-dev-update-component` | Change an existing primitive. |
79
- | `/web-ui-dev-design-component` | Apply the ImFusion brand to a component. |
80
- | `/web-ui-dev-story` | Author a Storybook story. |
81
- | `/web-ui-dev-commit` | Verify and commit a change. |
82
- | `/web-ui-dev-changelog` | Write the changelog entry or curate a release. |
83
- | `/web-ui-dev-release` | Prepare and ship a release. |
84
- | `/web-ui-dev-audit-docs` | Check docs for drift before a commit. |
85
- | `/web-ui-dev-llm-framework` | Keep the LLM framework diagrams in sync. |
86
- | `/web-ui-dev-eval-consumer-skills` | Evaluate the shipped consumer skills. |
87
- | `/web-ui-dev-claude-design-sync` | Update the design system in Claude Design. |
88
- | `/web-ui-dev-teardown-worktree` | Remove a finished worktree. |
89
- | `/web-ui-dev-mcp` | Recover one optional MCP capability. |
80
+ | Skill | Use it for |
81
+ | --------------------------------------- | ---------------------------------------------- |
82
+ | `/web-ui-dev-getting-started` | Route a first task based on profile and goal. |
83
+ | `/web-ui-dev-start` | Establish task context and working location. |
84
+ | `/web-ui-dev-new-component` | Add a primitive. |
85
+ | `/web-ui-dev-new-integration` | Add an integration with an optional peer. |
86
+ | `/web-ui-dev-new-icon` | Add custom icons from a design source. |
87
+ | `/web-ui-dev-update-component` | Change an existing primitive. |
88
+ | `/web-ui-dev-design-component` | Apply the ImFusion brand to a component. |
89
+ | `/web-ui-dev-story` | Author a Storybook story. |
90
+ | `/web-ui-dev-commit` | Verify and commit a change. |
91
+ | `/web-ui-dev-changelog` | Write the changelog entry or curate a release. |
92
+ | `/web-ui-dev-release` | Prepare and ship a release. |
93
+ | `/web-ui-dev-audit-docs` | Check docs for drift before a commit. |
94
+ | `/web-ui-dev-llm-framework` | Keep the LLM framework diagrams in sync. |
95
+ | `/web-ui-dev-eval-consumer-skills` | Evaluate the shipped consumer skills. |
96
+ | `/web-ui-dev-design-system-sync` | Publish the design system to Claude. |
97
+ | `/web-ui-dev-claude-design-sync-legacy` | Upload to the standalone Claude Design site. |
98
+ | `/web-ui-dev-teardown-worktree` | Remove a finished worktree. |
99
+ | `/web-ui-dev-mcp` | Recover one optional MCP capability. |
90
100
 
91
101
  ### Work on it from a consumer app
92
102
 
@@ -32,3 +32,37 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
32
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
33
  SOFTWARE.
34
34
  ```
35
+
36
+ ## Iconoir
37
+
38
+ - Project: [Iconoir](https://github.com/iconoir-icons/iconoir)
39
+ - License: [MIT](https://github.com/iconoir-icons/iconoir/blob/main/LICENSE)
40
+
41
+ The icons exported from `@imfusion/web-ui/icons` are generated from Iconoir SVG source, with modified corners, line caps, and
42
+ line joins.
43
+
44
+ The following license text applies only to those Iconoir-derived icons and is reproduced verbatim:
45
+
46
+ ```text
47
+ MIT License
48
+
49
+ Copyright (c) 2021 Luca Burgio
50
+
51
+ Permission is hereby granted, free of charge, to any person obtaining a copy
52
+ of this software and associated documentation files (the "Software"), to deal
53
+ in the Software without restriction, including without limitation the rights
54
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55
+ copies of the Software, and to permit persons to whom the Software is
56
+ furnished to do so, subject to the following conditions:
57
+
58
+ The above copyright notice and this permission notice shall be included in all
59
+ copies or substantial portions of the Software.
60
+
61
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
64
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
65
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
66
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
67
+ SOFTWARE.
68
+ ```
@@ -1,6 +1,6 @@
1
- import { t as e } from "./chunk-DmhlhrBa.js";
2
- import { t } from "./meta-j-7HGrWv.js";
3
- import { Ma as n, Xo as r, r as i } from "./icons-CaGCCwG-.js";
1
+ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
+ import { t } from "./meta-V_KyLeGn.js";
3
+ import { $o as n, Pa as r, r as i } from "./icons-DUxZcuf9.js";
4
4
  import { cx as a } from "class-variance-authority";
5
5
  import { Fragment as o, jsx as s, jsxs as c } from "react/jsx-runtime";
6
6
  import { useCallback as l, useEffect as u, useRef as d, useState as f } from "react";
@@ -33,7 +33,7 @@ var g = {
33
33
  InlineLink: () => y
34
34
  });
35
35
  function v({ copyable: e = !1, children: t, render: a, ...l }) {
36
- let { copied: u, copy: f } = h(), _ = d(null), v = u ? n : r;
36
+ let { copied: u, copy: f } = h(), _ = d(null), v = u ? r : n;
37
37
  return m({
38
38
  defaultTagName: "code",
39
39
  render: a,
@@ -86,7 +86,7 @@ function y({ kind: e = "external", ...t }) {
86
86
  }
87
87
  y.displayName = "Code.InlineLink";
88
88
  function b({ className: e, language: t, hideCopy: o = !1, children: l, ...u }) {
89
- let { copied: f, copy: p } = h(), m = d(null), _ = f ? n : r;
89
+ let { copied: f, copy: p } = h(), m = d(null), _ = f ? r : n;
90
90
  return /* @__PURE__ */ c("div", {
91
91
  "data-imf-ui-component": "Code.Block",
92
92
  className: a(g.block, e),
@@ -1,3 +1,13 @@
1
+ import { IconNode } from '../icons/create-icon';
2
+ export type IconOrigin = "iconoir" | "imfusion";
3
+ export type IconSource = {
4
+ name: string;
5
+ style: "regular" | "solid";
6
+ origin: IconOrigin;
7
+ /** Path of the source SVG inside its icon set, such as `regular/tool-3d-rotate.svg`. */
8
+ file: string;
9
+ nodes: IconNode[];
10
+ };
1
11
  export type IconMetadata = {
2
12
  filename: string;
3
13
  category: string;
@@ -8,6 +18,8 @@ export type IconCatalogRecord = {
8
18
  category: string;
9
19
  tags: string[];
10
20
  style: "regular" | "solid";
21
+ origin: IconOrigin;
22
+ file: string;
11
23
  };
12
24
  type IconMetadataSource = {
13
25
  commit: string;
@@ -15,10 +27,23 @@ type IconMetadataSource = {
15
27
  };
16
28
  export declare function parseIconMetadata(csv: string): IconMetadata[];
17
29
  export declare function validateIconMetadataSource(source: string): IconMetadataSource;
18
- export declare function buildIconCatalog(iconNames: readonly string[], metadata: readonly IconMetadata[]): IconCatalogRecord[];
19
- export declare function renderIconAliases(iconNames: readonly string[]): string;
30
+ export declare function buildIconCatalog(icons: readonly Pick<IconSource, "name" | "origin" | "file">[], metadata: readonly IconMetadata[]): IconCatalogRecord[];
31
+ export declare function parseIconSvg(source: string): IconNode[];
32
+ export declare function iconName(filename: string, style: IconSource["style"]): string;
33
+ /** Problems that keep an SVG from following the Web UI icon contract; empty when it does. */
34
+ export declare function validateIconSvg(source: string): string[];
35
+ export declare function readIconSet(directory: string, origin: IconOrigin): IconSource[];
36
+ export declare function mergeIconSets(iconoir: readonly IconSource[], custom: readonly IconSource[]): IconSource[];
37
+ export declare function iconoirDirectory(): string;
38
+ export declare function parseSharpenExclusions(source: string, icons: readonly IconSource[]): Set<string>;
39
+ export declare function sharpenIconSet(icons: readonly IconSource[], exclusions: ReadonlySet<string>): {
40
+ icons: IconSource[];
41
+ corners: number;
42
+ changed: number;
43
+ };
44
+ export declare function renderIconModule(icons: readonly IconSource[]): string;
20
45
  export declare function renderIconCatalogJson(records: readonly IconCatalogRecord[]): string;
21
46
  export declare function renderIconCatalog(records: readonly IconCatalogRecord[]): string;
22
- export declare function writeIconAliases(): void;
23
- export declare function writeIconCatalog(): void;
47
+ export declare function writeIconModule(icons: readonly IconSource[]): void;
48
+ export declare function writeIconCatalog(icons: readonly IconSource[]): void;
24
49
  export {};
@@ -0,0 +1,11 @@
1
+ import { IconNode } from '../icons/create-icon';
2
+ /** Replaces curves that round a corner or a line end between straight edges with the corner itself. */
3
+ export declare function sharpenPath(d: string, maxLeg: number): {
4
+ d: string;
5
+ corners: number;
6
+ };
7
+ /** Squares the rounded corners, line caps, and line joins of an icon. */
8
+ export declare function sharpenIcon(nodes: readonly IconNode[], maxLeg: number): {
9
+ nodes: IconNode[];
10
+ corners: number;
11
+ };
@@ -1,25 +1,10 @@
1
- /**
2
- * AppShell — application layout shell.
3
- *
4
- * The classic dashboard frame: a fixed header, collapsible navbar/aside
5
- * sidebars, an optional footer, and a scrolling main content area. Also called
6
- * an app layout, application frame, dashboard shell, or sidebar layout.
7
- *
8
- * Composed of seven sub-components used with dot-notation: `AppShell.Root` wraps
9
- * `AppShell.Header`, `AppShell.Navbar`, `AppShell.Aside`, `AppShell.Footer`,
10
- * `AppShell.Main`, and (inside a sidebar) `AppShell.Section`.
11
- *
12
- * Sizing is CSS-driven — override the `--imf-ui-appshell-*` custom properties
13
- * rather than passing dimension props. Below the responsive breakpoints the
14
- * navbar (`md`) and aside (`lg`) become sliding overlays toggled via the `open`
15
- * prop; the consumer wires that to a burger button.
16
- *
17
- * Copied and adapted from Mantine's AppShell; no upstream runtime dependency.
18
- * MIT licensed (see Mantine repo).
19
- *
20
- * @see https://mantine.dev/llms/core-app-shell.md
21
- */
22
- declare function Root(props: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
1
+ import { Button as ButtonPrimitive } from '@base-ui/react/button';
2
+ import { useRender } from '@base-ui/react/use-render';
3
+ import { VariantProps } from 'class-variance-authority';
4
+ declare const navbarSurface: (props?: ({
5
+ variant?: "default" | "branded" | null | undefined;
6
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
7
+ declare function Root({ ref, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
23
8
  declare namespace Root {
24
9
  var displayName: string;
25
10
  }
@@ -27,19 +12,31 @@ declare function Header(props: React.HTMLAttributes<HTMLElement>): import("react
27
12
  declare namespace Header {
28
13
  var displayName: string;
29
14
  }
30
- type NavbarProps = React.HTMLAttributes<HTMLElement> & {
31
- /** Whether the mobile overlay is open. Ignored above the `md` breakpoint, where the navbar is always visible. */
15
+ type DrawerProps = {
16
+ /** Whether the drawer is open below the breakpoint. Ignored while the section is docked. */
32
17
  open?: boolean;
18
+ /** Called when the drawer asks to open or close: scrim, swipe, or Escape. */
19
+ onOpenChange?: (open: boolean) => void;
33
20
  };
34
- declare function Navbar({ open, ...props }: NavbarProps): import("react/jsx-runtime").JSX.Element;
21
+ type NavbarProps = React.HTMLAttributes<HTMLElement> & VariantProps<typeof navbarSurface> & DrawerProps;
22
+ /**
23
+ * `variant="branded"` paints the primary color; children opt into on-color themselves. Below `md` the navbar opens as a
24
+ * drawer from the inline end.
25
+ */
26
+ declare function Navbar({ variant, open, onOpenChange, ...props }: NavbarProps): import("react/jsx-runtime").JSX.Element;
35
27
  declare namespace Navbar {
36
28
  var displayName: string;
37
29
  }
38
- type AsideProps = React.HTMLAttributes<HTMLElement> & {
39
- /** Whether the mobile overlay is open. Ignored above the `lg` breakpoint, where the aside is always visible. */
40
- open?: boolean;
30
+ type AsideProps = React.HTMLAttributes<HTMLElement> & DrawerProps & {
31
+ /** Adds a drag handle on the inline-start edge from the `lg` breakpoint up. Double-click or Home restores the default width. */
32
+ resizable?: boolean;
33
+ /** Called with the new width in px when a drag ends, on each arrow-key step, and on reset. */
34
+ onWidthChange?: (width: number) => void;
35
+ /** Accessible name of the drag handle. */
36
+ resizeLabel?: string;
41
37
  };
42
- declare function Aside({ open, ...props }: AsideProps): import("react/jsx-runtime").JSX.Element;
38
+ /** Below `lg` the aside opens as a drawer: from the bottom on phones, from the inline end on tablets. */
39
+ declare function Aside({ open, onOpenChange, resizable, onWidthChange, resizeLabel, children, ...props }: AsideProps): import("react/jsx-runtime").JSX.Element;
43
40
  declare namespace Aside {
44
41
  var displayName: string;
45
42
  }
@@ -59,4 +56,32 @@ declare function Section({ grow, ...props }: SectionProps): import("react/jsx-ru
59
56
  declare namespace Section {
60
57
  var displayName: string;
61
58
  }
62
- export { Root, Header, Navbar, Aside, Footer, Main, Section };
59
+ type BurgerProps = React.ComponentProps<typeof ButtonPrimitive> & {
60
+ /** Whether the navigation it controls is open; draws the cross and sets `aria-expanded`. */
61
+ opened?: boolean;
62
+ /** Accessible name. Defaults to "Open navigation" or "Close navigation" from `opened`. */
63
+ label?: string;
64
+ };
65
+ /**
66
+ * AppShell.Burger — the header's menu toggle: three sheared bands that cross when `opened`. Takes its color from the
67
+ * surface and hides from `md` up, where the navbar is docked.
68
+ */
69
+ declare function Burger({ opened, label, className, ...props }: BurgerProps): import("react/jsx-runtime").JSX.Element;
70
+ declare namespace Burger {
71
+ var displayName: string;
72
+ }
73
+ type NavItemProps = useRender.ComponentProps<"a"> & {
74
+ /** Leading icon, decorative. */
75
+ icon?: React.ReactNode;
76
+ /** One line under the label saying what is behind the link. */
77
+ description?: React.ReactNode;
78
+ };
79
+ /**
80
+ * AppShell.NavItem — a navbar link: icon, mono label, and an optional description. Takes its color from the navbar;
81
+ * `aria-current="page"` marks the current page. Pass a router link through `render`.
82
+ */
83
+ declare function NavItem({ icon, description, children, render, ...props }: NavItemProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
84
+ declare namespace NavItem {
85
+ var displayName: string;
86
+ }
87
+ export { Root, Header, Navbar, Aside, Footer, Main, Section, Burger, NavItem };
@@ -6,11 +6,12 @@ declare const button: (props?: ({
6
6
  chamfer?: boolean | null | undefined;
7
7
  radius?: "sm" | "md" | "lg" | "none" | "round" | null | undefined;
8
8
  context?: "default" | "oncolor" | null | undefined;
9
+ justify?: "center" | "spread" | null | undefined;
9
10
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
10
- interface Props extends React.ComponentProps<typeof ButtonPrimitive>, VariantProps<typeof button> {
11
- /** Leading slot — typically a label. When present, the label aligns right and the icon pins left. */
11
+ interface Props extends VariantProps<typeof button>, React.ComponentProps<typeof ButtonPrimitive> {
12
+ /** Leading slot, typically an icon. */
12
13
  startIcon?: React.ReactNode;
13
- /** Trailing slot — typically an icon. When present, the label aligns left and the icon pins right. */
14
+ /** Trailing slot, typically an icon. */
14
15
  endIcon?: React.ReactNode;
15
16
  }
16
17
  /**
@@ -21,5 +22,5 @@ interface Props extends React.ComponentProps<typeof ButtonPrimitive>, VariantPro
21
22
  */
22
23
  export declare function Button({ variant, size,
23
24
  /** Explicit saturated-surface context; this is never inferred from an ancestor. */
24
- context, chamfer, radius, startIcon, endIcon, children, ...props }: Props): import("react/jsx-runtime").JSX.Element;
25
+ context, chamfer, radius, justify, startIcon, endIcon, children, ...props }: Props): import("react/jsx-runtime").JSX.Element;
25
26
  export {};
@@ -42,6 +42,20 @@ declare function Image({ alt, aspectRatio, style, ...props }: ImageProps): impor
42
42
  declare namespace Image {
43
43
  var displayName: string;
44
44
  }
45
+ declare const status: (props?: ({
46
+ variant?: "positive" | "negative" | "warning" | "info" | null | undefined;
47
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
48
+ type StatusProps = React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof status>;
49
+ /**
50
+ * Card.Status — a tinted slot that marks the card's status with the variant's glyph. Pass
51
+ * children to replace the glyph. Like `Card.Image`, place it first among the slots: a column
52
+ * beside the body in a horizontal card, a band above it in a vertical one. Decorative
53
+ * (`aria-hidden`); the card's text carries the status.
54
+ */
55
+ declare function Status({ variant, children, ...props }: StatusProps): import("react/jsx-runtime").JSX.Element;
56
+ declare namespace Status {
57
+ var displayName: string;
58
+ }
45
59
  type SlotProps = React.HTMLAttributes<HTMLDivElement>;
46
60
  /** Card.Header — the padded title region at the top of the card body. */
47
61
  declare function Header(props: SlotProps): import("react/jsx-runtime").JSX.Element;
@@ -62,4 +76,4 @@ declare function Footer(props: SlotProps): import("react/jsx-runtime").JSX.Eleme
62
76
  declare namespace Footer {
63
77
  var displayName: string;
64
78
  }
65
- export { Root, Image, Header, Content, Footer };
79
+ export { Root, Image, Status, Header, Content, Footer };
@@ -29,8 +29,11 @@ export declare function Control(props: React.ComponentProps<typeof FieldPrimitiv
29
29
  export declare namespace Control {
30
30
  var displayName: string;
31
31
  }
32
- /** Field.Error — an inline validation message shown when its match condition fails. */
33
- export declare function Error(props: React.ComponentProps<typeof FieldPrimitive.Error>): import("react/jsx-runtime").JSX.Element;
32
+ /**
33
+ * Field.Error — an inline validation message shown when its match condition fails.
34
+ * It announces itself with `role="alert"`; pass another `role` to quiet it.
35
+ */
36
+ export declare function Error({ role, ...props }: React.ComponentProps<typeof FieldPrimitive.Error>): import("react/jsx-runtime").JSX.Element;
34
37
  export declare namespace Error {
35
38
  var displayName: string;
36
39
  }
@@ -0,0 +1,19 @@
1
+ import { Button } from '../button';
2
+ import { Icon, IconComponent } from '../icon';
3
+ interface Props extends Omit<React.ComponentProps<typeof Button>, "children" | "startIcon" | "endIcon" | "justify"> {
4
+ /** Icon component imported from `@imfusion/web-ui/icons`. */
5
+ glyph: IconComponent;
6
+ /** Accessible name; the button renders no visible text. */
7
+ label: string;
8
+ /** Props for the inner Icon, such as `strokeWidth` or a `size` override. */
9
+ iconProps?: Omit<React.ComponentProps<typeof Icon>, "glyph">;
10
+ }
11
+ /**
12
+ * IconButton — a square Button that shows a single Icon. Composes Button, so every Button variant and native attribute
13
+ * passes through.
14
+ */
15
+ export declare function IconButton({ glyph, label, iconProps, size, ...props }: Props): import("react/jsx-runtime").JSX.Element;
16
+ export declare namespace IconButton {
17
+ var displayName: string;
18
+ }
19
+ export {};
@@ -0,0 +1,2 @@
1
+ import { ComponentMeta } from '../../types/meta';
2
+ export declare const iconButtonMeta: ComponentMeta;
@@ -0,0 +1,2 @@
1
+ export { IconButton } from './icon-button';
2
+ export { iconButtonMeta } from './icon-button.meta';
@@ -1,7 +1,7 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { VariantProps } from 'class-variance-authority';
3
3
  declare const logo: (props?: ({
4
- size?: "sm" | "md" | "lg" | "hero" | "xs" | "xl" | "fit" | null | undefined;
4
+ size?: "sm" | "md" | "lg" | "hero" | "xl" | "xs" | "fit" | null | undefined;
5
5
  variant?: "oncolor" | "main" | "inherit" | "support" | "minor" | "brand" | null | undefined;
6
6
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
7
7
  type Props = Omit<React.HTMLAttributes<HTMLSpanElement>, "children"> & VariantProps<typeof logo> & {
@@ -0,0 +1,2 @@
1
+ export * as Meter from './meter';
2
+ export { meterMeta } from './meter.meta';
@@ -0,0 +1,33 @@
1
+ import { Meter as MeterPrimitive } from '@base-ui/react/meter';
2
+ /**
3
+ * Meter.Root — read-only measurement of a value within a known range.
4
+ *
5
+ * Without a visible `Meter.Label`, name the meter with `aria-label`.
6
+ *
7
+ * @doc https://base-ui.com/react/components/meter
8
+ * @llm https://base-ui.com/react/components/meter.md
9
+ */
10
+ export declare function Root({ min, max, ...props }: React.ComponentProps<typeof MeterPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
11
+ export declare namespace Root {
12
+ var displayName: string;
13
+ }
14
+ /** Meter.Label — accessible label for the meter. */
15
+ export declare function Label(props: React.ComponentProps<typeof MeterPrimitive.Label>): import("react/jsx-runtime").JSX.Element;
16
+ export declare namespace Label {
17
+ var displayName: string;
18
+ }
19
+ /** Meter.Value — formatted readout of the current value. */
20
+ export declare function Value(props: React.ComponentProps<typeof MeterPrimitive.Value>): import("react/jsx-runtime").JSX.Element;
21
+ export declare namespace Value {
22
+ var displayName: string;
23
+ }
24
+ /** Meter.Track — the full range. */
25
+ export declare function Track(props: React.ComponentProps<typeof MeterPrimitive.Track>): import("react/jsx-runtime").JSX.Element;
26
+ export declare namespace Track {
27
+ var displayName: string;
28
+ }
29
+ /** Meter.Indicator — filled portion of the track up to the value. */
30
+ export declare function Indicator(props: React.ComponentProps<typeof MeterPrimitive.Indicator>): import("react/jsx-runtime").JSX.Element;
31
+ export declare namespace Indicator {
32
+ var displayName: string;
33
+ }
@@ -0,0 +1,2 @@
1
+ import { ComponentMeta } from '../../types/meta';
2
+ export declare const meterMeta: ComponentMeta;
@@ -0,0 +1,2 @@
1
+ export * as Skeleton from './skeleton';
2
+ export { skeletonMeta } from './skeleton.meta';