Skip to content

Commit 51795bf

Browse files
author
jvictordev1
committed
fix: corrige aparição do texto da tecla enter nos campos e refatora para composition
1 parent 0891ea5 commit 51795bf

File tree

2 files changed

+160
-142
lines changed

2 files changed

+160
-142
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sysvale/cuida",
3-
"version": "3.146.0",
3+
"version": "3.146.1",
44
"description": "A design system built by Sysvale, using storybook and Vue components",
55
"repository": {
66
"type": "git",

src/components/PinInput.vue

Lines changed: 159 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
<template>
2-
<div
3-
class="pin-input__container"
4-
>
2+
<div class="pin-input__container">
53
<input
64
v-for="(number, index) in length"
75
:id="`pin-input${number}`"
86
:key="index"
9-
:ref="`pin-input${number}`"
7+
:ref="(input) => (pinInputRefs[number] = input)"
108
v-model="innerValue[number - 1]"
119
:type="visible ? 'text' : 'password'"
1210
maxlength="1"
@@ -21,159 +19,179 @@
2119
</div>
2220
</template>
2321

24-
<script>
25-
export default {
26-
props: {
27-
modelValue: {
28-
type: String,
29-
default: '',
30-
},
31-
length: {
32-
type: Number,
33-
default: 4
34-
},
35-
/**
36-
* Especifica o estado do TextInput. As opções são 'default', 'valid' e 'invalid'.
37-
*/
38-
state: {
39-
type: String,
40-
default: 'default',
41-
},
42-
visible: {
43-
type: Boolean,
44-
default: false,
45-
},
46-
/**
47-
* Especifica se o PinInput deve ser versão mobile.
48-
*/
49-
mobile: {
50-
type: Boolean,
51-
default: false,
52-
}
53-
},
22+
<script setup>
23+
import { ref, defineProps, defineEmits, computed, watch } from 'vue';
5424
55-
data() {
56-
return {
57-
innerValue: this.modelValue.split(''),
58-
};
25+
const props = defineProps({
26+
modelValue: {
27+
type: String,
28+
default: '',
5929
},
60-
61-
computed: {
62-
computedClass() {
63-
let classToUse = '';
64-
65-
switch (this.state) {
66-
case 'valid':
67-
classToUse = 'pin-input--valid';
68-
break;
69-
case 'invalid':
70-
classToUse = 'pin-input--invalid';
71-
break;
72-
default:
73-
classToUse = 'pin-input';
74-
}
75-
76-
return this.mobile ? `${classToUse} pin-input--mobile` : classToUse;
77-
},
30+
/**
31+
* Especifica a quantidade de caracteres no PIN.
32+
*/
33+
length: {
34+
type: Number,
35+
default: 4,
7836
},
79-
80-
watch: {
81-
modelValue(value) {
82-
this.innerValue = value.split('');
83-
},
37+
/**
38+
* Especifica o estado do TextInput. As opções são 'default', 'valid' e 'invalid'.
39+
*/
40+
state: {
41+
type: String,
42+
default: 'default',
8443
},
85-
86-
methods: {
87-
handleInput(event, index) {
88-
let stringifiedPin = this.innerValue.join('');
89-
90-
if (index < this.length && event.inputType !== 'deleteContentBackward') {
91-
let nextInput = this.$refs[`pin-input${index + 1}`][0];
92-
nextInput.focus();
93-
}
94-
95-
if (stringifiedPin.length === this.length) {
96-
this.$emit('update:modelValue', stringifiedPin);
97-
}
98-
},
99-
100-
handleBack(index) {
101-
if (index > 1) {
102-
this.innerValue[index - 1] = '';
103-
let previousInput = this.$refs[`pin-input${index - 1}`][0];
104-
105-
setTimeout(() => {
106-
previousInput.focus();
107-
}, 150);
108-
}
109-
},
110-
111-
fixCursorPosition(index) {
112-
let input = this.$refs[`pin-input${index}`][0];
113-
setTimeout(() => {
114-
input.setSelectionRange(1, 1);
115-
}, 3);
116-
},
117-
118-
changeInputContent(event, index) {
119-
this.innerValue.splice(index - 1, 1, event.key);
120-
if (index < this.length) {
121-
this.$refs[`pin-input${index + 1}`][0].focus();
122-
}
123-
124-
if (index === this.length) {
125-
this.$emit('update:modelValue', this.innerValue.join(''));
126-
}
127-
}
44+
/**
45+
* Especifica se os caracteres do PIN são visíveis ou não.
46+
*/
47+
visible: {
48+
type: Boolean,
49+
default: false,
50+
},
51+
/**
52+
* Especifica se o PinInput deve ser versão mobile.
53+
*/
54+
mobile: {
55+
type: Boolean,
56+
default: false,
12857
},
58+
});
59+
60+
const emits = defineEmits(['update:modelValue']);
61+
62+
const innerValue = ref(props.modelValue.split(''));
63+
const pinInputRefs = ref([]);
64+
65+
const computedClass = computed(() => {
66+
let classToUse = '';
67+
68+
switch (props.state) {
69+
case 'valid':
70+
classToUse = 'pin-input--valid';
71+
break;
72+
case 'invalid':
73+
classToUse = 'pin-input--invalid';
74+
break;
75+
default:
76+
classToUse = 'pin-input';
77+
}
78+
79+
return props.mobile ? `${classToUse} pin-input--mobile` : classToUse;
80+
});
81+
82+
watch(
83+
() => props.modelValue,
84+
(value) => {
85+
innerValue.value = value.split('');
86+
}
87+
);
88+
89+
function handleInput(event, index) {
90+
let stringifiedPin = innerValue.value.join('');
91+
const length = props.length;
92+
93+
if (index < length && event.inputType !== 'deleteContentBackward') {
94+
let nextInput = pinInputRefs.value[index + 1];
95+
nextInput.focus();
96+
}
97+
98+
if (stringifiedPin.length === length) {
99+
emits('update:modelValue', stringifiedPin);
100+
}
101+
}
102+
103+
function handleBack(index) {
104+
if (index > 1) {
105+
innerValue.value[index - 1] = '';
106+
let previousInput = pinInputRefs.value[index - 1];
107+
108+
setTimeout(() => {
109+
previousInput.focus();
110+
}, 150);
111+
}
112+
}
113+
114+
function handleForth(index) {
115+
if (index < props.length) {
116+
return pinInputRefs.value[index + 1].focus();
117+
}
118+
119+
pinInputRefs.value[index].blur();
120+
}
121+
122+
function fixCursorPosition(index) {
123+
let input = pinInputRefs.value[index];
124+
125+
setTimeout(() => {
126+
input.setSelectionRange(1, 1);
127+
}, 3);
128+
}
129+
130+
function changeInputContent(event, index) {
131+
if (event.key === 'Enter') {
132+
handleForth(index);
133+
134+
return;
135+
}
136+
137+
const length = props.length;
138+
139+
innerValue.value.splice(index - 1, 1, event.key);
140+
if (index < length) {
141+
pinInputRefs.value[index + 1].focus();
142+
}
143+
144+
if (index === length && innerValue.value.join('').length === length) {
145+
emits('update:modelValue', innerValue.value.join(''));
146+
}
129147
}
130148
</script>
131149

132150
<style lang="scss" scoped>
133151
@use '../assets/sass/tokens/index' as tokens;
134-
.pin-input {
135-
height: 40px;
136-
box-sizing: border-box;
137-
width: 36px;
138-
border-radius: tokens.$border-radius-extra-small;
139-
border: 1px solid tokens.$n-100;
140-
text-align: center;
141-
font-size: 1.5em;
142-
transition: tokens.$interaction;
143-
144-
&--mobile {
145-
@extend .pin-input;
146-
height: 48px;
147-
width: 42px;
148-
}
152+
.pin-input {
153+
height: 40px;
154+
box-sizing: border-box;
155+
width: 36px;
156+
border-radius: tokens.$border-radius-extra-small;
157+
border: 1px solid tokens.$n-100;
158+
text-align: center;
159+
font-size: 1.5em;
160+
transition: tokens.$interaction;
161+
162+
&--mobile {
163+
@extend .pin-input;
164+
height: 48px;
165+
width: 42px;
166+
}
149167
150-
&__container {
151-
display: flex;
152-
gap: 8px;
153-
}
168+
&__container {
169+
display: flex;
170+
gap: 8px;
171+
}
154172
155-
&:focus-visible {
156-
outline-color: tokens.$bn-300;
157-
color: tokens.$bn-300;
158-
transition: tokens.$interaction;
159-
}
173+
&:focus-visible {
174+
outline-color: tokens.$bn-300;
175+
color: tokens.$bn-300;
176+
transition: tokens.$interaction;
177+
}
160178
161-
&--valid {
162-
@extend .pin-input;
163-
border: 1px solid tokens.$gp-500;
179+
&--valid {
180+
@extend .pin-input;
181+
border: 1px solid tokens.$gp-500;
164182
165-
&:focus-visible {
166-
outline-color: tokens.$gp-500;
167-
}
183+
&:focus-visible {
184+
outline-color: tokens.$gp-500;
168185
}
186+
}
169187
170-
&--invalid {
171-
@extend .pin-input;
172-
border: 1px solid tokens.$rc-500;
188+
&--invalid {
189+
@extend .pin-input;
190+
border: 1px solid tokens.$rc-500;
173191
174-
&:focus-visible {
175-
outline-color: tokens.$rc-500;
176-
}
192+
&:focus-visible {
193+
outline-color: tokens.$rc-500;
177194
}
178195
}
179-
</style>
196+
}
197+
</style>

0 commit comments

Comments
 (0)