@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,425 @@
1
+ ---
2
+ component: VJoyDialog
3
+ status: draft
4
+ language: en
5
+ dsds: JoyDialog.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # Dialog
10
+
11
+ Use **`VJoyDialog`** when you need a modal overlay that interrupts the current task — confirmations, forms, multi-step flows, or focused messaging.
12
+
13
+ It teleports to `body` by default, supports header/body/footer slots, optional banner imagery, confirm/cancel CTAs, and exposes async `show()` / `hide()` methods. Use **`VJoyDialogTrigger`** when a declarative open trigger is simpler than imperative refs.
14
+
15
+ | | |
16
+ | --- | --- |
17
+ | **Code** | `VJoyDialog` from `@maltjoy/core-vue` |
18
+ | **Design** | [Figma — Joy Core Design System](https://www.figma.com/design/jfndp2QBJGS9yeuWbeGuvD/%F0%9F%9F%A0--Joy---Core-Design-System--official-) |
19
+ | **Storybook** | [VJoyDialog docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-overlays-vjoydialog--docs) |
20
+ | **DSDS (machine)** | [`JoyDialog.dsds.json`](./JoyDialog.dsds.json) |
21
+ | **Live API** | `joy_get_component_info("VJoyDialog")` |
22
+
23
+ ---
24
+
25
+ ## When to use this component
26
+
27
+ Use a dialog when the user must read, decide, or complete something before returning to the page behind it — for example confirming a destructive action, collecting a short form, or presenting a focused announcement.
28
+
29
+ Dialogs block interaction with the underlying page (modal overlay) and should be dismissed explicitly or via a clear cancel path.
30
+
31
+ ### When not to use this component
32
+
33
+ | Need | Use instead |
34
+ | --- | --- |
35
+ | Slide-in panel from the edge (filters, details, long forms) | `VJoyDrawer` |
36
+ | Lightweight contextual hint on hover/focus | `VJoyTooltip` |
37
+ | Inline expandable section on the same page | `VJoyAccordion` or page layout — not a dialog |
38
+ | Toast / transient feedback after an action | `VJoyToast` |
39
+ | Custom modal markup with ad-hoc CSS | Still use `VJoyDialog` + Joy tokens — don't reinvent overlay chrome |
40
+
41
+ > **Experimental:** `patternBrand` activates a centered brand layout with decorative shapes. Treat it as experimental until promoted; confirm with design before broad rollout.
42
+
43
+ ---
44
+
45
+ ## How it works
46
+
47
+ ### Anatomy
48
+
49
+ | Part | Required? | What it is |
50
+ | --- | --- | --- |
51
+ | Overlay | Yes | Semi-transparent backdrop; click dismisses unless `patternConfirm` |
52
+ | Container (`joy-dialog__inner`) | Yes | White card with elevation, padding, and max width |
53
+ | Preheader (`dialog-preheader`) | No | Short meta above the title (e.g. tag, badge) |
54
+ | Header (`dialog-header`) | Yes (content) | Dialog title — linked via `aria-labelledby` |
55
+ | Subheader (`dialog-subheader`) | No | Supporting description below the title |
56
+ | Close button | No* | Top-right `VJoyIconButton` (*hidden when `patternConfirm`) |
57
+ | Body (`dialog-body`) | Yes (content) | Main content; scrolls when tall |
58
+ | Footer | No | Cancel / confirm CTAs via props or slots |
59
+ | Banner | No | Optional top image via `bannerSrc` |
60
+ | Brand shapes | No | Decorative shapes when `patternBrand` is true |
61
+ | Indicators (`dialog-indicators`) | No | Step dots for multi-dialog flows (`VJoyIndicators`) |
62
+
63
+ ### Default values
64
+
65
+ - `size` defaults to **`default`** (580px container width; `large` → 780px)
66
+ - `open` defaults to **`false`**
67
+ - `teleport` defaults to **`body`**
68
+ - `preventBodyScroll` defaults to **`true`** (locks page scroll while open)
69
+ - `closeLabel` defaults to **`"Close dialog"`**
70
+ - `buttonSize` defaults to **`medium`** (footer CTAs)
71
+ - `bannerHeight` defaults to **`250`** (px, when `bannerSrc` is set)
72
+ - `patternConfirm` defaults to **`false`**
73
+ - `patternBrand` defaults to **`false`**
74
+
75
+ Props, events, slots, and exposed methods: use Joy MCP (`joy_get_component_info`, `joy_get_component_types`) or Storybook — this page focuses on **when** and **how**, not a full API dump.
76
+
77
+ ### Open / close lifecycle
78
+
79
+ 1. **Open** — set `open` or call `show()` on the exposed ref. Body scroll is prevented when `preventBodyScroll` is true.
80
+ 2. **Dismiss** — close icon, backdrop click, Escape key, or cancel CTA (default wiring). All fire `dialog:hide` when the leave transition starts.
81
+ 3. **Confirm** — default confirm CTA emits `dialog:confirm` only; you still handle persistence and closing.
82
+ 4. **Unmount while open** — emits `dialog:before-unmount` and restores body scroll.
83
+
84
+ `show()` and `hide()` are **async**. `hide({ fireHideEvent: false })` closes without emitting `dialog:hide`.
85
+
86
+ ---
87
+
88
+ ## Variants
89
+
90
+ Dialogs don't have color variants. Choose layout **patterns** and **size** by context.
91
+
92
+ ### Default pattern
93
+
94
+ Standard left-aligned header, optional subheader, scrollable body, footer CTAs right-aligned. Backdrop click, Escape, and close icon all dismiss.
95
+
96
+ Use for most product dialogs — forms, confirmations, informational modals.
97
+
98
+ ### Confirm pattern (`patternConfirm`)
99
+
100
+ Hides the close icon, disables backdrop dismiss, and ignores Escape. The user must choose a footer CTA (typically cancel or confirm).
101
+
102
+ Use when accidental dismissal would lose work or cause harm — destructive confirms, irreversible choices, or incomplete required input.
103
+
104
+ Avoid for low-stakes content where users expect quick escape (use the default pattern).
105
+
106
+ ### Brand pattern (`patternBrand`) — experimental
107
+
108
+ Centered text layout with decorative primary-colored shapes. Works with `patternConfirm`. Shapes cannot be disabled.
109
+
110
+ Use for brand moments, onboarding highlights, or marketing-style announcements approved by design.
111
+
112
+ Avoid combining with `bannerSrc` — they are not meant to work together. If you use an image in the body, set an explicit `width` on the `<img>`.
113
+
114
+ ### Banner image (`bannerSrc`)
115
+
116
+ Full-width image strip at the top of the dialog card.
117
+
118
+ Use for visual context (illustration, hero image) that supports the title.
119
+
120
+ Avoid when `patternBrand` is active. Prefer Joy DAM assets with known dimensions.
121
+
122
+ ### Not in the API: extra sizes
123
+
124
+ Only `default` and `large` exist in `TJoyDialogSizes`. Do not invent `small` / `medium` dialog sizes. Use `size="large"` for wider content; width tokens live in `--dialog-width` (override via CSS custom property only when design approves).
125
+
126
+ ---
127
+
128
+ ## Sizes
129
+
130
+ Container width is token-driven inside the component — **don't hardcode pixel widths** in apps.
131
+
132
+ | Size | Use when |
133
+ | --- | --- |
134
+ | `default` | Standard dialogs (580px on desktop) |
135
+ | `large` | Wider content — tables, two-column forms, rich media (780px on desktop) |
136
+
137
+ On viewports ≤ 767px the dialog becomes full-screen. Footer CTAs stack vertically on very narrow widths (≤ 400px).
138
+
139
+ Optional CSS overrides (use sparingly, with design approval):
140
+
141
+ - `--dialog-width` — container width
142
+ - `--dialog-padding` — inner padding (all sides)
143
+
144
+ ---
145
+
146
+ ## States
147
+
148
+ | State | What the user sees / can do |
149
+ | --- | --- |
150
+ | Closed | Not in DOM flow (`v-if="isOpen"`); no overlay |
151
+ | Opening | Enter transition (scale + fade, 300ms) |
152
+ | Open | Modal overlay; focusable body; dismiss via close / backdrop / Escape (unless `patternConfirm`) |
153
+ | Closing | Leave transition (100ms); `dialog:hide` fires at start |
154
+ | Closed (after transition) | Removed from DOM; `dialog:after-hide` fires; body scroll restored |
155
+ | Confirm pattern | No close icon; backdrop not dismissible; Escape disabled |
156
+ | Scrollable body | Long content scrolls inside body (`max-height` ~580px on desktop) |
157
+ | Demo / docs | `demoMode` prevents hide (Storybook only — not for production) |
158
+
159
+ Prefer `loading` on footer `VJoyButton` instances during async confirm work instead of silently disabling the dialog.
160
+
161
+ ---
162
+
163
+ ## Best practices
164
+
165
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
166
+
167
+ ### Hierarchy and placement
168
+
169
+ - **SHOULD** use one dialog per decision — don't stack unrelated modals.
170
+ - **SHOULD** use `dialog-indicators` + `VJoyIndicators` when navigating a sequence of related dialogs.
171
+ - **MUST NOT** use a dialog for content that fits inline on the page.
172
+
173
+ ### Implementation
174
+
175
+ - **MUST** use only documented props and enum values (MCP / `JoyDialog.types.ts`).
176
+ - **MUST** teleport to `body` in production (`teleport` default) — `disableTeleport` is for tests/docs.
177
+ - **MUST** wire `dialog:hide` (or call `hide()`) when using custom `dialog-cancel` / `dialog-confirm` slots.
178
+ - **MUST NOT** invent props (`width`, `variant`, `theme`, …).
179
+ - **MUST NOT** override `.joy-dialog` chrome (background, shadow, radius, overlay) with app CSS.
180
+ - **MUST NOT** use `demoMode` outside Storybook.
181
+
182
+ ### Interaction
183
+
184
+ - **MUST** provide a visible dismiss path in the default pattern (close icon and/or cancel CTA).
185
+ - **SHOULD** use `patternConfirm` only when dismissal risk is real.
186
+ - **SHOULD** call `show()` / `hide()` with `await` when chaining transitions or focus management.
187
+ - **SHOULD** listen to `dialog:after-open` before moving focus into the first field.
188
+
189
+ ### Footer CTAs
190
+
191
+ - **SHOULD** use `cancelText` / `confirmText` for simple cases (default `VJoyButton` wiring).
192
+ - **SHOULD** use `dialog-cancel` / `dialog-confirm` slots when you need custom variants, icons, or sizes — and **MUST** call `hide()` yourself on cancel.
193
+ - **SHOULD** use one `main` confirm CTA per dialog surface (see `VJoyButton` guidelines).
194
+
195
+ ### Do / don't
196
+
197
+ | Do | Don't |
198
+ | --- | --- |
199
+ | `VJoyDialogTrigger` for simple open buttons | Reimplement overlay + z-index stack |
200
+ | `patternConfirm` for destructive confirms | Default pattern with no cancel CTA |
201
+ | Explicit `closeLabel` when locale ≠ English default | Leave default "Close dialog" in localized apps |
202
+ | `size="large"` for wide tables/forms | Hardcode `width: 780px` on a wrapper |
203
+ | `bannerSrc` **or** `patternBrand` | Both at once |
204
+ | Set `width` on body images in brand pattern | Unsized images that blow layout |
205
+
206
+ ---
207
+
208
+ ## Content
209
+
210
+ Dialogs carry the highest-stakes copy on a surface. Title, description, and CTAs must be scannable and action-oriented.
211
+
212
+ ### Title formula
213
+
214
+ **Short noun phrase or question** — state the decision or topic, not the implementation:
215
+
216
+ - ✅ Delete project brief?
217
+ - ✅ Update billing address
218
+ - ✅ New feature: AI suggestions
219
+
220
+ **Subheader** — one sentence of context or consequence. Don't repeat the title.
221
+
222
+ ### Body copy
223
+
224
+ - **SHOULD** keep body text concise; link out for long legal or help content.
225
+ - **MUST** explain consequences before destructive confirms (what is deleted, whether it's reversible).
226
+ - **SHOULD NOT** bury the primary action below long paragraphs.
227
+
228
+ ### Footer CTA rules
229
+
230
+ Follow `VJoyButton` content rules. Dialog-specific expectations:
231
+
232
+ | Strength | Rule |
233
+ | --- | --- |
234
+ | **MUST** | Confirm CTA names the outcome — ✅ `Delete project`, `Save changes` |
235
+ | **MUST** | Cancel / dismiss CTA is neutral — ✅ `Cancel`, `Not now` |
236
+ | **MUST NOT** | Vague confirm — ❌ `OK`, `Yes` (unless paired with an unmistakable title) |
237
+ | **MUST NOT** | Guilt-trip cancel — ❌ `No thanks`, `I don't want to save` |
238
+ | **SHOULD** | Destructive confirm repeats the object — ✅ `Delete 6 files` |
239
+ | **SHOULD** | Match title wording between header and confirm CTA |
240
+ | **SHOULD** | ≤ 25 characters per button label; wrap, don't truncate |
241
+
242
+ ### Patterns
243
+
244
+ **Destructive confirm** — Title states the action; body states impact; `patternConfirm` with cancel + destructive-styled confirm (custom slot if needed). Example: title `Delete project brief?`, body `This cannot be undone.`, CTAs `Cancel` + `Delete project brief`.
245
+
246
+ **Informational** — Title + short body; single `main` or `primary` confirm (`Got it`, `Continue`). Default dismiss paths are enough; `patternConfirm` usually unnecessary.
247
+
248
+ **Multi-step** — Use `dialog-indicators` with `VJoyIndicators`; keep titles consistent per step; final step confirm names completion (`Finish setup`).
249
+
250
+ **Brand / promo (experimental)** — Centered copy; joyful tone allowed; still one clear primary CTA. Images need explicit dimensions.
251
+
252
+ **Localized apps** — Translate `closeLabel`, `cancelText`, `confirmText`, and all slot content. French copy may need articles/pronouns per `VJoyButton` FR guidance.
253
+
254
+ ---
255
+
256
+ ## Accessibility
257
+
258
+ Behaviors (what must happen), not slogans.
259
+
260
+ | Behavior | Expectation |
261
+ | --- | --- |
262
+ | Role | `role="dialog"` with `aria-modal="true"` |
263
+ | Name | Title in `dialog-header` referenced by `aria-labelledby` (`{id}-header`) |
264
+ | Description | Subheader content in `#dialogDescription` when present |
265
+ | Close control | `VJoyIconButton` with `closeLabel` (default: "Close dialog") |
266
+ | Keyboard | **Escape** dismisses unless `patternConfirm` |
267
+ | Focus | Body region is focusable (`tabindex="0"`); move focus into dialog on open when implementing custom flows |
268
+ | Scroll | Page scroll locked while open (`preventBodyScroll`) |
269
+ | Confirm pattern | User is not trapped without a labeled footer action |
270
+ | Motion | Enter/leave transitions; respect `prefers-reduced-motion` at app level if required |
271
+
272
+ Target: **WCAG 2.2 AA** where the product requires it.
273
+
274
+ ---
275
+
276
+ ## Examples
277
+
278
+ ```vue
279
+ <script setup lang="ts">
280
+ import { ref } from 'vue'
281
+ import { VJoyDialog } from '@maltjoy/core-vue'
282
+
283
+ const dialog = ref<InstanceType<typeof VJoyDialog>>()
284
+
285
+ async function openDialog() {
286
+ await dialog.value?.show()
287
+ }
288
+
289
+ async function onConfirm() {
290
+ // persist, then close
291
+ await dialog.value?.hide()
292
+ }
293
+ </script>
294
+
295
+ <template>
296
+ <!-- Basic dialog with prop-driven CTAs -->
297
+ <VJoyDialog
298
+ ref="dialog"
299
+ cancel-text="Cancel"
300
+ confirm-text="Save changes"
301
+ @dialog:confirm="onConfirm"
302
+ @dialog:hide="() => {}"
303
+ >
304
+ <template #dialog-header>Update profile</template>
305
+ <template #dialog-subheader>Changes apply to your public listing.</template>
306
+ <template #dialog-body>
307
+ <!-- form fields -->
308
+ </template>
309
+ </VJoyDialog>
310
+
311
+ <VJoyButton variant="primary" label="Edit profile" @click="openDialog" />
312
+
313
+ <!-- Confirm pattern (no accidental dismiss) -->
314
+ <VJoyDialog
315
+ pattern-confirm
316
+ cancel-text="Cancel"
317
+ confirm-text="Delete project"
318
+ @dialog:confirm="onConfirm"
319
+ >
320
+ <template #dialog-header>Delete project brief?</template>
321
+ <template #dialog-body>This action cannot be undone.</template>
322
+ </VJoyDialog>
323
+
324
+ <!-- Custom footer CTAs (you must call hide on cancel) -->
325
+ <VJoyDialog ref="customDialog">
326
+ <template #dialog-header>Custom actions</template>
327
+ <template #dialog-body>…</template>
328
+ <template #dialog-cancel>
329
+ <VJoyButton variant="ghost" label="Cancel" @click="customDialog?.hide()" />
330
+ </template>
331
+ <template #dialog-confirm>
332
+ <VJoyButton variant="main" label="Confirm" @click="onConfirm" />
333
+ </template>
334
+ </VJoyDialog>
335
+ </template>
336
+ ```
337
+
338
+ In Nuxt (or apps with auto-import), omit imports if `VJoyDialog` and `VJoyButton` are already global.
339
+
340
+ ---
341
+
342
+ ## Related
343
+
344
+ | Component | Use when |
345
+ | --- | --- |
346
+ | `VJoyDialogTrigger` | Declarative open trigger wrapping any activator |
347
+ | `VJoyDrawer` | Edge panel; long or exploratory content |
348
+ | `VJoyButton` | Footer CTAs (default or custom slots) |
349
+ | `VJoyIconButton` | Close control (built-in) |
350
+ | `VJoyIndicators` / `VJoyIndicator` | Multi-step dialog navigation |
351
+ | `VJoyTag` | Preheader badges (e.g. "New", "Beta") |
352
+ | `VJoyTitleBrand` | Brand-styled titles inside templates or dialogs |
353
+
354
+ ---
355
+
356
+ ## For agents
357
+
358
+ Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyDialog.dsds.json`](./JoyDialog.dsds.json).
359
+
360
+ ### Pick the right component
361
+
362
+ | If the intent is… | Emit… | Do not emit… |
363
+ | --- | --- | --- |
364
+ | Modal decision / form / confirm | `VJoyDialog` | Custom `position: fixed` div |
365
+ | Side panel / filters / details | `VJoyDrawer` | `VJoyDialog` with hacked full height |
366
+ | Simple open from a button | `VJoyDialog` + `VJoyDialogTrigger` | Inline overlay markup |
367
+ | Must prevent mis-click dismiss | `patternConfirm` | Default pattern without cancel |
368
+ | Brand onboarding moment | `patternBrand` (experimental) | Custom decorative CSS shapes |
369
+ | Hero image on top | `bannerSrc` | `patternBrand` + `bannerSrc` together |
370
+ | Icon-only close | Built-in close `VJoyIconButton` | Raw button with `×` character |
371
+
372
+ ### Hard rules
373
+
374
+ 1. **MUST** call MCP (`joy_get_component_info`, `joy_get_component_types`) before generating props.
375
+ 2. **MUST** populate `dialog-header` (accessible name) for every dialog.
376
+ 3. **MUST** handle `hide()` when using `dialog-cancel` / `dialog-confirm` slots.
377
+ 4. **MUST** use `cancelText` / `confirmText` only when default `VJoyButton` wiring is enough.
378
+ 5. **MUST NOT** invent props, sizes, or variants (`size` is only `default` \| `large`).
379
+ 6. **MUST NOT** set `demoMode` in product code.
380
+ 7. **MUST NOT** combine `bannerSrc` with `patternBrand`.
381
+ 8. **MUST NOT** override `.joy-dialog` overlay, shadow, radius, or z-index in app CSS.
382
+ 9. **SHOULD** use `patternConfirm` for destructive or data-loss scenarios.
383
+ 10. **SHOULD** set localized `closeLabel` when UI language ≠ English.
384
+ 11. **SHOULD** `await` `show()` / `hide()` when coordinating focus or route changes.
385
+
386
+ ### Slot checklist
387
+
388
+ - [ ] `dialog-header` — title present
389
+ - [ ] `dialog-subheader` — only if extra context needed
390
+ - [ ] `dialog-body` — main content
391
+ - [ ] `dialog-preheader` — optional meta (tag)
392
+ - [ ] `dialog-cancel` / `dialog-confirm` — only when customizing CTAs (+ manual `hide`)
393
+ - [ ] `dialog-indicators` — only for multi-step flows
394
+
395
+ ### Generation checklist
396
+
397
+ - [ ] Correct component (`VJoyDialog` or named alternative)
398
+ - [ ] Props / enums from MCP only (`size`, `buttonSize`, booleans)
399
+ - [ ] No invented props / no custom dialog chrome CSS
400
+ - [ ] Dismiss path defined (default or `patternConfirm` + footer)
401
+ - [ ] Confirm CTA label names the outcome (not bare `OK`)
402
+ - [ ] Custom slots wire `hide()` on cancel
403
+ - [ ] `closeLabel` localized when needed
404
+ - [ ] `bannerSrc` xor `patternBrand` — never both
405
+ - [ ] Images in brand pattern have explicit `width`
406
+
407
+ ---
408
+
409
+ ## DSDS mapping
410
+
411
+ This Markdown mirrors [`JoyDialog.dsds.json`](./JoyDialog.dsds.json) (DSDS **0.15.2**).
412
+
413
+ | Section here | DSDS block |
414
+ | --- | --- |
415
+ | When to use / not | `use-cases` |
416
+ | Anatomy | `anatomy` |
417
+ | Variants / sizes / patterns | `variants` |
418
+ | States | `states` |
419
+ | Best practices / content rules | `guidelines` (+ `content`) |
420
+ | Accessibility | `accessibility` |
421
+ | Examples | `sections` |
422
+ | For agents | `agentDocumentBlocks` |
423
+ | Props detail | `api` in JSON + Joy MCP |
424
+ | Imports | `imports` in JSON |
425
+ | Token sizing | `design-specifications` in JSON (`--dialog-width`, spacing tokens) |
@@ -0,0 +1,186 @@
1
+ ---
2
+ component: VJoyDialogTrigger
3
+ status: draft
4
+ language: en
5
+ dsds: JoyDialogTrigger.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # Dialog trigger
10
+
11
+ Use **`VJoyDialogTrigger`** when a declarative click target should open an existing **`VJoyDialog`** — for example a button or icon control wired to a dialog ref without writing a custom `@click` handler.
12
+
13
+ It renders the default slot as the activator, emits `click`, then calls the linked dialog’s async `show()` method. The trigger adds no visual chrome; styling and semantics come from the slotted control (commonly `VJoyButton` or `VJoyIconButton`).
14
+
15
+ | | |
16
+ | --- | --- |
17
+ | **Code** | `VJoyDialogTrigger` from `@maltjoy/core-vue` |
18
+ | **Design** | [Figma — Joy Core Design System](https://www.figma.com/design/jfndp2QBJGS9yeuWbeGuvD/%F0%9F%9F%A0--Joy---Core-Design-System--official-) |
19
+ | **Storybook** | [VJoyDialog docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-overlays-vjoydialog--docs) (subcomponent) |
20
+ | **DSDS (machine)** | [`JoyDialogTrigger.dsds.json`](./JoyDialogTrigger.dsds.json) |
21
+ | **Live API** | `joy_get_component_info("VJoyDialogTrigger")` |
22
+
23
+ ---
24
+
25
+ ## When to use this component
26
+
27
+ Use a dialog trigger when the user opens a modal from a visible control in the template — a labeled button, icon button, or link-style activator — and you already have a `VJoyDialog` with a template ref.
28
+
29
+ Pair **`VJoyDialog`** (content, overlay, dismiss rules) with **`VJoyDialogTrigger`** (open wiring). The trigger keeps open logic declarative: pass the dialog ref via `:dialog`, put the activator in the default slot.
30
+
31
+ You can place **multiple activators** in the default slot; each one opens the same dialog on click.
32
+
33
+ ### When not to use this component
34
+
35
+ | Need | Use instead |
36
+ | --- | --- |
37
+ | Open the dialog from code (route change, API callback, timer) | `await dialogRef.value?.show()` on the `VJoyDialog` ref |
38
+ | Slide-in panel from the edge | `VJoyDrawer` + `VJoyDrawerTrigger` |
39
+ | Mobile bottom sheet | `VJoyBottomSheet` + `VJoyBottomSheetTrigger` |
40
+ | Lightweight hover hint | `VJoyTooltip` |
41
+ | Custom modal markup with ad-hoc CSS | Still use `VJoyDialog` + `VJoyDialogTrigger` — don’t reinvent overlay chrome |
42
+
43
+ > **Removed from API:** Legacy Stencil `joy-dialog-trigger` used a string `dialog` id and optional `step` for multi-step flows. **`VJoyDialogTrigger` takes a `VJoyDialog` template ref only** — no `step` prop. Control dialog content and indicators on `VJoyDialog` itself.
44
+
45
+ ---
46
+
47
+ ## How it works
48
+
49
+ ### Anatomy
50
+
51
+ | Part | Required? | What it is |
52
+ | --- | --- | --- |
53
+ | Trigger wrapper | Yes | Headless Vue wrapper — no root DOM of its own beyond slotted nodes |
54
+ | Default slot (activator) | Yes | One or more click targets (`VJoyButton`, `<button>`, `VJoyIconButton`, …) |
55
+ | `dialog` prop | Yes | Template ref to the target `VJoyDialog` instance |
56
+ | `click` event | No* | Fires on activator click, **before** `dialog.show()` (*optional listener) |
57
+
58
+ On click, the component emits `click`, then awaits `renderedDialog.value?.show()`. A computed `renderedDialog` mirrors the `dialog` prop so the ref is read at click time — this avoids races when the dialog ref is still `null` on first mount.
59
+
60
+ ### Default values
61
+
62
+ - `dialog` — **required** in practice; type is `InstanceType<typeof VJoyDialog> | null | undefined` until the ref is bound
63
+
64
+ Props, events, and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
65
+
66
+ ### Composition pattern
67
+
68
+ ```vue
69
+ <VJoyDialog ref="myDialog">…</VJoyDialog>
70
+
71
+ <VJoyDialogTrigger :dialog="myDialog">
72
+ <VJoyButton variant="main" label="Open settings" />
73
+ </VJoyDialogTrigger>
74
+ ```
75
+
76
+ Declare `myDialog` as `ref<InstanceType<typeof VJoyDialog> | null>(null)`.
77
+
78
+ ---
79
+
80
+ ## Best practices
81
+
82
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
83
+
84
+ ### Structure
85
+
86
+ - **SHOULD** use one `VJoyDialog` per overlay and pass its ref to `:dialog`.
87
+ - **SHOULD** put a **focusable, named** control in the default slot (`VJoyButton`, `VJoyIconButton`, or native `<button>`).
88
+ - **SHOULD** prefer `VJoyDialogTrigger` over inline `@click="dialogRef?.show()"` when the open action is a template-local button.
89
+ - **MAY** render multiple activators in the default slot when several controls should open the same dialog.
90
+
91
+ ### Implementation
92
+
93
+ - **MUST** pass the `VJoyDialog` template ref to `:dialog` — not a string id.
94
+ - **MUST** use only documented props and events from component types / MCP.
95
+ - **MUST NOT** invent props (`step`, `open`, `variant`, …).
96
+ - **MUST NOT** add custom overlay or z-index CSS on the trigger — it has no visual surface.
97
+ - **SHOULD** handle dialog content, confirm/cancel, and dismiss rules on `VJoyDialog` (see [`JoyDialog.DSDS.guideline.md`](../JoyDialog/JoyDialog.DSDS.guideline.md)).
98
+ - **SHOULD** use imperative `show()` when opening is not tied to a slotted click target.
99
+
100
+ ### Do / don’t
101
+
102
+ | Do | Don’t |
103
+ | --- | --- |
104
+ | `VJoyButton` with clear label in the slot | Empty `<div @click>` without keyboard support |
105
+ | `:dialog="dialogRef"` bound to `ref<InstanceType<typeof VJoyDialog>>` | String id from legacy Stencil API |
106
+ | `VJoyDialog` for modal content and close behavior | Duplicate dialog markup next to the trigger |
107
+ | `dialogRef.value?.show()` for programmatic open | `VJoyDialogTrigger` with no slotted activator |
108
+ | Listen to `@click` for analytics before open | Rely on the trigger to close the dialog |
109
+
110
+ ---
111
+
112
+ ## Accessibility
113
+
114
+ `VJoyDialogTrigger` is a **behavioral** wrapper. Accessible name, role, and keyboard support come from the **slotted activator**.
115
+
116
+ | Behavior | Expectation |
117
+ | --- | --- |
118
+ | Role | No role on the wrapper — the slot child provides it (e.g. `button`) |
119
+ | Name | Activator **MUST** have an accessible name (`label` on `VJoyButton` / `VJoyIconButton`, visible text, or `aria-label`) |
120
+ | Keyboard | Activator **MUST** be focusable and activatable with **Enter** / **Space** when it is a button |
121
+ | Focus after open | Focus management is handled by `VJoyDialog` when the overlay opens — not by the trigger |
122
+ | Multiple triggers | Each activator needs its own accessible name |
123
+
124
+ Target: **WCAG 2.2 AA** where the product requires it — meet requirements through the slotted control and `VJoyDialog` focus trap / dismiss behavior.
125
+
126
+ ---
127
+
128
+ ## Examples
129
+
130
+ ```vue
131
+ <script setup lang="ts">
132
+ import { ref } from 'vue'
133
+ import {
134
+ VJoyDialog,
135
+ VJoyDialogTrigger,
136
+ VJoyButton,
137
+ VJoyIconButton,
138
+ } from '@maltjoy/core-vue'
139
+
140
+ const settingsDialog = ref<InstanceType<typeof VJoyDialog> | null>(null)
141
+
142
+ function onTriggerClick() {
143
+ // Optional: analytics or guard logic — runs before show()
144
+ }
145
+ </script>
146
+
147
+ <template>
148
+ <VJoyDialog ref="settingsDialog" cancel-text="Cancel" confirm-text="Save">
149
+ <template #dialog-header>Account settings</template>
150
+ <template #dialog-body>Update your preferences here.</template>
151
+ </VJoyDialog>
152
+
153
+ <!-- Primary button activator -->
154
+ <VJoyDialogTrigger :dialog="settingsDialog" @click="onTriggerClick">
155
+ <VJoyButton variant="main" label="Open settings" />
156
+ </VJoyDialogTrigger>
157
+
158
+ <!-- Multiple activators, same dialog -->
159
+ <VJoyDialogTrigger :dialog="settingsDialog">
160
+ <VJoyIconButton variant="ghost" icon="settings" label="Settings" />
161
+ <VJoyButton variant="secondary" label="Edit profile" />
162
+ </VJoyDialogTrigger>
163
+ </template>
164
+ ```
165
+
166
+ In Nuxt (or apps with auto-import), omit the import if `VJoyDialogTrigger` is already global.
167
+
168
+ For programmatic open without a trigger component:
169
+
170
+ ```vue
171
+ <button type="button" @click="settingsDialog?.show()">Open from code</button>
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Related
177
+
178
+ | Component | Use when |
179
+ | --- | --- |
180
+ | `VJoyDialog` | Modal content, overlay, dismiss rules, async `show()` / `hide()` |
181
+ | `VJoyButton` | Default labeled activator in the trigger slot |
182
+ | `VJoyIconButton` | Icon-only activator — pair with a meaningful `label` |
183
+ | `VJoyDrawerTrigger` | Same declarative pattern for `VJoyDrawer` |
184
+ | `VJoyBottomSheetTrigger` | Same pattern for `VJoyBottomSheet` |
185
+ | `VJoyTooltip` | Supplementary hint on the activator, not a modal |
186
+ | `VJoyDrawer` | Edge panel instead of centered modal |