@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,351 @@
1
+ ---
2
+ component: VJoySelectableItem
3
+ status: deprecated
4
+ language: en
5
+ dsds: JoySelectableItem.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # Selectable item
10
+
11
+ Use **`VJoySelectableItem`** when a choice should look like a **selectable tile** — a bordered card the user clicks to select or deselect — rather than a classic radio circle or checkbox row.
12
+
13
+ In single-selection mode it behaves like a radio (one value per `name` group). In multi-selection mode it embeds `VJoyCheckbox` inside the tile. In product code, compose items almost always through **`VJoySelectableItemGroup`**; use the item alone only when you own grouping, legend, and validation yourself.
14
+
15
+ > **Deprecated:** `VJoySelectableItem` and `VJoySelectableItemGroup` are deprecated. For new work, prefer `VJoyRadio` / `VJoyRadioGroup` (single choice), `VJoyCheckboxCard` (card-style booleans / multi-select), or `VJoyButtonCard` (navigation or action, not value selection). Keep this component only for maintaining existing flows until migration.
16
+
17
+ | | |
18
+ | --- | --- |
19
+ | **Code** | `VJoySelectableItem` from `@maltjoy/core-vue` |
20
+ | **Design** | [ZeroHeight — Selectable item](https://zeroheight.com/6bf479565/p/24f9a1-selectable-item) |
21
+ | **Storybook** | [VJoySelectableItemGroup docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-forms-vjoyselectableitemgroup--docs) (`VJoySelectableItem` is a subcomponent) |
22
+ | **DSDS (machine)** | [`JoySelectableItem.dsds.json`](./JoySelectableItem.dsds.json) |
23
+ | **Live API** | `joy_get_component_info("VJoySelectableItem")` (when indexed) — until then, read `VJoySelectableItem.vue` and `VJoySelectableItem.types.ts` |
24
+
25
+ ---
26
+
27
+ ## When to use this component
28
+
29
+ Use a selectable item when options should read as **peer tiles** in a horizontal or wrapped row — for example picking a plan cadence, a delivery speed, or a small set of filters where each option has a short label and optional sublabel.
30
+
31
+ Tiles work best with **2–5** options visible at once. Pair them inside `VJoySelectableItemGroup` so the fieldset, group label, `v-model:value`, and `invalid` / `errorMessage` are handled consistently.
32
+
33
+ ### When not to use this component
34
+
35
+ | Need | Use instead |
36
+ | --- | --- |
37
+ | New feature work (any card picker) | `VJoyRadio` + `outline`, `VJoyCheckboxCard`, or `VJoyButtonCard` per interaction type |
38
+ | Exactly one choice, compact list (no tile chrome) | `VJoyRadio` inside `VJoyRadioGroup` |
39
+ | Multiple independent checkboxes in a list | `VJoyCheckbox` / `VJoyCheckboxGroup` or `VJoyCheckboxCard` |
40
+ | Long or searchable option lists | `VJoySelect` |
41
+ | Card that navigates or runs an action | `VJoyButtonCard` |
42
+ | Custom clickable `<div>` tiles | Still use a Joy selection component + tokens — don’t reinvent tile chrome |
43
+
44
+ > **Removed from the API:** the `ai` visual variant existed in older releases and has been removed. Do not emit `variant="ai"` or custom AI tile styling on this component.
45
+
46
+ ---
47
+
48
+ ## How it works
49
+
50
+ ### Anatomy
51
+
52
+ | Part | Required? | What it is |
53
+ | --- | --- | --- |
54
+ | Wrapper | Yes | `.joy-selectable-item__wrapper` — click target and focus orchestration |
55
+ | Native control | Yes* | Hidden `<input type="radio">` when `multiple` is false; `VJoyCheckbox` when `multiple` is true |
56
+ | Tile surface | Yes | `.joy-selectable-item` — bordered, centered label area |
57
+ | Primary label | Yes | Default slot (single mode) or checkbox label slot (multiple mode) |
58
+ | Sublabel | No | `selectable-item-sublabel` slot or `subLabel` prop — stays normal weight when selected |
59
+ | Focus ring | Yes | Outline on the tile when the native control is focused — don’t remove it in product CSS |
60
+
61
+ ### Selection modes
62
+
63
+ Controlled by the `multiple` prop (usually set by `VJoySelectableItemGroup`).
64
+
65
+ | Mode | `multiple` | Control | Model on `@update:checked` |
66
+ | --- | --- | --- | --- |
67
+ | Single | `false` (default) | Hidden radio + `<label for="…">` | Emits the option `value` when selected; emits empty string when the user clicks the already-selected tile (deselect) |
68
+ | Multiple | `true` | `VJoyCheckbox` with `display-focus="false"` | Emits boolean checked state (group aggregates into a `value` array) |
69
+
70
+ ### Default values
71
+
72
+ - `disabled` defaults to **`false`**
73
+ - `invalid` defaults to **`false`**
74
+ - `multiple` defaults to **`false`**
75
+ - `required` defaults to **`false`**
76
+ - `id` — auto-generated via Vue `useId()` when omitted; **SHOULD** set explicitly when not used inside a group
77
+ - `checked` — controlled from parent / group; no implicit default in the component
78
+
79
+ Props, events, and slots: use Joy MCP (when available), Storybook, or `VJoySelectableItem.vue` — this page focuses on **when** and **how**, not a full API dump.
80
+
81
+ ### Grouping
82
+
83
+ - **SHOULD** render selectable items only inside `VJoySelectableItemGroup` in product forms.
84
+ - **MUST** give siblings the same `name` in single-selection mode so the browser treats them as one radio group.
85
+ - **MUST** set a distinct `value` (and stable `id`) per tile.
86
+ - Set group-level `invalid` and `errorMessage` on `VJoySelectableItemGroup`; the group forwards `invalid` to each item.
87
+
88
+ ---
89
+
90
+ ## Sizes
91
+
92
+ There is **no `size` prop**. Tile dimensions come from Joy tokens inside `JoySelectableItem.scss` — **don’t hardcode tile width or height** in apps.
93
+
94
+ | Aspect | Guidance |
95
+ | --- | --- |
96
+ | Min height | `--selectable-item-min-height` (54px) on single-selection tiles |
97
+ | Default width | `--selectable-item-flex-rule: 0 0 215px` per tile in a single-selection group |
98
+ | Full-width row | Set `fullWidth` on `VJoySelectableItemGroup` (single selection only) — tiles grow with `flex: 1` |
99
+ | Typography | `--joy-font-size-primary-300`; label bold when checked |
100
+ | Spacing | Group gap uses `--joy-core-spacing-5`; tile padding uses `--joy-core-spacing-3` (single) or checkbox label padding (multiple) |
101
+
102
+ ---
103
+
104
+ ## States
105
+
106
+ | State | What the user sees / can do |
107
+ | --- | --- |
108
+ | Default (unchecked) | Neutral border (`--joy-color-neutral-30`); normal label weight |
109
+ | Checked | Secondary border and text (`--joy-color-secondary-50`); primary label **bold**; sublabel stays normal weight |
110
+ | Hover | Border accent on enabled tiles (pointer devices) |
111
+ | Focus | Visible outline on the tile (`--joy-form-field-focus-width` / `--joy-form-field-focus-color`) |
112
+ | Disabled | Muted text and neutral background; `not-allowed` cursor — **explain why** when the reason isn’t obvious |
113
+ | Invalid | Error border on the tile (`--joy-color-error-50`); pair with `errorMessage` on the group — don’t rely on color alone |
114
+ | Focusing (wrapper) | `joy-selectable-item--focusing` while the inner control is focused |
115
+
116
+ In single-selection mode, clicking a **checked** tile clears the selection (emits `''`). Confirm product rules allow “no selection” before relying on this behavior.
117
+
118
+ ---
119
+
120
+ ## Best practices
121
+
122
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
123
+
124
+ ### Selection and hierarchy
125
+
126
+ - **SHOULD** offer **2–5** tiles; beyond that, prefer `VJoySelect` or a vertical radio/checkbox group.
127
+ - **SHOULD** pre-select a sensible default when one option is clearly recommended.
128
+ - **SHOULD** keep option labels parallel (same grammar and similar length).
129
+ - **MUST NOT** use selectable items for navigation or one-off actions — use `VJoyButtonCard`.
130
+ - **MUST NOT** build new features on this deprecated API — migrate to `VJoyRadio`, `VJoyCheckboxCard`, or `VJoyButtonCard`.
131
+
132
+ ### Implementation
133
+
134
+ - **MUST** bind `checked` and listen for `@update:checked` (or use `VJoySelectableItemGroup` with `v-model:value`).
135
+ - **MUST** use only documented props from `VJoySelectableItem.vue` / `TVJoySelectableItemProps`.
136
+ - **MUST** style with Joy tokens — no custom `.joy-selectable-item` chrome overrides.
137
+ - **MUST NOT** invent props (`variant`, `size`, `ai`, `color`, …).
138
+ - **MUST** set `value` on every item used in forms.
139
+ - **SHOULD** put primary copy in the default slot; `label` prop is not rendered by the Vue component — use the slot (or the group’s `label` / `item` slot).
140
+ - **SHOULD** use `subLabel` or `#selectable-item-sublabel` for secondary detail, not a second line in the primary label.
141
+
142
+ ### Interaction
143
+
144
+ - **MUST** set `disabled` on tiles the user cannot choose.
145
+ - **SHOULD** explain disabled tiles when the restriction isn’t clear from context.
146
+ - **SHOULD** use the group `item` slot (with `VJoyIcon` etc.) for rich tile content instead of bolting icons onto custom markup.
147
+
148
+ ### Do / don’t
149
+
150
+ | Do | Don’t |
151
+ | --- | --- |
152
+ | `VJoySelectableItemGroup` + `options` / `v-model:value` | Lone tiles without group legend or validation |
153
+ | Parallel short labels + sublabels | Long paragraphs inside the tile |
154
+ | `invalid` + `errorMessage` on the group | Red borders with no error text |
155
+ | Migrate new work to Radio / CheckboxCard / ButtonCard | New `VJoySelectableItem` usage |
156
+ | `fullWidth` for equal-width single-select rows | Hardcoded `215px` tile widths in app CSS |
157
+
158
+ ---
159
+
160
+ ## Content
161
+
162
+ Tile copy should make each option distinct at a glance and read consistently as a set.
163
+
164
+ ### Label formula
165
+
166
+ **Short noun phrase or concise statement** naming the option:
167
+
168
+ - ✅ Monthly
169
+ - ✅ Express delivery
170
+ - ✅ PDF export
171
+
172
+ Use the **same part of speech** across siblings.
173
+
174
+ ### Sublabel
175
+
176
+ One line of supporting detail — price, timing, eligibility. Sublabels stay regular weight when the tile is selected so the primary label carries emphasis.
177
+
178
+ ### Writing rules
179
+
180
+ | Strength | Rule |
181
+ | --- | --- |
182
+ | **MUST** | Label the **option**, not the action — ✅ `Standard` · ❌ `Select standard` |
183
+ | **MUST** | Keep primary labels ≤ ~30 characters; move detail to sublabel |
184
+ | **MUST** | Use sentence case for labels and sublabels |
185
+ | **MUST NOT** | Repeat the group legend in every tile label |
186
+ | **MUST NOT** | Use Yes / No as two tile labels when the question isn’t literally binary — name the outcomes |
187
+ | **SHOULD** | Put prices or counts in the sublabel, not the main label |
188
+ | **SHOULD** | Write the group `label` as a question or instruction (`Billing frequency`, `Export format`) |
189
+ | **SHOULD** | Keep `value` a stable programmatic key; localize slot content only |
190
+
191
+ ### Patterns
192
+
193
+ **Plan / tier pickers** — primary label = plan name; sublabel = price or cadence; optional icon via group `#item` slot.
194
+
195
+ **Validation** — group `label` + `errorMessage` when `invalid`: ✅ `Choose a delivery speed` + `Select one option to continue`.
196
+
197
+ ---
198
+
199
+ ## Accessibility
200
+
201
+ Behaviors (what must happen), not slogans.
202
+
203
+ | Behavior | Expectation |
204
+ | --- | --- |
205
+ | Role | Native `radio` (single) or `checkbox` (multiple) — not a clickable `<div>` alone |
206
+ | Name | Primary label from default slot (or checkbox label in multiple mode); group name from `VJoySelectableItemGroup` `label` / external `VJoyLabel` |
207
+ | Keyboard | **Space** toggles focused control; **Arrow keys** move between radios in the same `name` group (single mode) |
208
+ | Focus | Visible focus ring on the tile; checkbox inner focus ring suppressed via `display-focus="false"` to avoid double rings |
209
+ | Disabled | `disabled` on the native control; `aria-disabled` on the wrapper when disabled |
210
+ | Invalid | Error styling plus visible `errorMessage` from the group |
211
+ | Grouping | `VJoySelectableItemGroup` renders a `<fieldset>`; associate legend via `VJoyLabel` |
212
+
213
+ Target: **WCAG 2.2 AA** where the product requires it.
214
+
215
+ ---
216
+
217
+ ## Examples
218
+
219
+ ```vue
220
+ <script setup lang="ts">
221
+ import { ref } from 'vue'
222
+ import {
223
+ VJoySelectableItem,
224
+ VJoySelectableItemGroup,
225
+ type TJoySelectableItemOption,
226
+ } from '@maltjoy/core-vue'
227
+
228
+ const plan = ref('monthly')
229
+
230
+ const options: TJoySelectableItemOption[] = [
231
+ { id: 'plan-monthly', value: 'monthly', label: 'Monthly', subLabel: 'Billed each month' },
232
+ { id: 'plan-yearly', value: 'yearly', label: 'Yearly', subLabel: 'Save 20%' },
233
+ ]
234
+
235
+ // Standalone single-selection tile (unusual — prefer the group)
236
+ const standalone = ref('a')
237
+ </script>
238
+
239
+ <template>
240
+ <!-- Recommended: group + v-model:value -->
241
+ <VJoySelectableItemGroup
242
+ v-model:value="plan"
243
+ label="Billing frequency"
244
+ :options="options"
245
+ />
246
+
247
+ <!-- Multi-select -->
248
+ <VJoySelectableItemGroup
249
+ v-model:value="['pdf']"
250
+ multiple
251
+ label="Export formats"
252
+ :options="[
253
+ { id: 'fmt-pdf', value: 'pdf', label: 'PDF' },
254
+ { id: 'fmt-docx', value: 'docx', label: 'DOCX' },
255
+ ]"
256
+ />
257
+
258
+ <!-- Custom tile body via item slot -->
259
+ <VJoySelectableItemGroup v-model:value="plan" :options="options">
260
+ <template #item="option">
261
+ <strong>{{ option.label }}</strong>
262
+ </template>
263
+ </VJoySelectableItemGroup>
264
+
265
+ <!-- Standalone item (you manage group semantics) -->
266
+ <VJoySelectableItem
267
+ id="tile-a"
268
+ name="letters"
269
+ value="a"
270
+ :checked="standalone === 'a'"
271
+ @update:checked="(v) => { standalone = v as string }"
272
+ >
273
+ Option A
274
+ <template #selectable-item-sublabel>Detail for A</template>
275
+ </VJoySelectableItem>
276
+ </template>
277
+ ```
278
+
279
+ In Nuxt (or apps with auto-import), omit the import if components are already global.
280
+
281
+ ---
282
+
283
+ ## Related
284
+
285
+ | Component | Use when |
286
+ | --- | --- |
287
+ | `VJoySelectableItemGroup` | Fieldset, options array, `v-model:value`, `invalid`, `fullWidth` |
288
+ | `VJoyRadio` / `VJoyRadioGroup` | **Preferred** replacement for single selection (including `outline` cards) |
289
+ | `VJoyCheckboxCard` | **Preferred** replacement for card-style checkbox / multi-select |
290
+ | `VJoyButtonCard` | Card that navigates or triggers an action |
291
+ | `VJoyCheckbox` | Embedded inside multiple-mode tiles (`display-focus="false"`) |
292
+ | `VJoyLabel` / `VJoyFormError` | External legend or group-level error display |
293
+ | `VJoySelect` | Long dropdown lists instead of tiles |
294
+
295
+ ---
296
+
297
+ ## For agents
298
+
299
+ Maps to `agentDocumentBlocks` in [`JoySelectableItem.dsds.json`](./JoySelectableItem.dsds.json). **Do not use this component for new UI** — emit replacements below.
300
+
301
+ ### Pick the right component
302
+
303
+ | If the intent is… | Emit… | Do not emit… |
304
+ | --- | --- | --- |
305
+ | New single-choice card picker | `VJoyRadio` `theme="outline"` in `VJoyRadioGroup` | `VJoySelectableItem` |
306
+ | New multi-select card picker | `VJoyCheckboxCard` / `VJoyCheckboxGroup` | `VJoySelectableItemGroup` `multiple` |
307
+ | Card link or CTA | `VJoyButtonCard` | Selectable item tiles |
308
+ | Maintain legacy tile group | `VJoySelectableItemGroup` + options | Custom div tiles |
309
+ | Rich icon in tile | `#item` slot on group | Invented `icon` prop on item (not rendered) |
310
+
311
+ ### Hard rules
312
+
313
+ 1. **MUST** read `VJoySelectableItem.vue` and `VJoySelectableItem.types.ts` (or MCP when available) before generating props.
314
+ 2. **MUST** prefer `VJoySelectableItemGroup` over standalone items in forms.
315
+ 3. **MUST** set `id` and `value` on every option object; shared `name` for single-selection siblings.
316
+ 4. **MUST** bind group state with `v-model:value` (`string` single, `array` multiple).
317
+ 5. **MUST NOT** invent props — no `variant`, `size`, or `ai`.
318
+ 6. **MUST NOT** override `.joy-selectable-item` border, padding, min-height, or flex basis in product CSS.
319
+ 7. **MUST NOT** use for new features — deprecated in favor of Radio / CheckboxCard / ButtonCard.
320
+ 8. **SHOULD** set `invalid` and `errorMessage` on the group, not only on items.
321
+ 9. **SHOULD** use `subLabel` / `#selectable-item-sublabel` for secondary text.
322
+
323
+ ### Checklist
324
+
325
+ - [ ] Confirmed legacy maintenance (not greenfield) or documented migration target
326
+ - [ ] `VJoySelectableItemGroup` used for form fields when possible
327
+ - [ ] Each option has `id`, `value`, and label content in slot / `options`
328
+ - [ ] `v-model:value` type matches `multiple` (`string` vs `array`)
329
+ - [ ] No invented props / no custom tile chrome CSS
330
+ - [ ] Group `label` + `errorMessage` when `invalid`
331
+ - [ ] Parallel concise labels; detail in sublabel
332
+ - [ ] Replacement component identified for new work
333
+
334
+ ---
335
+
336
+ ## DSDS mapping
337
+
338
+ This Markdown mirrors [`JoySelectableItem.dsds.json`](./JoySelectableItem.dsds.json) (DSDS **0.15.2**).
339
+
340
+ | Section here | DSDS block |
341
+ | --- | --- |
342
+ | When to use / not | `use-cases` |
343
+ | Anatomy / selection modes | `anatomy` |
344
+ | Sizes (no size API) | `design-specifications` |
345
+ | States | `states` |
346
+ | Best practices / content rules | `guidelines` (+ `content`) |
347
+ | Accessibility | `accessibility` |
348
+ | Examples | `sections` |
349
+ | For agents | `agentDocumentBlocks` |
350
+ | Props detail | `api` in JSON + Joy MCP |
351
+ | Imports | `imports` in JSON |