@maltjoy/mcp-server 0.4.0 → 0.6.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -3
  3. package/dist/doc/VJoyAdminBanner/guideline.md +284 -0
  4. package/dist/doc/VJoyAvailability/guideline.md +352 -0
  5. package/dist/doc/VJoyAvatar/guideline.md +192 -0
  6. package/dist/doc/VJoyAvatarsList/guideline.md +328 -0
  7. package/dist/doc/VJoyBadge/guideline.md +169 -0
  8. package/dist/doc/VJoyBadgeLevel/guideline.md +166 -0
  9. package/dist/doc/VJoyBlockSkeleton/guideline.md +150 -0
  10. package/dist/doc/VJoyBottomSheet/guideline.md +345 -0
  11. package/dist/doc/VJoyBottomSheetTrigger/guideline.md +156 -0
  12. package/dist/doc/VJoyButton/guideline.md +371 -0
  13. package/dist/doc/VJoyButton/metadata.json +0 -16
  14. package/dist/doc/VJoyButtonCard/guideline.md +384 -0
  15. package/dist/doc/VJoyCheckbox/guideline.md +317 -0
  16. package/dist/doc/VJoyCheckboxCard/guideline.md +381 -0
  17. package/dist/doc/VJoyCheckboxGroup/guideline.md +363 -0
  18. package/dist/doc/VJoyCheckboxGroup/metadata.json +7 -7
  19. package/dist/doc/VJoyCollapse/guideline.md +362 -0
  20. package/dist/doc/VJoyCollapseItem/guideline.md +394 -0
  21. package/dist/doc/VJoyCompanyAvatar/guideline.md +162 -0
  22. package/dist/doc/VJoyDialog/guideline.md +425 -0
  23. package/dist/doc/VJoyDialogTrigger/guideline.md +186 -0
  24. package/dist/doc/VJoyDot/guideline.md +177 -0
  25. package/dist/doc/VJoyDrawer/guideline.md +392 -0
  26. package/dist/doc/VJoyDrawerTrigger/guideline.md +145 -0
  27. package/dist/doc/VJoyDropdown/guideline.md +393 -0
  28. package/dist/doc/VJoyDropdown/metadata.json +6 -6
  29. package/dist/doc/VJoyDropdownList/guideline.md +396 -0
  30. package/dist/doc/VJoyDropdownList/metadata.json +7 -7
  31. package/dist/doc/VJoyDropzone/guideline.md +390 -0
  32. package/dist/doc/VJoyDropzone/metadata.json +36 -1
  33. package/dist/doc/VJoyFilterBar/guideline.md +419 -0
  34. package/dist/doc/VJoyFilterBarButton/guideline.md +359 -0
  35. package/dist/doc/VJoyFloatingActionsBar/guideline.md +372 -0
  36. package/dist/doc/VJoyFormError/guideline.md +325 -0
  37. package/dist/doc/VJoyFormError/metadata.json +0 -14
  38. package/dist/doc/VJoyFormFieldSkeleton/guideline.md +159 -0
  39. package/dist/doc/VJoyFormGroup/guideline.md +285 -0
  40. package/dist/doc/VJoyFunnel/guideline.md +349 -0
  41. package/dist/doc/VJoyFunnelFooter/guideline.md +178 -0
  42. package/dist/doc/VJoyFunnelHeader/guideline.md +204 -0
  43. package/dist/doc/VJoyHighlight/guideline.md +169 -0
  44. package/dist/doc/VJoyIcon/JoyIcon.types.ts +1 -1
  45. package/dist/doc/VJoyIcon/guideline.md +168 -0
  46. package/dist/doc/VJoyIcon/metadata.json +0 -1
  47. package/dist/doc/VJoyIconButton/guideline.md +169 -0
  48. package/dist/doc/VJoyIconButton/metadata.json +1 -1
  49. package/dist/doc/VJoyIndicator/guideline.md +168 -0
  50. package/dist/doc/VJoyIndicators/guideline.md +183 -0
  51. package/dist/doc/VJoyInput/JoyInput.types.ts +1 -6
  52. package/dist/doc/VJoyInput/guideline.md +401 -0
  53. package/dist/doc/VJoyInput/metadata.json +5 -14
  54. package/dist/doc/VJoyInputDigit/guideline.md +381 -0
  55. package/dist/doc/VJoyInputNumber/guideline.md +414 -0
  56. package/dist/doc/VJoyInputNumber/metadata.json +22 -17
  57. package/dist/doc/VJoyInputPassword/guideline.md +379 -0
  58. package/dist/doc/VJoyInputPassword/metadata.json +0 -14
  59. package/dist/doc/VJoyLabel/guideline.md +200 -0
  60. package/dist/doc/VJoyLink/guideline.md +360 -0
  61. package/dist/doc/VJoyListItem/guideline.md +335 -0
  62. package/dist/doc/VJoyMenu/guideline.md +304 -0
  63. package/dist/doc/VJoyMenu/metadata.json +21 -21
  64. package/dist/doc/VJoyMenuItem/guideline.md +352 -0
  65. package/dist/doc/VJoyPagination/guideline.md +355 -0
  66. package/dist/doc/VJoyPanel/guideline.md +238 -0
  67. package/dist/doc/VJoyPanelSection/guideline.md +160 -0
  68. package/dist/doc/VJoyPasswordRequirement/guideline.md +336 -0
  69. package/dist/doc/VJoyPasswordRequirement/metadata.json +1 -1
  70. package/dist/doc/VJoyProductTour/JoyProductTour.types.ts +0 -1
  71. package/dist/doc/VJoyProductTour/guideline.md +455 -0
  72. package/dist/doc/VJoyProductTour/metadata.json +1 -1
  73. package/dist/doc/VJoyProductTourTrigger/guideline.md +167 -0
  74. package/dist/doc/VJoyProgressBar/guideline.md +348 -0
  75. package/dist/doc/VJoyRadio/guideline.md +346 -0
  76. package/dist/doc/VJoyRadioGroup/guideline.md +331 -0
  77. package/dist/doc/VJoyRatingStars/guideline.md +306 -0
  78. package/dist/doc/VJoyScreenLoader/guideline.md +172 -0
  79. package/dist/doc/VJoySelect/guideline.md +396 -0
  80. package/dist/doc/VJoySelectableItem/guideline.md +351 -0
  81. package/dist/doc/VJoySelectableItemGroup/guideline.md +370 -0
  82. package/dist/doc/VJoySeparator/guideline.md +161 -0
  83. package/dist/doc/VJoySnackbar/guideline.md +402 -0
  84. package/dist/doc/VJoySpinner/guideline.md +168 -0
  85. package/dist/doc/VJoyStep/guideline.md +182 -0
  86. package/dist/doc/VJoyStepper/guideline.md +390 -0
  87. package/dist/doc/VJoyTab/guideline.md +298 -0
  88. package/dist/doc/VJoyTabs/guideline.md +353 -0
  89. package/dist/doc/VJoyTag/guideline.md +226 -0
  90. package/dist/doc/VJoyTagsInput/guideline.md +387 -0
  91. package/dist/doc/VJoyTagsList/guideline.md +311 -0
  92. package/dist/doc/VJoyTagsList/metadata.json +27 -27
  93. package/dist/doc/VJoyTemplate/guideline.md +366 -0
  94. package/dist/doc/VJoyText/guideline.md +175 -0
  95. package/dist/doc/VJoyText/metadata.json +1 -1
  96. package/dist/doc/VJoyTextarea/guideline.md +378 -0
  97. package/dist/doc/VJoyTitleBrand/guideline.md +155 -0
  98. package/dist/doc/VJoyToggle/guideline.md +327 -0
  99. package/dist/doc/VJoyTooltip/guideline.md +322 -0
  100. package/dist/doc/VJoyUserCard/guideline.md +268 -0
  101. package/dist/doc/VJoyUserCard/metadata.json +3 -17
  102. package/dist/doc/VJoyWalkthrough/guideline.md +351 -0
  103. package/dist/doc/VJoyWalkthroughTrigger/guideline.md +171 -0
  104. package/dist/doc/VJoyWrapper/guideline.md +173 -0
  105. package/dist/doc/css-classes.json +1 -15
  106. package/dist/doc/design-tokens.json +1 -0
  107. package/dist/doc/index.json +20 -30
  108. package/dist/index.js +22 -2
  109. package/dist/index.js.map +1 -1
  110. package/dist/tools/get-component-guideline.d.ts +30 -0
  111. package/dist/tools/get-component-guideline.d.ts.map +1 -0
  112. package/dist/tools/get-component-guideline.js +51 -0
  113. package/dist/tools/get-component-guideline.js.map +1 -0
  114. package/dist/tools/get-documentation-page.d.ts +22 -0
  115. package/dist/tools/get-documentation-page.d.ts.map +1 -0
  116. package/dist/tools/get-documentation-page.js +21 -0
  117. package/dist/tools/get-documentation-page.js.map +1 -0
  118. package/dist/tools/list-documentation-pages.d.ts +22 -0
  119. package/dist/tools/list-documentation-pages.d.ts.map +1 -0
  120. package/dist/tools/list-documentation-pages.js +17 -0
  121. package/dist/tools/list-documentation-pages.js.map +1 -0
  122. package/dist/tools/search-documentation.d.ts +41 -0
  123. package/dist/tools/search-documentation.d.ts.map +1 -0
  124. package/dist/tools/search-documentation.js +25 -0
  125. package/dist/tools/search-documentation.js.map +1 -0
  126. package/dist/zeroheight-parser.d.ts +27 -0
  127. package/dist/zeroheight-parser.d.ts.map +1 -0
  128. package/dist/zeroheight-parser.js +77 -0
  129. package/dist/zeroheight-parser.js.map +1 -0
  130. package/package.json +10 -10
  131. package/dist/doc/VJoyMultiCheckbox/metadata.json +0 -332
