kitunga-web 0.1.105 → 0.1.107
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/dist/features/inputs/components/Inputs/CodeBoxes.d.ts +5 -7
- package/dist/features/inputs/components/Inputs/CodeBoxes.d.ts.map +1 -1
- package/dist/features/inputs/components/Inputs/CodeBoxes.js +40 -86
- package/dist/features/inputs/components/Inputs/CodeBoxes.js.map +1 -1
- package/dist/features/inputs/components/Inputs/CodeBoxes.module.css +31 -4
- package/package.json +1 -1
|
@@ -3,16 +3,14 @@ export type CodeBoxesSize = 'sm' | 'md' | 'lg';
|
|
|
3
3
|
export interface CodeBoxesProps {
|
|
4
4
|
value: string;
|
|
5
5
|
onChange?: (value: string) => void;
|
|
6
|
-
/**
|
|
7
|
-
* (convenção dos controls kitunga). */
|
|
8
|
-
size?: CodeBoxesSize;
|
|
9
|
-
/** Total de caixas — 6 para OTP, 10 para o código de pairing. */
|
|
6
|
+
/** Total de caixas — 6 para OTP, 8 para o código de pairing. */
|
|
10
7
|
length?: number;
|
|
11
|
-
/** Posições (1-based) depois das quais sai um separador.
|
|
12
|
-
* para XXXXX-XXXXX; [2, 4] para XX-XX-XX. */
|
|
8
|
+
/** Posições (1-based) depois das quais sai um separador. */
|
|
13
9
|
separators?: number[];
|
|
14
10
|
charset?: CodeBoxesCharset;
|
|
15
|
-
/**
|
|
11
|
+
/** sm/md/lg — caixa, gap e separador escalam juntos. */
|
|
12
|
+
size?: CodeBoxesSize;
|
|
13
|
+
/** Modo display — renderiza as caixas sem edição. */
|
|
16
14
|
readOnly?: boolean;
|
|
17
15
|
autoFocus?: boolean;
|
|
18
16
|
hasError?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBoxes.d.ts","sourceRoot":"","sources":["../../../../../src/features/inputs/components/Inputs/CodeBoxes.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CodeBoxes.d.ts","sourceRoot":"","sources":["../../../../../src/features/inputs/components/Inputs/CodeBoxes.tsx"],"names":[],"mappings":"AAmBA,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,cAAc,CAAC;AAC1D,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE/C,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,wDAAwD;IACxD,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,MAAU,EACV,UAAe,EACf,IAAW,EACX,OAAmB,EACnB,QAAgB,EAChB,SAAiB,EACjB,QAAgB,EAChB,QAAgB,EAChB,UAAU,EACV,EAAE,EACF,YAAY,EAAE,SAAS,GACxB,EAAE,cAAc,2CAkGhB"}
|
|
@@ -1,106 +1,60 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
// CodeBoxes — código em caixas segmentadas (estilo chave de produto).
|
|
4
|
-
// Dois modos:
|
|
5
|
-
// input — caixas editáveis (OTP do login, código do pairing);
|
|
6
|
-
// auto-avanço, backspace salta atrás, paste enche tudo.
|
|
7
|
-
// display — readonly: mostra um código já gerado (o device que quer
|
|
8
|
-
// entrar no pair mostra-o assim) — mesmo look, sem edição.
|
|
9
4
|
//
|
|
10
|
-
//
|
|
11
|
-
// (
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
|
|
5
|
+
// Arquitectura: UM input escondido cobre a fila inteira e recebe tudo
|
|
6
|
+
// (digitar, backspace, paste, autofill one-time-code) — as caixas são
|
|
7
|
+
// display puro. Foco nunca salta entre elementos, por isso o teclado
|
|
8
|
+
// mobile NUNCA fecha e reabre entre caixas. O cursor lógico é sempre
|
|
9
|
+
// a primeira caixa vazia — clicar onde for cai lá.
|
|
10
|
+
//
|
|
11
|
+
// Modos: input editável (OTP do login, código do pairing) e display
|
|
12
|
+
// readonly (o device que entra mostra o código gerado).
|
|
13
|
+
// `length` = quantas caixas; `separators` = posições (1-based) depois
|
|
14
|
+
// das quais sai o traço — ex.: [4] → XXXX-XXXX, [2,4] → XX-XX-XX.
|
|
15
|
+
import React, { useCallback, useRef, useState } from 'react';
|
|
15
16
|
import { Minus } from 'lucide-react';
|
|
16
17
|
import styles from './CodeBoxes.module.css';
|
|
17
|
-
function sanitizeChar(ch, charset) {
|
|
18
|
-
const upper = ch.toUpperCase();
|
|
19
|
-
if (charset === 'numeric')
|
|
20
|
-
return /[0-9]/.test(upper) ? upper : '';
|
|
21
|
-
return /[0-9A-Z]/.test(upper) ? upper : '';
|
|
22
|
-
}
|
|
23
18
|
function sanitizeValue(raw, charset, max) {
|
|
24
|
-
|
|
19
|
+
const pattern = charset === 'numeric' ? /[0-9]/ : /[0-9A-Z]/;
|
|
20
|
+
return [...raw.toUpperCase()].filter((c) => pattern.test(c)).join('').slice(0, max);
|
|
25
21
|
}
|
|
26
22
|
export default function CodeBoxes({ value, onChange, length = 6, separators = [], size = 'md', charset = 'numeric', readOnly = false, autoFocus = false, hasError = false, disabled = false, onComplete, id, 'aria-label': ariaLabel, }) {
|
|
27
23
|
const total = length;
|
|
28
|
-
const
|
|
24
|
+
const inputRef = useRef(null);
|
|
25
|
+
const [focused, setFocused] = useState(false);
|
|
29
26
|
const separatorsSet = new Set(separators);
|
|
30
27
|
const emit = useCallback((next) => {
|
|
31
28
|
onChange === null || onChange === void 0 ? void 0 : onChange(next);
|
|
32
29
|
if (next.length === total)
|
|
33
30
|
onComplete === null || onComplete === void 0 ? void 0 : onComplete(next);
|
|
34
31
|
}, [onChange, onComplete, total]);
|
|
35
|
-
const
|
|
36
|
-
var _a, _b;
|
|
37
|
-
(_a = refs.current[i]) === null || _a === void 0 ? void 0 : _a.focus();
|
|
38
|
-
(_b = refs.current[i]) === null || _b === void 0 ? void 0 : _b.select();
|
|
39
|
-
}, []);
|
|
40
|
-
// Só a PRIMEIRA caixa vazia pode receber foco — clicar na 4ª com 1
|
|
41
|
-
// preenchida redirecciona para a 2ª (a primeira vazia). Nunca salta
|
|
42
|
-
// caixas por cima; todas vazias → a primeira.
|
|
43
|
-
const focusFirstEmpty = useCallback((e) => {
|
|
44
|
-
const firstEmpty = Math.min(value.length, total - 1);
|
|
45
|
-
const el = e.currentTarget;
|
|
46
|
-
if (refs.current[firstEmpty] && el !== refs.current[firstEmpty]) {
|
|
47
|
-
e.preventDefault();
|
|
48
|
-
focusBox(firstEmpty);
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
el.select();
|
|
52
|
-
}
|
|
53
|
-
}, [value.length, total, focusBox]);
|
|
54
|
-
const handleInput = (i, raw) => {
|
|
32
|
+
const focusInput = useCallback(() => {
|
|
55
33
|
var _a;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
70
|
-
const handleKeyDown = (i, e) => {
|
|
71
|
-
if (e.key === 'Backspace') {
|
|
72
|
-
e.preventDefault();
|
|
73
|
-
if (value[i]) {
|
|
74
|
-
emit(value.slice(0, i) + value.slice(i + 1));
|
|
75
|
-
}
|
|
76
|
-
else if (i > 0) {
|
|
77
|
-
emit(value.slice(0, i - 1) + value.slice(i));
|
|
78
|
-
focusBox(i - 1);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
else if (e.key === 'ArrowLeft' && i > 0) {
|
|
82
|
-
e.preventDefault();
|
|
83
|
-
focusBox(i - 1);
|
|
84
|
-
}
|
|
85
|
-
else if (e.key === 'ArrowRight' && i < total - 1) {
|
|
34
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
35
|
+
}, []);
|
|
36
|
+
if (readOnly) {
|
|
37
|
+
return (_jsx("div", { className: `${styles.wrap} ${styles[size]} ${styles.readOnly}`, role: "group", "aria-label": ariaLabel, id: id, children: Array.from({ length: total }).map((_, i) => {
|
|
38
|
+
var _a;
|
|
39
|
+
const ch = (_a = value[i]) !== null && _a !== void 0 ? _a : '';
|
|
40
|
+
return (_jsxs(React.Fragment, { children: [_jsx("span", { className: `${styles.box} ${ch ? styles.filled : ''}`, children: ch }), separatorsSet.has(i + 1) && (_jsx("span", { className: styles.separator, "aria-hidden": "true", children: _jsx(Minus, { size: size === 'lg' ? 18 : size === 'sm' ? 13 : 16 }) }))] }, i));
|
|
41
|
+
}) }));
|
|
42
|
+
}
|
|
43
|
+
// A caixa "corrente" — a primeira vazia — veste o anel quando o
|
|
44
|
+
// input escondido tem foco. Código cheio: nenhuma acesa.
|
|
45
|
+
const currentIdx = value.length < total ? value.length : -1;
|
|
46
|
+
return (_jsxs("div", { className: `${styles.wrap} ${styles[size]} ${hasError ? styles.hasError : ''} ${disabled ? styles.isDisabled : ''}`, onMouseDown: (e) => {
|
|
86
47
|
e.preventDefault();
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
focusBox(Math.min(i + clean.length, total - 1));
|
|
99
|
-
};
|
|
100
|
-
return (_jsx("div", { className: `${styles.wrap} ${styles[size]} ${hasError ? styles.hasError : ''} ${readOnly ? styles.readOnly : ''}`, role: readOnly ? 'group' : undefined, "aria-label": ariaLabel, id: id, children: Array.from({ length: total }).map((_, i) => {
|
|
101
|
-
var _a;
|
|
102
|
-
const ch = (_a = value[i]) !== null && _a !== void 0 ? _a : '';
|
|
103
|
-
return (_jsxs(React.Fragment, { children: [readOnly ? (_jsx("span", { className: `${styles.box} ${ch ? styles.filled : ''}`, children: ch })) : (_jsx("input", { ref: (el) => { refs.current[i] = el; }, className: `${styles.box} ${ch ? styles.filled : ''}`, value: ch, inputMode: charset === 'numeric' ? 'numeric' : 'text', autoComplete: "off", autoCapitalize: "characters", disabled: disabled, autoFocus: autoFocus && i === 0, onChange: (e) => handleInput(i, e.target.value), onKeyDown: (e) => handleKeyDown(i, e), onPaste: (e) => handlePaste(i, e), onFocus: focusFirstEmpty, onMouseDown: focusFirstEmpty, "aria-label": `${ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : 'code'} ${i + 1}` })), separatorsSet.has(i + 1) && (_jsx("span", { className: styles.separator, "aria-hidden": "true", children: _jsx(Minus, { size: size === 'lg' ? 18 : size === 'sm' ? 13 : 16 }) }))] }, i));
|
|
104
|
-
}) }));
|
|
48
|
+
focusInput();
|
|
49
|
+
}, id: id, children: [_jsx("input", { ref: inputRef, className: styles.hiddenInput, value: value, inputMode: charset === 'numeric' ? 'numeric' : 'text', autoComplete: charset === 'numeric' ? 'one-time-code' : 'off', autoCapitalize: "characters", autoFocus: autoFocus, disabled: disabled, maxLength: total, "aria-label": ariaLabel, onChange: (e) => emit(sanitizeValue(e.target.value, charset, total)), onFocus: (e) => {
|
|
50
|
+
setFocused(true);
|
|
51
|
+
// O teclado virtual abre por cima — traz a fila para a vista
|
|
52
|
+
// (smooth: a janela ainda está a redimensionar).
|
|
53
|
+
e.currentTarget.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
|
54
|
+
}, onBlur: () => setFocused(false) }), Array.from({ length: total }).map((_, i) => {
|
|
55
|
+
var _a;
|
|
56
|
+
const ch = (_a = value[i]) !== null && _a !== void 0 ? _a : '';
|
|
57
|
+
return (_jsxs(React.Fragment, { children: [_jsx("span", { className: `${styles.box} ${ch ? styles.filled : ''} ${focused && i === currentIdx ? styles.current : ''}`, "aria-hidden": "true", children: ch }), separatorsSet.has(i + 1) && (_jsx("span", { className: styles.separator, "aria-hidden": "true", children: _jsx(Minus, { size: size === 'lg' ? 18 : size === 'sm' ? 13 : 16 }) }))] }, i));
|
|
58
|
+
})] }));
|
|
105
59
|
}
|
|
106
60
|
//# sourceMappingURL=CodeBoxes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBoxes.js","sourceRoot":"","sources":["../../../../../src/features/inputs/components/Inputs/CodeBoxes.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,sEAAsE;AACtE,
|
|
1
|
+
{"version":3,"file":"CodeBoxes.js","sourceRoot":"","sources":["../../../../../src/features/inputs/components/Inputs/CodeBoxes.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,sEAAsE;AACtE,EAAE;AACF,sEAAsE;AACtE,sEAAsE;AACtE,qEAAqE;AACrE,qEAAqE;AACrE,mDAAmD;AACnD,EAAE;AACF,oEAAoE;AACpE,wDAAwD;AACxD,sEAAsE;AACtE,kEAAkE;AAElE,OAAO,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,MAAM,MAAM,wBAAwB,CAAC;AA0B5C,SAAS,aAAa,CAAC,GAAW,EAAE,OAAyB,EAAE,GAAW;IACxE,MAAM,OAAO,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAC7D,OAAO,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,MAAM,GAAG,CAAC,EACV,UAAU,GAAG,EAAE,EACf,IAAI,GAAG,IAAI,EACX,OAAO,GAAG,SAAS,EACnB,QAAQ,GAAG,KAAK,EAChB,SAAS,GAAG,KAAK,EACjB,QAAQ,GAAG,KAAK,EAChB,QAAQ,GAAG,KAAK,EAChB,UAAU,EACV,EAAE,EACF,YAAY,EAAE,SAAS,GACR;IACf,MAAM,KAAK,GAAG,MAAM,CAAC;IACrB,MAAM,QAAQ,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAC;IAChD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IAE1C,MAAM,IAAI,GAAG,WAAW,CACtB,CAAC,IAAY,EAAE,EAAE;QACf,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,IAAI,CAAC,CAAC;QACjB,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK;YAAE,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAG,IAAI,CAAC,CAAC;IAChD,CAAC,EACD,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,CAC9B,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;;QAClC,MAAA,QAAQ,CAAC,OAAO,0CAAE,KAAK,EAAE,CAAC;IAC5B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CACL,cACE,SAAS,EAAE,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,EAC9D,IAAI,EAAC,OAAO,gBACA,SAAS,EACrB,EAAE,EAAE,EAAE,YAEL,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;;gBAC1C,MAAM,EAAE,GAAG,MAAA,KAAK,CAAC,CAAC,CAAC,mCAAI,EAAE,CAAC;gBAC1B,OAAO,CACL,MAAC,KAAK,CAAC,QAAQ,eACb,eAAM,SAAS,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,YAAG,EAAE,GAAQ,EACvE,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAC3B,eAAM,SAAS,EAAE,MAAM,CAAC,SAAS,iBAAc,MAAM,YACnD,KAAC,KAAK,IAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAI,GACxD,CACR,KANkB,CAAC,CAOL,CAClB,CAAC;YACJ,CAAC,CAAC,GACE,CACP,CAAC;IACJ,CAAC;IAED,gEAAgE;IAChE,yDAAyD;IACzD,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5D,OAAO,CACL,eACE,SAAS,EAAE,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,EACnH,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE;YACjB,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,UAAU,EAAE,CAAC;QACf,CAAC,EACD,EAAE,EAAE,EAAE,aAIN,gBACE,GAAG,EAAE,QAAQ,EACb,SAAS,EAAE,MAAM,CAAC,WAAW,EAC7B,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EACrD,YAAY,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,EAC7D,cAAc,EAAC,YAAY,EAC3B,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,KAAK,gBACJ,SAAS,EACrB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,EACpE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;oBACb,UAAU,CAAC,IAAI,CAAC,CAAC;oBACjB,6DAA6D;oBAC7D,iDAAiD;oBACjD,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAC1E,CAAC,EACD,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,GAC/B,EACD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;;gBAC1C,MAAM,EAAE,GAAG,MAAA,KAAK,CAAC,CAAC,CAAC,mCAAI,EAAE,CAAC;gBAC1B,OAAO,CACL,MAAC,KAAK,CAAC,QAAQ,eACb,eACE,SAAS,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,iBAC9F,MAAM,YAEjB,EAAE,GACE,EACN,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAC3B,eAAM,SAAS,EAAE,MAAM,CAAC,SAAS,iBAAc,MAAM,YACnD,KAAC,KAAK,IAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAI,GACxD,CACR,KAXkB,CAAC,CAYL,CAClB,CAAC;YACJ,CAAC,CAAC,IACE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -42,12 +42,14 @@
|
|
|
42
42
|
justify-content: center;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
.box {
|
|
46
46
|
cursor: text;
|
|
47
|
+
user-select: none;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
input
|
|
50
|
-
|
|
50
|
+
/* A caixa corrente (primeira vazia) veste o anel enquanto o input
|
|
51
|
+
escondido tem foco — o look de foco, sem o foco saltar. */
|
|
52
|
+
.box.current {
|
|
51
53
|
border-color: var(--border-focus);
|
|
52
54
|
background-color: var(--bg-primary);
|
|
53
55
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
@@ -67,11 +69,36 @@ input.box:focus {
|
|
|
67
69
|
cursor: default;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
/* O input escondido cobre a fila toda — recebe digitar/backspace/
|
|
73
|
+
paste; opacity 0 mas font 16px (mata o auto-zoom do iOS). */
|
|
74
|
+
.hiddenInput {
|
|
75
|
+
position: absolute;
|
|
76
|
+
inset: 0;
|
|
77
|
+
width: 100%;
|
|
78
|
+
height: 100%;
|
|
79
|
+
opacity: 0;
|
|
80
|
+
border: 0;
|
|
81
|
+
padding: 0;
|
|
82
|
+
margin: 0;
|
|
83
|
+
font-size: 16px;
|
|
84
|
+
caret-color: transparent;
|
|
85
|
+
background: transparent;
|
|
86
|
+
cursor: text;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.wrap {
|
|
90
|
+
position: relative;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.isDisabled .box {
|
|
71
94
|
opacity: 0.6;
|
|
72
95
|
cursor: not-allowed;
|
|
73
96
|
}
|
|
74
97
|
|
|
98
|
+
.isDisabled .hiddenInput {
|
|
99
|
+
cursor: default;
|
|
100
|
+
}
|
|
101
|
+
|
|
75
102
|
/* Tamanhos — a caixa, a gap e o separador escalam juntos: a gap do
|
|
76
103
|
flex é a mesma que distancia o traço, por isso size toca tudo. */
|
|
77
104
|
.sm.wrap {
|