@imfusion/web-ui 0.11.1-dev.6.gf4b6c627 → 0.11.1-dev.62.gfcd31b6e
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 +168 -1
- package/dist/{code-Cl9AzRyF.js → code-BaLXMEMa.js} +8 -8
- package/dist/components/autocomplete/autocomplete.d.ts +144 -0
- package/dist/components/autocomplete/autocomplete.meta.d.ts +2 -0
- package/dist/components/autocomplete/index.d.ts +2 -0
- package/dist/components/avatar/avatar.d.ts +1 -1
- package/dist/components/card/card.d.ts +3 -2
- package/dist/components/checkbox/checkbox.cva.d.ts +3 -0
- package/dist/components/combobox/combobox.cva.d.ts +37 -0
- package/dist/components/combobox/combobox.d.ts +171 -0
- package/dist/components/combobox/combobox.meta.d.ts +2 -0
- package/dist/components/combobox/index.d.ts +2 -0
- package/dist/components/dialog/dialog.d.ts +23 -3
- package/dist/components/file-drop-zone/collect-files.d.ts +56 -0
- package/dist/components/file-drop-zone/file-drop-zone-context.d.ts +15 -0
- package/dist/components/file-drop-zone/file-drop-zone.d.ts +185 -0
- package/dist/components/file-drop-zone/file-drop-zone.meta.d.ts +2 -0
- package/dist/components/file-drop-zone/format-bytes.d.ts +5 -0
- package/dist/components/file-drop-zone/index.d.ts +4 -0
- package/dist/components/image/image.d.ts +50 -0
- package/dist/components/image/image.meta.d.ts +2 -0
- package/dist/components/image/index.d.ts +2 -0
- package/dist/components/logo/logo.d.ts +1 -1
- package/dist/components/popover/popover.d.ts +2 -2
- package/dist/components/progress/index.d.ts +2 -0
- package/dist/components/progress/progress.d.ts +40 -0
- package/dist/components/progress/progress.meta.d.ts +2 -0
- package/dist/components/rich-link/rich-link.d.ts +1 -1
- package/dist/components/select/select.cva.d.ts +7 -0
- package/dist/components/select/select.d.ts +1 -1
- package/dist/components/tab-nav/index.d.ts +2 -0
- package/dist/components/tab-nav/tab-nav.d.ts +26 -0
- package/dist/components/tab-nav/tab-nav.meta.d.ts +2 -0
- package/dist/components/table/table.d.ts +8 -0
- package/dist/components/tabs/tabs-underline.cva.d.ts +6 -0
- package/dist/components/tabs/tabs.d.ts +13 -4
- package/dist/components/textarea/index.d.ts +2 -0
- package/dist/components/textarea/textarea.d.ts +32 -0
- package/dist/components/textarea/textarea.meta.d.ts +2 -0
- package/dist/components/toast/toast.d.ts +2 -2
- package/dist/components/typo/typo.d.ts +5 -1
- package/dist/docgen/component-sources.d.ts +4 -0
- package/dist/icon-button-roSB497o.js +171 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +4536 -2958
- package/dist/integrations/code-highlight.js +2 -2
- package/dist/integrations/frame-selection.js +1 -1
- package/dist/integrations/image-display-options.js +73 -71
- package/dist/integrations/layout-mode/index.d.ts +2 -0
- package/dist/integrations/layout-mode/layout-mode-view.d.ts +32 -0
- package/dist/integrations/layout-mode/layout-mode.d.ts +13 -0
- package/dist/integrations/layout-mode/layout-mode.meta.d.ts +2 -0
- package/dist/integrations/layout-mode.js +103 -0
- package/dist/integrations/view-tools/index.d.ts +4 -0
- package/dist/integrations/view-tools/use-view-interaction.d.ts +21 -0
- package/dist/integrations/view-tools/view-tools-view.d.ts +23 -0
- package/dist/integrations/view-tools/view-tools.d.ts +14 -0
- package/dist/integrations/view-tools/view-tools.meta.d.ts +2 -0
- package/dist/integrations/view-tools.js +133 -0
- package/dist/{resolve-state-props-DQf9WiGv.js → rolldown-runtime-Dy4uBu1J.js} +1 -12
- package/dist/row-CImu8yXV.js +136 -0
- package/dist/{scroll-area-z9Lf9uIk.js → scroll-area-CXQ_SxPX.js} +2 -1
- package/dist/{slider-Bf274cMe.js → slider-CpIZMAFl.js} +2 -1
- package/dist/style.css +2 -1
- package/dist/tabs-BqgyMmo6.js +173 -0
- package/dist/toggle-group-Bhb3qicp.js +31 -0
- package/dist/toggle-group-eGr6_hgQ.js +125 -0
- package/dist/utils/email.d.ts +4 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/initials.d.ts +4 -0
- package/dist/utils/item-parts.d.ts +23 -0
- package/dist/utils/stable-popup-height.d.ts +10 -0
- package/dist/utils-J6vbjIt1.js +46 -0
- package/package.json +4 -4
- package/src/docgen/doc.gen.json +5526 -1748
- package/src/llms/llms.gen.txt +52 -1
- package/src/llms/skills/imf-web-ui-audit/SKILL.md +5 -2
- package/src/llms/skills/imf-web-ui-conventions/SKILL.md +2 -2
- package/src/llms/skills/imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md +19 -2
- package/src/llms/skills/imf-web-ui-conventions/topics/assets.md +28 -4
- package/src/llms/skills/imf-web-ui-conventions/topics/components.md +10 -0
- package/src/llms/skills/imf-web-ui-conventions/topics/library-boundary.md +3 -0
- package/src/llms/skills/imf-web-ui-conventions/topics/npm-project.md +2 -1
- package/src/llms/skills/imf-web-ui-conventions/topics/react/composition.md +54 -0
- package/src/llms/skills/imf-web-ui-conventions/topics/react/effects.md +59 -0
- package/src/llms/skills/imf-web-ui-conventions/topics/react/state.md +41 -0
- package/src/llms/skills/imf-web-ui-conventions/topics/react.md +7 -60
- package/src/llms/skills/imf-web-ui-conventions/topics/styling.md +22 -1
- package/src/llms/skills/imf-web-ui-conventions/topics/tooling.md +3 -2
- package/src/llms/skills/imf-web-ui-conventions/topics/validation.md +7 -0
- package/src/llms/skills/imf-web-ui-ux/references/forms.md +3 -2
- package/src/llms/tokens.gen.json +19 -1
- package/dist/tabs-DsDSCA--.js +0 -376
package/src/llms/llms.gen.txt
CHANGED
|
@@ -19,6 +19,12 @@ The signed-in person's account row: the avatar in a lead column, the name or ema
|
|
|
19
19
|
Application layout shell for a header, sidebars, footer, and scrolling main area. Also called an app layout or dashboard shell; sizing is CSS-driven and sidebars can become sliding panels on small screens.
|
|
20
20
|
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .app-shell (jq: jq '.app-shell' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
21
21
|
|
|
22
|
+
## Autocomplete
|
|
23
|
+
- category: Inputs, status: experimental
|
|
24
|
+
Text input that suggests options as you type, keeping free text. Also called a typeahead or search suggestions. Use Combobox when the value must come from the list.
|
|
25
|
+
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .autocomplete (jq: jq '.autocomplete' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
26
|
+
- further reading (usage/anatomy, not props): https://base-ui.com/react/components/autocomplete.md
|
|
27
|
+
|
|
22
28
|
## Avatar
|
|
23
29
|
- category: Display, status: experimental
|
|
24
30
|
Round badge that stands for a person, showing their photo, their initials, or a person glyph. Also called a profile picture or user badge; for a signed-in account row with a name, use AccountCard.
|
|
@@ -78,6 +84,12 @@ Show-and-hide region for secondary content such as FAQs, settings, or details. A
|
|
|
78
84
|
Light, System, and Dark segments that set and remember the page's color scheme. Also called an appearance or theme switch; built on ToggleGroup, which is the choice for any other segmented selection.
|
|
79
85
|
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .color-scheme-toggle (jq: jq '.color-scheme-toggle' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
80
86
|
|
|
87
|
+
## Combobox
|
|
88
|
+
- category: Inputs, status: experimental
|
|
89
|
+
Text input with a filterable list of options, for choosing one or several from a long list. Also called a searchable select, typeahead, or multi-select. Use Select for short lists and Autocomplete when free text is allowed.
|
|
90
|
+
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .combobox (jq: jq '.combobox' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
91
|
+
- further reading (usage/anatomy, not props): https://base-ui.com/react/components/combobox.md
|
|
92
|
+
|
|
81
93
|
## CopyButton
|
|
82
94
|
- category: Buttons, status: stable
|
|
83
95
|
Copies a value to the clipboard and briefly shows confirmation. Also called a copy-to-clipboard button; commonly used with Code.Block.
|
|
@@ -107,6 +119,11 @@ Semantic group for related form controls with a shared legend. Also called a for
|
|
|
107
119
|
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .fieldset (jq: jq '.fieldset' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
108
120
|
- further reading (usage/anatomy, not props): https://base-ui.com/react/components/fieldset.md
|
|
109
121
|
|
|
122
|
+
## FileDropZone
|
|
123
|
+
- category: Inputs, status: experimental
|
|
124
|
+
Drop zone with picker buttons for files or whole folders, reporting accepted and rejected files. Also called a file upload area or dropzone. For a single native file control inside a form, use Input.
|
|
125
|
+
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .file-drop-zone (jq: jq '.file-drop-zone' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
126
|
+
|
|
110
127
|
## FrameSelection
|
|
111
128
|
- category: Inputs, status: experimental
|
|
112
129
|
Frame or slice picker bound to the focused frame of ImFusion image sets, with a focus and count readout. For a position picker not tied to the SDK, use Slider with variant="position".
|
|
@@ -123,6 +140,11 @@ Renders a Web UI icon with an optional semantic foreground color. The default in
|
|
|
123
140
|
Square button that shows a single icon and no visible text, with its accessible name from `label`. Also called an icon-only or toolbar button. Use Button with `startIcon` or `endIcon` when a text label is visible.
|
|
124
141
|
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .icon-button (jq: jq '.icon-button' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
125
142
|
|
|
143
|
+
## Image
|
|
144
|
+
- category: Display, status: experimental
|
|
145
|
+
Picture with AVIF and WebP sources, reserved space, lazy loading, and a fallback while it loads or when it fails. Also called a photo, thumbnail or media. Use Avatar for a person and Card.Image for a card's edge-to-edge slot.
|
|
146
|
+
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .image (jq: jq '.image' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
147
|
+
|
|
126
148
|
## ImageDisplayOptions
|
|
127
149
|
- category: Inputs, status: experimental
|
|
128
150
|
Panel and toolbar controls for an image dataset's display options, including window, level, gamma, and invert settings.
|
|
@@ -140,6 +162,12 @@ Single-line text input for form data entry. Also called a text field; it support
|
|
|
140
162
|
Shows a keyboard key or shortcut, such as the letter that activates a button. Also called a key hint; Button and Toggle render it through their `shortcut` prop.
|
|
141
163
|
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .kbd (jq: jq '.kbd' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
142
164
|
|
|
165
|
+
## LayoutMode
|
|
166
|
+
- category: Inputs, status: experimental
|
|
167
|
+
Picker bound to the ImFusion viewer's layout mode: Auto, Rows, Focus + stack, or Focus + rows, as a compact icon row or a labeled vertical list. Also called a layout or view arrangement switch; for a segmented choice not tied to the SDK, use ToggleGroup.
|
|
168
|
+
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .layout-mode (jq: jq '.layout-mode' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
169
|
+
- further reading (usage/anatomy, not props): https://docs.imfusion.com/
|
|
170
|
+
|
|
143
171
|
## Logo
|
|
144
172
|
- category: Display, status: stable
|
|
145
173
|
Renders a logo from a URL or inline React element with consistent sizing. Also called a wordmark or brand mark.
|
|
@@ -169,6 +197,12 @@ Floating panel anchored to a trigger for contextual content, quick forms, or act
|
|
|
169
197
|
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .popover (jq: jq '.popover' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
170
198
|
- further reading (usage/anatomy, not props): https://base-ui.com/react/components/popover.md
|
|
171
199
|
|
|
200
|
+
## Progress
|
|
201
|
+
- category: Display, status: experimental
|
|
202
|
+
Bar for the completion of a running task, such as an upload or export. Also called a progress bar. Indeterminate when the amount is unknown. Use Meter for a static measure within a range.
|
|
203
|
+
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .progress (jq: jq '.progress' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
204
|
+
- further reading (usage/anatomy, not props): https://base-ui.com/react/components/progress.md
|
|
205
|
+
|
|
172
206
|
## Prose
|
|
173
207
|
- category: Layout, status: experimental
|
|
174
208
|
Flow container that spaces long-form text and the blocks inside it. Also called an article or rich-text container. Use Stack or Row for UI layout.
|
|
@@ -229,6 +263,11 @@ Two-state control for an on/off setting that takes effect immediately. Also call
|
|
|
229
263
|
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .switch (jq: jq '.switch' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
230
264
|
- further reading (usage/anatomy, not props): https://base-ui.com/react/components/switch.md
|
|
231
265
|
|
|
266
|
+
## TabNav
|
|
267
|
+
- category: Display, status: experimental
|
|
268
|
+
Row of links to routes with a bar under the current one, such as the sections of a project. Also called route tabs or link tabs; use Tabs to switch panels on one page.
|
|
269
|
+
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .tab-nav (jq: jq '.tab-nav' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
270
|
+
|
|
232
271
|
## Table
|
|
233
272
|
- category: Display, status: stable
|
|
234
273
|
Presentational table parts for static tabular data. Pair them with a headless table library for sorting, pagination, or selection.
|
|
@@ -236,10 +275,16 @@ Presentational table parts for static tabular data. Pair them with a headless ta
|
|
|
236
275
|
|
|
237
276
|
## Tabs
|
|
238
277
|
- category: Display, status: stable
|
|
239
|
-
Switches between related panels within one view. Also called a tab strip or tab bar; it supports horizontal and vertical layouts.
|
|
278
|
+
Switches between related panels within one view. Also called a tab strip or tab bar; it supports horizontal and vertical layouts and a boxed or underline look. Use TabNav for links to routes.
|
|
240
279
|
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .tabs (jq: jq '.tabs' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
241
280
|
- further reading (usage/anatomy, not props): https://base-ui.com/react/components/tabs.md
|
|
242
281
|
|
|
282
|
+
## Textarea
|
|
283
|
+
- category: Inputs, status: experimental
|
|
284
|
+
Multi-line text input for longer free text, such as a description or note. Also called a text area; use Input for a single line. It reads validation state from Field.
|
|
285
|
+
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .textarea (jq: jq '.textarea' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
286
|
+
- further reading (usage/anatomy, not props): https://base-ui.com/react/components/input.md
|
|
287
|
+
|
|
243
288
|
## Toast
|
|
244
289
|
- category: Display, status: experimental
|
|
245
290
|
Transient message stack that reports the outcome of a background action without interrupting the page. Use for save confirmations, undo offers, and async progress; attach one to an element for contextual feedback like a copy confirmation. Also called a snackbar, notification, or flash message; for a message that stays inline in the page use Callout instead.
|
|
@@ -268,3 +313,9 @@ Hover- or focus-triggered label for brief help about a control or term. Also cal
|
|
|
268
313
|
- category: Display, status: stable
|
|
269
314
|
Semantic text primitives for display and standard headings, paragraphs, lists, quotes, links, and inline code. The namespace uses native HTML elements and token-based text roles.
|
|
270
315
|
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .typo (jq: jq '.typo' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
316
|
+
|
|
317
|
+
## ViewTools
|
|
318
|
+
- category: Inputs, status: experimental
|
|
319
|
+
Toolbar that limits mouse interaction in the ImFusion main 2D and MPR views to pan, zoom, or windowing, with a reset button for the view group. For a segmented control not tied to the SDK, use ToggleGroup.
|
|
320
|
+
- props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .view-tools (jq: jq '.view-tools' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
|
|
321
|
+
- further reading (usage/anatomy, not props): https://docs.imfusion.com/
|
|
@@ -66,8 +66,11 @@ next action is the add from that topic. A Vite config that reads tsconfig `paths
|
|
|
66
66
|
`vite-tsconfig-paths`) is Broken: it loads the React types package as React once Web UI comes from the registry. The fix is
|
|
67
67
|
to drop it and give the `#/` alias through `imports` in `package.json`. A major or minor mismatch between the project and Web
|
|
68
68
|
UI on a package listed under Aligned runtime packages in the `tooling` topic is a Deviation. Report both versions, with
|
|
69
|
-
`npm install <package>@<Web UI's version>` as the fix.
|
|
70
|
-
|
|
69
|
+
`npm install <package>@<Web UI's version>` as the fix. An `engines.node` that admits a Node outside the `engines.node` of the
|
|
70
|
+
installed `node_modules/@imfusion/web-ui/package.json` is a Deviation; report both ranges, with Web UI's as the fix. A route
|
|
71
|
+
file that holds several views inline is a Deviation, and so is a route whose only view sits alone in its `-` folder. Name the
|
|
72
|
+
views, with the move as the fix. A form whose state and validation are written by hand instead of TanStack Form is a
|
|
73
|
+
Deviation, however many forms share the pattern. Name each form, with TanStack Form and its existing schema as the fix.
|
|
71
74
|
|
|
72
75
|
## Topics
|
|
73
76
|
|
|
@@ -25,11 +25,11 @@ a gap or to make a deliberate deviation visible; do not refactor a project just
|
|
|
25
25
|
| [styling](topics/styling.md) | Writing CSS or customizing Web UI. |
|
|
26
26
|
| [tokens](topics/tokens.md) | Choosing an exact token name. |
|
|
27
27
|
| [class-names](topics/class-names.md) | Mapping variants and `className` to CSS. |
|
|
28
|
-
| [validation](topics/validation.md) | Accepting data from outside the frontend.
|
|
28
|
+
| [validation](topics/validation.md) | Accepting data from outside the frontend, or building a form. |
|
|
29
29
|
| [data](topics/data.md) | Adding API queries, mutations, or invalidation. |
|
|
30
30
|
| [project-structure](topics/project-structure.md) | Adding files or routes. |
|
|
31
31
|
| [testing](topics/testing.md) | Deciding what to test. |
|
|
32
|
-
| [tooling](topics/tooling.md) | Adding a dependency or
|
|
32
|
+
| [tooling](topics/tooling.md) | Adding a dependency, configuring a tool, or building a form. |
|
|
33
33
|
| [npm-project](topics/npm-project.md) | Changing `package.json`, scripts, pins, or Node. |
|
|
34
34
|
| [git](topics/git.md) | Configuring hooks or choosing verification scope. |
|
|
35
35
|
| [agent-tooling](topics/agent-tooling.md) | Installing skills or lifecycle hooks. |
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
One block per topic, one box per topic section. Check a box only after checking that section's rules against the repo. A full
|
|
4
4
|
audit checks every box; a scoped audit names its topics first and checks only their blocks. Blocks mirror each topic's `##`
|
|
5
|
-
sections one to one — change a topic's sections and this
|
|
5
|
+
sections one to one, and a topic split into a folder gets one `###` block per subtopic — change a topic's sections and this
|
|
6
|
+
file follows in the same commit.
|
|
6
7
|
|
|
7
8
|
## Library setup — `library-setup`
|
|
8
9
|
|
|
@@ -35,10 +36,23 @@ sections one to one — change a topic's sections and this file follows in the s
|
|
|
35
36
|
|
|
36
37
|
## React — `react`
|
|
37
38
|
|
|
39
|
+
### Composition — `react/composition`
|
|
40
|
+
|
|
38
41
|
- [ ] Composition: pages (smart containers), partials, dumb components
|
|
39
42
|
- [ ] Compose, don't configure
|
|
43
|
+
- [ ] Render rules
|
|
44
|
+
|
|
45
|
+
### State — `react/state`
|
|
46
|
+
|
|
40
47
|
- [ ] Put state where its truth lives
|
|
48
|
+
- [ ] State shape
|
|
49
|
+
- [ ] Fallbacks without TanStack
|
|
50
|
+
|
|
51
|
+
### Effects — `react/effects`
|
|
52
|
+
|
|
41
53
|
- [ ] Effects: last resort, and named
|
|
54
|
+
- [ ] Dependencies
|
|
55
|
+
- [ ] Effect Events for values the effect should not react to
|
|
42
56
|
|
|
43
57
|
## Components — `components`
|
|
44
58
|
|
|
@@ -46,6 +60,7 @@ sections one to one — change a topic's sections and this file follows in the s
|
|
|
46
60
|
- [ ] Grouping
|
|
47
61
|
- [ ] One file or a folder
|
|
48
62
|
- [ ] Colocation
|
|
63
|
+
- [ ] Semantic elements
|
|
49
64
|
|
|
50
65
|
## TypeScript & code style — `typescript`
|
|
51
66
|
|
|
@@ -80,6 +95,7 @@ sections one to one — change a topic's sections and this file follows in the s
|
|
|
80
95
|
- [ ] Schema first, type derived
|
|
81
96
|
- [ ] TanStack Router search params
|
|
82
97
|
- [ ] Failure handling
|
|
98
|
+
- [ ] Forms
|
|
83
99
|
|
|
84
100
|
## Data — `data`
|
|
85
101
|
|
|
@@ -127,7 +143,8 @@ sections one to one — change a topic's sections and this file follows in the s
|
|
|
127
143
|
## Assets — `assets`
|
|
128
144
|
|
|
129
145
|
- [ ] Importing
|
|
130
|
-
- [ ] Photographs: WebP
|
|
146
|
+
- [ ] Photographs: AVIF and WebP
|
|
147
|
+
- [ ] Loading
|
|
131
148
|
- [ ] Other formats
|
|
132
149
|
- [ ] Scope
|
|
133
150
|
|
|
@@ -8,15 +8,39 @@ consumed by document metadata or manifests, with a build step that serves the fi
|
|
|
8
8
|
For the library's favicon set and social sharing image, read `BrandAssets.mdx` through the packaged user-guide route in
|
|
9
9
|
`imf-web-ui`.
|
|
10
10
|
|
|
11
|
-
## Photographs: WebP
|
|
11
|
+
## Photographs: AVIF and WebP
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Encode photographs as AVIF and WebP at 800 and 1600px wide. A source narrower than a width skips it, and `srcSet` lists only
|
|
14
|
+
the widths that exist:
|
|
14
15
|
|
|
15
16
|
```sh
|
|
16
|
-
|
|
17
|
+
for w in 800 1600; do
|
|
18
|
+
magick source.png -resize "${w}x>" -quality 55 src/assets/name-$w.avif
|
|
19
|
+
magick source.png -resize "${w}x>" -quality 80 -define webp:method=6 src/assets/name-$w.webp
|
|
20
|
+
done
|
|
17
21
|
```
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
Render them through `<picture>`: an AVIF `<source>`, then a WebP `<source>`, each with `srcSet` and `sizes`, then an `<img>`
|
|
24
|
+
fallback. The browser takes the first format it supports at the width that fits. Both formats are supported by the browser
|
|
25
|
+
floor.
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
<picture>
|
|
29
|
+
<source type="image/avif" srcSet={`${name800Avif} 800w, ${name1600Avif} 1600w`} sizes="(max-width: 40rem) 100vw, 40rem" />
|
|
30
|
+
<source type="image/webp" srcSet={`${name800Webp} 800w, ${name1600Webp} 1600w`} sizes="(max-width: 40rem) 100vw, 40rem" />
|
|
31
|
+
<img src={name800Webp} width={800} height={400} alt="…" />
|
|
32
|
+
</picture>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`Image` from `@imfusion/web-ui` renders this `<picture>` from `avifSrcSet`, `webpSrcSet`, `srcSet`, `sizes`, `width`,
|
|
36
|
+
`height` and `alt`. It adds lazy loading and async decoding, a pulse while the image loads and a glyph when it fails. Use it
|
|
37
|
+
for content images instead of writing the `<picture>` by hand.
|
|
38
|
+
|
|
39
|
+
## Loading
|
|
40
|
+
|
|
41
|
+
Every `<img>` carries `width` and `height` in the source's aspect ratio, so the browser reserves its space before it loads.
|
|
42
|
+
An image below the fold gets `loading="lazy"` and `decoding="async"`. The one image that is the page's largest paint gets
|
|
43
|
+
`fetchpriority="high"` and loads eagerly.
|
|
20
44
|
|
|
21
45
|
## Other formats
|
|
22
46
|
|
|
@@ -53,3 +53,13 @@ Keep a component's stylesheet, tests, and local types beside the component. A co
|
|
|
53
53
|
be a layout or dumb component instead.
|
|
54
54
|
|
|
55
55
|
A route-local component keeps its stylesheet and tests in the route's `-` folder beside it.
|
|
56
|
+
|
|
57
|
+
## Semantic elements
|
|
58
|
+
|
|
59
|
+
Inside `AppShell`, the shell's parts render the landmarks: `AppShell.Header` a `<header>`, `AppShell.Navbar` a `<nav>`,
|
|
60
|
+
`AppShell.Aside` an `<aside>`, `AppShell.Main` the page's one `<main>`, and `AppShell.Footer` a `<footer>`. A page puts its
|
|
61
|
+
content inside those parts.
|
|
62
|
+
|
|
63
|
+
Custom markup uses the element for its meaning: `<section>` and `<article>` for content groups, `<time dateTime>` for a date,
|
|
64
|
+
`Button` for an action, and the router's `Link` for a destination. A page has one `Typo.H1`, and heading levels descend
|
|
65
|
+
without skipping.
|
|
@@ -7,6 +7,9 @@ integration seams.
|
|
|
7
7
|
|
|
8
8
|
- Do not import Base UI or another implementation package directly, including its stylesheet.
|
|
9
9
|
- If Web UI is missing a component or part, report the gap instead of reaching around it.
|
|
10
|
+
- Use what Web UI already ships before building your own: a component, a part, or a helper such as `initialsFromName`. A
|
|
11
|
+
native element or local function that duplicates one, such as a `div role="separator"` or a hand-written initials function,
|
|
12
|
+
is a finding.
|
|
10
13
|
- Import glyphs from `@imfusion/web-ui/icons` and render them with `Icon`.
|
|
11
14
|
|
|
12
15
|
## Stand in for a missing component
|
|
@@ -5,7 +5,8 @@ Keep project metadata, scripts, and dependency policy in `package.json` and the
|
|
|
5
5
|
## package.json
|
|
6
6
|
|
|
7
7
|
- Use ESM with `"type": "module"`.
|
|
8
|
-
- Set the
|
|
8
|
+
- Set `engines.node` to the range in Web UI's own `package.json`, so the app promises no Node that Web UI or the `#/` alias
|
|
9
|
+
rejects. A `.nvmrc` selects a version inside that range.
|
|
9
10
|
- Use the `#/` source alias when the project has one, and wire it through the package `imports` field.
|
|
10
11
|
- Set `private: true` only for packages that are never published.
|
|
11
12
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# React composition
|
|
2
|
+
|
|
3
|
+
Which role a component plays, and how parts combine.
|
|
4
|
+
|
|
5
|
+
## Composition: pages (smart containers), partials, dumb components
|
|
6
|
+
|
|
7
|
+
- **Pages** live in `routes/`. They load data, read URL state, coordinate actions, and compose the view. Route files hold the
|
|
8
|
+
search schema, loaders, and pending, error, and not-found components. They do not own component CSS. Route-local views and
|
|
9
|
+
forms live in the route's `-` folder, as [project-structure.md](../project-structure.md) describes, and that folder's
|
|
10
|
+
`.module.css` files are component styles.
|
|
11
|
+
- **Partials** are compositions that more than one route uses, extracted because they read as a unit. They have light logic
|
|
12
|
+
and no styling of their own.
|
|
13
|
+
- **Layout components** arrange content with `Stack`, `Row`, grids, and token gaps, and wrap long-form text in `Prose`.
|
|
14
|
+
- **Dumb components** receive data and callbacks, render UI, and own their styles. They do not fetch, route, or contain
|
|
15
|
+
business rules.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
function UserCard({ name, onEdit }: { name: string; onEdit: () => void }) {
|
|
19
|
+
return (
|
|
20
|
+
<Card.Root>
|
|
21
|
+
<Typo.P>{name}</Typo.P>
|
|
22
|
+
<Button onClick={onEdit}>Edit</Button>
|
|
23
|
+
</Card.Root>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Compose, don't configure
|
|
29
|
+
|
|
30
|
+
Compose small parts instead of making one component configurable through many boolean props. Lift shared state to the nearest
|
|
31
|
+
common parent.
|
|
32
|
+
|
|
33
|
+
## Render rules
|
|
34
|
+
|
|
35
|
+
These come from react.dev and hold for every component. Each names the React version it needs.
|
|
36
|
+
|
|
37
|
+
- **Render is pure (any version).** Never mutate props, state, context, or a value created before render. Mutating an object
|
|
38
|
+
the same render just created is fine.
|
|
39
|
+
- **No component defined inside another (any version).** A nested definition gets a new identity each render, so React
|
|
40
|
+
remounts it and its state resets. Define it at module level and pass data as props.
|
|
41
|
+
- **No `ref.current` during render (any version).** Read and write refs in effects and handlers, except for a lazy init. A
|
|
42
|
+
value that shapes the output belongs in state.
|
|
43
|
+
- **`ref` is a prop (React 19+).** Accept `ref` like any other prop in your own components; don't wrap them in `forwardRef`.
|
|
44
|
+
- **`useId` for accessibility ids (React 18+).** Use it for `htmlFor`, `aria-describedby`, and similar. Never use it for list
|
|
45
|
+
keys, and never hardcode its output in tests or selectors.
|
|
46
|
+
- **Error boundaries around UI units (any version).** Wrap a page section or widget, not every component. A boundary does not
|
|
47
|
+
catch errors from event handlers or async code; TanStack Query and Router surface those.
|
|
48
|
+
- **With the React Compiler on, no manual memoization by default.** `useMemo`, `useCallback`, and `React.memo` are only for a
|
|
49
|
+
measured case.
|
|
50
|
+
|
|
51
|
+
See [Keeping Components Pure](https://react.dev/learn/keeping-components-pure),
|
|
52
|
+
[Preserving and Resetting State](https://react.dev/learn/preserving-and-resetting-state),
|
|
53
|
+
[Referencing Values with Refs](https://react.dev/learn/referencing-values-with-refs), and
|
|
54
|
+
[`useId`](https://react.dev/reference/react/useId).
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# React effects
|
|
2
|
+
|
|
3
|
+
When an effect is the right tool, and how to write the ones that stay.
|
|
4
|
+
|
|
5
|
+
## Effects: last resort, and named
|
|
6
|
+
|
|
7
|
+
Use `useEffect` only to synchronize with something outside React. Do not use it for derived values, event responses, or
|
|
8
|
+
server sync.
|
|
9
|
+
|
|
10
|
+
A genuine effect belongs in a named custom hook. If it stays inline, name the callback:
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
useEffect(
|
|
14
|
+
function syncDocumentTitle() {
|
|
15
|
+
document.title = title;
|
|
16
|
+
},
|
|
17
|
+
[title]
|
|
18
|
+
);
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Destructure a primitive before putting it in an effect dependency array. Keep the returned query or route object intact
|
|
22
|
+
elsewhere so its namespace remains visible.
|
|
23
|
+
|
|
24
|
+
## Dependencies
|
|
25
|
+
|
|
26
|
+
- **No objects or functions as dependencies (any version).** They are new each render, so the effect re-runs every time.
|
|
27
|
+
Create them inside the effect, move them outside the component, or depend on the primitive they read.
|
|
28
|
+
- **Hidden `<Activity>` cleans up effects (React 19.2+).** A hidden subtree unmounts its effects and re-runs them when shown.
|
|
29
|
+
Don't rely on an effect running while its UI is hidden.
|
|
30
|
+
|
|
31
|
+
See [Removing Effect Dependencies](https://react.dev/learn/removing-effect-dependencies).
|
|
32
|
+
|
|
33
|
+
## Effect Events for values the effect should not react to
|
|
34
|
+
|
|
35
|
+
When an effect reads a value it should not react to, such as a callback prop or a setting used only once something happens,
|
|
36
|
+
move that logic into `useEffectEvent` (React 19.2+) instead of adding the value to the dependencies, mirroring it in a ref,
|
|
37
|
+
or suppressing the lint rule. Call the Effect Event only from inside the effect, and never use it to drop a value that should
|
|
38
|
+
re-run the effect. See [`useEffectEvent`](https://react.dev/reference/react/useEffectEvent).
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
const onConnected = useEffectEvent(function notifyConnected() {
|
|
42
|
+
if (!muted) toast("Connected");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
useEffect(
|
|
46
|
+
function connectToRoom() {
|
|
47
|
+
const connection = createConnection(roomId);
|
|
48
|
+
connection.on("connected", onConnected);
|
|
49
|
+
connection.connect();
|
|
50
|
+
|
|
51
|
+
return function disconnectFromRoom() {
|
|
52
|
+
connection.disconnect();
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
[roomId]
|
|
56
|
+
);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Read the React documentation when an effect decision is unclear.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# React state
|
|
2
|
+
|
|
3
|
+
Where each piece of state lives.
|
|
4
|
+
|
|
5
|
+
## Put state where its truth lives
|
|
6
|
+
|
|
7
|
+
Choose the first suitable level:
|
|
8
|
+
|
|
9
|
+
1. **URL state**: filters, sort, pagination, and active tab. Use TanStack Router search params and validate them.
|
|
10
|
+
2. **Server state**: API data. Use TanStack Query; do not copy it into `useState`.
|
|
11
|
+
3. **Subtree state**: state shared by a subtree and reset when it leaves. Use React context.
|
|
12
|
+
4. **Client state**: app-wide persistent state. Use TanStack Store only when the earlier levels do not fit.
|
|
13
|
+
5. **Local state**: one component's open state, draft, or input value. Use `useState`.
|
|
14
|
+
|
|
15
|
+
Shape state so it is not redundant or duplicated. Validate a form draft when it becomes a submitted domain value.
|
|
16
|
+
|
|
17
|
+
## State shape
|
|
18
|
+
|
|
19
|
+
- **One status, not exclusive booleans (any version).** `status: "idle" | "saving" | "error"` instead of `isSaving` and
|
|
20
|
+
`isError` that can both be true. Merge state variables that always change together.
|
|
21
|
+
- **Reducers are pure (any version).** No requests, toasts, or timers inside a reducer. Dispatch one action per user
|
|
22
|
+
interaction, from the event handler.
|
|
23
|
+
- **Slow renders (React 18+).** Keep text input state out of a transition. When a slow list follows a prop or hook value,
|
|
24
|
+
render it from `useDeferredValue(value)`.
|
|
25
|
+
|
|
26
|
+
See [Choosing the State Structure](https://react.dev/learn/choosing-the-state-structure) and
|
|
27
|
+
[Extracting State Logic into a Reducer](https://react.dev/learn/extracting-state-logic-into-a-reducer).
|
|
28
|
+
|
|
29
|
+
## Fallbacks without TanStack
|
|
30
|
+
|
|
31
|
+
TanStack Form and Query are the default. A project without them uses React's own tools:
|
|
32
|
+
|
|
33
|
+
- **Forms (React 19+):** `<form action={fn}>` needs no `preventDefault` and resets uncontrolled fields on success. Read
|
|
34
|
+
`useFormStatus` only in a child of the form. `useActionState` holds the result; dispatch it manually only inside an Action
|
|
35
|
+
or `startTransition`.
|
|
36
|
+
- **Optimistic updates (React 19+):** `useOptimistic`, with the setter called only inside an Action. Once the save succeeds,
|
|
37
|
+
the parent's value is the truth again.
|
|
38
|
+
|
|
39
|
+
See [`<form>`](https://react.dev/reference/react-dom/components/form),
|
|
40
|
+
[`useActionState`](https://react.dev/reference/react/useActionState), and
|
|
41
|
+
[`useOptimistic`](https://react.dev/reference/react/useOptimistic).
|
|
@@ -1,65 +1,12 @@
|
|
|
1
1
|
# React
|
|
2
2
|
|
|
3
3
|
Keep data flow one-way and components focused. Pages decide how data is loaded; presentational components decide how it
|
|
4
|
-
looks.
|
|
4
|
+
looks. Read the subtopic that matches the task.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
| Subtopic | Read when |
|
|
7
|
+
| ----------------------------------- | --------------------------------------------------------------- |
|
|
8
|
+
| [composition](react/composition.md) | Deciding a component's role, or composing parts. |
|
|
9
|
+
| [state](react/state.md) | Deciding where state lives. |
|
|
10
|
+
| [effects](react/effects.md) | Writing or reviewing `useEffect`, or reading values in effects. |
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
search schema, loaders, and pending, error, and not-found components. They do not own component CSS. Route-local views and
|
|
10
|
-
forms live in the route's `-` folder, as [project-structure.md](project-structure.md) describes, and that folder's
|
|
11
|
-
`.module.css` files are component styles.
|
|
12
|
-
- **Partials** are compositions that more than one route uses, extracted because they read as a unit. They have light logic
|
|
13
|
-
and no styling of their own.
|
|
14
|
-
- **Layout components** arrange content with `Stack`, `Row`, grids, and token gaps, and wrap long-form text in `Prose`.
|
|
15
|
-
- **Dumb components** receive data and callbacks, render UI, and own their styles. They do not fetch, route, or contain
|
|
16
|
-
business rules.
|
|
17
|
-
|
|
18
|
-
```tsx
|
|
19
|
-
function UserCard({ name, onEdit }: { name: string; onEdit: () => void }) {
|
|
20
|
-
return (
|
|
21
|
-
<Card.Root>
|
|
22
|
-
<Typo.P>{name}</Typo.P>
|
|
23
|
-
<Button onClick={onEdit}>Edit</Button>
|
|
24
|
-
</Card.Root>
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Compose, don't configure
|
|
30
|
-
|
|
31
|
-
Compose small parts instead of making one component configurable through many boolean props. Lift shared state to the nearest
|
|
32
|
-
common parent.
|
|
33
|
-
|
|
34
|
-
## Put state where its truth lives
|
|
35
|
-
|
|
36
|
-
Choose the first suitable level:
|
|
37
|
-
|
|
38
|
-
1. **URL state**: filters, sort, pagination, and active tab. Use TanStack Router search params and validate them.
|
|
39
|
-
2. **Server state**: API data. Use TanStack Query; do not copy it into `useState`.
|
|
40
|
-
3. **Subtree state**: state shared by a subtree and reset when it leaves. Use React context.
|
|
41
|
-
4. **Client state**: app-wide persistent state. Use TanStack Store only when the earlier levels do not fit.
|
|
42
|
-
5. **Local state**: one component's open state, draft, or input value. Use `useState`.
|
|
43
|
-
|
|
44
|
-
Shape state so it is not redundant or duplicated. Validate a form draft when it becomes a submitted domain value.
|
|
45
|
-
|
|
46
|
-
## Effects: last resort, and named
|
|
47
|
-
|
|
48
|
-
Use `useEffect` only to synchronize with something outside React. Do not use it for derived values, event responses, or
|
|
49
|
-
server sync.
|
|
50
|
-
|
|
51
|
-
A genuine effect belongs in a named custom hook. If it stays inline, name the callback:
|
|
52
|
-
|
|
53
|
-
```tsx
|
|
54
|
-
useEffect(
|
|
55
|
-
function syncDocumentTitle() {
|
|
56
|
-
document.title = title;
|
|
57
|
-
},
|
|
58
|
-
[title]
|
|
59
|
-
);
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Destructure a primitive before putting it in an effect dependency array. Keep the returned query or route object intact
|
|
63
|
-
elsewhere so its namespace remains visible.
|
|
64
|
-
|
|
65
|
-
Read the React documentation when a decomposition or effect decision is unclear.
|
|
12
|
+
Read the React documentation when a decomposition decision is unclear.
|
|
@@ -19,7 +19,8 @@ Use native CSS and Web UI's public seams. The library's CSS Modules and token na
|
|
|
19
19
|
transition: opacity var(--imf-ui-duration-quick-2) var(--imf-ui-ease-2);
|
|
20
20
|
|
|
21
21
|
&:focus-visible {
|
|
22
|
-
outline: var(--imf-ui-
|
|
22
|
+
outline: var(--imf-ui-focus-ring-width) solid var(--imf-ui-focus-ring-color);
|
|
23
|
+
outline-offset: var(--imf-ui-focus-ring-offset);
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
&[data-disabled] {
|
|
@@ -28,6 +29,13 @@ Use native CSS and Web UI's public seams. The library's CSS Modules and token na
|
|
|
28
29
|
}
|
|
29
30
|
```
|
|
30
31
|
|
|
32
|
+
## Focus ring
|
|
33
|
+
|
|
34
|
+
Web UI parts draw their own focus ring. Your own focusable elements draw the same one from the `--imf-ui-focus-ring-*`
|
|
35
|
+
tokens: `width` and `color` for the outline, and one of two offsets: `offset` outside a standalone control and `offset-inset`
|
|
36
|
+
for items inside a scrolling or tight container, which would clip an outside ring. A surface filled with a saturated color
|
|
37
|
+
sets `--imf-ui-focus-ring-color` to `--imf-ui-color-fg-oncolor` for everything inside it.
|
|
38
|
+
|
|
31
39
|
## Build custom UI from tokens
|
|
32
40
|
|
|
33
41
|
Use names from the shipped token index for colors, type, size, radius, and shadow. A literal beside a tokenized concept is a
|
|
@@ -54,6 +62,19 @@ hook, not a state flag.
|
|
|
54
62
|
}
|
|
55
63
|
```
|
|
56
64
|
|
|
65
|
+
Your own components follow the same seam. A container that changes a child sets a custom property; the child reads it with
|
|
66
|
+
its own default as the fallback, so it works with or without the container:
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
.panel {
|
|
70
|
+
--panel-row-gap: var(--imf-ui-size-2);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.row {
|
|
74
|
+
padding-block: var(--panel-row-gap, var(--imf-ui-size-3));
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
57
78
|
## Spacing
|
|
58
79
|
|
|
59
80
|
Web UI components have no outer margin. The parent sets the distance between its children: `Stack` and `Row` gaps in UI,
|
|
@@ -25,7 +25,8 @@ Use the tool's current documentation rather than memory.
|
|
|
25
25
|
|
|
26
26
|
Use the library that already owns the problem. Adopt Form for form rules, Query for caching and refetching, Router for URL
|
|
27
27
|
state, Table for sorting and pagination, and Hotkeys for keyboard shortcuts instead of rebuilding those layers. Web UI only
|
|
28
|
-
shows a key; the app binds it. Keep an existing project choice when it works.
|
|
28
|
+
shows a key; the app binds it. Keep an existing project choice when it works. A layer rebuilt by hand, such as form state in
|
|
29
|
+
`useState`, is not a choice to keep.
|
|
29
30
|
|
|
30
31
|
## Devtools
|
|
31
32
|
|
|
@@ -44,7 +45,7 @@ the Agent Skills the TanStack package provides.
|
|
|
44
45
|
Vite+ runs development, build, tests, format, lint, and staged checks through one `vp` binary configured in `vite.config.ts`.
|
|
45
46
|
Pin `vite-plus` exactly, alias `vite` to `npm:@voidzero-dev/vite-plus-core@<vite-plus version>`, pin `vitest` to the version
|
|
46
47
|
`vp toolchain vitest` reports, and repeat both pins under `overrides`. Import `defineConfig` from `vite-plus` and Vitest APIs
|
|
47
|
-
from `vite-plus/test`. It needs
|
|
48
|
+
from `vite-plus/test`. It needs Git 2.32 or later; the `npm-project` topic sets the Node range.
|
|
48
49
|
|
|
49
50
|
`vp <command>` is a built-in; `vp run <script>` runs a package script.
|
|
50
51
|
|
|
@@ -54,3 +54,10 @@ Use `.catch()` for malformed values that can safely fall back. Use `.default()`
|
|
|
54
54
|
- Use `parse` when invalid data is a contract failure that should reach the normal error boundary.
|
|
55
55
|
- Use `safeParse` when failure is expected and the caller can show a validation message.
|
|
56
56
|
- Keep trimming, coercion, transforms, and defaults in the boundary schema.
|
|
57
|
+
|
|
58
|
+
## Forms
|
|
59
|
+
|
|
60
|
+
Build forms with TanStack Form and validate user input in the form's validators with the Zod schema, so a field error and the
|
|
61
|
+
submitted value's type come from one schema. Field values held in `useState` and checked by hand with `safeParse` are a gap,
|
|
62
|
+
even when the project's other forms do the same. A project without TanStack Form follows the fallback in
|
|
63
|
+
[react/state.md](react/state.md#fallbacks-without-tanstack).
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Form UX
|
|
2
2
|
|
|
3
|
-
Read this before building a form with more than two fields.
|
|
4
|
-
|
|
3
|
+
Read this before building a form with more than two fields. Build it with TanStack Form, the form library the
|
|
4
|
+
`imf-web-ui-conventions` tooling topic names: it owns state and validation, and Web UI supplies the controls. These rules
|
|
5
|
+
cover structure and feedback.
|
|
5
6
|
|
|
6
7
|
## Structure
|
|
7
8
|
|
package/src/llms/tokens.gen.json
CHANGED
|
@@ -462,6 +462,24 @@
|
|
|
462
462
|
"value": "cubic-bezier(0, 0, 0.05, 1)"
|
|
463
463
|
}
|
|
464
464
|
],
|
|
465
|
+
"focus": [
|
|
466
|
+
{
|
|
467
|
+
"name": "--imf-ui-focus-ring-color",
|
|
468
|
+
"value": "var(--imf-ui-color-fg-primary)"
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"name": "--imf-ui-focus-ring-offset",
|
|
472
|
+
"value": "2px"
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
"name": "--imf-ui-focus-ring-offset-inset",
|
|
476
|
+
"value": "calc(var(--imf-ui-focus-ring-width) * -1)"
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"name": "--imf-ui-focus-ring-width",
|
|
480
|
+
"value": "var(--imf-ui-border-size-2)"
|
|
481
|
+
}
|
|
482
|
+
],
|
|
465
483
|
"font": [
|
|
466
484
|
{
|
|
467
485
|
"name": "--imf-ui-font-family-body",
|
|
@@ -955,5 +973,5 @@
|
|
|
955
973
|
}
|
|
956
974
|
]
|
|
957
975
|
},
|
|
958
|
-
"count":
|
|
976
|
+
"count": 237
|
|
959
977
|
}
|