@imfusion/web-ui 0.8.1-dev.2.g74f81c31 → 0.8.1-dev.20.g50b02289

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 (40) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/README.md +17 -17
  3. package/dist/components/account-card/account-card.d.ts +42 -12
  4. package/dist/components/card/card.d.ts +15 -1
  5. package/dist/components/field/field.d.ts +5 -2
  6. package/dist/components/slider/slider.d.ts +11 -1
  7. package/dist/components/typo/typo.d.ts +20 -11
  8. package/dist/index.js +1256 -1172
  9. package/dist/integrations/frame-selection/frame-selection-view.d.ts +24 -0
  10. package/dist/integrations/frame-selection/frame-selection.d.ts +21 -0
  11. package/dist/integrations/frame-selection/frame-selection.meta.d.ts +2 -0
  12. package/dist/integrations/frame-selection/index.d.ts +2 -0
  13. package/dist/integrations/frame-selection.js +121 -0
  14. package/dist/integrations/image-display-options.js +71 -70
  15. package/dist/llms/evals/runner/config.d.ts +1 -0
  16. package/dist/separator-BAxxttef.js +26 -0
  17. package/dist/slider-gyIYWSy3.js +116 -0
  18. package/dist/style.css +1 -1
  19. package/dist/tabs-9d4oaDwZ.js +295 -0
  20. package/dist/utils/break-hints.d.ts +3 -0
  21. package/dist/utils/status-glyphs.d.ts +4 -0
  22. package/dist/vite.js +1 -1
  23. package/dist/web-ui-cli.js +1 -1
  24. package/docs/user-guide/AgentTooling.mdx +8 -3
  25. package/package.json +1 -1
  26. package/src/docgen/doc.gen.json +188 -20
  27. package/src/llms/llms.gen.txt +9 -3
  28. package/src/llms/skills/imf-web-ui/SKILL.md +2 -0
  29. package/src/llms/skills/imf-web-ui-audit/SKILL.md +5 -3
  30. package/src/llms/skills/imf-web-ui-components/SKILL.md +3 -1
  31. package/src/llms/skills/imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md +1 -0
  32. package/src/llms/skills/imf-web-ui-conventions/topics/authentication.md +2 -1
  33. package/src/llms/skills/imf-web-ui-conventions/topics/data.md +5 -3
  34. package/src/llms/skills/imf-web-ui-conventions/topics/typescript.md +14 -0
  35. package/src/llms/skills/imf-web-ui-setup/SKILL.md +2 -0
  36. package/src/llms/skills/imf-web-ui-update/SKILL.md +37 -6
  37. package/src/llms/skills/imf-web-ui-user-profile/SKILL.md +95 -0
  38. package/src/llms/skills/imf-web-ui-ux/SKILL.md +2 -0
  39. package/dist/tabs-BS6rqrrA.js +0 -398
  40. /package/dist/{paths-Oi0v8x-w.js → paths-CUyf9wjm.js} +0 -0
