feat(Otp): add Otp compound component over createOtp - #787
Open
sridhar-3009 wants to merge 6 commits into
Open
Conversation
…ct paste focus - Wrap length/pattern as getters into createOtp and expose pattern as a Ref on the context — bare destructured props froze them at mount (Rating precedent), leaving inputmode and accepts() stale after a pattern prop change. - Re-sync the box DOM when a keystroke is rejected by the pattern or arrives while disabled/readonly/validating — the model doesn't change, so Vue skips the patch and the stale character lingered in the input. - Focus the next empty box after paste from distribute's start + written count — index + written overshot when the paste landed before index on a shorter value. - Route the Atom template ref through AtomExpose + toElement, track item elements as Element, and cast to HTMLElement only at the focus site. - aria-disabled on the group is a concrete boolean per the house ARIA contract; maturity since starts null until a release ships it.
…ked-input sync Adds regression coverage for the branches codecov flagged: paste filtering/truncation/next-empty-box focus and the disabled guard, arrow navigation clamped at both ends, backspace no-op on the first box, alphanumeric/custom-RegExp/reactive pattern handling, DOM re-sync of rejected and validation-locked keystrokes, single-fire and refire of onComplete, hidden input value/disabled syncing, and the exposed focusItem clamp.
Covers the exact lines codecov flagged: the readonly side of the disabled/readonly guards in beforeinput, keydown, and paste; backspace on a filled box deferring to the native input; unrelated keys falling through the keydown handler; paste without clipboard data; and the renderless slot path driving a consumer-rendered input through slot attrs. OtpItem now measures 100% statements/branches/lines locally.
- Declare the explicit 'update:model-value' emit alongside defineModel (vue-devtools event tracking; Input/Slider/Switch precedent). - Type the Root's imperative surface as an exported OtpRootExpose interface (Splitter precedent) and re-export it from the barrel. - Single-word locals per PHILOSOPHY 3.3: charValue -> char, with the typed character in onInput renamed to entered.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #519.
createOtphas shipped a complete, tested headless primitive for one-time-password / verification-code values since 1.0.0-alpha.5 (pattern-gated entry, completion detection, decisional asynconComplete), but there was no Vue component wrapping it — consumers had to hand-roll rendering, focus management, and keyboard/paste wiring themselves.What's added
Otp.Root,Otp.Item,Otp.HiddenInput— same Root/Item/HiddenInput shape asRatingandSlider:Otp.Rootcreates thecreateOtpcontext, bridges v-model, renders arole="group"container with a locale-driven defaultaria-label("Verification code"), and tracks each Item's element so focus can move between boxes.Otp.Itemrenders one character box (<input maxlength="1" autocomplete="one-time-code">by default —autocomplete="one-time-code"is the documented convention that lets mobile OSes offer SMS-code autofill). Handles:createOtp'sdistribute), sincemaxlengthwould otherwise silently truncate a multi-character paste to 1 chararia-label("Digit N of length")Otp.HiddenInputmirrorsRating.HiddenInput— auto-rendered whennameis set, for native form submission.Registered in the advisory a11y sweep (
packages/0/src/components/fixtures/Otp.vue) — clean, no axe violations. Added the two new locale keys (Otp.label,Otp.itemLabel) to the en catalog per the static locale-coverage check. BumpedOtp'smaturity.jsonentry fromdrafttopreview.Tests
23 tests in
Otp/index.test.tscovering rendering, v-model (including auto-advance, backspace-back, arrow-key nav, paste distribution, and the beforeinput pattern gate), disabled/readonly no-ops, thename/hidden-input path, andonComplete(both the completion signal and async rejection). 94%/98.5% statement/line coverage on the new files, consistent with other components in this codebase.Full suite: 4819 non-browser tests pass, 54 a11y-sweep browser tests pass, typecheck/knip/sherif clean.