JezK
Edit File: sc-verification-code.cjs.entry.js.map
{"file":"sc-verification-code.entry.cjs.js","mappings":";;;;;;AAAA,MAAM,qBAAqB,GAAG,srEAAsrE,CAAC;AACrtE,iCAAe,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2sBC6IV,UAAE,6OAMjB,UAAE;;;;;;;;","names":[],"sources":["src/components/ui/verification-code/sc-verification-code.scss?tag=sc-verification-code","src/components/ui/verification-code/sc-verification-code.tsx"],"sourcesContent":["sc-verification-code {\n --focus-ring: 0 0 0 var(--sc-focus-ring-width) var(--sc-focus-ring-color-primary);\n display: block;\n\n .sc-verification-code {\n display: flex;\n align-items: center;\n gap: var(--sc-spacing-small);\n margin-top: var(--sc-spacing-medium);\n margin-bottom: var(--sc-spacing-medium);\n\n input {\n flex: 1;\n min-width: 0;\n height: var(--sc-input-height, 48px);\n max-width: 64px;\n box-sizing: border-box;\n font-family: var(--sc-input-font-family);\n font-weight: var(--sc-input-font-weight);\n letter-spacing: var(--sc-input-letter-spacing);\n background-color: var(--sc-input-background-color);\n border: 1px solid var(--sc-input-border-color, var(--sc-input-border));\n border-radius: var(--sc-input-border-radius-medium);\n box-shadow: var(--sc-input-box-shadow);\n font-size: var(--sc-input-font-size-large);\n transition: var(--sc-input-transition, var(--sc-transition-medium)) color, var(--sc-input-transition, var(--sc-transition-medium)) border,\n var(--sc-input-transition, var(--sc-transition-medium)) box-shadow;\n cursor: text;\n text-align: center;\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus,\n &:-webkit-autofill:active {\n box-shadow: 0 0 0 var(--sc-input-height-large) var(--sc-input-background-color-hover) inset !important;\n -webkit-text-fill-color: var(--sc-input-color);\n }\n\n &::placeholder {\n color: var(--sc-input-placeholder-color);\n user-select: none;\n }\n\n &:focus {\n outline: none;\n background-color: var(--sc-input-background-color-focus);\n border-color: var(--sc-input-border-color-focus);\n box-shadow: var(--focus-ring);\n color: var(--sc-input-color-focus);\n z-index: 8;\n }\n }\n\n .sc-verification-code__separator {\n color: var(--sc-input-help-text-color);\n font-size: var(--sc-font-size-large);\n user-select: none;\n display: flex;\n align-items: center;\n }\n\n .visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n }\n}\n","/**\n * External dependencies.\n */\nimport { Component, Fragment, h, Element, Method, Prop, State } from '@stencil/core';\nimport { __ } from '@wordpress/i18n';\n\n@Component({\n tag: 'sc-verification-code',\n styleUrl: 'sc-verification-code.scss',\n})\nexport class ScVerificationCode {\n @Element() el: HTMLScVerificationCodeElement;\n\n /** Total number of inputs */\n @Prop() total: number = 6;\n\n /** The verification codes */\n @State() codes: string[] = Array(this.total).fill('');\n\n /** Whether the component is in a loading/verifying state */\n @Prop() loading: boolean = false;\n\n /** On change verification code */\n @Prop() onChange: (value: string) => void;\n\n handleKeyDown(e: KeyboardEvent, index: number) {\n if (e.key === 'Backspace' || e.key === 'Delete') {\n e.preventDefault();\n this.getElementByIndex(index).value = '';\n this.codes = [...this.codes.slice(0, index), '', ...this.codes.slice(index + 1)];\n if (index > 0) {\n this.focusInput(index - 1);\n }\n }\n }\n\n handleInput(e: InputEvent, index: number) {\n const target = e.target as HTMLInputElement;\n let value = target.value;\n\n // If value is greater than 1, then put all of the characters to the input one by one (e.g. paste).\n if (value.length > 1) {\n const newCodes = [...this.codes];\n for (let i = 0; i < this.total - index && i < value.length; i++) {\n const input = this.getElementByIndex(index + i);\n\n // No need to work with focus, we'll add that manually later.\n input.blur();\n\n input.value = value[i];\n newCodes[index + i] = value[i];\n }\n this.codes = newCodes;\n\n // Update the index to the last character to be able to continue typing.\n index = index + value.length - 1;\n\n // Finally update the value to the last character.\n value = value[value.length - 1];\n }\n\n if (index < this.codes.length) {\n this.codes = [...this.codes.slice(0, index), value, ...this.codes.slice(index + 1)];\n }\n\n if (index < this.codes.length - 1 && value.length > 0) {\n this.focusInput(index + 1);\n }\n\n // If it's the last input, unfocus it.\n if (index === this.codes.length - 1 && value.length > 0) {\n this.getElementByIndex(index).blur();\n }\n\n // Submit the code when all inputs are filled.\n if (this.filledAllInputs()) {\n this.handleCodeChange();\n }\n }\n\n handleCodeChange() {\n const verificationCode = (this.codes.join('') || '').trim();\n\n if (verificationCode.length === this.total) {\n this.onChange(verificationCode);\n }\n }\n\n focusInput(index: number) {\n const input = this.getElementByIndex(index);\n if (input) {\n input.focus();\n input.select();\n }\n }\n\n /** Focus the first code input. */\n @Method()\n async triggerFocus() {\n this.focusInput(0);\n }\n\n getElementByIndex(index: number): HTMLInputElement | null {\n return this.el.querySelector(`#code-input-${index}`) as HTMLInputElement;\n }\n\n handleFocus(e: FocusEvent) {\n const target = e.target as HTMLInputElement;\n target.select();\n }\n\n reset() {\n this.codes = Array(this.total).fill('');\n this.getElementByIndex(0)?.focus();\n }\n\n filledAllInputs = () => {\n return this.codes.join('').trim().length === this.total;\n };\n\n render() {\n return (\n <div class=\"sc-verification-code\">\n {Array.from({ length: this.total }).map((_, index) => (\n <Fragment>\n {index === Math.floor(this.total / 2) && (\n <span class=\"sc-verification-code__separator\" aria-hidden=\"true\">\n —\n </span>\n )}\n <input\n key={index}\n id={`code-input-${index}`}\n value={!!this.codes[index] ? this.codes[index] : ''}\n onInput={e => this.handleInput(e, index)}\n onKeyDown={e => this.handleKeyDown(e, index)}\n onFocus={e => this.handleFocus(e)}\n autocomplete=\"one-time-code\"\n inputmode=\"numeric\"\n pattern=\"[0-9]*\"\n autofocus={index === 0}\n required\n aria-label={__(`Verification code ${index + 1} of ${this.total}`, 'surecart')}\n />\n </Fragment>\n ))}\n\n <button type=\"submit\" class=\"visually-hidden\" onClick={() => this.onChange(this.codes.join(''))}>\n {__('Submit', 'surecart')}\n </button>\n </div>\n );\n }\n}\n"],"version":3}