@@ -2,7 +2,7 @@
2
2
  "account-card": {
3
3
  "root": {
4
4
  "name": "AccountCard.Root",
5
- "description": "AccountCard.Root — the link to the signed-in person's account, holding `AccountCard.Avatar`, `AccountCard.Title`, and\n`AccountCard.Description`. Pass a router link through `render`. `aria-current=\"page\"` marks it current with a tint and\nan inset rule. Its accessible name is the title and description; the avatar stays decorative.\n\nPlace `AccountCard.Action` beside the root, not inside it: a link cannot contain a button.",
5
+ "description": "AccountCard.Root — the signed-in person's card: `AccountCard.Link` and, in its top row, `AccountCard.Action`. The\naction sits beside the link, not inside it, since a link cannot contain a button.",
6
6
  "props": [
7
7
  {
8
8
  "name": "context",
@@ -10,27 +10,13 @@
10
10
  "type": "\"default\" | \"oncolor\" | null",
11
11
  "defaultValue": "default",
12
12
  "description": ""
13
- },
14
- {
15
- "name": "ref",
16
- "required": false,
17
- "type": "Ref<HTMLAnchorElement>",
18
- "defaultValue": null,
19
- "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}"
20
- },
21
- {
22
- "name": "render",
23
- "required": false,
24
- "type": "| ReactElement<\n unknown,\n string | JSXElementConstructor<any>\n >\n| ComponentRenderFn<HTMLProps, {}>",
25
- "defaultValue": null,
26
- "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."
27
13
  }
28
14
  ]
29
15
  },
30
16
  "subComponents": [
31
17
  {
32
18
  "name": "AccountCard.Action",
33
- "description": "AccountCard.Action — a trailing slot beside `AccountCard.Root`, such as a ghost icon `Button` that logs out. The\nbutton carries its own `aria-label` and its own `context`.",
19
+ "description": "AccountCard.Action — a slot in the card's top row, beside the link, such as a ghost icon `Button` that logs out. The\nbutton carries its own `aria-label` and its own `context`.",
34
20
  "props": []
35
21
  },
36
22
  {
@@ -55,12 +41,47 @@
55
41
  },
56
42
  {
57
43
  "name": "AccountCard.Description",
58
- "description": "AccountCard.Description — a second line such as organization and role. Truncates to one line.",
44
+ "description": "AccountCard.Description — the organization, under a rule at the foot of the card.",
45
+ "props": []
46
+ },
47
+ {
48
+ "name": "AccountCard.Group",
49
+ "description": "AccountCard.Group — a list of cards, such as accounts to switch between. Inside it a link with `aria-current=\"page\"`\nshows as current; a standalone card is always the signed-in account and shows no current state.",
50
+ "props": []
51
+ },
52
+ {
53
+ "name": "AccountCard.Link",
54
+ "description": "AccountCard.Link — the link to the account, holding `AccountCard.Avatar`, `AccountCard.Title`,\n`AccountCard.Subtitle`, `AccountCard.Description`, and `AccountCard.Role`. Pass a router link through `render`. Its\naccessible name is its text; the avatar stays decorative.",
55
+ "props": [
56
+ {
57
+ "name": "ref",
58
+ "required": false,
59
+ "type": "Ref<HTMLAnchorElement>",
60
+ "defaultValue": null,
61
+ "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}"
62
+ },
63
+ {
64
+ "name": "render",
65
+ "required": false,
66
+ "type": "| ReactElement<\n unknown,\n string | JSXElementConstructor<any>\n >\n| ComponentRenderFn<HTMLProps, {}>",
67
+ "defaultValue": null,
68
+ "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."
69
+ }
70
+ ]
71
+ },
72
+ {
73
+ "name": "AccountCard.Role",
74
+ "description": "AccountCard.Role — a mono uppercase label beside the description, such as the person's role.",
75
+ "props": []
76
+ },
77
+ {
78
+ "name": "AccountCard.Subtitle",
79
+ "description": "AccountCard.Subtitle — the quiet line under the title: the email's domain, or the whole email once the title is a\nname. Text wraps before an `@` and after a dot.",
59
80
  "props": []
60
81
  },
61
82
  {
62
83
  "name": "AccountCard.Title",
63
- "description": "AccountCard.Title — the account's name, or its email until a name exists. Truncates to one line.",
84
+ "description": "AccountCard.Title — the account's name, or the email's local part until a name exists. Set large; text wraps before\nan `@` and after a dot.",
64
85
  "props": []
65
86
  }
66
87
  ]
@@ -478,6 +499,19 @@
478
499
  "description": "Width divided by height, or \"auto\" to use the image's intrinsic ratio."
479
500
  }
480
501
  ]
