@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.
- package/LICENSE +21 -0
- package/README.md +30 -3
- package/dist/doc/VJoyAdminBanner/guideline.md +284 -0
- package/dist/doc/VJoyAvailability/guideline.md +352 -0
- package/dist/doc/VJoyAvatar/guideline.md +192 -0
- package/dist/doc/VJoyAvatarsList/guideline.md +328 -0
- package/dist/doc/VJoyBadge/guideline.md +169 -0
- package/dist/doc/VJoyBadgeLevel/guideline.md +166 -0
- package/dist/doc/VJoyBlockSkeleton/guideline.md +150 -0
- package/dist/doc/VJoyBottomSheet/guideline.md +345 -0
- package/dist/doc/VJoyBottomSheetTrigger/guideline.md +156 -0
- package/dist/doc/VJoyButton/guideline.md +371 -0
- package/dist/doc/VJoyButton/metadata.json +0 -16
- package/dist/doc/VJoyButtonCard/guideline.md +384 -0
- package/dist/doc/VJoyCheckbox/guideline.md +317 -0
- package/dist/doc/VJoyCheckboxCard/guideline.md +381 -0
- package/dist/doc/VJoyCheckboxGroup/guideline.md +363 -0
- package/dist/doc/VJoyCheckboxGroup/metadata.json +7 -7
- package/dist/doc/VJoyCollapse/guideline.md +362 -0
- package/dist/doc/VJoyCollapseItem/guideline.md +394 -0
- package/dist/doc/VJoyCompanyAvatar/guideline.md +162 -0
- package/dist/doc/VJoyDialog/guideline.md +425 -0
- package/dist/doc/VJoyDialogTrigger/guideline.md +186 -0
- package/dist/doc/VJoyDot/guideline.md +177 -0
- package/dist/doc/VJoyDrawer/guideline.md +392 -0
- package/dist/doc/VJoyDrawerTrigger/guideline.md +145 -0
- package/dist/doc/VJoyDropdown/guideline.md +393 -0
- package/dist/doc/VJoyDropdown/metadata.json +6 -6
- package/dist/doc/VJoyDropdownList/guideline.md +396 -0
- package/dist/doc/VJoyDropdownList/metadata.json +7 -7
- package/dist/doc/VJoyDropzone/guideline.md +390 -0
- package/dist/doc/VJoyDropzone/metadata.json +36 -1
- package/dist/doc/VJoyFilterBar/guideline.md +419 -0
- package/dist/doc/VJoyFilterBarButton/guideline.md +359 -0
- package/dist/doc/VJoyFloatingActionsBar/guideline.md +372 -0
- package/dist/doc/VJoyFormError/guideline.md +325 -0
- package/dist/doc/VJoyFormError/metadata.json +0 -14
- package/dist/doc/VJoyFormFieldSkeleton/guideline.md +159 -0
- package/dist/doc/VJoyFormGroup/guideline.md +285 -0
- package/dist/doc/VJoyFunnel/guideline.md +349 -0
- package/dist/doc/VJoyFunnelFooter/guideline.md +178 -0
- package/dist/doc/VJoyFunnelHeader/guideline.md +204 -0
- package/dist/doc/VJoyHighlight/guideline.md +169 -0
- package/dist/doc/VJoyIcon/JoyIcon.types.ts +1 -1
- package/dist/doc/VJoyIcon/guideline.md +168 -0
- package/dist/doc/VJoyIcon/metadata.json +0 -1
- package/dist/doc/VJoyIconButton/guideline.md +169 -0
- package/dist/doc/VJoyIconButton/metadata.json +1 -1
- package/dist/doc/VJoyIndicator/guideline.md +168 -0
- package/dist/doc/VJoyIndicators/guideline.md +183 -0
- package/dist/doc/VJoyInput/JoyInput.types.ts +1 -6
- package/dist/doc/VJoyInput/guideline.md +401 -0
- package/dist/doc/VJoyInput/metadata.json +5 -14
- package/dist/doc/VJoyInputDigit/guideline.md +381 -0
- package/dist/doc/VJoyInputNumber/guideline.md +414 -0
- package/dist/doc/VJoyInputNumber/metadata.json +22 -17
- package/dist/doc/VJoyInputPassword/guideline.md +379 -0
- package/dist/doc/VJoyInputPassword/metadata.json +0 -14
- package/dist/doc/VJoyLabel/guideline.md +200 -0
- package/dist/doc/VJoyLink/guideline.md +360 -0
- package/dist/doc/VJoyListItem/guideline.md +335 -0
- package/dist/doc/VJoyMenu/guideline.md +304 -0
- package/dist/doc/VJoyMenu/metadata.json +21 -21
- package/dist/doc/VJoyMenuItem/guideline.md +352 -0
- package/dist/doc/VJoyPagination/guideline.md +355 -0
- package/dist/doc/VJoyPanel/guideline.md +238 -0
- package/dist/doc/VJoyPanelSection/guideline.md +160 -0
- package/dist/doc/VJoyPasswordRequirement/guideline.md +336 -0
- package/dist/doc/VJoyPasswordRequirement/metadata.json +1 -1
- package/dist/doc/VJoyProductTour/JoyProductTour.types.ts +0 -1
- package/dist/doc/VJoyProductTour/guideline.md +455 -0
- package/dist/doc/VJoyProductTour/metadata.json +1 -1
- package/dist/doc/VJoyProductTourTrigger/guideline.md +167 -0
- package/dist/doc/VJoyProgressBar/guideline.md +348 -0
- package/dist/doc/VJoyRadio/guideline.md +346 -0
- package/dist/doc/VJoyRadioGroup/guideline.md +331 -0
- package/dist/doc/VJoyRatingStars/guideline.md +306 -0
- package/dist/doc/VJoyScreenLoader/guideline.md +172 -0
- package/dist/doc/VJoySelect/guideline.md +396 -0
- package/dist/doc/VJoySelectableItem/guideline.md +351 -0
- package/dist/doc/VJoySelectableItemGroup/guideline.md +370 -0
- package/dist/doc/VJoySeparator/guideline.md +161 -0
- package/dist/doc/VJoySnackbar/guideline.md +402 -0
- package/dist/doc/VJoySpinner/guideline.md +168 -0
- package/dist/doc/VJoyStep/guideline.md +182 -0
- package/dist/doc/VJoyStepper/guideline.md +390 -0
- package/dist/doc/VJoyTab/guideline.md +298 -0
- package/dist/doc/VJoyTabs/guideline.md +353 -0
- package/dist/doc/VJoyTag/guideline.md +226 -0
- package/dist/doc/VJoyTagsInput/guideline.md +387 -0
- package/dist/doc/VJoyTagsList/guideline.md +311 -0
- package/dist/doc/VJoyTagsList/metadata.json +27 -27
- package/dist/doc/VJoyTemplate/guideline.md +366 -0
- package/dist/doc/VJoyText/guideline.md +175 -0
- package/dist/doc/VJoyText/metadata.json +1 -1
- package/dist/doc/VJoyTextarea/guideline.md +378 -0
- package/dist/doc/VJoyTitleBrand/guideline.md +155 -0
- package/dist/doc/VJoyToggle/guideline.md +327 -0
- package/dist/doc/VJoyTooltip/guideline.md +322 -0
- package/dist/doc/VJoyUserCard/guideline.md +268 -0
- package/dist/doc/VJoyUserCard/metadata.json +3 -17
- package/dist/doc/VJoyWalkthrough/guideline.md +351 -0
- package/dist/doc/VJoyWalkthroughTrigger/guideline.md +171 -0
- package/dist/doc/VJoyWrapper/guideline.md +173 -0
- package/dist/doc/css-classes.json +1 -15
- package/dist/doc/design-tokens.json +1 -0
- package/dist/doc/index.json +20 -30
- package/dist/index.js +22 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/get-component-guideline.d.ts +30 -0
- package/dist/tools/get-component-guideline.d.ts.map +1 -0
- package/dist/tools/get-component-guideline.js +51 -0
- package/dist/tools/get-component-guideline.js.map +1 -0
- package/dist/tools/get-documentation-page.d.ts +22 -0
- package/dist/tools/get-documentation-page.d.ts.map +1 -0
- package/dist/tools/get-documentation-page.js +21 -0
- package/dist/tools/get-documentation-page.js.map +1 -0
- package/dist/tools/list-documentation-pages.d.ts +22 -0
- package/dist/tools/list-documentation-pages.d.ts.map +1 -0
- package/dist/tools/list-documentation-pages.js +17 -0
- package/dist/tools/list-documentation-pages.js.map +1 -0
- package/dist/tools/search-documentation.d.ts +41 -0
- package/dist/tools/search-documentation.d.ts.map +1 -0
- package/dist/tools/search-documentation.js +25 -0
- package/dist/tools/search-documentation.js.map +1 -0
- package/dist/zeroheight-parser.d.ts +27 -0
- package/dist/zeroheight-parser.d.ts.map +1 -0
- package/dist/zeroheight-parser.js +77 -0
- package/dist/zeroheight-parser.js.map +1 -0
- package/package.json +10 -10
- 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 |
|