@@ -0,0 +1,304 @@
1
+ ---
2
+ component: VJoyMenu
3
+ status: draft
4
+ language: en
5
+ dsds: JoyMenu.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # Menu
10
+
11
+ Use **`VJoyMenu`** when the user needs a **persistent vertical list of navigation destinations** — typically the sidebar in an app shell built with `VJoyTemplate`.
12
+
13
+ Compose it with **`VJoyMenuItem`** children for links, buttons, or router-aware navigation. Each item can show a leading icon, a trailing status icon, a current-page state, and disabled styling. Keyboard navigation (arrow keys, Home/End, Enter) is built in.
14
+
15
+ | | |
16
+ | --- | --- |
17
+ | **Code** | `VJoyMenu` + `VJoyMenuItem` from `@maltjoy/core-vue` |
18
+ | **Design** | [ZeroHeight — Menu](https://zeroheight.com/6bf479565/p/955426-menu) |
19
+ | **Storybook** | [VJoyMenu docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-navigation-vjoymenu--docs) |
20
+ | **DSDS (machine)** | [`JoyMenu.dsds.json`](./JoyMenu.dsds.json) |
21
+ | **Live API** | `joy_get_component_info("VJoyMenu")` · `joy_get_component_info("VJoyMenuItem")` |
22
+
23
+ ---
24
+
25
+ ## When to use this component
26
+
27
+ Use a menu when users move between **sections or routes** from a fixed sidebar — for example app settings areas, account navigation, or funnel step lists inside `VJoyTemplate`.
28
+
29
+ `VJoyMenuItem` supports plain anchors (`href`), buttons (`type="button"`), and framework links (`RouterLink` / `NuxtLink` via `type` + `linkProps`). Mark the active destination with `current`.
30
+
31
+ ### When not to use this component
32
+
33
+ | Need | Use instead |
34
+ | --- | --- |
35
+ | A contextual panel that opens from a trigger (overflow, filters) | `VJoyDropdown` |
36
+ | Switching peer content panels on the same page | `VJoyTabs` |
37
+ | Choosing one value inside a labeled form field | `VJoySelect` |
38
+ | Short hover-only hints | `VJoyTooltip` |
39
+ | Main content layout chrome | `VJoyPanel` (not as a wrapper around the menu) |
40
+ | Custom `<ul>` / sidebar markup with ad-hoc CSS | Still use `VJoyMenu` + `VJoyMenuItem` + Joy tokens |
41
+
42
+ > **Deprecated:** do not use the `items` prop on `VJoyMenu` for new work. Prefer `VJoyMenuItem` in the default slot. The `menu-item` slot only applies to the deprecated `items` API.
43
+
44
+ ---
45
+
46
+ ## How it works
47
+
48
+ `VJoyMenu` renders a bordered `<ul role="menu">`. Each `VJoyMenuItem` renders a `<li role="menuitem">` with an inner interactive element (`<a>`, `<button>`, or a custom link component).
49
+
50
+ ### Anatomy
51
+
52
+ | Part | Required? | What it is |
53
+ | --- | --- | --- |
54
+ | Menu list (`VJoyMenu`) | Yes | Root `<ul>` with border, radius, and keyboard handling |
55
+ | `aria-label` | Yes* | Accessible name for the menu (`ariaLabel` prop) — required when no visible heading labels the list |
56
+ | `VJoyMenuItem` (default slot) | Yes (preferred) | One row per destination |
57
+ | Leading icon | No | `icon` on `VJoyMenuItem` |
58
+ | Label | Yes | Primary text on each item (`label` prop) |
59
+ | Status icon | No | Trailing `status` + optional `statusColor` (check, warning, lock, …) |
60
+ | Current indicator | No | `current` highlights the active destination (`aria-current`) |
61
+ | `menu-item` slot | No | Custom inner content per row — **only** for deprecated `items` prop |
62
+
63
+ ### Default values
64
+
65
+ - `items` defaults to **`[]`** (deprecated — prefer slot composition)
66
+ - `VJoyMenuItem` `type` defaults to **`"a"`** (anchor)
67
+ - `disabled` defaults to **`false`**
68
+ - `current` defaults to **`false`**
69
+
70
+ Props, events, and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
71
+
72
+ ### Visual treatment
73
+
74
+ There is **no `variant` or `size` prop**. Item height, padding, colors, and border radius come from Joy tokens inside the component (e.g. `--joy-form-field-height-medium`, `--joy-core-radius-3`) — **don’t hardcode menu item heights or border colors** in product CSS.
75
+
76
+ The list uses `--menu-item-min-width: 120px` internally. Long labels truncate with ellipsis; the full label is available via the native `title` attribute.
77
+
78
+ ### App shell placement
79
+
80
+ In Malt apps, `VJoyMenu` belongs in **`VJoyTemplate`’s `#template-sidebar` slot** (enforced by the `require-vjoymenu-template-sidebar` ESLint rule). Do **not** nest `VJoyMenu` inside `VJoyPanel` (`no-vjoymenu-vjoypanel` rule) — the menu and panel serve different layout roles.
81
+
82
+ ---
83
+
84
+ ## States
85
+
86
+ | State | What the user sees / can do |
87
+ | --- | --- |
88
+ | Default | Neutral text; row is interactive |
89
+ | Hover | Secondary background highlight (pointer devices) |
90
+ | Focus | Inset focus ring on the inner control; current row also uses secondary background |
91
+ | Current (`current`) | Secondary background and text color — marks the active page/section |
92
+ | Disabled | Muted text, disabled background, `cursor: not-allowed`; not clickable |
93
+ | Keyboard active (deprecated `items` mode) | `aria-activedescendant` tracks the focused row while arrowing |
94
+ | Link item | Default `type="a"` or router link navigates on click / Enter |
95
+ | Button item | `type="button"` fires `@click` on `VJoyMenuItem` without navigation |
96
+
97
+ When a disabled item is visible, **explain why** nearby (tooltip or helper text) if the reason is not obvious from context.
98
+
99
+ ---
100
+
101
+ ## Best practices
102
+
103
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
104
+
105
+ ### Placement and hierarchy
106
+
107
+ - **MUST** place `VJoyMenu` inside `VJoyTemplate` `#template-sidebar` in app-shell layouts.
108
+ - **MUST NOT** nest `VJoyMenu` inside `VJoyPanel`.
109
+ - **SHOULD** mark exactly one item `current` for the active route or section (when applicable).
110
+ - **SHOULD** keep the menu list focused on navigation — avoid embedding heavy forms or multi-step panels inside menu rows.
111
+
112
+ ### Composition
113
+
114
+ - **MUST** use `VJoyMenuItem` children for new work — not the deprecated `items` prop.
115
+ - **MUST** set `aria-label` on `VJoyMenu` when the sidebar has no visible heading that names the list.
116
+ - **SHOULD** use `type="button"` only when the row triggers an in-page action without navigation.
117
+ - **SHOULD** use `RouterLink` / `NuxtLink` (`type` + `linkProps`) for SPA navigation instead of full page reloads.
118
+ - **SHOULD** use `status` icons sparingly — completion, warning, or lock states users must notice at a glance.
119
+
120
+ ### Implementation
121
+
122
+ - **MUST** use only documented prop values (MCP / `JoyMenu.types.ts` / `VJoyMenuItem` props).
123
+ - **MUST** style with Joy tokens — no custom `.joy-menu-list` or `.joy-menu-item` chrome overrides.
124
+ - **MUST NOT** invent props (`variant`, `size`, `open`, …).
125
+ - **MUST NOT** use `VJoyMenu` for transient overlay menus — use `VJoyDropdown`.
126
+
127
+ ### Do / don’t
128
+
129
+ | Do | Don’t |
130
+ | --- | --- |
131
+ | `VJoyMenu` + `VJoyMenuItem` in `#template-sidebar` | `items` prop for new screens |
132
+ | `current` on the active route | Multiple `current` items for one section |
133
+ | `RouterLink` / `NuxtLink` for in-app nav | Raw `<a href>` that reloads the SPA unnecessarily |
134
+ | `aria-label` when no visible list title | Unnamed menu for screen-reader users |
135
+ | `status` for lock / warning / done | Decorative status icons on every row |
136
+
137
+ ---
138
+
139
+ ## Content
140
+
141
+ Menu items are navigation labels. They should be scannable at a glance and parallel in grammar.
142
+
143
+ ### Label formula
144
+
145
+ **Navigation items:** **short noun or noun phrase** naming the destination — e.g. `Dashboard`, `Billing`, `Team members`.
146
+
147
+ **Action rows (`type="button"`):** **infinitive verb + noun** when the row triggers an action — e.g. `Sign out`, `Create project`.
148
+
149
+ **Status context:** rely on the `status` icon + `statusColor` for lock/warning/done; don’t repeat the same meaning in the label unless needed for clarity.
150
+
151
+ ### Writing rules
152
+
153
+ | Strength | Rule |
154
+ | --- | --- |
155
+ | **MUST** | Each `label` is unique within the menu |
156
+ | **MUST** | Labels stay concise — long text truncates with ellipsis (`title` shows the full string) |
157
+ | **MUST** | Disabled items include context elsewhere if the reason isn’t obvious |
158
+ | **MUST NOT** | Vague labels — ❌ `Click here`, ❌ `Menu item` |
159
+ | **MUST NOT** | Duplicate the section heading on every row when the group context is clear |
160
+ | **SHOULD** | ≤ 3 words per label where possible |
161
+ | **SHOULD** | Sentence case for multi-word labels |
162
+ | **SHOULD** | Parallel grammar across siblings (`Overview`, `Settings`, `Billing` — not mixed verb/noun styles) |
163
+ | **SHOULD** | Localize labels — menu copy is user-facing product UI |
164
+
165
+ ### Patterns
166
+
167
+ **App sidebar** — Group related destinations under `VJoyTemplate` sidebar chrome (headings outside the menu if needed). One `current` item matching the active route.
168
+
169
+ **Funnel / step list** — Each row is a step name (`Company details`, `Payment`). Use `status="check-circle"` + `statusColor="success"` for completed steps, `status="lock"` for locked future steps.
170
+
171
+ **Mixed link + action** — Navigation rows use default `type="a"` or router links; a final `Sign out` row uses `type="button"`.
172
+
173
+ ---
174
+
175
+ ## Accessibility
176
+
177
+ Behaviors (what must happen), not slogans.
178
+
179
+ | Behavior | Expectation |
180
+ | --- | --- |
181
+ | Menu role | `role="menu"` on the `<ul>`; each row `role="menuitem"` |
182
+ | Name | `aria-label` on `VJoyMenu` when no visible heading names the list |
183
+ | Current page | `aria-current` on the item with `current` |
184
+ | Disabled | `aria-disabled="true"`; not activatable |
185
+ | Row name | `aria-label` and `title` from each item’s `label` |
186
+ | Keyboard (list focus) | **ArrowDown** / **ArrowUp** move between enabled items; **Home** / **End** jump to first/last; **Enter** activates the focused row (clicks inner link/button); **Tab** clears active descendant tracking |
187
+ | Space | Prevented from scrolling when an item is focused (deprecated `items` keyboard path) |
188
+ | Focus ring | Visible inset ring on focused items — don’t remove in product CSS |
189
+ | Icons | Leading/trailing icons are decorative when the label conveys meaning (Joy default) |
190
+
191
+ Target: **WCAG 2.2 AA** where the product requires it.
192
+
193
+ ---
194
+
195
+ ## Examples
196
+
197
+ ```vue
198
+ <script setup lang="ts">
199
+ import { VJoyMenu, VJoyMenuItem } from '@maltjoy/core-vue'
200
+ import { NuxtLink } from '#components'
201
+ </script>
202
+
203
+ <template>
204
+ <!-- Preferred: VJoyMenuItem composition inside app shell -->
205
+ <VJoyTemplate>
206
+ <template #template-sidebar>
207
+ <VJoyMenu aria-label="Account navigation">
208
+ <VJoyMenuItem icon="user" label="Profile" href="/account/profile" />
209
+ <VJoyMenuItem icon="billing" label="Billing" href="/account/billing" current />
210
+ <VJoyMenuItem
211
+ icon="team"
212
+ label="Team members"
213
+ :type="NuxtLink"
214
+ :link-props="{ to: '/account/team' }"
215
+ />
216
+ <VJoyMenuItem
217
+ label="Security"
218
+ status="warning"
219
+ status-color="warning"
220
+ href="/account/security"
221
+ />
222
+ <VJoyMenuItem label="Archived" disabled icon="company-placeholder" status="lock" />
223
+ <VJoyMenuItem type="button" label="Sign out" @click="/* handle sign out */" />
224
+ </VJoyMenu>
225
+ </template>
226
+
227
+ <template #template-main>
228
+ <!-- page content -->
229
+ </template>
230
+ </VJoyTemplate>
231
+ </template>
232
+ ```
233
+
234
+ In Nuxt (or apps with auto-import), omit the import if `VJoyMenu` / `VJoyMenuItem` are already global. For Vue Router, pass `RouterLink` as `type` with `link-props="{ to: '...' }"` the same way as `NuxtLink` in Storybook.
235
+
236
+ ---
237
+
238
+ ## Related
239
+
240
+ | Component | Use when |
241
+ | --- | --- |
242
+ | `VJoyMenuItem` | Each row inside `VJoyMenu` (required for new work) |
243
+ | `VJoyTemplate` | App shell with `#template-sidebar` slot for the menu |
244
+ | `VJoyDropdown` | Contextual menus opened from a trigger |
245
+ | `VJoyTabs` | Peer content panels on one page |
246
+ | `VJoyPanel` | Main or sidebar content blocks — not as a parent of `VJoyMenu` |
247
+ | `VJoyIcon` | Icons on menu items (`icon`, `status`) |
248
+
249
+ ---
250
+
251
+ ## For agents
252
+
253
+ Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyMenu.dsds.json`](./JoyMenu.dsds.json).
254
+
255
+ ### Pick the right component
256
+
257
+ | If the intent is… | Emit… | Do not emit… |
258
+ | --- | --- | --- |
259
+ | Persistent sidebar / app navigation | `VJoyMenu` + `VJoyMenuItem` | `VJoyDropdown` |
260
+ | Overflow menu from a button | `VJoyDropdown` | `VJoyMenu` |
261
+ | Tab panels on one page | `VJoyTabs` | `VJoyMenu` for section switching |
262
+ | Form single-select | `VJoySelect` | `VJoyMenu` |
263
+ | SPA route link | `VJoyMenuItem` + `RouterLink`/`NuxtLink` | Raw `<li><a>` lists |
264
+
265
+ ### Hard rules
266
+
267
+ 1. **MUST** call `joy_get_component_info("VJoyMenu")` and `joy_get_component_info("VJoyMenuItem")` before generating props.
268
+ 2. **MUST** compose menus with `VJoyMenuItem` in the default slot — not the deprecated `items` prop.
269
+ 3. **MUST** set `aria-label` on `VJoyMenu` when no visible heading names the list.
270
+ 4. **MUST** place `VJoyMenu` in `VJoyTemplate` `#template-sidebar` for app-shell layouts.
271
+ 5. **MUST NOT** nest `VJoyMenu` inside `VJoyPanel`.
272
+ 6. **MUST NOT** invent props (`variant`, `size`, `open`, …) or override `.joy-menu-list` / `.joy-menu-item` chrome.
273
+ 7. **SHOULD** set `current` on the item matching the active route.
274
+ 8. **SHOULD** use `type="button"` only for non-navigation actions (e.g. sign out).
275
+
276
+ ### Checklist
277
+
278
+ - [ ] Correct component (`VJoyMenu` + `VJoyMenuItem`, or named alternative)
279
+ - [ ] Props from MCP / types only — no `items` prop on new code
280
+ - [ ] `aria-label` on the menu when needed
281
+ - [ ] `#template-sidebar` placement in `VJoyTemplate` layouts
282
+ - [ ] Not nested inside `VJoyPanel`
283
+ - [ ] At most one `current` item per logical section
284
+ - [ ] Router links use `type` + `linkProps`, not bare `href` reloads in SPAs
285
+ - [ ] No invented props / no custom menu chrome CSS
286
+
287
+ ---
288
+
289
+ ## DSDS mapping
290
+
291
+ This Markdown mirrors [`JoyMenu.dsds.json`](./JoyMenu.dsds.json) (DSDS **0.15.2**).
292
+
293
+ | Section here | DSDS block |
294
+ | --- | --- |
295
+ | When to use / not | `use-cases` |
296
+ | Anatomy | `anatomy` |
297
+ | Visual treatment (no variants/sizes) | `design-specifications` |
298
+ | States | `states` |
299
+ | Best practices / content rules | `guidelines` (+ `content`) |
300
+ | Accessibility | `accessibility` |
301
+ | Examples | `sections` |
302
+ | For agents | `agentDocumentBlocks` |
303
+ | Props detail | `api` in JSON + Joy MCP |
304
+ | Imports | `imports` in JSON |
@@ -27,7 +27,7 @@
27
27
  "type": "string | undefined",
28
28
  "declarations": [
29
29
  {
30
- "file": "/home/kevincarnaille/dev/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
30
+ "file": "/Users/pierrereynaud/Documents/Work/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
31
31
  "range": [
32
32
  80,
33
33
  92
@@ -52,7 +52,7 @@
52
52
  "type": "string",
53
53
  "declarations": [
54
54
  {
55
- "file": "/home/kevincarnaille/dev/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
55
+ "file": "/Users/pierrereynaud/Documents/Work/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
56
56
  "range": [
57
57
  97,
58
58
  111
@@ -70,7 +70,7 @@
70
70
  "type": "string | undefined",
71
71
  "declarations": [
72
72
  {
73
- "file": "/home/kevincarnaille/dev/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
73
+ "file": "/Users/pierrereynaud/Documents/Work/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
74
74
  "range": [
75
75
  116,
76
76
  130
@@ -88,7 +88,7 @@
88
88
  "type": "JoyIconsId | undefined",
89
89
  "declarations": [
90
90
  {
91
- "file": "/home/kevincarnaille/dev/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
91
+ "file": "/Users/pierrereynaud/Documents/Work/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
92
92
  "range": [
93
93
  135,
94
94
  153
@@ -123,16 +123,16 @@
123
123
  "\"arrow-right\"",
124
124
  "\"art\"",
125
125
  "\"axa-logo\"",
126
- "\"badge-recommended-hover\"",
127
- "\"badge-recommended\"",
128
126
  "\"ban\"",
129
127
  "\"bank\"",
130
128
  "\"bars\"",
131
129
  "\"bell\"",
130
+ "\"bike\"",
132
131
  "\"block-shield\"",
133
132
  "\"bricks\"",
134
- "\"briefcase-hover\"",
135
133
  "\"briefcase\"",
134
+ "\"building-column\"",
135
+ "\"business-suitcase\"",
136
136
  "\"calendar\"",
137
137
  "\"camcorder\"",
138
138
  "\"camera-device\"",
@@ -159,12 +159,13 @@
159
159
  "\"clock\"",
160
160
  "\"cloud-upload\"",
161
161
  "\"code\"",
162
+ "\"colaborator-add\"",
162
163
  "\"communication\"",
163
164
  "\"company-placeholder\"",
165
+ "\"computer\"",
164
166
  "\"conditions\"",
165
167
  "\"conference\"",
166
168
  "\"contact\"",
167
- "\"cookie\"",
168
169
  "\"cost-plus\"",
169
170
  "\"creditcard\"",
170
171
  "\"cross\"",
@@ -184,17 +185,19 @@
184
185
  "\"eye\"",
185
186
  "\"facebook\"",
186
187
  "\"favorite-add\"",
188
+ "\"favotite-add\"",
187
189
  "\"fee\"",
188
190
  "\"file-check\"",
189
191
  "\"file-pdf\"",
190
192
  "\"file\"",
191
193
  "\"five-day\"",
192
194
  "\"flag\"",
195
+ "\"folder-arrow-down\"",
196
+ "\"folder-text\"",
193
197
  "\"freelancer-placeholder\"",
194
198
  "\"fullscren\"",
199
+ "\"furniture\"",
195
200
  "\"gasoline\"",
196
- "\"globe-hover\"",
197
- "\"globe\"",
198
201
  "\"google\"",
199
202
  "\"granular-report\"",
200
203
  "\"graph-high\"",
@@ -211,7 +214,6 @@
211
214
  "\"home\"",
212
215
  "\"ico-list\"",
213
216
  "\"identity-switch\"",
214
- "\"image\"",
215
217
  "\"info-circle\"",
216
218
  "\"instagram\"",
217
219
  "\"insurance\"",
@@ -220,7 +222,6 @@
220
222
  "\"legal-check\"",
221
223
  "\"legal\"",
222
224
  "\"linkedin\"",
223
- "\"list-file\"",
224
225
  "\"list\"",
225
226
  "\"location\"",
226
227
  "\"lock\"",
@@ -236,18 +237,16 @@
236
237
  "\"money\"",
237
238
  "\"mood-bad\"",
238
239
  "\"mood-good\"",
239
- "\"newspaper\"",
240
+ "\"moped\"",
241
+ "\"motorcycle\"",
240
242
  "\"open-conversation\"",
241
243
  "\"paperclip\"",
242
244
  "\"pen\"",
243
245
  "\"pencil\"",
244
246
  "\"phone\"",
245
- "\"plane-full\"",
246
247
  "\"plus-circle\"",
247
248
  "\"pound-circle\"",
248
249
  "\"print\"",
249
- "\"profile-picture-hover\"",
250
- "\"profile-picture\"",
251
250
  "\"projectmanager-agile\"",
252
251
  "\"qr-code\"",
253
252
  "\"question-circle\"",
@@ -273,15 +272,13 @@
273
272
  "\"sort-asc\"",
274
273
  "\"sort-desc\"",
275
274
  "\"sparkle\"",
276
- "\"sparkles\"",
277
275
  "\"star-fill\"",
278
276
  "\"star-half\"",
279
- "\"star-message\"",
280
277
  "\"star\"",
281
- "\"super-malter\"",
282
278
  "\"swipe\"",
283
279
  "\"switch\"",
284
280
  "\"sync-reset\"",
281
+ "\"sync\"",
285
282
  "\"tab-inverted\"",
286
283
  "\"tab\"",
287
284
  "\"taxi\"",
@@ -301,6 +298,9 @@
301
298
  "\"user-lighter\"",
302
299
  "\"user-remove\"",
303
300
  "\"user\"",
301
+ "\"users-add\"",
302
+ "\"users-check\"",
303
+ "\"users-remove\"",
304
304
  "\"users\"",
305
305
  "\"video-camera\"",
306
306
  "\"videogame\"",
@@ -332,7 +332,7 @@
332
332
  "type": "boolean | undefined",
333
333
  "declarations": [
334
334
  {
335
- "file": "/home/kevincarnaille/dev/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
335
+ "file": "/Users/pierrereynaud/Documents/Work/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
336
336
  "range": [
337
337
  158,
338
338
  176
@@ -363,7 +363,7 @@
363
363
  "type": "boolean | undefined",
364
364
  "declarations": [
365
365
  {
366
- "file": "/home/kevincarnaille/dev/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
366
+ "file": "/Users/pierrereynaud/Documents/Work/design-system/packages/core-vue/src/components/JoyMenu/JoyMenu.types.ts",
367
367
  "range": [
368
368
  219,
369
369
  238