502
+ },
503
+ {
504
+ "name": "Card.Status",
505
+ "description": "Card.Status — a tinted slot that marks the card's status with the variant's glyph. Pass\nchildren to replace the glyph. Like `Card.Image`, place it first among the slots: a column\nbeside the body in a horizontal card, a band above it in a vertical one. Decorative\n(`aria-hidden`); the card's text carries the status.",
506
+ "props": [
507
+ {
508
+ "name": "variant",
509
+ "required": false,
510
+ "type": "| \"info\"\n| \"positive\"\n| \"warning\"\n| \"negative\"\n| null",
511
+ "defaultValue": "info",
512
+ "description": ""
513
+ }
514
+ ]
481
515
  }
482
516
  ]
483
517
  },
@@ -1942,7 +1976,7 @@
1942
1976
  },
1943
1977
  {
1944
1978
  "name": "Field.Error",
1945
- "description": "Field.Error — an inline validation message shown when its match condition fails.",
1979
+ "description": "Field.Error — an inline validation message shown when its match condition fails.\nIt announces itself with `role=\"alert\"`; pass another `role` to quiet it.",
1946
1980
  "props": [
1947
1981
  {
1948
1982
  "name": "className",
@@ -5535,7 +5569,7 @@
5535
5569
  "slider": {
5536
5570
  "root": {
5537
5571
  "name": "Slider.Root",
5538
- "description": "Slider.Root — value selector along a continuous or stepped track.",
5572
+ "description": "Slider.Root — value selector along a continuous or stepped track.\n\n`variant=\"position\"` draws a scrollbar-like trough and bar thumb for picking one position\nbetween `min` and `max`, such as a slice or frame; `onValueChange` reports the position.",
5539
5573
  "props": [
5540
5574
  {
5541
5575
  "name": "className",
@@ -5683,6 +5717,13 @@
5683
5717
  "type": "number | readonly number[]",
5684
5718
  "defaultValue": null,
5685
5719
  "description": "The value of the slider.\nFor ranged sliders, provide an array with two values."
5720
+ },
5721
+ {
5722
+ "name": "variant",
5723
+ "required": false,
5724
+ "type": "\"default\" | \"position\" | null",
5725
+ "defaultValue": "default",
5726
+ "description": ""
5686
5727
  }
5687
5728
  ]
5688
5729
  },
@@ -7766,6 +7807,13 @@
7766
7807
  "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
7767
7808
  "defaultValue": "support",
7768
7809
  "description": ""
7810
+ },
7811
+ {
7812
+ "name": "weight",
7813
+ "required": false,
7814
+ "type": "\"strong\" | \"regular\" | \"medium\"",
7815
+ "defaultValue": null,
7816
+ "description": "Font weight. Omit to keep the member's default; `medium` firms up short body text on cards."
7769
7817
  }
7770
7818
  ]
7771
7819
  },
@@ -7793,6 +7841,40 @@
7793
7841
  "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
7794
7842
  "defaultValue": "main",
7795
7843
  "description": ""
7844
+ },
7845
+ {
7846
+ "name": "weight",
7847
+ "required": false,
7848
+ "type": "\"strong\" | \"regular\" | \"medium\"",
7849
+ "defaultValue": null,
7850
+ "description": "Font weight. Omit to keep the member's default; `medium` firms up short body text on cards."
7851
+ }
7852
+ ]
7853
+ },
7854
+ {
7855
+ "name": "Typo.Eyebrow",
7856
+ "description": "Typo.Eyebrow — short uppercase label above a heading. Also called a kicker or overline.",
7857
+ "props": [
7858
+ {
7859
+ "name": "ref",
7860
+ "required": false,
7861
+ "type": "Ref<HTMLHeadingElement>",
7862
+ "defaultValue": null,
7863
+ "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}"
7864
+ },
7865
+ {
7866
+ "name": "render",
7867
+ "required": false,
7868
+ "type": "| ReactElement<\n unknown,\n string | JSXElementConstructor<any>\n >\n| ComponentRenderFn<HTMLProps, {}>",
7869
+ "defaultValue": null,
7870
+ "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."
7871
+ },
7872
+ {
7873
+ "name": "variant",
7874
+ "required": false,
7875
+ "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
7876
+ "defaultValue": "support",
7877
+ "description": ""
7796
7878
  }
7797
7879
  ]
7798
7880
  },
