ilibras-widget 1.5.3 → 1.6.0
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/CHANGELOG.md +51 -0
- package/README.md +1 -0
- package/dist/ilibras-widget.cjs +188 -16
- package/dist/ilibras-widget.js +188 -16
- package/dist/ilibras-widget.mjs +188 -16
- package/index.d.ts +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,57 @@ Todas as mudanças notáveis neste projeto serão documentadas neste arquivo.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [1.6.0] - 2026-09-29
|
|
8
|
+
|
|
9
|
+
### 🧭 Avisa antes de levar a pessoa para o iLibras
|
|
10
|
+
|
|
11
|
+
Ao clicar em **Iniciar atendimento em Libras** ou em **Agendar uma conversa**,
|
|
12
|
+
o widget agora mostra, no lugar do formulário, o aviso de que a pessoa será
|
|
13
|
+
redirecionada para o iLibras — numa aba nova — e só segue quando ela confirma
|
|
14
|
+
em **Continuar para o iLibras**. **Voltar** (ou Esc) devolve o formulário com o
|
|
15
|
+
nome ainda preenchido.
|
|
16
|
+
|
|
17
|
+
O atendimento só é criado **depois** do "sim". Criar antes e perguntar depois
|
|
18
|
+
deixaria um atendimento órfão na fila de quem desistiu — com o alarme dos
|
|
19
|
+
intérpretes tocando para ninguém.
|
|
20
|
+
|
|
21
|
+
### 🗂️ A aba nova abre dentro do clique
|
|
22
|
+
|
|
23
|
+
A aba do iLibras passa a ser aberta no próprio clique de confirmação, em
|
|
24
|
+
branco ("Abrindo o iLibras…"), e só recebe o endereço quando o atendimento
|
|
25
|
+
volta criado. Antes ela era aberta depois da resposta da API — e `window.open`
|
|
26
|
+
depois de um `await` já não conta como gesto do usuário, que é quando o
|
|
27
|
+
bloqueador de pop-up age. Se a criação falhar, a aba reservada é fechada e a
|
|
28
|
+
pessoa volta ao formulário, onde está a explicação do que houve. O plano B de
|
|
29
|
+
sempre (trocar a página da aba atual) continua valendo para quando nem a aba
|
|
30
|
+
do clique é permitida.
|
|
31
|
+
|
|
32
|
+
### ⚙️ Nova opção: `confirmarRedirecionamento`
|
|
33
|
+
|
|
34
|
+
Ligada por padrão. Com `false`, o widget se comporta como antes da 1.6.0: o
|
|
35
|
+
botão cria o atendimento e abre o iLibras direto.
|
|
36
|
+
|
|
37
|
+
### ♿ Acessibilidade
|
|
38
|
+
|
|
39
|
+
- O aviso é um `alertdialog` com título e texto ligados: ao receber o foco, o
|
|
40
|
+
leitor de tela lê os dois antes do botão.
|
|
41
|
+
- O foco vai para **Continuar** ao abrir o aviso e volta ao botão que a pessoa
|
|
42
|
+
tinha apertado ao sair dele.
|
|
43
|
+
- A região de status saiu de dentro do formulário: escondida junto com ele
|
|
44
|
+
durante o aviso, deixaria de anunciar o andamento do envio.
|
|
45
|
+
- O botão de contorno (agendar, e agora também **Voltar**) ganhou foco visível
|
|
46
|
+
próprio, inclusive em alto contraste — antes dependia do padrão do navegador.
|
|
47
|
+
|
|
48
|
+
### 🧪 Testes
|
|
49
|
+
|
|
50
|
+
`tests/confirmacao.test.mjs` exercita o fluxo na build publicada, com rede e
|
|
51
|
+
janelas simuladas: nada enviado antes da confirmação, aba aberta antes da
|
|
52
|
+
requisição, aba fechada na falha, clique duplo criando um atendimento só.
|
|
53
|
+
Rodada contra a 1.5.3, a suíte reprova em 9 de 10 casos — o único que passa é
|
|
54
|
+
o da opção desligada, que é justamente o comportamento antigo.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
7
58
|
## [1.5.3] - 2026-09-18
|
|
8
59
|
|
|
9
60
|
### 🩹 Conserta o widget que sumiu da tela na 1.5.1
|
package/README.md
CHANGED
|
@@ -168,6 +168,7 @@ new ILibrasWidget({
|
|
|
168
168
|
| `buttonText` | `string` | `'Iniciar atendimento em Libras'` | Texto do botão de envio |
|
|
169
169
|
| `agendamento` | `boolean` | `true` | Mostra o segundo botão, que leva direto à escolha de data e horário em vez da fila ao vivo. Deixe `false` em site que só atende ao vivo |
|
|
170
170
|
| `scheduleButtonText` | `string` | `'Agendar uma conversa'` | Texto do botão de agendamento |
|
|
171
|
+
| `confirmarRedirecionamento` | `boolean` | `true` | Avisa que a pessoa vai para o site do iLibras, numa aba nova, e só cria o atendimento depois que ela confirma. Com `false`, o botão cria o atendimento e abre o iLibras direto, como antes da v1.6.0 |
|
|
171
172
|
| `token` | `string` | `''` | **OBRIGATÓRIO** — token de autenticação da API |
|
|
172
173
|
| `zIndex` | `number` | `9999` | Z-index do widget |
|
|
173
174
|
| `apiUrl` | `string` | endpoint de produção | Endpoint de cadastro. Troque apenas para apontar a um ambiente de homologação |
|
package/dist/ilibras-widget.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* iLibras Widget v1.
|
|
2
|
+
* iLibras Widget v1.6.0
|
|
3
3
|
* https://github.com/Dimendes-Solucoes/Ilibras_widget
|
|
4
4
|
* Licença MIT
|
|
5
5
|
*
|
|
@@ -385,6 +385,42 @@ var CSS = `/**
|
|
|
385
385
|
text-align: center;
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
+
/* Aviso de saída para o iLibras: toma o lugar do formulário até a pessoa
|
|
389
|
+
confirmar ou voltar. O atributo hidden precisa de regra própria nos dois —
|
|
390
|
+
o display: flex de cada um venceria o atributo, e os dois apareceriam
|
|
391
|
+
juntos. (Sem crase nos comentários deste arquivo: ele é embutido num
|
|
392
|
+
template literal do JS, e uma crase aqui muda a forma do build inteiro.) */
|
|
393
|
+
#ilibras-widget-container .ilibras-widget-form[hidden],
|
|
394
|
+
#ilibras-widget-container .ilibras-widget-confirmacao[hidden] {
|
|
395
|
+
display: none !important;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
#ilibras-widget-container .ilibras-widget-confirmacao {
|
|
399
|
+
display: flex;
|
|
400
|
+
flex-direction: column;
|
|
401
|
+
gap: 12px;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-titulo {
|
|
405
|
+
margin: 0;
|
|
406
|
+
font-size: 17px;
|
|
407
|
+
font-weight: 600;
|
|
408
|
+
line-height: 1.35;
|
|
409
|
+
color: #073657;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-texto {
|
|
413
|
+
margin: 0 0 6px;
|
|
414
|
+
font-size: 14px;
|
|
415
|
+
line-height: 1.5;
|
|
416
|
+
color: #495057;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/* "Voltar" tem o visual do botão de agendar, sem a margem que o cola à dica. */
|
|
420
|
+
#ilibras-widget-container .ilibras-widget-confirmacao .ilibras-widget-agendar {
|
|
421
|
+
margin-top: 0;
|
|
422
|
+
}
|
|
423
|
+
|
|
388
424
|
/* Responsividade */
|
|
389
425
|
@media (max-width: 480px) {
|
|
390
426
|
#ilibras-widget-container .ilibras-widget-modal {
|
|
@@ -633,10 +669,11 @@ var CSS = `/**
|
|
|
633
669
|
font-weight: 600;
|
|
634
670
|
}
|
|
635
671
|
|
|
672
|
+
/* Fora do formulário desde a v1.6.0, então a distância vem daqui e não do gap. */
|
|
636
673
|
#ilibras-widget-container .ilibras-widget-status {
|
|
637
674
|
font-size: 13px;
|
|
638
675
|
color: #495057;
|
|
639
|
-
margin: 0;
|
|
676
|
+
margin: 14px 0 0;
|
|
640
677
|
min-height: 1em;
|
|
641
678
|
}
|
|
642
679
|
|
|
@@ -645,6 +682,7 @@ var CSS = `/**
|
|
|
645
682
|
#ilibras-widget-container .ilibras-widget-button:focus-visible,
|
|
646
683
|
#ilibras-widget-container .ilibras-widget-close:focus-visible,
|
|
647
684
|
#ilibras-widget-container .ilibras-widget-submit:focus-visible,
|
|
685
|
+
#ilibras-widget-container .ilibras-widget-agendar:focus-visible,
|
|
648
686
|
#ilibras-widget-container .ilibras-widget-form-group input:focus-visible,
|
|
649
687
|
#ilibras-widget-container .ilibras-widget-checkbox-label input:focus-visible,
|
|
650
688
|
#ilibras-widget-container .ilibras-widget-fallback a:focus-visible {
|
|
@@ -665,6 +703,7 @@ var CSS = `/**
|
|
|
665
703
|
#ilibras-widget-container .ilibras-widget-button:focus-visible,
|
|
666
704
|
#ilibras-widget-container .ilibras-widget-close:focus-visible,
|
|
667
705
|
#ilibras-widget-container .ilibras-widget-submit:focus-visible,
|
|
706
|
+
#ilibras-widget-container .ilibras-widget-agendar:focus-visible,
|
|
668
707
|
#ilibras-widget-container .ilibras-widget-form-group input:focus-visible {
|
|
669
708
|
outline: 3px solid Highlight;
|
|
670
709
|
}
|
|
@@ -718,10 +757,15 @@ var CSS = `/**
|
|
|
718
757
|
color: #9ecbff;
|
|
719
758
|
}
|
|
720
759
|
|
|
721
|
-
#ilibras-widget-container .ilibras-widget-title
|
|
760
|
+
#ilibras-widget-container .ilibras-widget-title,
|
|
761
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-titulo {
|
|
722
762
|
color: #e6f0f8;
|
|
723
763
|
}
|
|
724
764
|
|
|
765
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-texto {
|
|
766
|
+
color: #c9c9c9;
|
|
767
|
+
}
|
|
768
|
+
|
|
725
769
|
#ilibras-widget-container .ilibras-widget-header {
|
|
726
770
|
background: #1e1e1e;
|
|
727
771
|
border-left-color: #333;
|
|
@@ -749,6 +793,10 @@ var defaultConfig = {
|
|
|
749
793
|
// uma agenda que ninguém cobre é pior do que não ter o botão.
|
|
750
794
|
agendamento: true,
|
|
751
795
|
scheduleButtonText: "Agendar uma conversa",
|
|
796
|
+
// Avisa que a pessoa vai sair do site para o iLibras e espera a confirmação
|
|
797
|
+
// antes de criar o atendimento. Sair do site em que se estava, para uma aba
|
|
798
|
+
// nova, sem saber antes, desorienta — sobretudo quem usa leitor de tela.
|
|
799
|
+
confirmarRedirecionamento: true,
|
|
752
800
|
token: "",
|
|
753
801
|
zIndex: 9999,
|
|
754
802
|
apiUrl: "https://sistema.ilibras.com.br/api/public/widget/cadastrar",
|
|
@@ -779,6 +827,7 @@ var ILibrasWidget = class {
|
|
|
779
827
|
this.enviando = false;
|
|
780
828
|
this.abertoEm = null;
|
|
781
829
|
this.focoAnterior = null;
|
|
830
|
+
this.modoPendente = null;
|
|
782
831
|
this.init();
|
|
783
832
|
}
|
|
784
833
|
init() {
|
|
@@ -881,10 +930,30 @@ var ILibrasWidget = class {
|
|
|
881
930
|
<span class="ilibras-widget-dica ilibras-widget-dica-agendar" id="ilibras-widget-agendar-dica">
|
|
882
931
|
Escolha data e horário em vez de esperar na fila.
|
|
883
932
|
</span>` : ""}
|
|
884
|
-
|
|
885
|
-
<!-- Estado do envio, anunciado sem roubar o foco de quem digita. -->
|
|
886
|
-
<p class="ilibras-widget-status" id="ilibras-widget-status" role="status" aria-live="polite"></p>
|
|
887
933
|
</form>
|
|
934
|
+
|
|
935
|
+
<!-- Aviso de saída do site. Ocupa o lugar do formulário em vez de
|
|
936
|
+
abrir uma janela por cima: o diálogo já é modal, e um segundo
|
|
937
|
+
diálogo empilhado confunde quem navega por leitor de tela. -->
|
|
938
|
+
<div id="ilibras-widget-confirmacao" class="ilibras-widget-confirmacao" role="alertdialog"
|
|
939
|
+
aria-labelledby="ilibras-widget-confirmacao-titulo"
|
|
940
|
+
aria-describedby="ilibras-widget-confirmacao-texto" hidden>
|
|
941
|
+
<h3 class="ilibras-widget-confirmacao-titulo" id="ilibras-widget-confirmacao-titulo">
|
|
942
|
+
Você será redirecionado para o iLibras
|
|
943
|
+
</h3>
|
|
944
|
+
<p class="ilibras-widget-confirmacao-texto" id="ilibras-widget-confirmacao-texto"></p>
|
|
945
|
+
<button type="button" id="ilibras-widget-confirmar" class="ilibras-widget-submit">
|
|
946
|
+
Continuar para o iLibras
|
|
947
|
+
</button>
|
|
948
|
+
<button type="button" id="ilibras-widget-voltar" class="ilibras-widget-agendar">
|
|
949
|
+
Voltar
|
|
950
|
+
</button>
|
|
951
|
+
</div>
|
|
952
|
+
|
|
953
|
+
<!-- Estado do envio, anunciado sem roubar o foco de quem digita. Fica
|
|
954
|
+
fora do formulário: escondido junto com ele durante o aviso de
|
|
955
|
+
saída, o leitor de tela deixaria de anunciar o que acontece. -->
|
|
956
|
+
<p class="ilibras-widget-status" id="ilibras-widget-status" role="status" aria-live="polite"></p>
|
|
888
957
|
</div>
|
|
889
958
|
</div>
|
|
890
959
|
`;
|
|
@@ -897,6 +966,10 @@ var ILibrasWidget = class {
|
|
|
897
966
|
this.agendar = container.querySelector("#ilibras-widget-agendar");
|
|
898
967
|
this.aviso = container.querySelector("#ilibras-widget-aviso");
|
|
899
968
|
this.status = container.querySelector("#ilibras-widget-status");
|
|
969
|
+
this.confirmacao = container.querySelector("#ilibras-widget-confirmacao");
|
|
970
|
+
this.confirmacaoTexto = container.querySelector("#ilibras-widget-confirmacao-texto");
|
|
971
|
+
this.confirmar = container.querySelector("#ilibras-widget-confirmar");
|
|
972
|
+
this.voltar = container.querySelector("#ilibras-widget-voltar");
|
|
900
973
|
}
|
|
901
974
|
escapar(texto) {
|
|
902
975
|
const div = document.createElement("div");
|
|
@@ -909,6 +982,10 @@ var ILibrasWidget = class {
|
|
|
909
982
|
this.modal.addEventListener("keydown", (e) => {
|
|
910
983
|
if (e.key === "Escape") {
|
|
911
984
|
e.stopPropagation();
|
|
985
|
+
if (!this.confirmacao.hidden) {
|
|
986
|
+
if (!this.enviando) this.cancelarConfirmacao();
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
912
989
|
this.closeWidget();
|
|
913
990
|
return;
|
|
914
991
|
}
|
|
@@ -924,6 +1001,8 @@ var ILibrasWidget = class {
|
|
|
924
1001
|
if (this.agendar) {
|
|
925
1002
|
this.agendar.addEventListener("click", (e) => this.handleSubmit(e, "agendamento"));
|
|
926
1003
|
}
|
|
1004
|
+
this.confirmar.addEventListener("click", () => this.confirmarRedirecionamento());
|
|
1005
|
+
this.voltar.addEventListener("click", () => this.cancelarConfirmacao());
|
|
927
1006
|
}
|
|
928
1007
|
prenderFoco(evento) {
|
|
929
1008
|
const focaveis = Array.from(this.modal.querySelectorAll(FOCAVEIS)).filter((el) => el.offsetParent !== null || el === document.activeElement);
|
|
@@ -953,6 +1032,7 @@ var ILibrasWidget = class {
|
|
|
953
1032
|
this.container.querySelector("#ilibras-name").focus();
|
|
954
1033
|
}
|
|
955
1034
|
closeWidget() {
|
|
1035
|
+
this.mostrarFormulario();
|
|
956
1036
|
this.modal.classList.remove("ilibras-widget-modal-open");
|
|
957
1037
|
this.botao.classList.remove("ilibras-widget-button-open");
|
|
958
1038
|
this.botao.setAttribute("aria-expanded", "false");
|
|
@@ -1120,6 +1200,85 @@ var ILibrasWidget = class {
|
|
|
1120
1200
|
invalido.focus();
|
|
1121
1201
|
return;
|
|
1122
1202
|
}
|
|
1203
|
+
if (this.config.confirmarRedirecionamento) {
|
|
1204
|
+
this.pedirConfirmacao(modo);
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
await this.criarAtendimento(modo);
|
|
1208
|
+
}
|
|
1209
|
+
// ─── Aviso de saída ─────────────────────────────────────────────────────
|
|
1210
|
+
/**
|
|
1211
|
+
* Troca o formulário pelo aviso de que a pessoa vai para o iLibras. Nada é
|
|
1212
|
+
* enviado ainda: o atendimento só nasce no "Continuar".
|
|
1213
|
+
*/
|
|
1214
|
+
pedirConfirmacao(modo) {
|
|
1215
|
+
this.modoPendente = modo;
|
|
1216
|
+
this.confirmacaoTexto.textContent = modo === "agendamento" ? "O agendamento é feito no site do iLibras, que abre em uma nova aba. Lá você escolhe o dia e o horário da conversa." : "O atendimento em Libras acontece no site do iLibras, que abre em uma nova aba. Lá você entra na fila e aguarda um intérprete.";
|
|
1217
|
+
this.confirmar.textContent = "Continuar para o iLibras";
|
|
1218
|
+
this.form.hidden = true;
|
|
1219
|
+
this.confirmacao.hidden = false;
|
|
1220
|
+
this.anunciar("");
|
|
1221
|
+
this.confirmar.focus();
|
|
1222
|
+
}
|
|
1223
|
+
/** "Voltar": o formulário reaparece como estava, com o nome digitado. */
|
|
1224
|
+
cancelarConfirmacao() {
|
|
1225
|
+
if (this.enviando) return;
|
|
1226
|
+
const modo = this.modoPendente;
|
|
1227
|
+
this.mostrarFormulario();
|
|
1228
|
+
const origem = modo === "agendamento" && this.agendar ? this.agendar : this.submit;
|
|
1229
|
+
origem.focus();
|
|
1230
|
+
}
|
|
1231
|
+
mostrarFormulario() {
|
|
1232
|
+
this.modoPendente = null;
|
|
1233
|
+
this.confirmacao.hidden = true;
|
|
1234
|
+
this.form.hidden = false;
|
|
1235
|
+
}
|
|
1236
|
+
async confirmarRedirecionamento() {
|
|
1237
|
+
if (this.enviando || !this.modoPendente) return;
|
|
1238
|
+
const aba = this.reservarAba();
|
|
1239
|
+
await this.criarAtendimento(this.modoPendente, aba);
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Abre uma aba em branco para receber o iLibras assim que o atendimento
|
|
1243
|
+
* existir. Devolve null quando o navegador barra — aí vale o caminho antigo.
|
|
1244
|
+
*/
|
|
1245
|
+
reservarAba() {
|
|
1246
|
+
let aba = null;
|
|
1247
|
+
try {
|
|
1248
|
+
aba = window.open("", "_blank");
|
|
1249
|
+
} catch (e) {
|
|
1250
|
+
aba = null;
|
|
1251
|
+
}
|
|
1252
|
+
if (!aba) return null;
|
|
1253
|
+
aba.opener = null;
|
|
1254
|
+
try {
|
|
1255
|
+
const doc = aba.document;
|
|
1256
|
+
doc.title = "Abrindo o iLibras…";
|
|
1257
|
+
doc.documentElement.lang = "pt-BR";
|
|
1258
|
+
doc.body.style.cssText = "font:16px/1.5 system-ui,-apple-system,Segoe UI,sans-serif;padding:32px;color:#073657";
|
|
1259
|
+
doc.body.textContent = "Abrindo o iLibras…";
|
|
1260
|
+
} catch (e) {
|
|
1261
|
+
}
|
|
1262
|
+
return aba;
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Leva a pessoa ao endereço devolvido pelo iLibras: na aba reservada quando
|
|
1266
|
+
* ela existe, numa aba nova quando não, e na atual como último recurso.
|
|
1267
|
+
*/
|
|
1268
|
+
irPara(destino, abaReservada) {
|
|
1269
|
+
if (abaReservada && !abaReservada.closed) {
|
|
1270
|
+
abaReservada.location.href = destino;
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1273
|
+
const aba = window.open(destino, "_blank");
|
|
1274
|
+
if (aba) {
|
|
1275
|
+
aba.opener = null;
|
|
1276
|
+
} else {
|
|
1277
|
+
window.location.assign(destino);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
// ─── Criação do atendimento ─────────────────────────────────────────────
|
|
1281
|
+
async criarAtendimento(modo, abaReservada = null) {
|
|
1123
1282
|
const v = this.valores();
|
|
1124
1283
|
const corpo = new FormData();
|
|
1125
1284
|
corpo.append("nome", v.nome);
|
|
@@ -1132,15 +1291,17 @@ var ILibrasWidget = class {
|
|
|
1132
1291
|
const destino = resultado.link_fila || resultado.link || resultado.url || resultado.redirect;
|
|
1133
1292
|
if (!destino) throw new FalhaDeServico("resposta_inesperada");
|
|
1134
1293
|
this.anunciar(modo === "agendamento" ? "Cadastro feito. Abrindo o calendário para escolher data e horário." : "Atendimento criado. Abrindo a sala de atendimento.");
|
|
1135
|
-
|
|
1136
|
-
if (aba) {
|
|
1137
|
-
aba.opener = null;
|
|
1138
|
-
} else {
|
|
1139
|
-
window.location.assign(destino);
|
|
1140
|
-
}
|
|
1294
|
+
this.irPara(destino, abaReservada);
|
|
1141
1295
|
this.form.reset();
|
|
1142
1296
|
this.closeWidget();
|
|
1143
1297
|
} catch (erro) {
|
|
1298
|
+
if (abaReservada && !abaReservada.closed) {
|
|
1299
|
+
try {
|
|
1300
|
+
abaReservada.close();
|
|
1301
|
+
} catch (e) {
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
this.mostrarFormulario();
|
|
1144
1305
|
this.tratarFalha(erro);
|
|
1145
1306
|
} finally {
|
|
1146
1307
|
this.travarEnvio(false, modo);
|
|
@@ -1148,14 +1309,25 @@ var ILibrasWidget = class {
|
|
|
1148
1309
|
}
|
|
1149
1310
|
travarEnvio(travado, modo = "fila") {
|
|
1150
1311
|
this.enviando = travado;
|
|
1151
|
-
for (const botao of [this.submit, this.agendar]) {
|
|
1312
|
+
for (const botao of [this.submit, this.agendar, this.confirmar, this.voltar]) {
|
|
1152
1313
|
if (botao) botao.disabled = travado;
|
|
1153
1314
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1315
|
+
let ativo;
|
|
1316
|
+
let rotulo;
|
|
1317
|
+
if (!this.confirmacao.hidden) {
|
|
1318
|
+
ativo = this.confirmar;
|
|
1319
|
+
rotulo = "Continuar para o iLibras";
|
|
1320
|
+
} else {
|
|
1321
|
+
const usouAgendar = modo === "agendamento" && this.agendar;
|
|
1322
|
+
ativo = usouAgendar ? this.agendar : this.submit;
|
|
1323
|
+
rotulo = usouAgendar ? this.config.scheduleButtonText : this.config.buttonText;
|
|
1324
|
+
}
|
|
1157
1325
|
ativo.setAttribute("aria-busy", travado ? "true" : "false");
|
|
1158
1326
|
ativo.textContent = travado ? "Enviando..." : rotulo;
|
|
1327
|
+
if (!travado) {
|
|
1328
|
+
this.confirmar.setAttribute("aria-busy", "false");
|
|
1329
|
+
this.confirmar.textContent = "Continuar para o iLibras";
|
|
1330
|
+
}
|
|
1159
1331
|
if (travado) this.anunciar("Enviando seus dados. Aguarde.");
|
|
1160
1332
|
}
|
|
1161
1333
|
/**
|
package/dist/ilibras-widget.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* iLibras Widget v1.
|
|
2
|
+
* iLibras Widget v1.6.0
|
|
3
3
|
* https://github.com/Dimendes-Solucoes/Ilibras_widget
|
|
4
4
|
* Licença MIT
|
|
5
5
|
*
|
|
@@ -359,6 +359,42 @@
|
|
|
359
359
|
text-align: center;
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
+
/* Aviso de saída para o iLibras: toma o lugar do formulário até a pessoa
|
|
363
|
+
confirmar ou voltar. O atributo hidden precisa de regra própria nos dois —
|
|
364
|
+
o display: flex de cada um venceria o atributo, e os dois apareceriam
|
|
365
|
+
juntos. (Sem crase nos comentários deste arquivo: ele é embutido num
|
|
366
|
+
template literal do JS, e uma crase aqui muda a forma do build inteiro.) */
|
|
367
|
+
#ilibras-widget-container .ilibras-widget-form[hidden],
|
|
368
|
+
#ilibras-widget-container .ilibras-widget-confirmacao[hidden] {
|
|
369
|
+
display: none !important;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
#ilibras-widget-container .ilibras-widget-confirmacao {
|
|
373
|
+
display: flex;
|
|
374
|
+
flex-direction: column;
|
|
375
|
+
gap: 12px;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-titulo {
|
|
379
|
+
margin: 0;
|
|
380
|
+
font-size: 17px;
|
|
381
|
+
font-weight: 600;
|
|
382
|
+
line-height: 1.35;
|
|
383
|
+
color: #073657;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-texto {
|
|
387
|
+
margin: 0 0 6px;
|
|
388
|
+
font-size: 14px;
|
|
389
|
+
line-height: 1.5;
|
|
390
|
+
color: #495057;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/* "Voltar" tem o visual do botão de agendar, sem a margem que o cola à dica. */
|
|
394
|
+
#ilibras-widget-container .ilibras-widget-confirmacao .ilibras-widget-agendar {
|
|
395
|
+
margin-top: 0;
|
|
396
|
+
}
|
|
397
|
+
|
|
362
398
|
/* Responsividade */
|
|
363
399
|
@media (max-width: 480px) {
|
|
364
400
|
#ilibras-widget-container .ilibras-widget-modal {
|
|
@@ -607,10 +643,11 @@
|
|
|
607
643
|
font-weight: 600;
|
|
608
644
|
}
|
|
609
645
|
|
|
646
|
+
/* Fora do formulário desde a v1.6.0, então a distância vem daqui e não do gap. */
|
|
610
647
|
#ilibras-widget-container .ilibras-widget-status {
|
|
611
648
|
font-size: 13px;
|
|
612
649
|
color: #495057;
|
|
613
|
-
margin: 0;
|
|
650
|
+
margin: 14px 0 0;
|
|
614
651
|
min-height: 1em;
|
|
615
652
|
}
|
|
616
653
|
|
|
@@ -619,6 +656,7 @@
|
|
|
619
656
|
#ilibras-widget-container .ilibras-widget-button:focus-visible,
|
|
620
657
|
#ilibras-widget-container .ilibras-widget-close:focus-visible,
|
|
621
658
|
#ilibras-widget-container .ilibras-widget-submit:focus-visible,
|
|
659
|
+
#ilibras-widget-container .ilibras-widget-agendar:focus-visible,
|
|
622
660
|
#ilibras-widget-container .ilibras-widget-form-group input:focus-visible,
|
|
623
661
|
#ilibras-widget-container .ilibras-widget-checkbox-label input:focus-visible,
|
|
624
662
|
#ilibras-widget-container .ilibras-widget-fallback a:focus-visible {
|
|
@@ -639,6 +677,7 @@
|
|
|
639
677
|
#ilibras-widget-container .ilibras-widget-button:focus-visible,
|
|
640
678
|
#ilibras-widget-container .ilibras-widget-close:focus-visible,
|
|
641
679
|
#ilibras-widget-container .ilibras-widget-submit:focus-visible,
|
|
680
|
+
#ilibras-widget-container .ilibras-widget-agendar:focus-visible,
|
|
642
681
|
#ilibras-widget-container .ilibras-widget-form-group input:focus-visible {
|
|
643
682
|
outline: 3px solid Highlight;
|
|
644
683
|
}
|
|
@@ -692,10 +731,15 @@
|
|
|
692
731
|
color: #9ecbff;
|
|
693
732
|
}
|
|
694
733
|
|
|
695
|
-
#ilibras-widget-container .ilibras-widget-title
|
|
734
|
+
#ilibras-widget-container .ilibras-widget-title,
|
|
735
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-titulo {
|
|
696
736
|
color: #e6f0f8;
|
|
697
737
|
}
|
|
698
738
|
|
|
739
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-texto {
|
|
740
|
+
color: #c9c9c9;
|
|
741
|
+
}
|
|
742
|
+
|
|
699
743
|
#ilibras-widget-container .ilibras-widget-header {
|
|
700
744
|
background: #1e1e1e;
|
|
701
745
|
border-left-color: #333;
|
|
@@ -723,6 +767,10 @@
|
|
|
723
767
|
// uma agenda que ninguém cobre é pior do que não ter o botão.
|
|
724
768
|
agendamento: true,
|
|
725
769
|
scheduleButtonText: "Agendar uma conversa",
|
|
770
|
+
// Avisa que a pessoa vai sair do site para o iLibras e espera a confirmação
|
|
771
|
+
// antes de criar o atendimento. Sair do site em que se estava, para uma aba
|
|
772
|
+
// nova, sem saber antes, desorienta — sobretudo quem usa leitor de tela.
|
|
773
|
+
confirmarRedirecionamento: true,
|
|
726
774
|
token: "",
|
|
727
775
|
zIndex: 9999,
|
|
728
776
|
apiUrl: "https://sistema.ilibras.com.br/api/public/widget/cadastrar",
|
|
@@ -753,6 +801,7 @@
|
|
|
753
801
|
this.enviando = false;
|
|
754
802
|
this.abertoEm = null;
|
|
755
803
|
this.focoAnterior = null;
|
|
804
|
+
this.modoPendente = null;
|
|
756
805
|
this.init();
|
|
757
806
|
}
|
|
758
807
|
init() {
|
|
@@ -855,10 +904,30 @@
|
|
|
855
904
|
<span class="ilibras-widget-dica ilibras-widget-dica-agendar" id="ilibras-widget-agendar-dica">
|
|
856
905
|
Escolha data e horário em vez de esperar na fila.
|
|
857
906
|
</span>` : ""}
|
|
858
|
-
|
|
859
|
-
<!-- Estado do envio, anunciado sem roubar o foco de quem digita. -->
|
|
860
|
-
<p class="ilibras-widget-status" id="ilibras-widget-status" role="status" aria-live="polite"></p>
|
|
861
907
|
</form>
|
|
908
|
+
|
|
909
|
+
<!-- Aviso de saída do site. Ocupa o lugar do formulário em vez de
|
|
910
|
+
abrir uma janela por cima: o diálogo já é modal, e um segundo
|
|
911
|
+
diálogo empilhado confunde quem navega por leitor de tela. -->
|
|
912
|
+
<div id="ilibras-widget-confirmacao" class="ilibras-widget-confirmacao" role="alertdialog"
|
|
913
|
+
aria-labelledby="ilibras-widget-confirmacao-titulo"
|
|
914
|
+
aria-describedby="ilibras-widget-confirmacao-texto" hidden>
|
|
915
|
+
<h3 class="ilibras-widget-confirmacao-titulo" id="ilibras-widget-confirmacao-titulo">
|
|
916
|
+
Você será redirecionado para o iLibras
|
|
917
|
+
</h3>
|
|
918
|
+
<p class="ilibras-widget-confirmacao-texto" id="ilibras-widget-confirmacao-texto"></p>
|
|
919
|
+
<button type="button" id="ilibras-widget-confirmar" class="ilibras-widget-submit">
|
|
920
|
+
Continuar para o iLibras
|
|
921
|
+
</button>
|
|
922
|
+
<button type="button" id="ilibras-widget-voltar" class="ilibras-widget-agendar">
|
|
923
|
+
Voltar
|
|
924
|
+
</button>
|
|
925
|
+
</div>
|
|
926
|
+
|
|
927
|
+
<!-- Estado do envio, anunciado sem roubar o foco de quem digita. Fica
|
|
928
|
+
fora do formulário: escondido junto com ele durante o aviso de
|
|
929
|
+
saída, o leitor de tela deixaria de anunciar o que acontece. -->
|
|
930
|
+
<p class="ilibras-widget-status" id="ilibras-widget-status" role="status" aria-live="polite"></p>
|
|
862
931
|
</div>
|
|
863
932
|
</div>
|
|
864
933
|
`;
|
|
@@ -871,6 +940,10 @@
|
|
|
871
940
|
this.agendar = container.querySelector("#ilibras-widget-agendar");
|
|
872
941
|
this.aviso = container.querySelector("#ilibras-widget-aviso");
|
|
873
942
|
this.status = container.querySelector("#ilibras-widget-status");
|
|
943
|
+
this.confirmacao = container.querySelector("#ilibras-widget-confirmacao");
|
|
944
|
+
this.confirmacaoTexto = container.querySelector("#ilibras-widget-confirmacao-texto");
|
|
945
|
+
this.confirmar = container.querySelector("#ilibras-widget-confirmar");
|
|
946
|
+
this.voltar = container.querySelector("#ilibras-widget-voltar");
|
|
874
947
|
}
|
|
875
948
|
escapar(texto) {
|
|
876
949
|
const div = document.createElement("div");
|
|
@@ -883,6 +956,10 @@
|
|
|
883
956
|
this.modal.addEventListener("keydown", (e) => {
|
|
884
957
|
if (e.key === "Escape") {
|
|
885
958
|
e.stopPropagation();
|
|
959
|
+
if (!this.confirmacao.hidden) {
|
|
960
|
+
if (!this.enviando) this.cancelarConfirmacao();
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
886
963
|
this.closeWidget();
|
|
887
964
|
return;
|
|
888
965
|
}
|
|
@@ -898,6 +975,8 @@
|
|
|
898
975
|
if (this.agendar) {
|
|
899
976
|
this.agendar.addEventListener("click", (e) => this.handleSubmit(e, "agendamento"));
|
|
900
977
|
}
|
|
978
|
+
this.confirmar.addEventListener("click", () => this.confirmarRedirecionamento());
|
|
979
|
+
this.voltar.addEventListener("click", () => this.cancelarConfirmacao());
|
|
901
980
|
}
|
|
902
981
|
prenderFoco(evento) {
|
|
903
982
|
const focaveis = Array.from(this.modal.querySelectorAll(FOCAVEIS)).filter((el) => el.offsetParent !== null || el === document.activeElement);
|
|
@@ -927,6 +1006,7 @@
|
|
|
927
1006
|
this.container.querySelector("#ilibras-name").focus();
|
|
928
1007
|
}
|
|
929
1008
|
closeWidget() {
|
|
1009
|
+
this.mostrarFormulario();
|
|
930
1010
|
this.modal.classList.remove("ilibras-widget-modal-open");
|
|
931
1011
|
this.botao.classList.remove("ilibras-widget-button-open");
|
|
932
1012
|
this.botao.setAttribute("aria-expanded", "false");
|
|
@@ -1094,6 +1174,85 @@
|
|
|
1094
1174
|
invalido.focus();
|
|
1095
1175
|
return;
|
|
1096
1176
|
}
|
|
1177
|
+
if (this.config.confirmarRedirecionamento) {
|
|
1178
|
+
this.pedirConfirmacao(modo);
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
await this.criarAtendimento(modo);
|
|
1182
|
+
}
|
|
1183
|
+
// ─── Aviso de saída ─────────────────────────────────────────────────────
|
|
1184
|
+
/**
|
|
1185
|
+
* Troca o formulário pelo aviso de que a pessoa vai para o iLibras. Nada é
|
|
1186
|
+
* enviado ainda: o atendimento só nasce no "Continuar".
|
|
1187
|
+
*/
|
|
1188
|
+
pedirConfirmacao(modo) {
|
|
1189
|
+
this.modoPendente = modo;
|
|
1190
|
+
this.confirmacaoTexto.textContent = modo === "agendamento" ? "O agendamento é feito no site do iLibras, que abre em uma nova aba. Lá você escolhe o dia e o horário da conversa." : "O atendimento em Libras acontece no site do iLibras, que abre em uma nova aba. Lá você entra na fila e aguarda um intérprete.";
|
|
1191
|
+
this.confirmar.textContent = "Continuar para o iLibras";
|
|
1192
|
+
this.form.hidden = true;
|
|
1193
|
+
this.confirmacao.hidden = false;
|
|
1194
|
+
this.anunciar("");
|
|
1195
|
+
this.confirmar.focus();
|
|
1196
|
+
}
|
|
1197
|
+
/** "Voltar": o formulário reaparece como estava, com o nome digitado. */
|
|
1198
|
+
cancelarConfirmacao() {
|
|
1199
|
+
if (this.enviando) return;
|
|
1200
|
+
const modo = this.modoPendente;
|
|
1201
|
+
this.mostrarFormulario();
|
|
1202
|
+
const origem = modo === "agendamento" && this.agendar ? this.agendar : this.submit;
|
|
1203
|
+
origem.focus();
|
|
1204
|
+
}
|
|
1205
|
+
mostrarFormulario() {
|
|
1206
|
+
this.modoPendente = null;
|
|
1207
|
+
this.confirmacao.hidden = true;
|
|
1208
|
+
this.form.hidden = false;
|
|
1209
|
+
}
|
|
1210
|
+
async confirmarRedirecionamento() {
|
|
1211
|
+
if (this.enviando || !this.modoPendente) return;
|
|
1212
|
+
const aba = this.reservarAba();
|
|
1213
|
+
await this.criarAtendimento(this.modoPendente, aba);
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Abre uma aba em branco para receber o iLibras assim que o atendimento
|
|
1217
|
+
* existir. Devolve null quando o navegador barra — aí vale o caminho antigo.
|
|
1218
|
+
*/
|
|
1219
|
+
reservarAba() {
|
|
1220
|
+
let aba = null;
|
|
1221
|
+
try {
|
|
1222
|
+
aba = window.open("", "_blank");
|
|
1223
|
+
} catch (e) {
|
|
1224
|
+
aba = null;
|
|
1225
|
+
}
|
|
1226
|
+
if (!aba) return null;
|
|
1227
|
+
aba.opener = null;
|
|
1228
|
+
try {
|
|
1229
|
+
const doc = aba.document;
|
|
1230
|
+
doc.title = "Abrindo o iLibras…";
|
|
1231
|
+
doc.documentElement.lang = "pt-BR";
|
|
1232
|
+
doc.body.style.cssText = "font:16px/1.5 system-ui,-apple-system,Segoe UI,sans-serif;padding:32px;color:#073657";
|
|
1233
|
+
doc.body.textContent = "Abrindo o iLibras…";
|
|
1234
|
+
} catch (e) {
|
|
1235
|
+
}
|
|
1236
|
+
return aba;
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Leva a pessoa ao endereço devolvido pelo iLibras: na aba reservada quando
|
|
1240
|
+
* ela existe, numa aba nova quando não, e na atual como último recurso.
|
|
1241
|
+
*/
|
|
1242
|
+
irPara(destino, abaReservada) {
|
|
1243
|
+
if (abaReservada && !abaReservada.closed) {
|
|
1244
|
+
abaReservada.location.href = destino;
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
const aba = window.open(destino, "_blank");
|
|
1248
|
+
if (aba) {
|
|
1249
|
+
aba.opener = null;
|
|
1250
|
+
} else {
|
|
1251
|
+
window.location.assign(destino);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
// ─── Criação do atendimento ─────────────────────────────────────────────
|
|
1255
|
+
async criarAtendimento(modo, abaReservada = null) {
|
|
1097
1256
|
const v = this.valores();
|
|
1098
1257
|
const corpo = new FormData();
|
|
1099
1258
|
corpo.append("nome", v.nome);
|
|
@@ -1106,15 +1265,17 @@
|
|
|
1106
1265
|
const destino = resultado.link_fila || resultado.link || resultado.url || resultado.redirect;
|
|
1107
1266
|
if (!destino) throw new FalhaDeServico("resposta_inesperada");
|
|
1108
1267
|
this.anunciar(modo === "agendamento" ? "Cadastro feito. Abrindo o calendário para escolher data e horário." : "Atendimento criado. Abrindo a sala de atendimento.");
|
|
1109
|
-
|
|
1110
|
-
if (aba) {
|
|
1111
|
-
aba.opener = null;
|
|
1112
|
-
} else {
|
|
1113
|
-
window.location.assign(destino);
|
|
1114
|
-
}
|
|
1268
|
+
this.irPara(destino, abaReservada);
|
|
1115
1269
|
this.form.reset();
|
|
1116
1270
|
this.closeWidget();
|
|
1117
1271
|
} catch (erro) {
|
|
1272
|
+
if (abaReservada && !abaReservada.closed) {
|
|
1273
|
+
try {
|
|
1274
|
+
abaReservada.close();
|
|
1275
|
+
} catch (e) {
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
this.mostrarFormulario();
|
|
1118
1279
|
this.tratarFalha(erro);
|
|
1119
1280
|
} finally {
|
|
1120
1281
|
this.travarEnvio(false, modo);
|
|
@@ -1122,14 +1283,25 @@
|
|
|
1122
1283
|
}
|
|
1123
1284
|
travarEnvio(travado, modo = "fila") {
|
|
1124
1285
|
this.enviando = travado;
|
|
1125
|
-
for (const botao of [this.submit, this.agendar]) {
|
|
1286
|
+
for (const botao of [this.submit, this.agendar, this.confirmar, this.voltar]) {
|
|
1126
1287
|
if (botao) botao.disabled = travado;
|
|
1127
1288
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1289
|
+
let ativo;
|
|
1290
|
+
let rotulo;
|
|
1291
|
+
if (!this.confirmacao.hidden) {
|
|
1292
|
+
ativo = this.confirmar;
|
|
1293
|
+
rotulo = "Continuar para o iLibras";
|
|
1294
|
+
} else {
|
|
1295
|
+
const usouAgendar = modo === "agendamento" && this.agendar;
|
|
1296
|
+
ativo = usouAgendar ? this.agendar : this.submit;
|
|
1297
|
+
rotulo = usouAgendar ? this.config.scheduleButtonText : this.config.buttonText;
|
|
1298
|
+
}
|
|
1131
1299
|
ativo.setAttribute("aria-busy", travado ? "true" : "false");
|
|
1132
1300
|
ativo.textContent = travado ? "Enviando..." : rotulo;
|
|
1301
|
+
if (!travado) {
|
|
1302
|
+
this.confirmar.setAttribute("aria-busy", "false");
|
|
1303
|
+
this.confirmar.textContent = "Continuar para o iLibras";
|
|
1304
|
+
}
|
|
1133
1305
|
if (travado) this.anunciar("Enviando seus dados. Aguarde.");
|
|
1134
1306
|
}
|
|
1135
1307
|
/**
|
package/dist/ilibras-widget.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* iLibras Widget v1.
|
|
2
|
+
* iLibras Widget v1.6.0
|
|
3
3
|
* https://github.com/Dimendes-Solucoes/Ilibras_widget
|
|
4
4
|
* Licença MIT
|
|
5
5
|
*
|
|
@@ -359,6 +359,42 @@ var CSS = `/**
|
|
|
359
359
|
text-align: center;
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
+
/* Aviso de saída para o iLibras: toma o lugar do formulário até a pessoa
|
|
363
|
+
confirmar ou voltar. O atributo hidden precisa de regra própria nos dois —
|
|
364
|
+
o display: flex de cada um venceria o atributo, e os dois apareceriam
|
|
365
|
+
juntos. (Sem crase nos comentários deste arquivo: ele é embutido num
|
|
366
|
+
template literal do JS, e uma crase aqui muda a forma do build inteiro.) */
|
|
367
|
+
#ilibras-widget-container .ilibras-widget-form[hidden],
|
|
368
|
+
#ilibras-widget-container .ilibras-widget-confirmacao[hidden] {
|
|
369
|
+
display: none !important;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
#ilibras-widget-container .ilibras-widget-confirmacao {
|
|
373
|
+
display: flex;
|
|
374
|
+
flex-direction: column;
|
|
375
|
+
gap: 12px;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-titulo {
|
|
379
|
+
margin: 0;
|
|
380
|
+
font-size: 17px;
|
|
381
|
+
font-weight: 600;
|
|
382
|
+
line-height: 1.35;
|
|
383
|
+
color: #073657;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-texto {
|
|
387
|
+
margin: 0 0 6px;
|
|
388
|
+
font-size: 14px;
|
|
389
|
+
line-height: 1.5;
|
|
390
|
+
color: #495057;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/* "Voltar" tem o visual do botão de agendar, sem a margem que o cola à dica. */
|
|
394
|
+
#ilibras-widget-container .ilibras-widget-confirmacao .ilibras-widget-agendar {
|
|
395
|
+
margin-top: 0;
|
|
396
|
+
}
|
|
397
|
+
|
|
362
398
|
/* Responsividade */
|
|
363
399
|
@media (max-width: 480px) {
|
|
364
400
|
#ilibras-widget-container .ilibras-widget-modal {
|
|
@@ -607,10 +643,11 @@ var CSS = `/**
|
|
|
607
643
|
font-weight: 600;
|
|
608
644
|
}
|
|
609
645
|
|
|
646
|
+
/* Fora do formulário desde a v1.6.0, então a distância vem daqui e não do gap. */
|
|
610
647
|
#ilibras-widget-container .ilibras-widget-status {
|
|
611
648
|
font-size: 13px;
|
|
612
649
|
color: #495057;
|
|
613
|
-
margin: 0;
|
|
650
|
+
margin: 14px 0 0;
|
|
614
651
|
min-height: 1em;
|
|
615
652
|
}
|
|
616
653
|
|
|
@@ -619,6 +656,7 @@ var CSS = `/**
|
|
|
619
656
|
#ilibras-widget-container .ilibras-widget-button:focus-visible,
|
|
620
657
|
#ilibras-widget-container .ilibras-widget-close:focus-visible,
|
|
621
658
|
#ilibras-widget-container .ilibras-widget-submit:focus-visible,
|
|
659
|
+
#ilibras-widget-container .ilibras-widget-agendar:focus-visible,
|
|
622
660
|
#ilibras-widget-container .ilibras-widget-form-group input:focus-visible,
|
|
623
661
|
#ilibras-widget-container .ilibras-widget-checkbox-label input:focus-visible,
|
|
624
662
|
#ilibras-widget-container .ilibras-widget-fallback a:focus-visible {
|
|
@@ -639,6 +677,7 @@ var CSS = `/**
|
|
|
639
677
|
#ilibras-widget-container .ilibras-widget-button:focus-visible,
|
|
640
678
|
#ilibras-widget-container .ilibras-widget-close:focus-visible,
|
|
641
679
|
#ilibras-widget-container .ilibras-widget-submit:focus-visible,
|
|
680
|
+
#ilibras-widget-container .ilibras-widget-agendar:focus-visible,
|
|
642
681
|
#ilibras-widget-container .ilibras-widget-form-group input:focus-visible {
|
|
643
682
|
outline: 3px solid Highlight;
|
|
644
683
|
}
|
|
@@ -692,10 +731,15 @@ var CSS = `/**
|
|
|
692
731
|
color: #9ecbff;
|
|
693
732
|
}
|
|
694
733
|
|
|
695
|
-
#ilibras-widget-container .ilibras-widget-title
|
|
734
|
+
#ilibras-widget-container .ilibras-widget-title,
|
|
735
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-titulo {
|
|
696
736
|
color: #e6f0f8;
|
|
697
737
|
}
|
|
698
738
|
|
|
739
|
+
#ilibras-widget-container .ilibras-widget-confirmacao-texto {
|
|
740
|
+
color: #c9c9c9;
|
|
741
|
+
}
|
|
742
|
+
|
|
699
743
|
#ilibras-widget-container .ilibras-widget-header {
|
|
700
744
|
background: #1e1e1e;
|
|
701
745
|
border-left-color: #333;
|
|
@@ -723,6 +767,10 @@ var defaultConfig = {
|
|
|
723
767
|
// uma agenda que ninguém cobre é pior do que não ter o botão.
|
|
724
768
|
agendamento: true,
|
|
725
769
|
scheduleButtonText: "Agendar uma conversa",
|
|
770
|
+
// Avisa que a pessoa vai sair do site para o iLibras e espera a confirmação
|
|
771
|
+
// antes de criar o atendimento. Sair do site em que se estava, para uma aba
|
|
772
|
+
// nova, sem saber antes, desorienta — sobretudo quem usa leitor de tela.
|
|
773
|
+
confirmarRedirecionamento: true,
|
|
726
774
|
token: "",
|
|
727
775
|
zIndex: 9999,
|
|
728
776
|
apiUrl: "https://sistema.ilibras.com.br/api/public/widget/cadastrar",
|
|
@@ -753,6 +801,7 @@ var ILibrasWidget = class {
|
|
|
753
801
|
this.enviando = false;
|
|
754
802
|
this.abertoEm = null;
|
|
755
803
|
this.focoAnterior = null;
|
|
804
|
+
this.modoPendente = null;
|
|
756
805
|
this.init();
|
|
757
806
|
}
|
|
758
807
|
init() {
|
|
@@ -855,10 +904,30 @@ var ILibrasWidget = class {
|
|
|
855
904
|
<span class="ilibras-widget-dica ilibras-widget-dica-agendar" id="ilibras-widget-agendar-dica">
|
|
856
905
|
Escolha data e horário em vez de esperar na fila.
|
|
857
906
|
</span>` : ""}
|
|
858
|
-
|
|
859
|
-
<!-- Estado do envio, anunciado sem roubar o foco de quem digita. -->
|
|
860
|
-
<p class="ilibras-widget-status" id="ilibras-widget-status" role="status" aria-live="polite"></p>
|
|
861
907
|
</form>
|
|
908
|
+
|
|
909
|
+
<!-- Aviso de saída do site. Ocupa o lugar do formulário em vez de
|
|
910
|
+
abrir uma janela por cima: o diálogo já é modal, e um segundo
|
|
911
|
+
diálogo empilhado confunde quem navega por leitor de tela. -->
|
|
912
|
+
<div id="ilibras-widget-confirmacao" class="ilibras-widget-confirmacao" role="alertdialog"
|
|
913
|
+
aria-labelledby="ilibras-widget-confirmacao-titulo"
|
|
914
|
+
aria-describedby="ilibras-widget-confirmacao-texto" hidden>
|
|
915
|
+
<h3 class="ilibras-widget-confirmacao-titulo" id="ilibras-widget-confirmacao-titulo">
|
|
916
|
+
Você será redirecionado para o iLibras
|
|
917
|
+
</h3>
|
|
918
|
+
<p class="ilibras-widget-confirmacao-texto" id="ilibras-widget-confirmacao-texto"></p>
|
|
919
|
+
<button type="button" id="ilibras-widget-confirmar" class="ilibras-widget-submit">
|
|
920
|
+
Continuar para o iLibras
|
|
921
|
+
</button>
|
|
922
|
+
<button type="button" id="ilibras-widget-voltar" class="ilibras-widget-agendar">
|
|
923
|
+
Voltar
|
|
924
|
+
</button>
|
|
925
|
+
</div>
|
|
926
|
+
|
|
927
|
+
<!-- Estado do envio, anunciado sem roubar o foco de quem digita. Fica
|
|
928
|
+
fora do formulário: escondido junto com ele durante o aviso de
|
|
929
|
+
saída, o leitor de tela deixaria de anunciar o que acontece. -->
|
|
930
|
+
<p class="ilibras-widget-status" id="ilibras-widget-status" role="status" aria-live="polite"></p>
|
|
862
931
|
</div>
|
|
863
932
|
</div>
|
|
864
933
|
`;
|
|
@@ -871,6 +940,10 @@ var ILibrasWidget = class {
|
|
|
871
940
|
this.agendar = container.querySelector("#ilibras-widget-agendar");
|
|
872
941
|
this.aviso = container.querySelector("#ilibras-widget-aviso");
|
|
873
942
|
this.status = container.querySelector("#ilibras-widget-status");
|
|
943
|
+
this.confirmacao = container.querySelector("#ilibras-widget-confirmacao");
|
|
944
|
+
this.confirmacaoTexto = container.querySelector("#ilibras-widget-confirmacao-texto");
|
|
945
|
+
this.confirmar = container.querySelector("#ilibras-widget-confirmar");
|
|
946
|
+
this.voltar = container.querySelector("#ilibras-widget-voltar");
|
|
874
947
|
}
|
|
875
948
|
escapar(texto) {
|
|
876
949
|
const div = document.createElement("div");
|
|
@@ -883,6 +956,10 @@ var ILibrasWidget = class {
|
|
|
883
956
|
this.modal.addEventListener("keydown", (e) => {
|
|
884
957
|
if (e.key === "Escape") {
|
|
885
958
|
e.stopPropagation();
|
|
959
|
+
if (!this.confirmacao.hidden) {
|
|
960
|
+
if (!this.enviando) this.cancelarConfirmacao();
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
886
963
|
this.closeWidget();
|
|
887
964
|
return;
|
|
888
965
|
}
|
|
@@ -898,6 +975,8 @@ var ILibrasWidget = class {
|
|
|
898
975
|
if (this.agendar) {
|
|
899
976
|
this.agendar.addEventListener("click", (e) => this.handleSubmit(e, "agendamento"));
|
|
900
977
|
}
|
|
978
|
+
this.confirmar.addEventListener("click", () => this.confirmarRedirecionamento());
|
|
979
|
+
this.voltar.addEventListener("click", () => this.cancelarConfirmacao());
|
|
901
980
|
}
|
|
902
981
|
prenderFoco(evento) {
|
|
903
982
|
const focaveis = Array.from(this.modal.querySelectorAll(FOCAVEIS)).filter((el) => el.offsetParent !== null || el === document.activeElement);
|
|
@@ -927,6 +1006,7 @@ var ILibrasWidget = class {
|
|
|
927
1006
|
this.container.querySelector("#ilibras-name").focus();
|
|
928
1007
|
}
|
|
929
1008
|
closeWidget() {
|
|
1009
|
+
this.mostrarFormulario();
|
|
930
1010
|
this.modal.classList.remove("ilibras-widget-modal-open");
|
|
931
1011
|
this.botao.classList.remove("ilibras-widget-button-open");
|
|
932
1012
|
this.botao.setAttribute("aria-expanded", "false");
|
|
@@ -1094,6 +1174,85 @@ var ILibrasWidget = class {
|
|
|
1094
1174
|
invalido.focus();
|
|
1095
1175
|
return;
|
|
1096
1176
|
}
|
|
1177
|
+
if (this.config.confirmarRedirecionamento) {
|
|
1178
|
+
this.pedirConfirmacao(modo);
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
await this.criarAtendimento(modo);
|
|
1182
|
+
}
|
|
1183
|
+
// ─── Aviso de saída ─────────────────────────────────────────────────────
|
|
1184
|
+
/**
|
|
1185
|
+
* Troca o formulário pelo aviso de que a pessoa vai para o iLibras. Nada é
|
|
1186
|
+
* enviado ainda: o atendimento só nasce no "Continuar".
|
|
1187
|
+
*/
|
|
1188
|
+
pedirConfirmacao(modo) {
|
|
1189
|
+
this.modoPendente = modo;
|
|
1190
|
+
this.confirmacaoTexto.textContent = modo === "agendamento" ? "O agendamento é feito no site do iLibras, que abre em uma nova aba. Lá você escolhe o dia e o horário da conversa." : "O atendimento em Libras acontece no site do iLibras, que abre em uma nova aba. Lá você entra na fila e aguarda um intérprete.";
|
|
1191
|
+
this.confirmar.textContent = "Continuar para o iLibras";
|
|
1192
|
+
this.form.hidden = true;
|
|
1193
|
+
this.confirmacao.hidden = false;
|
|
1194
|
+
this.anunciar("");
|
|
1195
|
+
this.confirmar.focus();
|
|
1196
|
+
}
|
|
1197
|
+
/** "Voltar": o formulário reaparece como estava, com o nome digitado. */
|
|
1198
|
+
cancelarConfirmacao() {
|
|
1199
|
+
if (this.enviando) return;
|
|
1200
|
+
const modo = this.modoPendente;
|
|
1201
|
+
this.mostrarFormulario();
|
|
1202
|
+
const origem = modo === "agendamento" && this.agendar ? this.agendar : this.submit;
|
|
1203
|
+
origem.focus();
|
|
1204
|
+
}
|
|
1205
|
+
mostrarFormulario() {
|
|
1206
|
+
this.modoPendente = null;
|
|
1207
|
+
this.confirmacao.hidden = true;
|
|
1208
|
+
this.form.hidden = false;
|
|
1209
|
+
}
|
|
1210
|
+
async confirmarRedirecionamento() {
|
|
1211
|
+
if (this.enviando || !this.modoPendente) return;
|
|
1212
|
+
const aba = this.reservarAba();
|
|
1213
|
+
await this.criarAtendimento(this.modoPendente, aba);
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Abre uma aba em branco para receber o iLibras assim que o atendimento
|
|
1217
|
+
* existir. Devolve null quando o navegador barra — aí vale o caminho antigo.
|
|
1218
|
+
*/
|
|
1219
|
+
reservarAba() {
|
|
1220
|
+
let aba = null;
|
|
1221
|
+
try {
|
|
1222
|
+
aba = window.open("", "_blank");
|
|
1223
|
+
} catch (e) {
|
|
1224
|
+
aba = null;
|
|
1225
|
+
}
|
|
1226
|
+
if (!aba) return null;
|
|
1227
|
+
aba.opener = null;
|
|
1228
|
+
try {
|
|
1229
|
+
const doc = aba.document;
|
|
1230
|
+
doc.title = "Abrindo o iLibras…";
|
|
1231
|
+
doc.documentElement.lang = "pt-BR";
|
|
1232
|
+
doc.body.style.cssText = "font:16px/1.5 system-ui,-apple-system,Segoe UI,sans-serif;padding:32px;color:#073657";
|
|
1233
|
+
doc.body.textContent = "Abrindo o iLibras…";
|
|
1234
|
+
} catch (e) {
|
|
1235
|
+
}
|
|
1236
|
+
return aba;
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Leva a pessoa ao endereço devolvido pelo iLibras: na aba reservada quando
|
|
1240
|
+
* ela existe, numa aba nova quando não, e na atual como último recurso.
|
|
1241
|
+
*/
|
|
1242
|
+
irPara(destino, abaReservada) {
|
|
1243
|
+
if (abaReservada && !abaReservada.closed) {
|
|
1244
|
+
abaReservada.location.href = destino;
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
const aba = window.open(destino, "_blank");
|
|
1248
|
+
if (aba) {
|
|
1249
|
+
aba.opener = null;
|
|
1250
|
+
} else {
|
|
1251
|
+
window.location.assign(destino);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
// ─── Criação do atendimento ─────────────────────────────────────────────
|
|
1255
|
+
async criarAtendimento(modo, abaReservada = null) {
|
|
1097
1256
|
const v = this.valores();
|
|
1098
1257
|
const corpo = new FormData();
|
|
1099
1258
|
corpo.append("nome", v.nome);
|
|
@@ -1106,15 +1265,17 @@ var ILibrasWidget = class {
|
|
|
1106
1265
|
const destino = resultado.link_fila || resultado.link || resultado.url || resultado.redirect;
|
|
1107
1266
|
if (!destino) throw new FalhaDeServico("resposta_inesperada");
|
|
1108
1267
|
this.anunciar(modo === "agendamento" ? "Cadastro feito. Abrindo o calendário para escolher data e horário." : "Atendimento criado. Abrindo a sala de atendimento.");
|
|
1109
|
-
|
|
1110
|
-
if (aba) {
|
|
1111
|
-
aba.opener = null;
|
|
1112
|
-
} else {
|
|
1113
|
-
window.location.assign(destino);
|
|
1114
|
-
}
|
|
1268
|
+
this.irPara(destino, abaReservada);
|
|
1115
1269
|
this.form.reset();
|
|
1116
1270
|
this.closeWidget();
|
|
1117
1271
|
} catch (erro) {
|
|
1272
|
+
if (abaReservada && !abaReservada.closed) {
|
|
1273
|
+
try {
|
|
1274
|
+
abaReservada.close();
|
|
1275
|
+
} catch (e) {
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
this.mostrarFormulario();
|
|
1118
1279
|
this.tratarFalha(erro);
|
|
1119
1280
|
} finally {
|
|
1120
1281
|
this.travarEnvio(false, modo);
|
|
@@ -1122,14 +1283,25 @@ var ILibrasWidget = class {
|
|
|
1122
1283
|
}
|
|
1123
1284
|
travarEnvio(travado, modo = "fila") {
|
|
1124
1285
|
this.enviando = travado;
|
|
1125
|
-
for (const botao of [this.submit, this.agendar]) {
|
|
1286
|
+
for (const botao of [this.submit, this.agendar, this.confirmar, this.voltar]) {
|
|
1126
1287
|
if (botao) botao.disabled = travado;
|
|
1127
1288
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1289
|
+
let ativo;
|
|
1290
|
+
let rotulo;
|
|
1291
|
+
if (!this.confirmacao.hidden) {
|
|
1292
|
+
ativo = this.confirmar;
|
|
1293
|
+
rotulo = "Continuar para o iLibras";
|
|
1294
|
+
} else {
|
|
1295
|
+
const usouAgendar = modo === "agendamento" && this.agendar;
|
|
1296
|
+
ativo = usouAgendar ? this.agendar : this.submit;
|
|
1297
|
+
rotulo = usouAgendar ? this.config.scheduleButtonText : this.config.buttonText;
|
|
1298
|
+
}
|
|
1131
1299
|
ativo.setAttribute("aria-busy", travado ? "true" : "false");
|
|
1132
1300
|
ativo.textContent = travado ? "Enviando..." : rotulo;
|
|
1301
|
+
if (!travado) {
|
|
1302
|
+
this.confirmar.setAttribute("aria-busy", "false");
|
|
1303
|
+
this.confirmar.textContent = "Continuar para o iLibras";
|
|
1304
|
+
}
|
|
1133
1305
|
if (travado) this.anunciar("Enviando seus dados. Aguarde.");
|
|
1134
1306
|
}
|
|
1135
1307
|
/**
|
package/index.d.ts
CHANGED
|
@@ -42,6 +42,15 @@ export interface ILibrasConfig {
|
|
|
42
42
|
/** Texto do botão de agendamento. Padrão: `'Agendar uma conversa'`. */
|
|
43
43
|
scheduleButtonText?: string;
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Avisa que a pessoa vai para o site do iLibras, numa aba nova, e espera a
|
|
47
|
+
* confirmação antes de criar o atendimento. Padrão: `true`.
|
|
48
|
+
*
|
|
49
|
+
* Com `false`, o widget volta ao comportamento anterior à v1.6.0: cria o
|
|
50
|
+
* atendimento e abre o iLibras direto do botão.
|
|
51
|
+
*/
|
|
52
|
+
confirmarRedirecionamento?: boolean;
|
|
53
|
+
|
|
45
54
|
/** Empilhamento. Padrão: `9999`. */
|
|
46
55
|
zIndex?: number;
|
|
47
56
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ilibras-widget",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Widget de acessibilidade em Libras: formulário embarcável que leva a pessoa surda ao atendimento com intérprete, ao vivo ou agendado",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/ilibras-widget.cjs",
|