@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,390 @@
1
+ ---
2
+ component: VJoyDropzone
3
+ status: draft
4
+ language: en
5
+ dsds: JoyDropzone.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # Dropzone
10
+
11
+ Use **`VJoyDropzone`** when the user needs to upload one or more files by dragging them into a target area or browsing the file system.
12
+
13
+ It supports single or multiple selection, MIME-type and size validation, per-file update/delete actions, and slots for helper text and custom file rows. Bind with `v-model` to an array of `File` instances or objects with at least a `name` property (for already-uploaded files).
14
+
15
+ | | |
16
+ | --- | --- |
17
+ | **Code** | `VJoyDropzone` from `@maltjoy/core-vue` |
18
+ | **Design** | [Figma — Joy Core Design System](https://www.figma.com/design/jfndp2QBJGS9yeuWbeGuvD/) |
19
+ | **Storybook** | [VJoyDropzone docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-forms-vjoydropzone--docs) |
20
+ | **DSDS (machine)** | [`JoyDropzone.dsds.json`](./JoyDropzone.dsds.json) |
21
+ | **Live API** | `joy_get_component_info("VJoyDropzone")` |
22
+
23
+ ---
24
+
25
+ ## When to use this component
26
+
27
+ Use a dropzone when someone must attach a document or image — résumé, invoice, identity proof, portfolio asset — and drag-and-drop or browse is the right interaction.
28
+
29
+ Pair it with a visible label (`label` prop or external `VJoyLabel`), constraints in `dropzone-subtitle` or `dropzone-legend` (accepted formats, max size), and form-level validation via the `invalid` prop when the field is required.
30
+
31
+ ### When not to use this component
32
+
33
+ | Need | Use instead |
34
+ | --- | --- |
35
+ | A single compact file picker without drag-and-drop chrome | Native `<input type="file">` styled inside a form — only when design explicitly allows; prefer `VJoyDropzone` for consistency |
36
+ | Upload progress / async server upload UI with cancel buttons | Compose upload logic in the app; `VJoyDropzone` manages selection and validation, not network transfer |
37
+ | Image cropping or in-place editing before upload | A dedicated cropper/editor flow — then pass the result into `v-model` |
38
+ | Choosing from files already stored in the product | A file browser / document picker — not a local filesystem dropzone |
39
+ | Custom-styled drag area / ad-hoc file list | Still use `VJoyDropzone` + Joy tokens and slots — don’t reinvent chrome |
40
+
41
+ > **Legacy Stencil (`joy-dropzone`):** do not port deprecated props (`loading`, `buttonText`, `buttonCancelText`, `uploadingText`, `descriptionText`, …). The Vue component uses slots and `v-model` instead.
42
+
43
+ ---
44
+
45
+ ## How it works
46
+
47
+ ### Anatomy
48
+
49
+ | Part | Required? | What it is |
50
+ | --- | --- | --- |
51
+ | Root container | Yes | `.joy-dropzone` wrapper; state classes (`--empty`, `--dragover`, `--invalid`, `--disabled`) |
52
+ | Label | No | `VJoyLabel` from the `label` prop, associated with the hidden file input via `name` / `id` |
53
+ | Drop area | Yes | `.joy-dropzone__area` — dashed border (empty) or solid border (filled) |
54
+ | Hidden file `<input>` | Yes | `type="file"`; visually hidden; `tabindex="-1"`; opened programmatically on browse / update |
55
+ | File list | When `v-model` has items | `VJoyDropzoneFileItem` rows (name, optional info, update/delete actions) |
56
+ | Instruction block | When empty, or multiple with no invalid files | Icon, description (`dropzone-description`), subtitle (`dropzone-subtitle`) |
57
+ | Browse link | In default description | `VJoyLink` inside default copy — “browse” opens the file picker |
58
+ | Legend | No | `dropzone-legend` slot below the area (helper / requirements) |
59
+ | Form error | When validation fails (single-file mode) | `VJoyFormError` below the area — replaces legend while error is shown |
60
+ | Per-file error | Multiple mode only | Inline message on the offending `VJoyDropzoneFileItem` |
61
+
62
+ ### Default values
63
+
64
+ - `multiple` defaults to **`false`**
65
+ - `accept` defaults to **`[]`** (all MIME types allowed)
66
+ - `maxSize` defaults to **`32`** (megabytes per file)
67
+ - `deleteLabel` defaults to **`"Delete this file"`**
68
+ - `updateLabel` defaults to **`"Update this file"`**
69
+ - `errorTextFormat` defaults to **`"This format is not supported"`**
70
+ - `errorTextMaxSize` defaults to a message including `maxSize` (e.g. “The file is over 32MB…”)
71
+ - `errorTextFormatAndMaxSize` defaults to a combined format + size message
72
+ - `canDelete` defaults to **`true`**
73
+ - `disabled` defaults to **`false`**
74
+ - `invalid` defaults to **`false`**
75
+
76
+ Props, events, and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
77
+
78
+ ---
79
+
80
+ ## Variants
81
+
82
+ `VJoyDropzone` has no visual `variant` prop. Behavior splits into **upload mode** and **surface state**.
83
+
84
+ ### Single file (`multiple` false, default)
85
+
86
+ Use when exactly one attachment is expected — profile document, signed contract, single receipt.
87
+
88
+ Replacing a file updates the sole item in `v-model`. Format/size errors show in `VJoyFormError` below the zone; `dropzone-legend` is hidden while that error is visible.
89
+
90
+ ### Multiple files (`multiple` true)
91
+
92
+ Use when several attachments are allowed — supporting documents, gallery uploads, batch imports.
93
+
94
+ New files append to `v-model`. Format/size errors appear on each invalid row; the instruction block stays visible so users can add more files (unless every file is valid). `dropzone-legend` remains visible alongside per-file errors.
95
+
96
+ ### Not in the API: upload progress / CTA buttons
97
+
98
+ ZeroHeight and the legacy Stencil `joy-dropzone` describe **Upload** / **Cancel** buttons and a **loading** state. **`VJoyDropzone` does not expose these.** Handle server upload, progress, and cancellation in application code after files are in `v-model`.
99
+
100
+ ### Not in the API: file extension strings in `accept`
101
+
102
+ Validation compares `file.type` (MIME) against `accept` entries. Do not pass bare extensions like `".pdf"` — use MIME types such as `application/pdf`, `image/jpeg`.
103
+
104
+ ---
105
+
106
+ ## States
107
+
108
+ | State | What the user sees / can do |
109
+ | --- | --- |
110
+ | Empty (default) | Dashed neutral border; cloud icon; “Drag and drop…” + browse link; click or drop adds files |
111
+ | Drag over | Secondary border and tinted background while a file hovers (not when `disabled`) |
112
+ | Filled | Solid border, neutral background; file row(s) with name; update/delete icon buttons |
113
+ | Invalid (file rules) | Error border and icon color; single mode → `VJoyFormError`; multiple → per-file error text |
114
+ | Invalid (`invalid` prop) | Same error styling for parent form feedback (e.g. required empty field) — does not replace MIME/size checks |
115
+ | Disabled | Muted chrome; no drag, browse, update, or delete; explain why nearby |
116
+ | With legend | Helper text in `dropzone-legend` below the area (hidden in single-file mode when a file validation error is shown) |
117
+
118
+ The exposed `invalid` ref reflects **file validation** (`accept`, `maxSize`) only. The `invalid` **prop** is for **external** form state. Either or both can apply the invalid appearance.
119
+
120
+ ---
121
+
122
+ ## Best practices
123
+
124
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
125
+
126
+ ### Labels and forms
127
+
128
+ - **MUST** provide a visible label (`label`, `VJoyLabel`, or equivalent) for every dropzone in a form.
129
+ - **MUST** set `name` uniquely on the page — it wires `id`, label `for`, and the native file input.
130
+ - **SHOULD** wrap label + dropzone + errors in `VJoyFormGroup` for consistent spacing.
131
+ - **SHOULD** state accepted formats and max size in `dropzone-subtitle` or `dropzone-legend`.
132
+
133
+ ### Implementation
134
+
135
+ - **MUST** bind `v-model` to an array (`File[]` or `{ name: string }[]` for pre-existing files).
136
+ - **MUST** use MIME types in `accept` (e.g. `['application/pdf', 'image/jpeg']`).
137
+ - **MUST** style with Joy tokens — no custom `.joy-dropzone` border, radius, or padding overrides.
138
+ - **MUST NOT** invent props (`loading`, `buttonText`, `legend` as a prop, …).
139
+ - **MUST** override `deleteLabel` / `updateLabel` when the default strings are too generic for context.
140
+ - **SHOULD** use `canDelete={false}` when files must not be removable (audit trail) while keeping update available.
141
+ - **SHOULD** read exposed `invalid` (template ref) or validate `v-model` before submit when `accept` / `maxSize` matter.
142
+
143
+ ### Validation and errors
144
+
145
+ - **MUST** set `invalid` when the parent form marks the field required and empty.
146
+ - **MUST** show file rule failures via built-in messages (`errorText*` props) — not only red borders.
147
+ - **MUST NOT** rely on border color alone for required-field errors — use `invalid` + helper copy or `VJoyFormError` from the parent when appropriate.
148
+ - **SHOULD** customize `errorTextFormat`, `errorTextMaxSize`, and `errorTextFormatAndMaxSize` when defaults are too vague.
149
+
150
+ ### Do / don’t
151
+
152
+ | Do | Don’t |
153
+ | --- | --- |
154
+ | `v-model` + unique `name` | Orphan dropzone with no label |
155
+ | MIME types in `accept` | Extension strings like `.pdf` |
156
+ | `dropzone-subtitle` for “PDF, 10 MB max” | Requirements only in error messages after failure |
157
+ | `invalid` for required empty field | Expect `invalid` prop to validate file type/size |
158
+ | App-level upload after selection | Built-in Upload/Cancel buttons from Stencil |
159
+ | Joy dropzone tokens | Hardcoded dashed borders or custom file rows |
160
+
161
+ ---
162
+
163
+ ## Content
164
+
165
+ The dropzone exposes description, subtitle, legend, and error copy. All must help users pick a **valid** file the **first** time.
166
+
167
+ ### Label formula
168
+
169
+ **Noun phrase** describing what to upload:
170
+
171
+ - ✅ Supporting documents
172
+ - ✅ Profile photo
173
+ - ✅ Signed contract
174
+
175
+ Use sentence case. Match terminology used elsewhere on the form.
176
+
177
+ ### Description formula (default slot)
178
+
179
+ **Drag instruction + browse action** — the default is “Drag and drop a document, or **browse**”. Override with `dropzone-description` when the asset type is specific:
180
+
181
+ - ✅ Drag and drop your CV, or **browse**
182
+ - ✅ Drag and drop an invoice, or **browse**
183
+
184
+ Keep the browse affordance as a link (`VJoyLink` in the slot) so keyboard and screen-reader users can open the picker.
185
+
186
+ ### Subtitle / legend formula
187
+
188
+ **Constraints in one line** — formats and size:
189
+
190
+ - ✅ PDF or JPEG. Maximum 10 MB per file.
191
+ - ✅ One file only. PNG, max 5 MB.
192
+
193
+ Use `dropzone-subtitle` inside the zone; use `dropzone-legend` for supplementary helper text below.
194
+
195
+ ### Error messages
196
+
197
+ Explain **what failed** and **how to fix it**:
198
+
199
+ - ✅ This format is not supported. Upload a PDF or JPEG file.
200
+ - ✅ The file is over 10 MB. Upload a file smaller than 10 MB.
201
+ - ❌ Invalid file
202
+ - ❌ Upload failed
203
+
204
+ Override via `errorTextFormat`, `errorTextMaxSize`, and `errorTextFormatAndMaxSize` when defaults need product-specific wording.
205
+
206
+ ### Writing rules
207
+
208
+ | Strength | Rule |
209
+ | --- | --- |
210
+ | **MUST** | Every dropzone has a visible label — not description-only |
211
+ | **MUST** | Error messages state the problem and the fix |
212
+ | **MUST** | `deleteLabel` / `updateLabel` describe the action on **this** file |
213
+ | **MUST NOT** | Use “please,” “thank you,” or Latinisms (per Joy content guidelines) |
214
+ | **SHOULD** | Use present tense and active voice |
215
+ | **SHOULD** | Use sentence case and terminal punctuation in helper lines |
216
+ | **SHOULD** | Keep subtitle/legend to one short line when possible |
217
+ | **SHOULD** (FR) | Follow French grammar for labels and error strings when the UI is localized |
218
+
219
+ ---
220
+
221
+ ## Accessibility
222
+
223
+ Behaviors (what must happen), not slogans.
224
+
225
+ | Behavior | Expectation |
226
+ | --- | --- |
227
+ | Role | Native `input[type="file"]` for selection; visible label via `VJoyLabel` or external label with matching `for` |
228
+ | Name | From `label` prop or associated `VJoyLabel`; file actions named via `updateLabel` / `deleteLabel` on `VJoyIconButton` |
229
+ | Keyboard | Browse via label/link activation; hidden input is not tab-stopped (`tabindex="-1"`) — ensure the instruction area / link is reachable |
230
+ | Focus | Update and delete are real buttons (`VJoyIconButton`); custom `file-actions` must be focusable and named |
231
+ | Drag and drop | Supplementary to browse — never the only path; click/tap must open the file picker |
232
+ | Invalid | Error border + `VJoyFormError` (single) or per-file error text (multiple); `role="alert"` via `VJoyFormError` |
233
+ | Disabled | No interaction; muted styles; **explain why** in nearby text — do not rely on color alone |
234
+ | Custom slots | `file-actions` icons need `label` / accessible names; decorative icons `aria-hidden` |
235
+
236
+ Target: **WCAG 2.2 AA** where the product requires it.
237
+
238
+ ---
239
+
240
+ ## Examples
241
+
242
+ ```vue
243
+ <script setup lang="ts">
244
+ import { ref } from 'vue'
245
+ import {
246
+ VJoyDropzone,
247
+ VJoyFormGroup,
248
+ VJoyLabel,
249
+ } from '@maltjoy/core-vue'
250
+
251
+ const files = ref<File[]>([])
252
+ const documents = ref<{ name: string }[]>([])
253
+ const showRequiredError = ref(false)
254
+ </script>
255
+
256
+ <template>
257
+ <!-- Single file, default copy -->
258
+ <VJoyDropzone name="cv-upload" v-model="files" label="CV" />
259
+
260
+ <!-- Constrained upload with helper text -->
261
+ <VJoyDropzone
262
+ name="invoice"
263
+ v-model="files"
264
+ label="Invoice"
265
+ :accept="['application/pdf', 'image/jpeg']"
266
+ :max-size="10"
267
+ >
268
+ <template #dropzone-subtitle>PDF or JPEG. Maximum 10 MB.</template>
269
+ <template #dropzone-legend>We use this document for billing verification only.</template>
270
+ </VJoyDropzone>
271
+
272
+ <!-- Multiple files with existing server-side names -->
273
+ <VJoyDropzone name="attachments" v-model="documents" multiple>
274
+ <template #file-information="{ file }">
275
+ Uploaded on {{ (file as { uploadedDate?: string }).uploadedDate }}
276
+ </template>
277
+ </VJoyDropzone>
278
+
279
+ <!-- External label + required validation -->
280
+ <VJoyFormGroup>
281
+ <VJoyLabel for="contract-upload" required>Signed contract</VJoyLabel>
282
+ <VJoyDropzone
283
+ id="contract-upload"
284
+ name="contract-upload"
285
+ v-model="files"
286
+ :invalid="showRequiredError && files.length === 0"
287
+ :accept="['application/pdf']"
288
+ >
289
+ <template #dropzone-subtitle>PDF only. Maximum 32 MB.</template>
290
+ </VJoyDropzone>
291
+ </VJoyFormGroup>
292
+ </template>
293
+ ```
294
+
295
+ In Nuxt (or apps with auto-import), omit the import if `VJoyDropzone` is already global.
296
+
297
+ ---
298
+
299
+ ## Related
300
+
301
+ | Component | Use when |
302
+ | --- | --- |
303
+ | `VJoyLabel` | Rich labels (legend, tooltip, required) above the dropzone |
304
+ | `VJoyFormGroup` | Group label, dropzone, and errors with consistent gap |
305
+ | `VJoyFormError` | Additional form-level errors outside built-in file validation |
306
+ | `VJoyIconButton` | Custom per-file actions in `file-actions` |
307
+ | `VJoyLink` | Browse affordance inside `dropzone-description` |
308
+ | `VJoyWrapper` | Layout around multiple form fields |
309
+
310
+ ---
311
+
312
+ ## For agents
313
+
314
+ Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyDropzone.dsds.json`](./JoyDropzone.dsds.json).
315
+
316
+ ### Pick the right component
317
+
318
+ | If the intent is… | Emit… | Do not emit… |
319
+ | --- | --- | --- |
320
+ | Local file upload with drag-and-drop | `VJoyDropzone` | Custom dashed `div` + hidden input |
321
+ | Single attachment | `VJoyDropzone` (default `multiple`) | `multiple` with only one slot |
322
+ | Several attachments | `VJoyDropzone` + `multiple` | Repeated single dropzones |
323
+ | Show already-uploaded file names | `v-model` with `{ name: string }[]` | Fake rows outside the component |
324
+ | Required empty field on submit | `invalid` prop + parent validation | Only red border, no message |
325
+ | PDF/JPEG only | `accept` with MIME types | `accept=".pdf,.jpg"` |
326
+ | Upload progress / cancel | App logic after `v-model` update | `loading`, `buttonText`, Stencil-only props |
327
+
328
+ ### Hard rules
329
+
330
+ 1. **MUST** call `joy_get_component_info("VJoyDropzone")` before generating props.
331
+ 2. **MUST** bind `v-model` to an array (`File` or `{ name: string }` items).
332
+ 3. **MUST** set unique `name` on every instance.
333
+ 4. **MUST** use MIME strings in `accept` (e.g. `application/pdf`, not `.pdf`).
334
+ 5. **MUST** set `invalid` for parent-required validation; use `errorText*` for format/size copy.
335
+ 6. **MUST NOT** emit Stencil-only props (`loading`, `buttonText`, `buttonCancelText`, `uploadingText`, `legend` as prop, …).
336
+ 7. **MUST NOT** override `.joy-dropzone` border, radius, background, or padding.
337
+ 8. **SHOULD** populate `dropzone-subtitle` with format and size limits when `accept` or `maxSize` is restricted.
338
+ 9. **SHOULD** set contextual `deleteLabel` / `updateLabel` (e.g. “Remove invoice”, “Replace invoice”).
339
+ 10. **SHOULD** use `VJoyFormGroup` + `VJoyLabel` when the label needs required/optional markers.
340
+
341
+ ### Valid props (from Joy MCP)
342
+
343
+ | Prop | Notes |
344
+ | --- | --- |
345
+ | `name` | Required string, unique per page |
346
+ | `modelValue` / `v-model` | Required `(File \| { name: string })[]` |
347
+ | `multiple` | Boolean, default `false` |
348
+ | `accept` | `string[]` MIME types, default `[]` |
349
+ | `maxSize` | Number (MB), default `32` |
350
+ | `label` | Optional top label |
351
+ | `canDelete` | Boolean, default `true` |
352
+ | `disabled` | Boolean, default `false` |
353
+ | `invalid` | Boolean, external form state |
354
+ | `deleteLabel`, `updateLabel` | Accessible names for file actions |
355
+ | `errorTextFormat`, `errorTextMaxSize`, `errorTextFormatAndMaxSize` | Validation copy |
356
+
357
+ Slots: `dropzone-description`, `dropzone-subtitle`, `dropzone-legend`, `file-information`, `file-actions` (slot prop `file`).
358
+
359
+ ### Checklist
360
+
361
+ - [ ] Correct component (`VJoyDropzone` or named alternative)
362
+ - [ ] Props from MCP only — no Stencil-only API
363
+ - [ ] `v-model` array + unique `name`
364
+ - [ ] Visible label (prop or `VJoyLabel`)
365
+ - [ ] MIME types in `accept` when restricted
366
+ - [ ] `dropzone-subtitle` / `dropzone-legend` for constraints
367
+ - [ ] `invalid` for required-empty; built-in errors for format/size
368
+ - [ ] No custom dropzone chrome CSS
369
+ - [ ] `deleteLabel` / `updateLabel` contextual when needed
370
+ - [ ] Disabled state explained if user-visible
371
+
372
+ ---
373
+
374
+ ## DSDS mapping
375
+
376
+ This Markdown mirrors [`JoyDropzone.dsds.json`](./JoyDropzone.dsds.json) (DSDS **0.15.2**).
377
+
378
+ | Section here | DSDS block |
379
+ | --- | --- |
380
+ | When to use / not | `use-cases` |
381
+ | Anatomy | `anatomy` |
382
+ | Variants (modes) | `variants` |
383
+ | States | `states` |
384
+ | Best practices / content rules | `guidelines` (+ `content`) |
385
+ | Accessibility | `accessibility` |
386
+ | Examples | `sections` |
387
+ | For agents | `agentDocumentBlocks` |
388
+ | Props detail | `api` in JSON + Joy MCP |
389
+ | Imports | `imports` in JSON |
390
+ | Token sizing | `design-specifications` in JSON (`--joy-core-radius-4`, `--joy-form-border-width`, form-field height on file rows) |
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "JoyDropzone",
3
3
  "displayName": "VJoyDropzone",
4
- "description": "A file upload component with drag-and-drop functionality for handling file selection and management.\nSupports single or multiple file uploads, file validation and customizable file displays.\nFeatures visual feedback for drag states, error handling, and flexible content slots for file information and actions.\n\nThe dropzone required as `v-model` an array containing objects with at least the \"name\" property.",
4
+ "description": "A file upload component with drag-and-drop functionality for handling file selection and management.\nSupports single or multiple file uploads, file validation and customizable file displays.\nFeatures visual feedback for disabled, invalid, and drag states, error handling, and flexible content slots for file information and actions.\n\nThe dropzone requires a `v-model` bound to an array containing objects with at least the `name` property (or `File` instances).\n\nUse `label` to display a label above the dropzone. Use `canDelete` (default `true`) to hide the delete button on file items while keeping update available. Set `disabled` to block uploads, drag-and-drop, and file actions. Set `invalid` for parent form feedback (e.g. required empty field); it adds invalid styling but does not replace format/size validation. The exposed `invalid` ref only reflects file validation (`accept`, `maxSize`); the `invalid` prop is for external form state—both can apply the invalid appearance.\n\nSlots: `dropzone-description` for the main instruction (default text with browse link), `dropzone-subtitle` for an optional hint line (empty by default), `dropzone-legend` for helper text below the zone, `file-information` and `file-actions` for per-file content (slot prop `file`). In single-file mode, `dropzone-legend` is hidden when a format or size error is shown (`VJoyFormError` instead); in multiple mode, errors appear on each file item and the legend stays visible.",
5
5
  "category": "Forms",
6
6
  "props": [
7
7
  {
@@ -18,6 +18,15 @@
18
18
  "description": "Dropzone input name. Must be unique on the page.",
19
19
  "possibleValues": null
20
20
  },
21
+ {
22
+ "name": "label",
23
+ "type": "string | undefined",
24
+ "required": false,
25
+ "description": "Display a label on top of the dropzone.",
26
+ "possibleValues": [
27
+ "string"
28
+ ]
29
+ },
21
30
  {
22
31
  "name": "multiple",
23
32
  "type": "boolean | undefined",
@@ -115,6 +124,28 @@
115
124
  "false",
116
125
  "true"
117
126
  ]
127
+ },
128
+ {
129
+ "name": "disabled",
130
+ "type": "boolean | undefined",
131
+ "required": false,
132
+ "default": "false",
133
+ "description": "Disable the dropzone.",
134
+ "possibleValues": [
135
+ "false",
136
+ "true"
137
+ ]
138
+ },
139
+ {
140
+ "name": "invalid",
141
+ "type": "boolean | undefined",
142
+ "required": false,
143
+ "default": "false",
144
+ "description": "When true, applies invalid styling (e.g. parent form required + dirty). Does not replace file format/size validation.",
145
+ "possibleValues": [
146
+ "false",
147
+ "true"
148
+ ]
118
149
  }
119
150
  ],
120
151
  "events": [],
@@ -127,6 +158,10 @@
127
158
  "name": "dropzone-description",
128
159
  "description": "Block description of the dropzone"
129
160
  },
161
+ {
162
+ "name": "dropzone-subtitle",
163
+ "description": "Block subtitle of the dropzone"
164
+ },
130
165
  {
131
166
  "name": "file-information",
132
167
  "description": "Add information under the file name"