@@ -7976,6 +8058,13 @@
7976
8058
  "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
7977
8059
  "defaultValue": "oncolor",
7978
8060
  "description": ""
8061
+ },
8062
+ {
8063
+ "name": "weight",
8064
+ "required": false,
8065
+ "type": "\"strong\" | \"regular\" | \"medium\"",
8066
+ "defaultValue": null,
8067
+ "description": "Font weight. Omit to keep the member's default; `medium` firms up short body text on cards."
7979
8068
  }
7980
8069
  ]
7981
8070
  },
@@ -8037,6 +8126,13 @@
8037
8126
  "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
8038
8127
  "defaultValue": "main",
8039
8128
  "description": ""
8129
+ },
8130
+ {
8131
+ "name": "weight",
8132
+ "required": false,
8133
+ "type": "\"strong\" | \"regular\" | \"medium\"",
8134
+ "defaultValue": null,
8135
+ "description": "Font weight. Omit to keep the member's default; `medium` firms up short body text on cards."
8040
8136
  }
8041
8137
  ]
8042
8138
  },
@@ -8071,6 +8167,13 @@
8071
8167
  "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
8072
8168
  "defaultValue": "primary",
8073
8169
  "description": ""
8170
+ },
8171
+ {
8172
+ "name": "weight",
8173
+ "required": false,
8174
+ "type": "\"strong\" | \"regular\" | \"medium\"",
8175
+ "defaultValue": null,
8176
+ "description": "Font weight. Omit to keep the member's default; `medium` firms up short body text on cards."
8074
8177
  }
8075
8178
  ]
8076
8179
  },
@@ -8098,6 +8201,13 @@
8098
8201
  "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
8099
8202
  "defaultValue": "main",
8100
8203
  "description": ""
8204
+ },
8205
+ {
8206
+ "name": "weight",
8207
+ "required": false,
8208
+ "type": "\"strong\" | \"regular\" | \"medium\"",
8209
+ "defaultValue": null,
8210
+ "description": "Font weight. Omit to keep the member's default; `medium` firms up short body text on cards."
8101
8211
  }
8102
8212
  ]
8103
8213
  },
@@ -8125,6 +8235,13 @@
8125
8235
  "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
8126
8236
  "defaultValue": "main",
8127
8237
  "description": ""
8238
+ },
8239
+ {
8240
+ "name": "weight",
8241
+ "required": false,
8242
+ "type": "\"strong\" | \"regular\" | \"medium\"",
8243
+ "defaultValue": null,
8244
+ "description": "Font weight. Omit to keep the member's default; `medium` firms up short body text on cards."
8128
8245
  }
8129
8246
  ]
8130
8247
  },
@@ -8152,6 +8269,13 @@
8152
8269
  "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
8153
8270
  "defaultValue": "minor",
8154
8271
  "description": ""
8272
+ },
8273
+ {
8274
+ "name": "weight",
8275
+ "required": false,
8276
+ "type": "\"strong\" | \"regular\" | \"medium\"",
8277
+ "defaultValue": null,
8278
+ "description": "Font weight. Omit to keep the member's default; `medium` firms up short body text on cards."
8155
8279
  }
8156
8280
  ]
8157
8281
  },
@@ -8179,6 +8303,13 @@
8179
8303
  "type": "| \"main\"\n| \"support\"\n| \"minor\"\n| \"brand\"\n| \"primary\"\n| \"negative\"\n| \"positive\"\n| \"warning\"\n| \"info\"\n| \"oncolor\"\n| \"accent-1\"\n| \"accent-2\"\n| \"accent-3\"\n| null",
8180
8304
  "defaultValue": "main",
8181
8305
  "description": ""
