From 87a1ac13584a58c6a5eb66ef507609ee8f690b08 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Thu, 21 May 2026 17:42:40 -0300 Subject: [PATCH] templates/editor: defer insercao pos-transicao + pointer-events na saida MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trava persistia mesmo apos fix anterior. Causa raiz: append no form ocorria durante a transicao CSS do drawer (250ms slide out). Vue reagia ao v-model -> Jodit re-renderia HTML com nova variavel -> concorrencia entre repaint do drawer saindo + reflow do Jodit mobile = trava. Fix: 1. setTimeout(280ms) — append no form so executa DEPOIS que a transicao do drawer terminou. Drawer sai limpo, depois Jodit re-renderiza isolado. 2. CSS: .dte-mobile-drawer:not(.is-open) ganha pointer-events:none durante saida. Evita captura de touch/click "perdidos" que tentavam triggerar handlers no drawer ja saindo. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/DocumentTemplateEditor.vue | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/features/documents/components/DocumentTemplateEditor.vue b/src/features/documents/components/DocumentTemplateEditor.vue index 1678a01..1dc0bb9 100644 --- a/src/features/documents/components/DocumentTemplateEditor.vue +++ b/src/features/documents/components/DocumentTemplateEditor.vue @@ -66,28 +66,37 @@ const editorRodape = ref(null) function insertVariable(varKey) { const tag = `{{${varKey}}}` + + // No mobile: 1) fecha drawer (imediato); 2) deferir append do form e + // re-render do Jodit pra DEPOIS da transição (250ms). Modificar o form + // durante a transição causa concorrência entre repaint do drawer + // saindo + Jodit re-rendering com novo HTML → trava. + if (isMobile.value) { + drawerOpen.value = false; + const field = cursorField.value; + // setTimeout > duração da transição CSS (.dte-mobile-drawer = 250ms) + setTimeout(() => { + form.value[field] = (form.value[field] || '') + tag; + if (!form.value.variaveis.includes(varKey)) { + form.value.variaveis = [...form.value.variaveis, varKey]; + } + }, 280); + return; + } + + // Desktop: insertHTML mantém posição do cursor const editorMap = { cabecalho_html: editorCabecalho, corpo_html: editorCorpo, rodape_html: editorRodape } const editorRef = editorMap[cursorField.value] - - // No mobile: drawer está aberto, foco está nos botões do drawer. - // Tentar editor.insertHTML enquanto o cursor está fora do Jodit faz - // ele travar tentando resolver selection. Usamos o fallback (append - // direto no form via v-model) e fechamos o drawer ANTES — Jodit - // sincroniza com v-model na próxima tick. - if (isMobile.value) { - drawerOpen.value = false; - form.value[cursorField.value] = (form.value[cursorField.value] || '') + tag - } else if (editorRef?.value?.insertHTML) { + if (editorRef?.value?.insertHTML) { editorRef.value.insertHTML(tag) } else { form.value[cursorField.value] = (form.value[cursorField.value] || '') + tag } - // Adiciona a variavel na lista se nao estiver if (!form.value.variaveis.includes(varKey)) { form.value.variaveis = [...form.value.variaveis, varKey] } @@ -504,6 +513,9 @@ onBeforeUnmount(() => { box-shadow: 4px 0 24px rgba(0, 0, 0, 0.18); } .dte-mobile-drawer.is-open { transform: translateX(0); } +/* Durante a transição de saída, drawer ignora eventos pra não capturar + touch/click "perdidos" e prevenir trava no Jodit. */ +.dte-mobile-drawer:not(.is-open) { pointer-events: none; } .dte-mobile-drawer__tabs { display: flex;