por qué no lo haces más simple?
const input = document.getElementById('giftcard-input');
const validKeys = /[a-z0-9\-]/i;
const validLetters = /[a-z]/i;
input.onkeydown = (e) => {
const char = e.key;
const currentStr = input.value;
const currentStrLen = currentStr.length;
// agrega teclas especiales como backspace o flecha derecha/izq
if (char === "Backspace") {
return true;
}
if (validKeys.test(char)) {
// ya tenemos 10 digitos, 2 guiones, 5 letras
if (currentStrLen === 17) {
return false;
}
// debe ser numero
if (currentStrLen < 5 || currentStrLen > 11) {
return !isNaN(char);
// debe ser guion
} else if (currentStrLen === 5 || currentStrLen === 11) {
return char === "-";
// debe ser letra
} else {
return validLetters.test(char);
}
}
// no es ningun char valido, no lo aceptamos en el input
return false;
}
tambien podrias hacerlo por partes como -4 sugerio arriba, tomas los primeros 5, validas, luego los siguientes 5, etc.
otra es tener 3 inputs diferentes y solo validar si es letra o digito, podrias usar el attributo pattern y required en el input para que el navegador lo valide solo.
no hay necesidad de complicarse con tanto regex ni tratar de solucionar para cualquier caso inexistente.