@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,360 @@
1
+ ---
2
+ component: VJoyLink
3
+ status: draft
4
+ language: en
5
+ dsds: JoyLink.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # Link
10
+
11
+ Use **`VJoyLink`** when the user should navigate to another page, resource, or URL — inline in body copy, as a standalone call-to-action after a paragraph, or embedded in patterns such as dropzones and highlights.
12
+
13
+ It renders as a native `<a>` when `href` is set, or as a `<button>` when there is no `href` (link-styled control for in-page actions). Optional leading icons, two color contexts (`teal`, `white`), and inherited typography keep links scannable without custom CSS.
14
+
15
+ | | |
16
+ | --- | --- |
17
+ | **Code** | `VJoyLink` from `@maltjoy/core-vue` |
18
+ | **Design** | [ZeroHeight — Link](https://zeroheight.com/6bf479565/p/4070710) |
19
+ | **Storybook** | [VJoyLink docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-buttons-vjoylink--docs) |
20
+ | **DSDS (machine)** | [`JoyLink.dsds.json`](./JoyLink.dsds.json) |
21
+ | **Live API** | `joy_get_component_info("VJoyLink")` |
22
+
23
+ ---
24
+
25
+ ## When to use this component
26
+
27
+ Use a link when the outcome is **navigation** — opening another route, an external site, documentation, or a downloadable resource — and the control should read as text, not a filled button.
28
+
29
+ Typical placements: a word or phrase inside a sentence, a short standalone line after explanatory copy, or an embedded affordance inside another component (for example the “browse” action in `VJoyDropzone`).
30
+
31
+ When there is no destination URL but you still want link typography for a **secondary, low-emphasis action** in tight space (and a `VJoyButton` `ghost` variant would compete with a stronger CTA), omit `href` and render as a `<button>` with `type="button"`.
32
+
33
+ ### When not to use this component
34
+
35
+ | Need | Use instead |
36
+ | --- | --- |
37
+ | Primary or emphasized actions (submit, confirm, save) | `VJoyButton` (`main`, `primary`, …) |
38
+ | Navigation with button chrome (filled / outlined CTA) | `VJoyButton` + `href` attribute |
39
+ | Icon-only control (no visible text) | `VJoyIconButton` |
40
+ | Complex card-style navigation CTA | `VJoyButtonCard` |
41
+ | App or sidebar navigation lists | `VJoyMenu` + `VJoyMenuItem` |
42
+ | Read-only text with no navigation | `VJoyText` or plain copy |
43
+ | Custom-styled `<a>` / `<button>` in product CSS | Still use `VJoyLink` + Joy tokens |
44
+
45
+ ---
46
+
47
+ ## How it works
48
+
49
+ ### Anatomy
50
+
51
+ | Part | Required? | What it is |
52
+ | --- | --- | --- |
53
+ | Root | Yes | `<a>` when `href` is set; `<button>` when `href` is omitted |
54
+ | Label (`default` slot or `text`) | Yes* | Visible link text in `.joy-link__text` |
55
+ | Leading icon | No | `VJoyIcon` when `icon` is set; inherits color and font size |
56
+ | Focus ring | Yes | `2px` border on `:focus-visible` — don’t remove in product CSS |
57
+
58
+ \*Provide copy via the default slot **or** the `text` prop. If both are omitted, the link has no accessible name.
59
+
60
+ Native attributes (`target`, `rel`, `aria-*`, `disabled`, …) pass through via `$attrs` on the root element.
61
+
62
+ ### Default values
63
+
64
+ - `color` defaults to **`teal`**
65
+ - `href` defaults to **unset** (root becomes `<button>`)
66
+ - `icon`, `text`, and `type` default to **unset**
67
+
68
+ When the root is a `<button>`, set **`type="button"`** unless the control should submit a form (`type="submit"`).
69
+
70
+ Props and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
71
+
72
+ ### Link vs button root
73
+
74
+ | `href` | Root | Use when |
75
+ | --- | --- | --- |
76
+ | Set | `<a href="…">` | Real navigation (same tab, new tab, external URL, download) |
77
+ | Omitted | `<button>` | In-page action with link appearance (open picker, toggle panel, cancel inline edit) |
78
+
79
+ Don’t use a `<button>` root when the user expects a URL in the status bar or “open in new tab”. Don’t use `href="#"` as a fake button — omit `href` and use `type="button"` instead.
80
+
81
+ ---
82
+
83
+ ## Variants
84
+
85
+ `color` chooses **contrast against the background**, not arbitrary branding.
86
+
87
+ ### `teal` (default)
88
+
89
+ Use on **light** surfaces for standard product links (secondary palette: default, hover, visited tokens).
90
+
91
+ This is the default for body copy, forms, panels, and most in-app UI.
92
+
93
+ ### `white`
94
+
95
+ Use on **dark or saturated** backgrounds (hero bands, snackbars, inverted footers) where `teal` would fail contrast.
96
+
97
+ Active press reduces opacity (`0.7`) while keeping neutral-0 text. Don’t use `white` on light backgrounds.
98
+
99
+ ### Not in the API: size / underline mode
100
+
101
+ There is no `size` prop — font size and line height **inherit** from the parent. There is no prop to force always-underlined vs hover-underline; underline appears on **hover** on the label span. Don’t invent `size`, `variant`, or `underline` props.
102
+
103
+ ---
104
+
105
+ ## Sizes
106
+
107
+ `VJoyLink` exposes **no size API**. Density comes from surrounding typography.
108
+
109
+ | Aspect | Guidance |
110
+ | --- | --- |
111
+ | Font size / line height | Inherited from parent — wrap in `VJoyText` or body styles as needed |
112
+ | Icon | `--icon-size: inherit` — scales with link text |
113
+ | Touch target | Rely on natural text size + padding from focus border; don’t shrink below readable body text for tappability |
114
+
115
+ **Don’t** hardcode font sizes or link colors on `.joy-link` in product CSS.
116
+
117
+ ---
118
+
119
+ ## States
120
+
121
+ | State | What the user sees / can do |
122
+ | --- | --- |
123
+ | Default | Bold text; `teal` uses secondary-30, default (no color class) uses neutral-40 |
124
+ | Hover | Label color shifts to hover token; **underline** on `.joy-link__text` |
125
+ | Focus | Visible `2px` focus border (`neutral-60` token) — keyboard / AT |
126
+ | Active / visited | Visited color (`secondary-90` for `teal`; `white` stays neutral-0) |
127
+ | With icon | Icon matches link color; spacing via `--joy-core-spacing-2` |
128
+ | Button root | Same visuals; activate with **Space** / **Enter**; set `type` explicitly |
129
+
130
+ External links opened in a new tab should use `target="_blank"` and `rel="noopener noreferrer"` (or your app’s security standard) via native attributes.
131
+
132
+ ---
133
+
134
+ ## Best practices
135
+
136
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
137
+
138
+ ### When to use link vs button
139
+
140
+ - **SHOULD** use `VJoyLink` + `href` for navigation (in-app routes, external sites, files).
141
+ - **SHOULD** use `VJoyButton` for actions that change data or confirm decisions, even when they navigate afterward.
142
+ - **SHOULD** use `VJoyLink` without `href` only for **low-emphasis in-page** actions where button chrome would overpower the layout.
143
+ - **MUST NOT** use `VJoyLink` for the principal CTA on a surface — use `VJoyButton` `main` / `primary`.
144
+
145
+ ### Implementation
146
+
147
+ - **MUST** use only `color` values from MCP or `JoyLink.types.ts` (`teal`, `white`).
148
+ - **MUST** provide visible label text via the default slot or `text` prop.
149
+ - **MUST** use Joy tokens — no custom `.joy-link` color, font-weight, or underline overrides.
150
+ - **MUST NOT** invent props (`size`, `variant`, `underline`, …).
151
+ - **SHOULD** prefer the **default slot** for simple text; use `text` for Storybook / generated UIs.
152
+ - **SHOULD** set `type="button"` on button roots inside forms.
153
+ - **SHOULD** pass `target` and `rel` for external / new-tab links via `$attrs`.
154
+
155
+ ### Interaction
156
+
157
+ - **MUST NOT** use `href="#"` with `@click.prevent` as a button substitute — omit `href` instead.
158
+ - **SHOULD** add an external-link icon (`icon` prop) when the destination is off-platform, if space allows.
159
+ - **SHOULD** pick `color="white"` only on backgrounds verified with design tokens.
160
+
161
+ ### Do / don’t
162
+
163
+ | Do | Don’t |
164
+ | --- | --- |
165
+ | `href` for real URLs | `href="#"` for JavaScript actions |
166
+ | `type="button"` on non-submit button roots | Bare `<button>` inside forms (accidental submit) |
167
+ | Specific destination labels | “Click here”, “See more”, “Know more” |
168
+ | `teal` on light UI | `white` on white cards |
169
+ | `VJoyButton` for primary actions | `VJoyLink` styled as a CTA button |
170
+
171
+ ---
172
+
173
+ ## Content
174
+
175
+ Links name **where the user goes** or **what they open**. Keep copy short, specific, and scannable.
176
+
177
+ ### Copy formula
178
+
179
+ **Verb + object** (standalone) or a **minimal noun phrase** (inline):
180
+
181
+ - ✅ View freelancer portfolio
182
+ - ✅ Compare pricing plans
183
+ - ✅ Update your profile
184
+ - ❌ Click here to update your profile
185
+ - ❌ Know more
186
+
187
+ Aim for **~3 words** and **one idea** per link.
188
+
189
+ ### Writing rules
190
+
191
+ | Strength | Rule |
192
+ | --- | --- |
193
+ | **MUST** | Name the destination or outcome — not the mechanics of clicking |
194
+ | **MUST NOT** | Vague labels — ❌ “Click here”, “Go to”, “See more”, “Know more” |
195
+ | **MUST NOT** | Punctuation inside inline links (except proper nouns / product names) |
196
+ | **SHOULD** | ≤ ~3 words when possible |
197
+ | **SHOULD** | Sentence case; capitalize product/feature names only |
198
+ | **SHOULD** | For external sites, use the **site or resource name**, not the raw URL |
199
+ | **SHOULD** | Pair external navigation with an icon when it aids recognition |
200
+ | **SHOULD** (FR) | Non-breaking spaces before `;`, `?`, `!`, and `:` |
201
+
202
+ ### Patterns
203
+
204
+ **Standalone links** (after a paragraph or in a footer) — Use a short phrase or question; apply the link to the **whole phrase**, not a single word.
205
+
206
+ - ✅ *Need help choosing a freelancer?*
207
+ - ❌ Only linking the word “help” in a longer sentence meant to stand alone
208
+
209
+ **Inline links** (inside body copy) — Prefer **start or end** of the sentence for scanability. Don’t bury the link mid-sentence when a standalone phrase would work.
210
+
211
+ **Embedded in components** — Follow the parent pattern (`VJoyDropzone` browse link, `VJoyHighlight` actions, snackbar inline HTML). Match parent `color` (`white` on dark snackbars).
212
+
213
+ **Link-styled button** — Label should still describe the action (`Browse files`, `Choose another date`), not navigation, because there is no `href`.
214
+
215
+ ---
216
+
217
+ ## Accessibility
218
+
219
+ Behaviors (what must happen), not slogans.
220
+
221
+ | Behavior | Expectation |
222
+ | --- | --- |
223
+ | Role | Native `<a href>` or `<button>` — never a clickable `<span>` |
224
+ | Name | From default slot or `text`; must be non-empty |
225
+ | Keyboard | Links: **Enter** activates; buttons: **Enter** and **Space** |
226
+ | Focus | Keep `:focus-visible` border — `2px solid` using Joy focus token |
227
+ | External | `target="_blank"` links need clear copy; add `rel` as required by security policy |
228
+ | Icons | Decorative icons should be `aria-hidden` (Joy icon default); don’t rely on icon alone for the name |
229
+ | Button root | Set `type="button"` to avoid accidental form submission |
230
+ | Disabled | Use native `disabled` on `<button>`; for `<a>`, avoid fake disabled links — remove or explain in copy |
231
+
232
+ Target: **WCAG 2.2 AA** where the product requires it.
233
+
234
+ ---
235
+
236
+ ## Examples
237
+
238
+ ```vue
239
+ <script setup lang="ts">
240
+ import { VJoyLink } from '@maltjoy/core-vue'
241
+ </script>
242
+
243
+ <template>
244
+ <!-- External navigation -->
245
+ <VJoyLink href="https://malt.com" text="Visit Malt" />
246
+
247
+ <!-- Inline in copy (slot) -->
248
+ <p>
249
+ You can
250
+ <VJoyLink href="/help/pricing">compare pricing plans</VJoyLink>
251
+ before subscribing.
252
+ </p>
253
+
254
+ <!-- With icon (e.g. external / download) -->
255
+ <VJoyLink
256
+ href="https://example.com/report.pdf"
257
+ icon="download"
258
+ target="_blank"
259
+ rel="noopener noreferrer"
260
+ >
261
+ Download report
262
+ </VJoyLink>
263
+
264
+ <!-- On dark background -->
265
+ <VJoyLink href="/learn-more" color="white">
266
+ Learn more
267
+ </VJoyLink>
268
+
269
+ <!-- Link-styled button (no navigation) -->
270
+ <VJoyLink type="button" @click="openFilePicker">
271
+ Browse files
272
+ </VJoyLink>
273
+ </template>
274
+ ```
275
+
276
+ In Nuxt (or apps with auto-import), omit the import if `VJoyLink` is already global.
277
+
278
+ ---
279
+
280
+ ## Related
281
+
282
+ | Component | Use when |
283
+ | --- | --- |
284
+ | `VJoyButton` | Primary actions or navigation with button chrome |
285
+ | `VJoyIconButton` | Icon-only actions |
286
+ | `VJoyText` | Non-interactive body typography |
287
+ | `VJoyDropzone` | File upload with embedded browse link pattern |
288
+ | `VJoyHighlight` | Emphasized blocks that may include links |
289
+ | `VJoyMenu` / `VJoyMenuItem` | Structured navigation lists |
290
+ | `VJoyIcon` | Icon primitive used inside the link |
291
+
292
+ ---
293
+
294
+ ## For agents
295
+
296
+ Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyLink.dsds.json`](./JoyLink.dsds.json).
297
+
298
+ ### Pick the right component
299
+
300
+ | If the intent is… | Emit… | Do not emit… |
301
+ | --- | --- | --- |
302
+ | Navigate in body copy or light CTA text | `VJoyLink` + `href` | `VJoyButton` `ghost` in a paragraph |
303
+ | Principal or form action | `VJoyButton` | `VJoyLink` as page CTA |
304
+ | Navigate with filled button look | `VJoyButton` + `href` attribute | `VJoyLink` + custom button CSS |
305
+ | In-page action, link appearance | `VJoyLink` without `href` + `type="button"` | `href="#"` + `@click` |
306
+ | Icon only | `VJoyIconButton` | `VJoyLink` with icon and no text |
307
+ | Dark / snackbar surface | `VJoyLink` + `color="white"` | `color="teal"` on dark backgrounds |
308
+
309
+ ### Hard rules
310
+
311
+ 1. **MUST** call `joy_get_component_info("VJoyLink")` and/or `joy_get_component_types("VJoyLink")` (or read `JoyLink.types.ts`) before generating props.
312
+ 2. **MUST** set `href` when the user navigates to a URL; omit `href` only for button-semantics actions.
313
+ 3. **MUST** supply label text via the default slot or `text` prop.
314
+ 4. **MUST** use only documented props: `href`, `color`, `icon`, `text`, `type`.
315
+ 5. **MUST** pass native HTML attributes (`target`, `rel`, `aria-*`, `disabled`, …) as attributes on `VJoyLink`, not as invented props.
316
+ 6. **MUST NOT** invent props (`size`, `variant`, `underline`, `external`, …).
317
+ 7. **MUST NOT** override `.joy-link` colors, font-weight, or underline behavior in app CSS.
318
+ 8. **MUST NOT** use `href="#"` for non-navigation click handlers.
319
+ 9. **SHOULD** default to `color="teal"` on light surfaces.
320
+ 10. **SHOULD** set `type="button"` on button roots unless submitting a form.
321
+
322
+ ### Valid enums (from `JoyLink.types.ts`)
323
+
324
+ | Prop | Values |
325
+ | --- | --- |
326
+ | `color` | `teal`, `white` |
327
+ | `type` | `button`, `submit`, `reset` (only when root is `<button>`) |
328
+ | `icon` | Any `TJoyIconsNames` value (see Joy Icon docs / MCP) |
329
+
330
+ ### Checklist
331
+
332
+ - [ ] Correct component (`VJoyLink` or named alternative)
333
+ - [ ] Props / enums from MCP or types only
334
+ - [ ] `href` set for navigation; omitted only for button-mode actions
335
+ - [ ] Label via slot or `text` — not empty
336
+ - [ ] `type="button"` on non-submit button roots
337
+ - [ ] `color` matches background (`teal` vs `white`)
338
+ - [ ] No invented props / no custom `.joy-link` chrome CSS
339
+ - [ ] External / new-tab links use appropriate `target` and `rel`
340
+ - [ ] Copy is specific — no “click here” / “see more”
341
+
342
+ ---
343
+
344
+ ## DSDS mapping
345
+
346
+ This Markdown mirrors [`JoyLink.dsds.json`](./JoyLink.dsds.json) (DSDS **0.15.2**).
347
+
348
+ | Section here | DSDS block |
349
+ | --- | --- |
350
+ | When to use / not | `use-cases` |
351
+ | Anatomy / link vs button | `anatomy` |
352
+ | Colors | `variants` |
353
+ | Inherited sizing | `design-specifications` |
354
+ | States | `states` |
355
+ | Best practices / content rules | `guidelines` (+ `content`) |
356
+ | Accessibility | `accessibility` |
357
+ | Examples | `sections` |
358
+ | For agents | `agentDocumentBlocks` |
359
+ | Props detail | `api` in JSON + Joy MCP |
360
+ | Imports | `imports` in JSON |
@@ -0,0 +1,335 @@
1
+ ---
2
+ component: VJoyListItem
3
+ status: draft
4
+ language: en
5
+ dsds: JoyListItem.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # List item
10
+
11
+ Use **`VJoyListItem`** when you need a **bordered, interactive row** in a list — a primary label on the left, optional leading icon, and secondary content or actions on the right.
12
+
13
+ The whole row shows hover feedback and emits `click` when the user activates the container. Use the slots for copy and trailing UI (buttons, badges, metadata); keep real controls in `list-item-right` as proper Joy components.
14
+
15
+ | | |
16
+ | --- | --- |
17
+ | **Code** | `VJoyListItem` from `@maltjoy/core-vue` |
18
+ | **Design** | [Figma — Joy Core Design System](https://www.figma.com/design/jfndp2QBJGS9yeuWbeGuvD/) |
19
+ | **Storybook** | [VJoyListItem docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-view-vjoylistitem--docs) |
20
+ | **DSDS (machine)** | [`JoyListItem.dsds.json`](./JoyListItem.dsds.json) |
21
+ | **Live API** | `joy_get_component_info("VJoyListItem")` |
22
+
23
+ ---
24
+
25
+ ## When to use this component
26
+
27
+ Use a list item when several entries share the same layout — title or summary on the left, optional icon, and a trailing action or status on the right. Typical jobs: settings rows with a CTA, document or project lists with a per-row button, or stacked cards where each row is tappable.
28
+
29
+ Stack multiple `VJoyListItem` instances inside a `VJoyWrapper` (column layout) or a semantic `<ul>` / `<ol>` when the list is meaningful document structure.
30
+
31
+ ### When not to use this component
32
+
33
+ | Need | Use instead |
34
+ | --- | --- |
35
+ | Persistent app or sidebar navigation | `VJoyMenu` + `VJoyMenuItem` |
36
+ | Options inside a dropdown overlay | `VJoyDropdownList` (via `VJoyDropdown`) |
37
+ | Rich user profile summary (avatar, rating, link) | `VJoyUserCard` |
38
+ | Selectable option cards (single or multi) | `VJoySelectableItem` / `VJoySelectableItemGroup` |
39
+ | Plain bullet list without row chrome | `VJoyText` or semantic list markup + Joy spacing tokens |
40
+ | Full panel with header, body, and footer | `VJoyPanel` |
41
+ | Custom bordered row with ad-hoc CSS | Still use `VJoyListItem` + Joy tokens — don’t reinvent chrome |
42
+
43
+ ---
44
+
45
+ ## How it works
46
+
47
+ ### Anatomy
48
+
49
+ | Part | Required? | What it is |
50
+ | --- | --- | --- |
51
+ | Root container | Yes | `<div class="joy-list-item">` — border, background, hover, and `@click` emission |
52
+ | Inner layout | Yes | `VJoyWrapper` (`row`, `space-between`, `nowrap`) splitting left and right |
53
+ | Left area | Yes | `joy-list-item__left` — optional icon + primary text |
54
+ | Leading icon | No | `VJoyIcon` when `icon` is set (`joy-list-item__left-icon`) |
55
+ | Primary text | Yes* | `list-item-left` slot content (rendered in `joy-font-primary-300` inside a `<p>`) |
56
+ | Right area | No | `list-item-right` slot — actions, badges, metadata, secondary controls |
57
+ | Focus ring | No* | Not built into the root — see Accessibility |
58
+
59
+ \*Provide meaningful content in `list-item-left` for every row. Keyboard/focus behavior is not provided on the root; see Accessibility when the row itself must be activatable.
60
+
61
+ ### Default values
62
+
63
+ - `icon` is **optional** — omit when the label alone is clear
64
+ - No `variant`, `size`, `disabled`, or `href` props on this component
65
+
66
+ Props, events, and slots: use Joy MCP (`joy_get_component_info`) or Storybook — this page focuses on **when** and **how**, not a full API dump.
67
+
68
+ ### Slots and events
69
+
70
+ | Slot / event | Role |
71
+ | --- | --- |
72
+ | `list-item-left` | Primary label or summary (required for meaningful rows) |
73
+ | `list-item-right` | Trailing UI — prefer `VJoyButton`, `VJoyTag`, `VJoyBadge`, or short text |
74
+ | `@click` | Fired when the user clicks the root container (bubbles from children unless stopped) |
75
+
76
+ ### Not in the API: default slot
77
+
78
+ There is **no default slot**. Content belongs in `list-item-left` and `list-item-right` only.
79
+
80
+ ### Not in the API: `variant`, `size`, `disabled`
81
+
82
+ `VJoyListItem` exposes only `icon` plus the two named slots. Do not emit `variant`, `size`, `disabled`, or `href` on this component. Use real controls in `list-item-right` (for example a disabled `VJoyButton`) when an action cannot run.
83
+
84
+ ---
85
+
86
+ ## States
87
+
88
+ | State | What the user sees / can do |
89
+ | --- | --- |
90
+ | Default | Neutral border (`--joy-color-neutral-30`), background `--joy-color-neutral-10`, pointer cursor |
91
+ | Hover | Background `--joy-color-neutral-20`, border `--joy-color-neutral-40` (pointer devices) |
92
+ | Click | Root emits `click`; parent handles navigation or selection |
93
+ | With icon | Leading icon in neutral-60; does not replace the text label |
94
+ | Right-slot controls | Buttons and links in `list-item-right` remain independently interactive |
95
+
96
+ There is no built-in selected, disabled, or loading state on the row itself.
97
+
98
+ ---
99
+
100
+ ## Best practices
101
+
102
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
103
+
104
+ ### Layout and hierarchy
105
+
106
+ - **SHOULD** keep one clear idea per row — primary copy in `list-item-left`, one main action or status in `list-item-right`.
107
+ - **SHOULD** use `icon` only when it reinforces the row topic (document, user, settings) — not on every row for decoration.
108
+ - **MUST NOT** nest another full `VJoyListItem` inside a row slot.
109
+ - **SHOULD** stack rows with consistent vertical spacing (`VJoyWrapper` `direction="column"` + `row-gap`).
110
+
111
+ ### Implementation
112
+
113
+ - **MUST** use only documented props from MCP or `VJoyListItem.vue` (`icon` only).
114
+ - **MUST** use Joy tokens — no custom `.joy-list-item` border, radius, padding, or hover overrides.
115
+ - **MUST** put primary copy in `list-item-left` and trailing UI in `list-item-right`.
116
+ - **MUST NOT** invent props (`variant`, `size`, `disabled`, `href`, …).
117
+ - **SHOULD** call `@click.stop` on interactive children in `list-item-right` when the row `@click` should not fire for button presses.
118
+
119
+ ### Interaction
120
+
121
+ - **SHOULD** use `@click` on the row only when the whole row shares one action (open detail, select row).
122
+ - **SHOULD** use `list-item-right` for distinct actions (Edit, Delete) instead of overloading row click.
123
+ - **MUST NOT** rely on row click alone for critical actions without a visible control or accessible name on the row.
124
+
125
+ ### Do / don’t
126
+
127
+ | Do | Don’t |
128
+ | --- | --- |
129
+ | `list-item-left` + `list-item-right` slots | Default slot or unstructured divs |
130
+ | `@click.stop` on nested buttons | Row navigation firing when user clicks a button |
131
+ | `VJoyButton` / `VJoyTag` in the right slot | Raw `<button>` with custom styles |
132
+ | Short, scannable left labels | Paragraphs of body copy in `list-item-left` |
133
+ | Joy spacing between stacked rows | Hardcoded margins on `.joy-list-item` |
134
+
135
+ ---
136
+
137
+ ## Content
138
+
139
+ List rows expose user-facing copy in `list-item-left` and optional metadata or actions on the right. Follow the same parallelism rules as product lists (see Joy content guidelines — Lists).
140
+
141
+ ### Left label formula
142
+
143
+ **Short noun phrase or concise statement** naming the row:
144
+
145
+ - ✅ Contract renewal
146
+ - ✅ Q3 marketing budget
147
+ - ✅ Two-factor authentication
148
+
149
+ Use **parallel structure** across siblings in the same list (all nouns, or all short verb phrases).
150
+
151
+ ### Right slot copy
152
+
153
+ - **Actions** — verb + object on buttons (`Review contract`, `Download PDF`). Prefer `VJoyButton` `size="xsmall"` or `small` for density.
154
+ - **Status** — short tokens (`Pending`, `Active`) via `VJoyBadge` or `VJoyTag`, not full sentences.
155
+ - **Metadata** — dates, counts, or file size in neutral supporting style — keep to one line.
156
+
157
+ ### Writing rules
158
+
159
+ | Strength | Rule |
160
+ | --- | --- |
161
+ | **MUST** | Every row has identifiable primary text in `list-item-left` — icon alone is not enough |
162
+ | **MUST** | Keep `list-item-left` to roughly one line when possible; move detail to a sub-page or panel |
163
+ | **MUST** | Use parallel grammar across items in the same list |
164
+ | **MUST NOT** | Repeat the page title in every row label |
165
+ | **MUST NOT** | Put the only action label only in `list-item-right` with an empty left slot |
166
+ | **SHOULD** | Sentence case for labels and button text |
167
+ | **SHOULD** | Match terminology with the page heading and adjacent UI |
168
+ | **SHOULD** | Localize slot content; `icon` names stay programmatic (`TJoyIconsNames`) |
169
+
170
+ ### Patterns
171
+
172
+ **Action list** — Left: resource name. Right: single `VJoyButton` (`xsmall`). Row `@click` optional for “open detail”; button uses `@click.stop` for the explicit action.
173
+
174
+ **Status list** — Left: item name. Right: `VJoyBadge` or status text. Row click opens detail if the whole card is tappable.
175
+
176
+ **Icon + title** — `icon` reinforces category (document, folder, user). Label still spells out the item name.
177
+
178
+ ---
179
+
180
+ ## Accessibility
181
+
182
+ Behaviors (what must happen), not slogans.
183
+
184
+ | Behavior | Expectation |
185
+ | --- | --- |
186
+ | Role | Root is a **generic `<div>`** — not a native button or link |
187
+ | Name | Primary accessible name should come from visible `list-item-left` text; icon is decorative unless redundant with text |
188
+ | Keyboard | **No built-in keyboard activation** on the row — if the row is activatable, parent must add focusable semantics (`tabindex`, `role="button"`, Enter/Space) or use a link/button pattern |
189
+ | Focus | No focus ring on the root by default — focus moves to real controls in `list-item-right` |
190
+ | Click | `@click` on the container; stop propagation on nested buttons/links when they perform a different action |
191
+ | Right-slot controls | **MUST** be real `VJoyButton`, `VJoyLink`, or native interactive elements with accessible names |
192
+ | Lists | When rows form a meaningful list, wrap in `<ul>` / `<ol>` with appropriate list semantics or ensure structure is exposed to assistive tech |
193
+
194
+ Target: **WCAG 2.2 AA** where the product requires it. Do not assume the row is accessible as a single control without additional markup.
195
+
196
+ ---
197
+
198
+ ## Examples
199
+
200
+ ```vue
201
+ <script setup lang="ts">
202
+ import { VJoyListItem, VJoyButton, VJoyBadge, VJoyWrapper } from '@maltjoy/core-vue'
203
+
204
+ function openDetail(id: string) {
205
+ // navigate or open panel
206
+ }
207
+
208
+ function reviewContract(event: Event) {
209
+ event.stopPropagation()
210
+ // explicit action
211
+ }
212
+ </script>
213
+
214
+ <template>
215
+ <VJoyWrapper direction="column" row-gap="3">
216
+ <!-- Row with icon + trailing action -->
217
+ <VJoyListItem
218
+ icon="edit-document"
219
+ @click="openDetail('contract-1')"
220
+ >
221
+ <template #list-item-left>
222
+ Contract renewal — Acme Corp
223
+ </template>
224
+ <template #list-item-right>
225
+ <VJoyButton
226
+ variant="main"
227
+ size="xsmall"
228
+ label="Review"
229
+ @click="reviewContract"
230
+ />
231
+ </template>
232
+ </VJoyListItem>
233
+
234
+ <!-- Status metadata on the right -->
235
+ <VJoyListItem icon="folder">
236
+ <template #list-item-left>
237
+ Q3 marketing budget
238
+ </template>
239
+ <template #list-item-right>
240
+ <VJoyBadge label="Pending" />
241
+ </template>
242
+ </VJoyListItem>
243
+
244
+ <!-- Text-only row -->
245
+ <VJoyListItem @click="openDetail('settings-2fa')">
246
+ <template #list-item-left>
247
+ Two-factor authentication
248
+ </template>
249
+ </VJoyListItem>
250
+ </VJoyWrapper>
251
+ </template>
252
+ ```
253
+
254
+ In Nuxt (or apps with auto-import), omit the import if `VJoyListItem` is already global.
255
+
256
+ ---
257
+
258
+ ## Related
259
+
260
+ | Component | Use when |
261
+ | --- | --- |
262
+ | `VJoyWrapper` | Vertical stack spacing between rows |
263
+ | `VJoyIcon` | Leading icon primitive (used internally when `icon` is set) |
264
+ | `VJoyButton` | Trailing actions in `list-item-right` |
265
+ | `VJoyBadge` / `VJoyTag` | Status or category on the right |
266
+ | `VJoyMenuItem` | Navigation menus with proper menu semantics |
267
+ | `VJoyDropdownList` | Selectable options inside dropdowns |
268
+ | `VJoyUserCard` | Full user profile card layout |
269
+ | `VJoyPanel` | Section with header, body, and footer |
270
+
271
+ ---
272
+
273
+ ## For agents
274
+
275
+ Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyListItem.dsds.json`](./JoyListItem.dsds.json).
276
+
277
+ ### Pick the right component
278
+
279
+ | If the intent is… | Emit… | Do not emit… |
280
+ | --- | --- | --- |
281
+ | Bordered list row with left label + right action | `VJoyListItem` | Custom flex card div |
282
+ | Sidebar / app nav item | `VJoyMenuItem` inside `VJoyMenu` | `VJoyListItem` |
283
+ | Dropdown menu option | `VJoyDropdownList` / `VJoyDropdown` | `VJoyListItem` in overlays |
284
+ | User profile block | `VJoyUserCard` | `VJoyListItem` + avatar hacks |
285
+ | Row with only `icon` + default slot | `VJoyListItem` with `list-item-left` / `list-item-right` | Default slot (does not exist) |
286
+
287
+ ### Hard rules
288
+
289
+ 1. **MUST** call `joy_get_component_info("VJoyListItem")` (or read `VJoyListItem.vue`) before generating props.
290
+ 2. **MUST** use slots `list-item-left` and `list-item-right` — there is no default slot.
291
+ 3. **MUST** use only the `icon` prop plus slots; `icon` values are `TJoyIconsNames`.
292
+ 4. **MUST** handle row actions via `@click` on `VJoyListItem` when the whole row is tappable.
293
+ 5. **MUST** use `@click.stop` on buttons in `list-item-right` when row `@click` would conflict.
294
+ 6. **MUST NOT** emit `variant`, `size`, `disabled`, `href`, or other invented props.
295
+ 7. **MUST NOT** override `.joy-list-item` border, background, radius, padding, or hover styles.
296
+ 8. **SHOULD** put primary label text in `list-item-left` on every row.
297
+ 9. **SHOULD** use `VJoyButton` `size="xsmall"` or `small` for trailing actions (see Storybook default).
298
+ 10. **SHOULD** stack multiple items in `VJoyWrapper` `direction="column"` with `row-gap`.
299
+
300
+ ### Valid API (from component source + MCP)
301
+
302
+ | Kind | Names |
303
+ | --- | --- |
304
+ | Props | `icon` (optional, `TJoyIconsNames`) |
305
+ | Events | `click` |
306
+ | Slots | `list-item-left`, `list-item-right` |
307
+
308
+ ### Checklist
309
+
310
+ - [ ] Correct component (`VJoyListItem` or named alternative from table above)
311
+ - [ ] `list-item-left` populated with primary label
312
+ - [ ] `list-item-right` for actions/status when needed
313
+ - [ ] No invented props / no custom `.joy-list-item` chrome CSS
314
+ - [ ] `@click.stop` on nested buttons when row also has `@click`
315
+ - [ ] Trailing controls are real Joy components with accessible names
316
+ - [ ] Row keyboard/focus addressed in parent if whole row must be activatable
317
+
318
+ ---
319
+
320
+ ## DSDS mapping
321
+
322
+ This Markdown mirrors [`JoyListItem.dsds.json`](./JoyListItem.dsds.json) (DSDS **0.15.2**).
323
+
324
+ | Section here | DSDS block |
325
+ | --- | --- |
326
+ | When to use / not | `use-cases` |
327
+ | Anatomy | `anatomy` |
328
+ | States | `states` |
329
+ | Best practices / content rules | `guidelines` (+ `content`) |
330
+ | Accessibility | `accessibility` |
331
+ | Examples | `sections` |
332
+ | For agents | `agentDocumentBlocks` |
333
+ | Props detail | `api` in JSON + Joy MCP |
334
+ | Imports | `imports` in JSON |
335
+ | Token styling | `design-specifications` in JSON (`--joy-color-neutral-*`, `--joy-core-radius-3`) |