8306
+ },
8307
+ {
8308
+ "name": "weight",
8309
+ "required": false,
8310
+ "type": "\"strong\" | \"regular\" | \"medium\"",
8311
+ "defaultValue": null,
8312
+ "description": "Font weight. Omit to keep the member's default; `medium` firms up short body text on cards."
8182
8313
  }
8183
8314
  ]
8184
8315
  }
@@ -8288,6 +8419,43 @@
8288
8419
  }
8289
8420
  ]
8290
8421
  },
8422
+ "frame-selection": {
8423
+ "root": {
8424
+ "name": "FrameSelection",
8425
+ "description": "FrameSelection - a position slider bound to the focused frame of the multi-frame image sets in `data`.\nEvery matching image set follows the slider, and a `{focus} | {count}` readout sits beside it.\nRenders nothing when `data` holds no multi-frame image set.\n\nMust render inside an `ImFusionProvider`.",
8426
+ "props": [
8427
+ {
8428
+ "name": "data",
8429
+ "required": true,
8430
+ "type": "HandleArray<Data>",
8431
+ "defaultValue": null,
8432
+ "description": "Datasets to scan, for example from `useVisibleData()`. Non-image data, single-frame image sets, and image sets whose\nframe count differs from the first multi-frame set are ignored."
8433
+ },
8434
+ {
8435
+ "name": "disabled",
8436
+ "required": false,
8437
+ "type": "boolean",
8438
+ "defaultValue": "false",
8439
+ "description": "Whether the slider ignores user interaction."
8440
+ },
8441
+ {
8442
+ "name": "label",
8443
+ "required": false,
8444
+ "type": "string",
8445
+ "defaultValue": "Frame",
8446
+ "description": "Accessible name of the slider thumb."
8447
+ },
8448
+ {
8449
+ "name": "orientation",
8450
+ "required": false,
8451
+ "type": "\"horizontal\" | \"vertical\"",
8452
+ "defaultValue": "horizontal",
8453
+ "description": "Direction of the slider; the vertical layout stacks the readout under it."
8454
+ }
8455
+ ]
8456
+ },
8457
+ "subComponents": []
8458
+ },
8291
8459
  "image-display-options": {
8292
8460
  "root": {
8293
8461
  "name": "ImageDisplayOptions",
@@ -11,7 +11,7 @@ props, which always live in the docgen file above.
11
11
 
12
12
  ## AccountCard
13
13
  - category: Display, status: experimental
14
- Link to the signed-in person's account, with avatar, name or email, and a second line such as organization and role. Also called an ID card or user row; for a bare person badge, use Avatar.
14
+ Card linking to the signed-in person's account: avatar, a large name or email, a quiet line under it, and organization and role at its foot, with a trailing action such as Log out. Also called an ID card or user row; for a bare person badge, use Avatar.
15
15
  - props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .account-card (jq: jq '.account-card' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
16
16
 
17
17
  ## AppShell
@@ -38,7 +38,7 @@ Persistent, in-place status message for information, success, warnings, and erro
38
38
 
39
39
  ## Card
40
40
  - category: Layout, status: stable
41
- Surface container for related content on a tonal background. Also called a panel or tile; compose it from optional image, header, content, and footer parts.
41
+ Surface container for related content on a tonal background. Also called a panel or tile; compose it from optional image, status, header, content, and footer parts.
42
42
  - props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .card (jq: jq '.card' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
43
43
 
44
44
  ## Checkbox
@@ -96,6 +96,12 @@ Semantic group for related form controls with a shared legend. Also called a for
96
96
  - 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)
97
97
  - further reading (usage/anatomy, not props): https://base-ui.com/react/components/fieldset.md
98
98
 
99
+ ## FrameSelection
100
+ - category: Inputs, status: experimental
101
+ 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".
102
+ - props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .frame-selection (jq: jq '.frame-selection' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
103
+ - further reading (usage/anatomy, not props): https://docs.imfusion.com/
104
+
99
105
  ## Icon
100
106
  - category: Display, status: stable
101
107
  Renders a Web UI icon with an optional semantic foreground color. The default inherits the surrounding currentColor.
@@ -160,7 +166,7 @@ Line that divides content horizontally or vertically. Also called a divider or r
160
166
 
161
167
  ## Slider
162
168
  - category: Inputs, status: stable
163
- Numeric input for choosing one value or a range by dragging a thumb. Also called a range input; use it when relative magnitude matters.
169
+ Numeric input for choosing one value or a range by dragging a thumb. Also called a range input; use it when relative magnitude matters. The position variant is a scrubber for picking one slice or frame.
164
170
  - props: node_modules/@imfusion/web-ui/src/docgen/doc.gen.json -> .slider (jq: jq '.slider' node_modules/@imfusion/web-ui/src/docgen/doc.gen.json)
165
171
  - further reading (usage/anatomy, not props): https://base-ui.com/react/components/slider.md
166
172
 
@@ -11,6 +11,8 @@ description:
11
11
  Start here for UI work and library questions in a project that uses `@imfusion/web-ui`. This skill is a map, not a second
12
12
  copy of every convention.
13
13
 
14
+ Invoke `imf-web-ui-user-profile` first and explain at its levels throughout.
15
+
14
16
  ## 1. Decide whether guidance is needed
15
17
 
16
18
  Skip a companion when the task is explicit and small, an existing local pattern already solves it in the file being changed,
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: imf-web-ui-audit
3
3
  description:
4
- "Audit an existing ImFusion frontend against the @imfusion/web-ui conventions without changing files. Use this for a
5
- project health check, a pre-setup review, or one named topic. Report broken and missing pieces, working deviations,
4
+ "Audit an existing ImFusion frontend against the @imfusion/web-ui conventions without changing project files. Use this for
5
+ a project health check, a pre-setup review, or one named topic. Report broken and missing pieces, working deviations,
6
6
  evidence, and an ordered plan."
7
7
  argument-hint: "[full|<topic>]"
8
- allowed-tools: Read Glob Grep
8
+ allowed-tools: Read Glob Grep Skill
9
9
  ---
10
10
 
11
11
  # Audit a consumer project
@@ -21,6 +21,8 @@ it low, and do not let it crowd the sections a consumer has to act on.
21
21
 
22
22
  ## Workflow
23
23
 
24
+ Invoke `imf-web-ui-user-profile` first and explain at its levels throughout.
25
+
24
26
  1. Resolve the argument. Bare means `full`; an unknown topic is an error, not a reason to widen the scope.
25
27
  2. Enter plan mode unless this audit is being called as verification by another skill or the host has no plan mode.
26
28
  3. Read the report template and existing reviewer notes, then dispatch one investigator per in-scope topic. Tell each
@@ -4,13 +4,15 @@ description:
4
4
  "Look up @imfusion/web-ui component APIs, compound parts, defaults, and icon glyphs without reading source. Use this
5
5
  whenever a consumer task names a Web UI component or icon and you need to choose a prop, part, default, or glyph. Do not
6
6
  use it to choose between components or bootstrap a project."
7
- allowed-tools: Bash
7
+ allowed-tools: Bash Skill
8
8
  ---
9
9
 
10
10
  # Look up components
11
11
 
12
12
  Use the generated package indexes. They are smaller and more reliable than reading the library source.
13
13
 
14
+ Invoke `imf-web-ui-user-profile` first and explain at its levels throughout.
15
+
14
16
  ## Component lookup
15
17
 
16
18
  1. Read the identity index first, even when you already know the component's name: it gives the docgen key and the status.
@@ -50,6 +50,7 @@ sections one to one — change a topic's sections and this file follows in the s
50
50
 
51
51
  - [ ] Types
52
52
  - [ ] Immutability & expressions
53
+ - [ ] Functions
53
54
  - [ ] Naming
54
55
 
55
56
  ## Styling — `styling`
@@ -19,7 +19,8 @@ Use one server-backed current-user query as the identity source:
19
19
 
20
20
  - Put it in `api/auth/queries.ts` and define its key and schema with the [data.md](data.md) pattern.
21
21
  - Expose query options as `context.api.auth.getUser()`.
22
- - Call `ensureQueryData` in a loader or a query hook in a component.
22
+ - Call `queryClient.query({ ...options, staleTime: "static" })` in a loader (see [data.md](data.md)) or a query hook in a
23
+ component.
23
24
  - Keep credentials and access tokens out of React state.
24
25
  - Do not infer authentication from local storage, decoded tokens, route flags, or permission-gated UI.
25
26
 
@@ -85,9 +85,11 @@ export function getDetails(options?: QueryOptions<User>) {
85
85
  }
86
86
  ```
87
87
 
88
- Callers choose `ensureQueryData`, `useSuspenseQuery`, or another Query API. Mutation factories likewise return
89
- `mutationOptions`, own their mutation key and parsing, and are passed to `useMutation`; do not inline those options at the
90
- call site.
88
+ Callers choose `queryClient.query`, `useSuspenseQuery`, or another Query API. A router loader reads the cache with
89
+ `queryClient.query({ ...options, staleTime: "static" })`, not the deprecated `ensureQueryData` or `fetchQuery`. Keep
90
+ `"static"`: without it the factory's `staleTime` applies (default 0), so every loader run waits on the network and the page's
91
+ `useQuery` refetches on mount. Mutation factories likewise return `mutationOptions`, own their mutation key and parsing, and
92
+ are passed to `useMutation`; do not inline those options at the call site.
91
93
 
92
94
  ## Router context access
93
95
 
@@ -30,6 +30,20 @@ input. Use `toSorted` and `toReversed` instead of their mutating counterparts.
30
30
  A loop is fine when it has a real early exit or measured hot-path benefit. A long chain or a `reduce` with several jobs wants
31
31
  named intermediate values.
32
32
 
33
+ ## Functions
34
+
35
+ Declare a named function with `function`, including a local helper inside a component. A callback passed inline as a prop or
36
+ argument stays an arrow.
37
+
38
+ ```tsx
39
+ function resetCaptcha() {
40
+ captcha.current?.reset();
41
+ }
42
+
43
+ <Button onClick={() => setOpen(true)}>Open</Button>;
44
+ items.map(item => item.id);
45
+ ```
46
+
33
47
  ## Naming
34
48
 
35
49
  Name what a value is, not how it is built. Booleans read as assertions (`isOpen`, `hasAccess`, `canSubmit`). Props use `onX`;
@@ -15,6 +15,8 @@ working choices.
15
15
 
16
16
  ## Workflow
17
17
 
18
+ Invoke `imf-web-ui-user-profile` first and explain at its levels throughout.
19
+
18
20
  1. Resolve the scope. A named topic limits the assessment to that topic. A bare invocation means `full`, unless the request
19
21
  is about one topic, in which case that topic is the scope: answer what was asked and offer the wider sweep rather than
20
22
  running it. If the argument is unknown, list the supported topics and point to `imf-web-ui-audit`.
@@ -5,7 +5,7 @@ description:
5
5
  lifecycle hooks. Refresh the base first, verify it, then audit any consumer migration separately. Preserve user work and
6
6
  get approval before each commit."
7
7
  argument-hint: "[--dry-run] [optional version or reason]"
8
- allowed-tools: Bash Read Grep
8
+ allowed-tools: Bash Read Grep Skill
9
9
  ---
10
10
 
11
11
  # Update Web UI
@@ -13,6 +13,22 @@ allowed-tools: Bash Read Grep
13
13
  This workflow has two possible commits: the package/tooling update, then an optional consumer migration. Keep them separate.
14
14
  Never overwrite user changes or commit without fresh approval.
15
15
 
16
+ ## Before you start
17
+
18
+ Invoke `imf-web-ui-user-profile` first and explain at its levels throughout.
19
+
20
+ Open with a short orientation, before any command runs, so the person knows the route and when they will be asked:
21
+
22
+ 1. **Preflight**: check the project and stop on uncommitted work.
23
+ 2. **Base update**: install the new package, refresh the skills and hooks, verify, then ask to commit.
24
+ 3. **Migration check**: read what the new releases changed and report what this project needs; changes and their separate
25
+ commit wait for approval.
26
+ 4. **Full audit**: offer `imf-web-ui-audit full`, a read-only check of the whole project against the conventions, wider than
27
+ what this release changed.
28
+
29
+ Name the decision points up front: `latest` or `dev` when the installed version is a prerelease, the base commit, the
30
+ migration commit, and the audit offer. With `--dry-run`, say the run stops after preflight and changes nothing.
31
+
16
32
  ## Preflight
17
33
 
18
34
  1. Work from the frontend package root. In a monorepo, find the package that owns the Web UI dependency.
@@ -20,9 +36,22 @@ Never overwrite user changes or commit without fresh approval.
20
36
  if another lockfile is the active one.
21
37
  3. Record `git status --short`, the installed Web UI version, the installed skill harness(es), hooks, registrations, and
22
38
  `AGENTS.md` fence.
23
- 4. Check for another npm process and stop on a conflict. Uncommitted work is also a conflict: report it and stop before the
24
- first mutating command, even if it looks unrelated to this workflow: what the update touches is only known once it runs,
25
- and the person can commit, stash, or wave it through in one reply. Never reset, clean, restore, or hide it.
39
+ 4. Check for another npm process in this package and stop on a conflict:
40
+
41
+ ```sh
42
+ pgrep npm # process IDs only
43
+ lsof -a -d cwd -p <pid> -Fn # the folder a process runs in
44
+ ps -o args= -p <pid> # its command, only when that folder is this package
45
+ ```
46
+
47
+ A running install, update, or `ci` in this package is a conflict; a long-running `npm exec` server is not. Full process
48
+ listings such as `pgrep -fl` or `ps aux` print every program's arguments, secrets included, so keep them out of the
49
+ transcript.
50
+
51
+ Uncommitted work is also a conflict: report it and stop before the first mutating command, even if it looks unrelated to
52
+ this workflow: what the update touches is only known once it runs, and the person can commit, stash, or wave it through in
53
+ one reply. Never reset, clean, restore, or hide it.
54
+
26
55
  5. With `--dry-run`, stop after reporting what would happen. Do not install, format, stage, commit, or ask for commit
27
56
  approval.
28
57
 
@@ -87,12 +116,13 @@ Update files : <paths>
87
116
  Held back : <paths or none>
88
117
  Conflicts : <paths or none>
89
118
  Commit : <message or not proposed>
119
+ Next : migration check, then the optional full audit
90
120
  ```
91
121
 
92
122
  Ask: **Approve these update-owned changes and commit them?** Stage only approved update paths and follow the repository's
93
123
  commit workflow.
94
124
 
95
- ## Audit the consumer migration
125
+ ## Check the consumer migration
96
126
 
97
127
  Start this phase only after the base update commit exists. Read `node_modules/@imfusion/web-ui/CHANGELOG.md`: every release
98
128
  section after the pre-update version, up to and including the new one. Each section's highlights, migration guide, and
@@ -119,7 +149,8 @@ releases read, then report separately:
119
149
  Do not infer a replacement from a name. Inspect the implementation, styles, and call sites. If there are no findings, say so
120
150
  and do not make an empty migration commit.
121
151
 
122
- Ask whether to run `imf-web-ui-audit full`. Run it only after an explicit yes.
152
+ Offer `imf-web-ui-audit full` as the next step: the migration check covered what the releases changed, the audit checks the
153
+ whole project against the conventions and changes nothing. Run it only after an explicit yes.
123
154
 
124
155
  For approved migration work, ask: **Approve these consumer migration changes and commit them separately?** Then stage only
125
156
  the approved paths, verify again, and use a separate imperative commit message.