@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,372 @@
1
+ ---
2
+ component: VJoyFloatingActionsBar
3
+ status: draft
4
+ language: en
5
+ dsds: JoyFloatingActionsBar.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # Floating actions bar
10
+
11
+ Use **`VJoyFloatingActionsBar`** when contextual next steps should stay visible at the bottom of the viewport — for example bulk actions after a multi-select, or a primary CTA while the user scrolls a long form.
12
+
13
+ It teleports to `body` by default, splits **`content`** (left) and **`actions`** (right) slots, and adapts from a floating card on desktop to a full-width bar on mobile.
14
+
15
+ | | |
16
+ | --- | --- |
17
+ | **Code** | `VJoyFloatingActionsBar` from `@maltjoy/core-vue` |
18
+ | **Design** | [ZeroHeight — Floating action bar](https://zeroheight.com/6bf479565/) (page id `8415609`) |
19
+ | **Storybook** | [VJoyFloatingActionsBar docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-overlays-vjoyfloatingactionsbar--docs) |
20
+ | **DSDS (machine)** | [`JoyFloatingActionsBar.dsds.json`](./JoyFloatingActionsBar.dsds.json) |
21
+ | **Live API** | `joy_get_component_info("VJoyFloatingActionsBar")` |
22
+
23
+ ---
24
+
25
+ ## When to use this component
26
+
27
+ Use a floating actions bar when a **user action changes what they can do next** — typically after selecting items in a list or table — and those next steps should remain reachable without scrolling back to a page footer.
28
+
29
+ The bar surfaces **flow-specific CTAs** (create mission, publish, submit) together with optional context on the left (selection count, avatars, short status). It appears in response to context; hide it when that context clears.
30
+
31
+ ### When not to use this component
32
+
33
+ | Need | Use instead |
34
+ | --- | --- |
35
+ | Confirmation or status after an action completes | `pushVJoySnackbar` |
36
+ | Inline, persistent helper or field-level message | `VJoyHighlight` |
37
+ | Blocking decision or multi-field input | `VJoyDialog` |
38
+ | Slide-in panel with its own header/footer | `VJoyDrawer` |
39
+ | Actions that are always visible at the bottom of a form (not selection-driven) | Page layout / form footer — not a floating bar |
40
+ | Extra CTAs when the page already has bottom buttons for the same flow | Existing page footer — don’t duplicate actions |
41
+ | Custom fixed bottom bar with ad-hoc CSS | Still use `VJoyFloatingActionsBar` + Joy tokens |
42
+
43
+ ---
44
+
45
+ ## How it works
46
+
47
+ ### Anatomy
48
+
49
+ | Part | Required? | What it is |
50
+ | --- | --- | --- |
51
+ | Teleport host | Yes | Renders into `appendTo` (default `body`) after mount |
52
+ | Bar container | Yes | White card (`joy-bgcolor-neutral-0`), elevation-2, radius-4 |
53
+ | Inner row | Yes | Flex row; horizontal alignment from `justify` |
54
+ | Content slot | No | Left area — selection summary, avatars, short copy |
55
+ | Actions slot | Yes (content) | Right area — one or more `VJoyButton` (or compatible controls) |
56
+ | Scoped modifier | No | `floating-actions-bar--scoped` when `appendTo` is not `body` |
57
+
58
+ ### Default values
59
+
60
+ - `height` defaults to **`92px`**
61
+ - `appendTo` defaults to **`body`**
62
+ - `justify` defaults to **`space-between`**
63
+
64
+ Props and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
65
+
66
+ ### Layout and teleport
67
+
68
+ 1. **Mount** — the bar teleports only after `onMounted` (avoids SSR / hydration issues).
69
+ 2. **Desktop (default `appendTo`)** — `position: fixed`, ~80% width, centered, offset from bottom (`--joy-core-spacing-6`), respects `--layout-padding-left`.
70
+ 3. **Mobile (≤ 991px)** — full width, flush to bottom, square corners.
71
+ 4. **Scoped target** — when `appendTo` is not `body`, desktop uses `position: sticky`; mobile still uses `position: fixed`.
72
+
73
+ **Visibility** is controlled by the parent — wrap in `v-if` / `v-show` when selection or draft state changes. The component does not manage open/close itself.
74
+
75
+ ---
76
+
77
+ ## Variants
78
+
79
+ `VJoyFloatingActionsBar` has no color variant prop. Choose **layout** via `justify` and **composition** via the two slots.
80
+
81
+ ### `space-between` (default)
82
+
83
+ Content on the left, actions on the right — the common bulk-selection pattern (avatars + count + primary CTA).
84
+
85
+ Use when both slots carry meaning.
86
+
87
+ ### `flex-end`
88
+
89
+ Actions aligned to the trailing edge; content slot omitted or empty.
90
+
91
+ Use for a single CTA or a right-aligned button group (publish workflows, submit bars).
92
+
93
+ ### Other `justify` values
94
+
95
+ `center`, `space-around`, `space-evenly`, and `flex-start` are supported for edge layouts (Storybook, narrow canvases, centered toolbars). Prefer `space-between` or `flex-end` in product UI unless design specifies otherwise.
96
+
97
+ ### Not in the API: `primaryActionLabel`
98
+
99
+ Tests or legacy snippets may reference `primaryActionLabel`. It is **not** on `VJoyFloatingActionsBar` props — wire actions only through the **`actions`** slot.
100
+
101
+ ---
102
+
103
+ ## Sizes
104
+
105
+ Single default height — no `size` prop on the bar itself. Action density comes from **`VJoyButton` `size`** inside the `actions` slot (stories use `small`).
106
+
107
+ | Control | Use when |
108
+ | --- | --- |
109
+ | Default `height` (`92px`) | Standard button row + one line of content |
110
+ | Custom `height` | Taller content in the `content` slot (multi-line copy, stacked chips) — adjust only when default clips content |
111
+
112
+ **Don’t** hardcode bar width, shadow, or bottom offset in product CSS — the component owns layout tokens (`--joy-core-spacing-*`, `--joy-core-z-index-fixed-content`, `--layout-padding-left`).
113
+
114
+ ---
115
+
116
+ ## States
117
+
118
+ | State | What the user sees / can do |
119
+ | --- | --- |
120
+ | Hidden (default) | Parent does not render the bar — no selection / no draft context |
121
+ | Visible (desktop) | Floating card above page content; actions reachable while scrolling |
122
+ | Visible (mobile) | Full-width bottom bar; may cover page footer — account for padding |
123
+ | Scoped (`appendTo` ≠ `body`) | Bar sticks within a canvas (drawer, Storybook, embedded preview) |
124
+ | Content only | `content` slot filled, `actions` empty — rare; usually pair with actions |
125
+ | Actions only | `justify="flex-end"`; trailing CTAs without left context |
126
+ | Multiple actions | Gap between buttons (`--joy-core-spacing-3`); follow button hierarchy (`main` + `secondary` / `ghost`) |
127
+
128
+ ---
129
+
130
+ ## Best practices
131
+
132
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
133
+
134
+ ### When to show
135
+
136
+ - **SHOULD** show the bar only when context warrants it (selection active, unsaved draft, publish step) — hide it when context clears.
137
+ - **SHOULD** reflect **next steps in the current flow** in the `actions` slot — not a grab bag of unrelated shortcuts.
138
+ - **MUST NOT** use the bar for action feedback (saved, error, sent) — use `pushVJoySnackbar`.
139
+ - **MUST NOT** duplicate CTAs already fixed at the bottom of the same page for the same decision.
140
+
141
+ ### Hierarchy and composition
142
+
143
+ - **SHOULD** use at most one **`main`** button in `actions` per bar (see `VJoyButton` hierarchy).
144
+ - **SHOULD** order actions left-to-right by emphasis: `ghost` / `secondary` before `main` (Cancel · Save draft · Publish).
145
+ - **SHOULD** keep `content` slot to **short, scannable context** (count, avatars, one line of status) — not secondary page content.
146
+ - **SHOULD** use `justify="flex-end"` when there is no meaningful left content.
147
+
148
+ ### Implementation
149
+
150
+ - **MUST** use only documented props and `justify` enum values from MCP / `VJoyFloatingActionsBar.vue`.
151
+ - **MUST** place CTAs in the **`actions`** slot — no invented `primaryActionLabel` or similar props.
152
+ - **MUST** use Joy tokens — no custom `.floating-actions-bar` chrome (background, shadow, radius, position).
153
+ - **MUST NOT** invent props (`variant`, `open`, `primaryAction`, `visible`, …).
154
+ - **SHOULD** use `VJoyButton` with `size="small"` in the bar for consistent density.
155
+ - **SHOULD** set `appendTo` to a scoped selector in Storybook, drawers, or tests — default `body` for app pages.
156
+
157
+ ### Do / don’t
158
+
159
+ | Do | Don’t |
160
+ | --- | --- |
161
+ | `v-if` when selection count > 0 | Always-visible bar with no context |
162
+ | `content`: “3 freelancers selected” + avatars | Paragraphs of help text in `content` |
163
+ | `actions`: flow CTAs (`Create mission`, `Publish`) | Snackbar-style “Saved successfully” |
164
+ | One `main` + companions in `actions` | Two competing `main` buttons |
165
+ | Hide bar when context clears | Leave bar up after deselect all |
166
+ | `justify="flex-end"` for actions-only | Empty `content` with default `space-between` |
167
+
168
+ ---
169
+
170
+ ## Content
171
+
172
+ The bar carries **context on the left** and **action labels on the right**. Keep both scannable at a glance.
173
+
174
+ ### Content slot formula
175
+
176
+ **Count + object** or **short status** tied to the selection:
177
+
178
+ - ✅ 3 freelancers selected
179
+ - ✅ 12 files selected
180
+ - ✅ Unsaved changes
181
+
182
+ Use `VJoyText`, `VJoyAvatarsList`, and `VJoyWrapper` as in Storybook — don’t invent new summary patterns.
183
+
184
+ ### Action label formula
185
+
186
+ Follow **`VJoyButton`** rules — **verb + noun**, ≤ 25 characters:
187
+
188
+ - ✅ Create mission
189
+ - ✅ Publish
190
+ - ✅ Save draft
191
+ - ✅ Submit
192
+
193
+ Destructive or irreversible actions name the object: ✅ `Delete projects (3)`.
194
+
195
+ ### Writing rules
196
+
197
+ | Strength | Rule |
198
+ | --- | --- |
199
+ | **MUST** | Content slot states **what is selected or pending** — not marketing copy |
200
+ | **MUST** | Action labels describe the **next step**, not generic “Submit” / “Click” |
201
+ | **MUST NOT** | Use the bar for success/error toasts |
202
+ | **MUST NOT** | Push secondary page content into `content` to fill space |
203
+ | **SHOULD** | Include a numeric count when multiple items are selected |
204
+ | **SHOULD** | Match terminology with the list/table above (same noun: freelancer, file, mission) |
205
+ | **SHOULD** | Use sentence case for content; button labels follow button guidelines |
206
+ | **SHOULD** (FR) | Follow French grammar for counts and labels when the UI is localized |
207
+
208
+ ### Patterns
209
+
210
+ **Bulk selection** — `content`: compressed avatars + count. `actions`: single `main` CTA for the bulk operation.
211
+
212
+ **Publish / save workflow** — `justify="flex-end"`. `actions`: `ghost` Cancel · `secondary` Save draft · `main` Publish.
213
+
214
+ **Long form submit** — `actions` only, `justify="flex-end"`, one `main` Submit while the user scrolls — only if there is no duplicate footer CTA.
215
+
216
+ ---
217
+
218
+ ## Accessibility
219
+
220
+ Behaviors (what must happen), not slogans.
221
+
222
+ | Behavior | Expectation |
223
+ | --- | --- |
224
+ | Role | Layout container — not a dialog; actions inside use native buttons from `VJoyButton` |
225
+ | Name | Selection context in `content` must be readable text (not color-only); buttons keep their own labels |
226
+ | Keyboard | All `actions` controls must be focusable and operable via keyboard — use `VJoyButton`, not clickable `<div>`s |
227
+ | Focus | Bar does not trap focus; tab order follows DOM order (content then actions) |
228
+ | Visibility | Parent `v-if` should remove the bar from the tab order when context clears |
229
+ | Mobile | Full-width bar may cover content — ensure page has bottom padding or the bar hides when not needed |
230
+ | Motion | No enter/leave animation in the component — avoid jarring show/hide without app-level consideration |
231
+ | Z-index | Uses `--joy-core-z-index-fixed-content` — don’t stack opaque overlays that hide the bar’s actions without reason |
232
+
233
+ Target: **WCAG 2.2 AA** where the product requires it.
234
+
235
+ ---
236
+
237
+ ## Examples
238
+
239
+ ```vue
240
+ <script setup lang="ts">
241
+ import { computed, ref } from 'vue'
242
+ import {
243
+ VJoyFloatingActionsBar,
244
+ VJoyButton,
245
+ VJoyText,
246
+ VJoyWrapper,
247
+ VJoyAvatarsList,
248
+ VJoyAvatar,
249
+ } from '@maltjoy/core-vue'
250
+
251
+ const selectedIds = ref<string[]>(['a', 'b', 'c'])
252
+ const hasSelection = computed(() => selectedIds.value.length > 0)
253
+ </script>
254
+
255
+ <template>
256
+ <!-- Bulk selection -->
257
+ <VJoyFloatingActionsBar v-if="hasSelection">
258
+ <template #content>
259
+ <VJoyWrapper no-margin column-gap="3" align="center">
260
+ <VJoyAvatarsList compress>
261
+ <VJoyAvatar full-name="Alice Dupont" size="small" />
262
+ <VJoyAvatar full-name="Bob Martin" size="small" />
263
+ <VJoyAvatar full-name="Carol White" size="small" />
264
+ </VJoyAvatarsList>
265
+ <VJoyText preset="primary-400">
266
+ {{ selectedIds.length }} freelancers selected
267
+ </VJoyText>
268
+ </VJoyWrapper>
269
+ </template>
270
+ <template #actions>
271
+ <VJoyButton variant="main" size="small" label="Create mission" />
272
+ </template>
273
+ </VJoyFloatingActionsBar>
274
+
275
+ <!-- Actions only — publish workflow -->
276
+ <VJoyFloatingActionsBar justify="flex-end">
277
+ <template #actions>
278
+ <VJoyButton variant="ghost" size="small" label="Cancel" />
279
+ <VJoyButton variant="secondary" size="small" label="Save draft" />
280
+ <VJoyButton variant="main" size="small" label="Publish" />
281
+ </template>
282
+ </VJoyFloatingActionsBar>
283
+ </template>
284
+ ```
285
+
286
+ Storybook / scoped canvas — teleport into a host element:
287
+
288
+ ```vue
289
+ <VJoyFloatingActionsBar append-to="#my-canvas">
290
+ <template #actions>
291
+ <VJoyButton variant="main" size="small" label="Submit" />
292
+ </template>
293
+ </VJoyFloatingActionsBar>
294
+ ```
295
+
296
+ In Nuxt (or apps with auto-import), omit the import if `VJoyFloatingActionsBar` is already global.
297
+
298
+ ---
299
+
300
+ ## Related
301
+
302
+ | Component | Use when |
303
+ | --- | --- |
304
+ | `VJoyButton` | CTAs in the `actions` slot |
305
+ | `VJoyText` | Short status copy in `content` |
306
+ | `VJoyAvatarsList` / `VJoyAvatar` | Selected people in `content` |
307
+ | `VJoyWrapper` | Horizontal layout inside `content` |
308
+ | `pushVJoySnackbar` | Transient feedback after an action |
309
+ | `VJoyHighlight` | Inline persistent messages |
310
+ | `VJoyDialog` | Blocking confirm or form |
311
+ | `VJoyDrawer` | Side panel with its own action area |
312
+
313
+ ---
314
+
315
+ ## For agents
316
+
317
+ Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyFloatingActionsBar.dsds.json`](./JoyFloatingActionsBar.dsds.json).
318
+
319
+ ### Pick the right component
320
+
321
+ | If the intent is… | Emit… | Do not emit… |
322
+ | --- | --- | --- |
323
+ | Bulk / contextual bottom actions while scrolling | `VJoyFloatingActionsBar` + slots | Custom `position: fixed` div |
324
+ | Toast after save/send | `pushVJoySnackbar` | Floating bar with success text |
325
+ | Inline error under a field | `VJoyHighlight` | Bar in `content` slot |
326
+ | Modal confirm | `VJoyDialog` | Bar with only Cancel/Confirm |
327
+ | Always-on form footer (no selection) | Page footer layout | `VJoyFloatingActionsBar` always mounted |
328
+ | Primary CTA prop | `#actions` slot + `VJoyButton` | `primaryActionLabel` (invalid) |
329
+
330
+ ### Hard rules
331
+
332
+ 1. **MUST** call `joy_get_component_info("VJoyFloatingActionsBar")` (or read `VJoyFloatingActionsBar.vue`) before generating props.
333
+ 2. **MUST** put buttons in the **`actions`** slot — no invented action props.
334
+ 3. **MUST** control visibility with parent `v-if` / `v-show` when context applies.
335
+ 4. **MUST** use only `justify` values from the documented enum.
336
+ 5. **MUST NOT** invent props (`primaryActionLabel`, `open`, `variant`, `visible`, …).
337
+ 6. **MUST NOT** override `.floating-actions-bar` position, width, shadow, or background in app CSS.
338
+ 7. **SHOULD** use `justify="flex-end"` when `content` is empty.
339
+ 8. **SHOULD** use `VJoyButton` `size="small"` in `actions`.
340
+ 9. **SHOULD** use at most one `variant="main"` button per bar.
341
+
342
+ ### Checklist
343
+
344
+ - [ ] Correct component (or named alternative from table above)
345
+ - [ ] Props / `justify` enum from MCP only
346
+ - [ ] Actions in `#actions` slot — no `primaryActionLabel`
347
+ - [ ] Parent controls show/hide when context changes
348
+ - [ ] No invented props / no custom bar chrome CSS
349
+ - [ ] Not used for snackbar-style feedback
350
+ - [ ] No duplicate footer CTAs for the same flow
351
+ - [ ] Button labels follow `VJoyButton` content rules
352
+ - [ ] `content` is short context — not secondary page content
353
+
354
+ ---
355
+
356
+ ## DSDS mapping
357
+
358
+ This Markdown mirrors [`JoyFloatingActionsBar.dsds.json`](./JoyFloatingActionsBar.dsds.json) (DSDS **0.15.2**).
359
+
360
+ | Section here | DSDS block |
361
+ | --- | --- |
362
+ | When to use / not | `use-cases` |
363
+ | Anatomy / layout | `anatomy` |
364
+ | `justify` / composition | `variants` |
365
+ | Height / responsive layout | `design-specifications` |
366
+ | States | `states` |
367
+ | Best practices / content rules | `guidelines` (+ `content`) |
368
+ | Accessibility | `accessibility` |
369
+ | Examples | `sections` |
370
+ | For agents | `agentDocumentBlocks` |
371
+ | Props detail | `api` in JSON + Joy MCP |
372
+ | Imports | `imports` in JSON |
@@ -0,0 +1,325 @@
1
+ ---
2
+ component: VJoyFormError
3
+ status: draft
4
+ language: en
5
+ dsds: JoyFormError.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # Form error
10
+
11
+ Use **`VJoyFormError`** when a form field or group failed validation and the user needs a **persistent, inline** explanation directly below the control.
12
+
13
+ It shows a warning icon, error-colored text (`--joy-color-error-50`), and `role="alert"` so assistive tech announces the message. Pass a string array via `errors`, or use the default slot when you need custom markup (for example a hand-built `<ul>` / `<li>` list).
14
+
15
+ | | |
16
+ | --- | --- |
17
+ | **Code** | `VJoyFormError` from `@maltjoy/core-vue` |
18
+ | **Design** | [Figma — Joy Core Design System](https://www.figma.com/design/jfndp2QBJGS9yeuWbeGuvD/) |
19
+ | **Storybook** | [VJoyFormError docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-forms-vjoyformerror--docs) |
20
+ | **DSDS (machine)** | [`JoyFormError.dsds.json`](./JoyFormError.dsds.json) |
21
+ | **Live API** | `joy_get_component_info("VJoyFormError")` |
22
+
23
+ ---
24
+
25
+ ## When to use this component
26
+
27
+ Use a form error when validation failed for a specific field or group and the user must read **what went wrong** and **how to fix it** before continuing.
28
+
29
+ Place it **immediately below** the related control (input, select, checkbox group, dropzone, etc.). Pair it with the field’s `invalid` state so error styling is consistent on both the control and the message.
30
+
31
+ For a single message, pass one string in `errors`. For several related failures on the same field, pass multiple strings or render a `<ul>` / `<li>` list in the default slot.
32
+
33
+ ### When not to use this component
34
+
35
+ | Need | Use instead |
36
+ | --- | --- |
37
+ | Page-level or section-level failure (not tied to one field) | `VJoyHighlight` (`level="error"`) |
38
+ | Transient feedback after an action (saved, failed request) | `pushVJoySnackbar` |
39
+ | Blocking decision or multi-step correction | `VJoyDialog` |
40
+ | Helper text before any error occurs | `VJoyLabel` legend slot, field description, or `VJoyHighlight` (`level="info"`) |
41
+ | Custom red text / icon row with ad-hoc CSS | Still use `VJoyFormError` + Joy tokens — don’t reinvent error chrome |
42
+
43
+ > **Deprecated:** `visible` — inject or remove the component with `v-if` / `v-show` instead. The prop remains in the API for legacy markup but should not be used on new work.
44
+
45
+ > **Not in the API:** `message` — pass copy via the `errors` prop or the default slot. Do not emit `message="…"`.
46
+
47
+ ---
48
+
49
+ ## How it works
50
+
51
+ ### Anatomy
52
+
53
+ | Part | Required? | What it is |
54
+ | --- | --- | --- |
55
+ | Root container | Yes | `div` with `data-joy-form-error`, `role="alert"`, class `joy-form-error` |
56
+ | Warning icon | Yes | `VJoyIcon` (`warning-triangle`), class `joy-icon-error` |
57
+ | Message body | Yes | Default slot **or** auto-generated `<ul>` / `<li>` from `errors` |
58
+ | Bottom spacing | Yes* | Default `margin-bottom: var(--joy-core-spacing-5)` — *removed when `noMargin` is true |
59
+
60
+ The root is **not rendered** when there is no default slot content and `errors` is empty or omitted.
61
+
62
+ ### Default values
63
+
64
+ - `noMargin` defaults to **`false`**
65
+ - `visible` defaults to **`true`** (deprecated — prefer conditional rendering)
66
+ - `errors` is **optional** — omit when using the default slot
67
+
68
+ Props and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
69
+
70
+ ### Content modes
71
+
72
+ | Mode | When to use |
73
+ | --- | --- |
74
+ | `errors` prop | One or more plain strings; component renders `<ul>` / `<li>` automatically |
75
+ | Default slot | Custom HTML (multiple lines, mixed content, framework-templated markup) |
76
+
77
+ When both slot and `errors` are provided, the **slot takes precedence** (`errors` is ignored).
78
+
79
+ ---
80
+
81
+ ## States
82
+
83
+ | State | What the user sees / can do |
84
+ | --- | --- |
85
+ | Hidden (no content) | Nothing in the DOM — no `errors`, no default slot |
86
+ | Visible (single error) | Icon + one line of error text |
87
+ | Visible (multiple errors) | Icon + bulletless list (`<ul>` / `<li>`) |
88
+ | `noMargin` | Same visible error without bottom margin (parent handles spacing, e.g. `VJoyFormGroup`) |
89
+
90
+ There is no hover, focus, or disabled state — the component is presentational feedback, not interactive.
91
+
92
+ ---
93
+
94
+ ## Best practices
95
+
96
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
97
+
98
+ ### Placement and pairing
99
+
100
+ - **MUST** place `VJoyFormError` directly below the field or group it describes.
101
+ - **MUST** set `invalid` on the related form control when showing an error — red border or outline alone is not enough.
102
+ - **MUST** show the error only when validation has failed (typically `v-if` on a boolean or error string).
103
+ - **SHOULD** show one focused message per field when possible; use multiple list items only when several distinct fixes are required.
104
+ - **MUST NOT** use `VJoyFormError` for success or neutral helper copy.
105
+
106
+ ### Implementation
107
+
108
+ - **MUST** use only documented props (`errors`, `noMargin`) and the default slot from MCP or `VJoyFormError.vue`.
109
+ - **MUST** style with Joy tokens — no custom `.joy-form-error` chrome (color, icon, spacing).
110
+ - **MUST NOT** invent props (`message`, `variant`, `size`, `level`, …).
111
+ - **MUST NOT** rely on the deprecated `visible` prop — use `v-if` / `v-show`.
112
+ - **SHOULD** use `noMargin` when the parent layout (`VJoyFormGroup`, `VJoyWrapper`) already applies field spacing.
113
+ - **SHOULD** prefer `errors` for simple string messages; use the slot only when markup cannot be expressed as strings.
114
+
115
+ ### Do / don’t
116
+
117
+ | Do | Don’t |
118
+ | --- | --- |
119
+ | `invalid` on field + `VJoyFormError` below | Red field border with no message |
120
+ | `:errors="['Enter a valid email address']"` | `message="…"` prop |
121
+ | `v-if="showError"` to toggle visibility | Deprecated `visible={false}` in DOM |
122
+ | Short, actionable copy | Generic `Invalid` or `Error` |
123
+ | `noMargin` inside `VJoyFormGroup` when spacing doubles | Stacking default margin on top of group gap |
124
+
125
+ ---
126
+
127
+ ## Content
128
+
129
+ Error copy must tell the user what failed and what to do next.
130
+
131
+ ### Message formula
132
+
133
+ **What went wrong + how to fix it** (imperative or instructive):
134
+
135
+ - ✅ `Enter a valid email address`
136
+ - ✅ `Password must be at least 8 characters`
137
+ - ✅ `Choose a delivery method`
138
+
139
+ Avoid blame, jargon, or internal codes unless the user needs them.
140
+
141
+ ### Single vs multiple messages
142
+
143
+ | Pattern | When |
144
+ | --- | --- |
145
+ | One string in `errors` | Single rule failed (format, required, length) |
146
+ | Multiple `errors` entries or `<li>` items | Several independent fixes on the same field (rare — prefer one clear message) |
147
+
148
+ Keep list items parallel (same grammatical structure).
149
+
150
+ ### Writing rules
151
+
152
+ | Strength | Rule |
153
+ | --- | --- |
154
+ | **MUST** | State what is wrong and how to fix it — ✅ `Enter a valid email address` · ❌ `Invalid` |
155
+ | **MUST** | Use sentence case; no trailing period for single-line errors unless product copy requires it |
156
+ | **MUST NOT** | Repeat the field label as the entire message — ❌ `Email` |
157
+ | **MUST NOT** | Expose raw API / stack traces to end users |
158
+ | **SHOULD** | Keep messages ≤ ~80 characters when possible |
159
+ | **SHOULD** | Match terminology with the field label (`Email address` label → `Enter a valid email address`) |
160
+ | **SHOULD** | Localize all strings passed to `errors` or the slot |
161
+ | **SHOULD** (FR) | Use correct gender/agreement for past-participle adjectives in French error strings |
162
+
163
+ ### Patterns
164
+
165
+ **Required field on submit** — Show after submit or blur: `You must enter a name`.
166
+
167
+ **Format validation** — After blur or when format is unambiguous: `Enter a valid email address`.
168
+
169
+ **Group validation** — One `VJoyFormError` below `VJoyRadioGroup` / `VJoyCheckboxGroup`: `Select one option to continue`.
170
+
171
+ **Composed fields** — `VJoyTagsInput` and similar components use the default slot for multiple error types in one list.
172
+
173
+ ---
174
+
175
+ ## Accessibility
176
+
177
+ Behaviors (what must happen), not slogans.
178
+
179
+ | Behavior | Expectation |
180
+ | --- | --- |
181
+ | Role | `role="alert"` on the root — announces when the error appears |
182
+ | Visibility | Render with `v-if` when there is an error; component omits itself when `errors` is empty and slot is empty |
183
+ | Name | Message text is plain content inside the alert — no extra `aria-label` needed when copy is descriptive |
184
+ | Icon | Warning triangle is decorative; meaning is carried by the text |
185
+ | Field association | Pair with `invalid` on the control; associate label + field with `VJoyLabel` / `for` + `id` |
186
+ | Timing | Show errors after submit, blur, or when the value is clearly invalid — avoid shouting on first keystroke unless format is unambiguous |
187
+ | Color | Error color (`--joy-color-error-50`) supplements text — never the only signal |
188
+
189
+ Target: **WCAG 2.2 AA** where the product requires it.
190
+
191
+ ---
192
+
193
+ ## Examples
194
+
195
+ ```vue
196
+ <script setup lang="ts">
197
+ import { ref } from 'vue'
198
+ import {
199
+ VJoyInput,
200
+ VJoyFormError,
201
+ VJoyFormGroup,
202
+ VJoyLabel,
203
+ VJoyCheckbox,
204
+ } from '@maltjoy/core-vue'
205
+
206
+ const email = ref('')
207
+ const showEmailError = ref(false)
208
+ const accepted = ref(false)
209
+
210
+ function validateEmail() {
211
+ showEmailError.value = !email.value.includes('@')
212
+ }
213
+ </script>
214
+
215
+ <template>
216
+ <!-- Single error via errors prop -->
217
+ <VJoyFormGroup>
218
+ <VJoyInput
219
+ v-model="email"
220
+ name="email"
221
+ label="Email address"
222
+ :invalid="showEmailError"
223
+ @blur="validateEmail"
224
+ />
225
+ <VJoyFormError
226
+ v-if="showEmailError"
227
+ :errors="['Enter a valid email address']"
228
+ />
229
+ </VJoyFormGroup>
230
+
231
+ <!-- Multiple errors via slot -->
232
+ <VJoyFormError v-if="showEmailError">
233
+ <ul>
234
+ <li>Email is not valid</li>
235
+ <li>Password is not strong enough</li>
236
+ </ul>
237
+ </VJoyFormError>
238
+
239
+ <!-- Checkbox with noMargin inside a group -->
240
+ <VJoyFormGroup>
241
+ <VJoyLabel for="terms">Terms and conditions</VJoyLabel>
242
+ <VJoyCheckbox id="terms" v-model="accepted" value="yes">
243
+ I accept the terms
244
+ </VJoyCheckbox>
245
+ <VJoyFormError
246
+ v-if="!accepted"
247
+ no-margin
248
+ :errors="['You must accept the terms and conditions']"
249
+ />
250
+ </VJoyFormGroup>
251
+ </template>
252
+ ```
253
+
254
+ In Nuxt (or apps with auto-import), omit the import if `VJoyFormError` is already global.
255
+
256
+ ---
257
+
258
+ ## Related
259
+
260
+ | Component | Use when |
261
+ | --- | --- |
262
+ | `VJoyInput` / `VJoyTextarea` / `VJoySelect` | Fields that accept `invalid` and sit above the error |
263
+ | `VJoyLabel` | Accessible label and optional legend above the field |
264
+ | `VJoyFormGroup` | Groups label, control, and error with consistent spacing |
265
+ | `VJoyWrapper` | Column layout between fields when not using `VJoyFormGroup` |
266
+ | `VJoyRadioGroup` / `VJoyCheckboxGroup` | Group-level validation with one error below the set |
267
+ | `VJoyHighlight` | Section- or page-level error/info banners |
268
+ | `pushVJoySnackbar` | Transient action feedback, not inline validation |
269
+
270
+ ---
271
+
272
+ ## For agents
273
+
274
+ Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyFormError.dsds.json`](./JoyFormError.dsds.json).
275
+
276
+ ### Pick the right component
277
+
278
+ | If the intent is… | Emit… | Do not emit… |
279
+ | --- | --- | --- |
280
+ | Inline validation under a field | `VJoyFormError` + `invalid` on the field | Raw `<p class="error">` |
281
+ | Single error string | `VJoyFormError` with `:errors="['…']"` | `message="…"` prop |
282
+ | Multiple errors, custom markup | `VJoyFormError` + default slot (`<ul>` / `<li>`) | Multiple separate alert divs |
283
+ | Page / banner error | `VJoyHighlight` `level="error"` | `VJoyFormError` at page top |
284
+ | Toast after save/fail | `pushVJoySnackbar` | `VJoyFormError` |
285
+
286
+ ### Hard rules
287
+
288
+ 1. **MUST** call `joy_get_component_info("VJoyFormError")` (or read `VJoyFormError.vue`) before generating props.
289
+ 2. **MUST** pair with `invalid` on the related form control when validation failed.
290
+ 3. **MUST** pass messages via `errors` (string array) or the default slot — **not** a `message` prop.
291
+ 4. **MUST** use `v-if` (or parent conditional) to show/hide errors — **not** deprecated `visible`.
292
+ 5. **MUST NOT** invent props (`message`, `variant`, `size`, `level`, …) or custom `.joy-form-error` CSS.
293
+ 6. **MUST NOT** render `VJoyFormError` when there is no error content (empty `errors` renders nothing).
294
+ 7. **SHOULD** use `noMargin` when nested in `VJoyFormGroup` or when parent gap already applies.
295
+ 8. **SHOULD** keep copy actionable: what failed + how to fix.
296
+
297
+ ### Checklist
298
+
299
+ - [ ] Correct component (inline field error, not snackbar/highlight)
300
+ - [ ] Props from MCP / source only (`errors`, `noMargin`, default slot)
301
+ - [ ] Related field has `invalid` when error is shown
302
+ - [ ] `v-if` (or equivalent) — no `visible` prop
303
+ - [ ] No `message` prop / no invented props
304
+ - [ ] No custom error chrome CSS
305
+ - [ ] Actionable error copy (not bare `Invalid`)
306
+ - [ ] Placed directly below the described control
307
+
308
+ ---
309
+
310
+ ## DSDS mapping
311
+
312
+ This Markdown mirrors [`JoyFormError.dsds.json`](./JoyFormError.dsds.json) (DSDS **0.15.2**).
313
+
314
+ | Section here | DSDS block |
315
+ | --- | --- |
316
+ | When to use / not | `use-cases` |
317
+ | Anatomy | `anatomy` |
318
+ | States | `states` |
319
+ | Best practices / content rules | `guidelines` (+ `content`) |
320
+ | Accessibility | `accessibility` |
321
+ | Examples | `sections` |
322
+ | For agents | `agentDocumentBlocks` |
323
+ | Props detail | `api` in JSON + Joy MCP |
324
+ | Imports | `imports` in JSON |
325
+ | Error color / typography | `design-specifications` (`--form-error-color`, `--joy-color-error-50`, `primary-300`) |