@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,381 @@
1
+ ---
2
+ component: VJoyInputDigit
3
+ status: draft
4
+ language: en
5
+ dsds: JoyInputDigit.dsds.json
6
+ dsdsVersion: "0.15.2"
7
+ ---
8
+
9
+ # Input digit
10
+
11
+ Use **`VJoyInputDigit`** when the user must enter a **fixed-length numeric code** — SMS or email verification (OTP), two-factor authentication, or a short PIN.
12
+
13
+ It renders a row of single-character fields, auto-advances focus as digits are typed, supports paste across slots, and binds to `v-model` as one joined string. Each slot is a `VJoyInput` with `autocomplete="one-time-code"` for mobile OTP autofill.
14
+
15
+ | | |
16
+ | --- | --- |
17
+ | **Code** | `VJoyInputDigit` from `@maltjoy/core-vue` |
18
+ | **Design** | [Figma — Joy Core Design System](https://www.figma.com/design/jfndp2QBJGS9yeuWbeGuvD/) |
19
+ | **Storybook** | [VJoyInputDigit docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-forms-vjoyinputdigit--docs) |
20
+ | **DSDS (machine)** | [`JoyInputDigit.dsds.json`](./JoyInputDigit.dsds.json) |
21
+ | **Live API** | `joy_get_component_info("VJoyInputDigit")` |
22
+
23
+ ---
24
+
25
+ ## When to use this component
26
+
27
+ Use an input digit when the expected value is **exactly N digits** (default **6**) and splitting the code into separate boxes helps users read, verify, and paste codes from SMS or authenticator apps.
28
+
29
+ Typical flows: account verification after sign-up, login step-up, payment confirmation, or device pairing. Pair the control with a visible group label (`VJoyLabel`), instructions, and `VJoyFormError` when validation fails.
30
+
31
+ ### When not to use this component
32
+
33
+ | Need | Use instead |
34
+ | --- | --- |
35
+ | Single-line free text (email, name, search) | `VJoyInput` |
36
+ | Password with show/hide toggle | `VJoyInputPassword` |
37
+ | Numeric value with unit (€, %, days…) | `VJoyInputNumber` |
38
+ | Multi-line text | `VJoyTextarea` |
39
+ | Alphanumeric or variable-length codes | `VJoyInput` (with `maxlength` and validation) |
40
+ | Choosing from a known set of options | `VJoySelect` or `VJoyRadio` |
41
+ | Several hand-built single-char `VJoyInput`s | `VJoyInputDigit` — it handles focus, paste, and joined `v-model` |
42
+ | Custom-styled OTP boxes | Still use `VJoyInputDigit` + Joy tokens |
43
+
44
+ ---
45
+
46
+ ## How it works
47
+
48
+ ### Anatomy
49
+
50
+ | Part | Required? | What it is |
51
+ | --- | --- | --- |
52
+ | Wrapper | Yes | Root `.joy-input-digit__wrapper` (inline-flex column) |
53
+ | Slot row | Yes | `.joy-input-digit` flex container with gap between cells |
54
+ | Digit cell | Yes | One `VJoyInput` per slot (`size="medium"`, `type="number"`, `inputmode="numeric"`, `maxlength="1"`) |
55
+ | Joined value | Yes | `v-model` / `modelValue` — all digits concatenated (e.g. `"204918"`) |
56
+ | Focus ring | Yes | Inherited from inner `VJoyInput` — do not remove in product CSS |
57
+
58
+ Native attributes (`data-test`, `aria-*`, etc.) passed on the component are forwarded to **every** inner `<input>`. The `name` prop becomes a prefix: `name-1`, `name-2`, … per slot.
59
+
60
+ ### Default values
61
+
62
+ - `modelValue` defaults to **`""`**
63
+ - `length` defaults to **`6`** (minimum effective length is **1**)
64
+ - `invalid` defaults to **`false`**
65
+ - `disabled` defaults to **`false`**
66
+ - `name` defaults to **`"joy-input-digit"`**
67
+ - `inputAriaLabel` defaults to **`"Digit"`** — each slot gets `{inputAriaLabel} {index}/{length}` (e.g. `Digit 1/6`)
68
+
69
+ Props, events, and exposed members: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
70
+
71
+ ### Interaction model
72
+
73
+ - **Type** — Digits `0–9` only; non-numeric keys are blocked. Entering a digit moves focus to the next slot.
74
+ - **Multi-char input** — Typing or pasting several digits at once fills subsequent slots from the current index.
75
+ - **Backspace** — Clears the current slot; if already empty, focus moves to the previous slot.
76
+ - **Arrow keys** — Left / right move between slots; up / down are suppressed.
77
+ - **Paste** — Clipboard text is sanitized to digits and distributed across slots from the focused index.
78
+ - **Focus / click** — Content of the active slot is selected for easy replacement.
79
+
80
+ `change` emits whenever the joined value changes (with the originating `Event`). Use `focusInput(index)` from a template ref when you need programmatic focus (e.g. after a resend-code action).
81
+
82
+ ---
83
+
84
+ ## Variants
85
+
86
+ `VJoyInputDigit` has **no visual variant prop** (no primary/secondary). Meaning comes from **state** (`invalid`, `disabled`) applied uniformly to every slot.
87
+
88
+ ### Default (valid)
89
+
90
+ Use for standard OTP entry. Inner inputs use centered text and Joy form-field tokens.
91
+
92
+ ### Invalid
93
+
94
+ Set `invalid` when the submitted code failed verification. Pair with `VJoyFormError` (or equivalent) — the red border on each cell is not enough on its own.
95
+
96
+ Avoid toggling `invalid` while the user is still typing unless the code length is complete and clearly wrong.
97
+
98
+ ### Disabled
99
+
100
+ Use when entry is blocked (cooldown, permissions, workflow step). **Always explain why** nearby.
101
+
102
+ ### Not in the API: per-slot size
103
+
104
+ Inner inputs are always `size="medium"` with digit-specific geometry from `--input-digit-*` tokens in `JoyInputDigit.scss`. There is no `size` prop — do not simulate small/large OTP cells with custom CSS.
105
+
106
+ ### Not in the API: letters or separators
107
+
108
+ Only single numeric digits are accepted. Alphanumeric codes or masked patterns (e.g. `XXX-XXX`) are not supported — use `VJoyInput` with validation instead.
109
+
110
+ ---
111
+
112
+ ## Sizes
113
+
114
+ The component exposes **no size API**. Cell width, height, gap, radius, and font size are defined by Joy tokens inside the component:
115
+
116
+ | Token / aspect | Source |
117
+ | --- | --- |
118
+ | Cell width | `--joy-core-spacing-9` via `--input-digit-width` |
119
+ | Cell height | `--input-digit-height` (56px in component SCSS) |
120
+ | Corner radius | `--joy-core-radius-3` |
121
+ | Gap between cells | `--input-digit-gap` (10px) |
122
+ | Typography | `--joy-font-size-primary-600` |
123
+
124
+ **Do not hardcode** OTP box dimensions in apps — overrides break alignment with `VJoyInput` focus and error states.
125
+
126
+ ---
127
+
128
+ ## States
129
+
130
+ | State | What the user sees / can do |
131
+ | --- | --- |
132
+ | Default | Empty or partially filled slots; editable; neutral borders from inner `VJoyInput` |
133
+ | Focus | Active slot selected; visible focus ring on the inner input |
134
+ | Filled | Digits centered in each cell; joined `modelValue` updates on every change |
135
+ | Invalid | Error border and text color on **all** slots when `invalid` is true |
136
+ | Disabled | All slots non-interactive; muted styling; explain why nearby |
137
+ | Paste | Multiple digits fill from the focused index; non-digits stripped |
138
+
139
+ ---
140
+
141
+ ## Best practices
142
+
143
+ Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
144
+
145
+ ### Labels and forms
146
+
147
+ - **MUST** provide a visible group label (`VJoyLabel` or equivalent) describing what code is expected — slots alone are not a sufficient name.
148
+ - **MUST** set `name` to a stable, form-specific prefix (e.g. `signup-otp`) so autofill and tests bind correctly.
149
+ - **SHOULD** set `inputAriaLabel` to match the group label context — ✅ `Security code digit` · default `Digit` is generic.
150
+ - **SHOULD** wrap the field with instructions and errors in `VJoyWrapper` for consistent spacing.
151
+ - **SHOULD** match `length` to the backend contract (4, 6, 8…) — do not assume 6 if the API expects another length.
152
+
153
+ ### Implementation
154
+
155
+ - **MUST** bind with `v-model` (`modelValue` / `update:modelValue`).
156
+ - **MUST** use only documented props from MCP or `JoyInputDigit.types.ts`.
157
+ - **MUST** style with Joy tokens — no custom `.joy-input-digit` chrome (width, height, gap, border).
158
+ - **MUST NOT** invent props (`size`, `variant`, `mask`, `separator`, …).
159
+ - **MUST NOT** compose several standalone `VJoyInput` fields for OTP — use `VJoyInputDigit`.
160
+ - **MUST** set `invalid` when showing a verification error and render `VJoyFormError` with a actionable message.
161
+ - **SHOULD** call `focusInput(0)` after resending a code so keyboard users can continue immediately.
162
+
163
+ ### Interaction
164
+
165
+ - **SHOULD** auto-submit or advance the flow when `modelValue.length === length` only if the product spec requires it — still handle invalid codes gracefully.
166
+ - **SHOULD** offer “Resend code” as a separate action (link or button), not inside the digit cells.
167
+ - **MUST NOT** clear the field silently on error without telling the user what to do next.
168
+
169
+ ### Do / don’t
170
+
171
+ | Do | Don’t |
172
+ | --- | --- |
173
+ | `VJoyInputDigit` + group label + error message | Six bare inputs with no label |
174
+ | `length` aligned with server OTP size | Always default 6 when API sends 4 digits |
175
+ | `inputAriaLabel` tied to the flow (`Verification code digit`) | Rely on `Digit` in production |
176
+ | `invalid` + `VJoyFormError` on failed verify | Red cells with no explanation |
177
+ | Joy digit tokens | Hardcoded `48px` / `56px` cell sizes |
178
+ | Paste-friendly joined `v-model` | Manual per-cell state in the parent |
179
+
180
+ ---
181
+
182
+ ## Content
183
+
184
+ Copy around an OTP field should reduce anxiety and tell users **where** the code comes from and **what** to do if it fails.
185
+
186
+ ### Group label formula
187
+
188
+ **Noun phrase** naming the code, not the action:
189
+
190
+ - ✅ Verification code
191
+ - ✅ Security code
192
+ - ✅ Authentication code
193
+
194
+ ### Instruction formula
195
+
196
+ **Where the code was sent + what to enter**:
197
+
198
+ - ✅ `Enter the 6-digit code we sent to name@company.com.`
199
+ - ✅ `Enter the code from your authenticator app.`
200
+
201
+ ### Error formula
202
+
203
+ **What failed + how to recover**:
204
+
205
+ - ✅ `That code didn’t work. Check the message and try again, or resend a new code.`
206
+ - ❌ `Invalid code`
207
+
208
+ ### Writing rules
209
+
210
+ | Strength | Rule |
211
+ | --- | --- |
212
+ | **MUST** | Label the group, not each cell — cell names come from `inputAriaLabel` |
213
+ | **MUST** | State code length when it is not 6 — ✅ `Enter the 4-digit PIN` with `length="4"` |
214
+ | **MUST** | Error messages explain retry or resend — not only `Invalid` |
215
+ | **MUST NOT** | Use placeholder text inside digit cells — they are single-digit inputs |
216
+ | **MUST NOT** | Embed the secret code in helper text |
217
+ | **SHOULD** | Mention expiry or resend cooldown in helper text when applicable |
218
+ | **SHOULD** | Keep `inputAriaLabel` short and consistent with the visible label |
219
+ | **SHOULD** | Localize group label, instructions, errors, and `inputAriaLabel` together |
220
+
221
+ ### Patterns
222
+
223
+ **Email / SMS OTP** — Label “Verification code”, instruction with destination email or phone, resend link below, auto-focus first slot on mount.
224
+
225
+ **2FA app** — Label “Authentication code”, instruction references the app; `length` often 6.
226
+
227
+ **PIN (4 digits)** — Set `length="4"`; label “PIN” or “Security PIN”; avoid calling it a “password” unless it truly is one.
228
+
229
+ **Failed verify** — Set `invalid`, show `VJoyFormError`, keep entered digits visible so the user can edit rather than retype from scratch unless security policy requires clearing.
230
+
231
+ ---
232
+
233
+ ## Accessibility
234
+
235
+ Behaviors (what must happen), not slogans.
236
+
237
+ | Behavior | Expectation |
238
+ | --- | --- |
239
+ | Role | Row of native `<input type="number">` elements (via inner `VJoyInput`) |
240
+ | Group name | From associated `VJoyLabel` / page heading — supplement with instructions |
241
+ | Per-slot name | `aria-label` from `inputAriaLabel` + index (`Verification code digit 1/6`) |
242
+ | Value | Joined string via `v-model`; each cell holds one digit |
243
+ | Keyboard | Digits `0–9`; **Backspace** edits or moves back; **Arrow left/right** move between slots; **Tab** moves out of the group |
244
+ | Focus | Visible focus ring on the active inner input — do not remove focus tokens |
245
+ | Paste | Supported; non-digits stripped — announce errors separately via `VJoyFormError` |
246
+ | Autofill | `autocomplete="one-time-code"` on each input for SMS OTP autofill on supported platforms |
247
+ | Invalid | `invalid` styles all slots; pair with `VJoyFormError` (`role="alert"`) for the message |
248
+ | Disabled | All slots `disabled`; do not rely on color alone — provide text explanation |
249
+ | Tracking | Each inner input exposes `data-joy-form-field` for design-system field collection |
250
+
251
+ Target: **WCAG 2.2 AA** where the product requires it.
252
+
253
+ ---
254
+
255
+ ## Examples
256
+
257
+ ```vue
258
+ <script setup lang="ts">
259
+ import { ref } from 'vue'
260
+ import {
261
+ VJoyInputDigit,
262
+ VJoyLabel,
263
+ VJoyFormError,
264
+ VJoyWrapper,
265
+ } from '@maltjoy/core-vue'
266
+
267
+ const code = ref('')
268
+ const showError = ref(false)
269
+
270
+ async function verify() {
271
+ showError.value = code.value.length === 6 && code.value !== '123456'
272
+ }
273
+ </script>
274
+
275
+ <template>
276
+ <VJoyWrapper direction="column" row-gap="4">
277
+ <VJoyLabel for="signup-otp">Verification code</VJoyLabel>
278
+ <p>Enter the 6-digit code we sent to your email.</p>
279
+
280
+ <VJoyInputDigit
281
+ id="signup-otp"
282
+ v-model="code"
283
+ name="signup-otp"
284
+ :length="6"
285
+ input-aria-label="Verification code digit"
286
+ :invalid="showError"
287
+ @change="verify"
288
+ />
289
+
290
+ <VJoyFormError
291
+ v-if="showError"
292
+ message="That code didn't work. Check your email and try again."
293
+ />
294
+ </VJoyWrapper>
295
+
296
+ <!-- 4-digit PIN -->
297
+ <VJoyInputDigit
298
+ v-model="code"
299
+ name="device-pin"
300
+ :length="4"
301
+ input-aria-label="PIN digit"
302
+ disabled
303
+ />
304
+ </template>
305
+ ```
306
+
307
+ In Nuxt (or apps with auto-import), omit the import if `VJoyInputDigit` is already global.
308
+
309
+ ---
310
+
311
+ ## Related
312
+
313
+ | Component | Use when |
314
+ | --- | --- |
315
+ | `VJoyInput` | Single-line free text; not fixed-length numeric codes |
316
+ | `VJoyLabel` | Group label above the digit row |
317
+ | `VJoyFormError` | Inline message when verification fails |
318
+ | `VJoyWrapper` | Spacing between label, digit row, helper, and error |
319
+ | `VJoyButton` | Submit, resend code, or continue after entry |
320
+ | `VJoyInputPassword` | Secret strings with visibility toggle |
321
+ | `VJoyInputNumber` | Numeric values with optional unit suffix |
322
+
323
+ ---
324
+
325
+ ## For agents
326
+
327
+ Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyInputDigit.dsds.json`](./JoyInputDigit.dsds.json).
328
+
329
+ ### Pick the right component
330
+
331
+ | If the intent is… | Emit… | Do not emit… |
332
+ | --- | --- | --- |
333
+ | Fixed-length numeric OTP / PIN | `VJoyInputDigit` | Multiple `VJoyInput` with `maxlength="1"` |
334
+ | Single-line text or email | `VJoyInput` | `VJoyInputDigit` |
335
+ | Alphanumeric backup codes | `VJoyInput` + validation | `VJoyInputDigit` |
336
+ | Password | `VJoyInputPassword` | `VJoyInputDigit` |
337
+ | Amount with currency unit | `VJoyInputNumber` | `VJoyInputDigit` |
338
+
339
+ ### Hard rules
340
+
341
+ 1. **MUST** call `joy_get_component_info("VJoyInputDigit")` or read `JoyInputDigit.types.ts` before generating props.
342
+ 2. **MUST** bind `v-model` for the joined digit string.
343
+ 3. **MUST** set `name` to a unique form prefix.
344
+ 4. **MUST** set `length` to match the expected code size (default `6`).
345
+ 5. **MUST** set `inputAriaLabel` to a meaningful base string (not bare `Digit` in product UI).
346
+ 6. **MUST** set `invalid` when verification fails and render `VJoyFormError` with a message.
347
+ 7. **MUST NOT** invent props (`size`, `variant`, `mask`, `type`, …).
348
+ 8. **MUST NOT** override `.joy-input-digit` or inner `.joy-input` width, height, gap, or border.
349
+ 9. **SHOULD** pair with a visible `VJoyLabel` and short instructions.
350
+ 10. **SHOULD** use `focusInput(0)` on the exposed ref after resend-code actions.
351
+
352
+ ### Checklist
353
+
354
+ - [ ] Correct component (`VJoyInputDigit`, not manual OTP inputs)
355
+ - [ ] Props from MCP or types only
356
+ - [ ] `v-model` + `name` present
357
+ - [ ] `length` matches backend OTP size
358
+ - [ ] Visible group label + `inputAriaLabel` aligned with copy
359
+ - [ ] `invalid` + `VJoyFormError` on verification failure
360
+ - [ ] No invented props / no custom digit-cell CSS
361
+ - [ ] Disabled state explained if user-visible
362
+
363
+ ---
364
+
365
+ ## DSDS mapping
366
+
367
+ This Markdown mirrors [`JoyInputDigit.dsds.json`](./JoyInputDigit.dsds.json) (DSDS **0.15.2**).
368
+
369
+ | Section here | DSDS block |
370
+ | --- | --- |
371
+ | When to use / not | `use-cases` |
372
+ | Anatomy / interaction | `anatomy` |
373
+ | Variants (state-based) | `variants` |
374
+ | Sizes (fixed geometry) | `design-specifications` |
375
+ | States | `states` |
376
+ | Best practices / content rules | `guidelines` (+ `content`) |
377
+ | Accessibility | `accessibility` |
378
+ | Examples | `sections` |
379
+ | For agents | `agentDocumentBlocks` |
380
+ | Props detail | `api` in JSON + Joy MCP |
381
+ | Imports | `imports` in JSON |