Ir ao conteúdo
SEED engenhariaDesign System

Componentes

67. Edição em linha

estávelseed-componentes.md v1.43 · §67seção 73 de 9867-edicao-em-linha-estavel-f7-5-2026-08-16.md · MD5 98711697

Título completo no canon: Edição em linha — estável (F7.5, 2026-08-16 · promovido em 2026-08-17 pelo gate visual do Rafael — verbatim: "aprovado") · IL1–IL14 · fecha C15 · bancada banco-edicao-linha.html v0.2 · suite-edicao-linha.mjs 23 · 0 · 0

O que é. O valor exibido vira campo no próprio lugar, sem abrir formulário nem modal. O §48 (painel) já tinha o caso da gradePN37: "a lente Tabela é planilha: setas navegam entre células, Enter abre editor na própria célula". O que faltava era o componente que a grade consome, e que também serve fora dela: título de registro, campo do painel de detalhe (§49), item de lista (§43).

Fronteira declarada, e ela é o coração do §67: esta seção especifica a passagem do estado de leitura para o de edição e de volta. Qual controle aparece na edição não é decisão dela (IL13) — monetário abre o §59, data abre o §61, escolha abre o §60, pessoa abre o §62, prioridade abre o §63. A bancada exercita texto e número, e declara os demais em vez de simulá-los: simular componente que já existe cria uma segunda verdade que ninguém mantém.

67.0 Rodada zero — SEM INSTÂNCIA ISOLÁVEL, e a diferença importa#

O veredito aqui não é "não visitado". A edição direta foi lida no produto de referência — ela é a origem do bloco PN22–PN41 do §48, que nasceu de leitura visual em 2026-08-13. O que não existe é uma instância do componente isolado: no produto ele aparece sempre dentro da grade, e nunca como controle avulso com estados próprios.

Veredito: SEM INSTÂNCIA ISOLÁVEL. Consequência de método: o insumo de leitura visual desta seção já está gasto no §48 — e é por isso que o §67 nasce citando PN27, PN28, PN29 e PN37 em vez de reabrir a leitura. Herdar decisão medida é mais barato e mais honesto que remedir mal.

67.1 RITO — três rodadas encadeadas#

Rodada Fonte O que trouxe
R1 — canon ARIA APG — Button Pattern · SC 2.1.1 Keyboard Não existe padrão APG de "inline edit". O que existe é o padrão do botão: o valor em repouso precisa ser um controle de verdade para ser alcançável e anunciável (IL1). E o SC 2.1.1 é o que elimina o duplo clique como caminho único — duplo clique não tem equivalente de teclado
R2 — mercado/stack PatternFly — Inline edit · Semrush Intergalactic — InlineEdit a11y PatternFly: existe um action-group explícito de salvar/cancelar que só aparece na edição, e o padrão pede preservar o contexto visual — "within the context of their current view", sem modal, sem transição destrutiva. Semrush: Enter abre e, dentro da edição, salva; Esc volta descartando; aria-describedby liga a mensagem de erro. Nenhum dos dois define o comportamento do blur — a decisão ficou em aberto no mercado, e por isso ela é decidida aqui com o porquê escrito
R3 — normas WCAG 2.2: SC 3.2.2 On Input · SC 2.5.8 Target Size · SC 4.1.3 Status Messages O SC 3.2.2 responde a pergunta que mais confunde: salvar ao sair do campo NÃO é mudança de contexto — contexto é viewport, foco ou conteúdo que muda o significado da página; "uma mudança de conteúdo nem sempre é uma mudança de contexto". O que o critério proíbe é a mudança automática sem aviso prévio: submeter o formulário ao preencher um campo, ou mover o foco sozinho sem estar descrito antes. Daí o IL11

67.2 A decisão que mais custa: clicar fora CONFIRMA#

O mercado não decide isso (R2), então a decisão é da casa, e ela tem lado.

Clicar fora é o acidente mais comum num campo em linha. As duas escolhas erram de formas assimétricas:

Escolha O que o acidente causa Recuperável?
blur cancela destrói o que a pessoa digitou Não. O texto nunca existiu em lugar nenhum
blur confirma grava um valor que a pessoa talvez não quisesse Sim — desfazer de 8 segundos, já contratado no PN28

Entre um erro reversível e um irreversível, o sistema escolhe o reversível. E o Esc continua existindo para quem quer descartar de propósito — a diferença entre descartar por decisão e descartar por acidente é a decisão.

E há um efeito colateral que só aparece implementando: o blur do campo dispara antes do clique no botão ✕. Sem tratamento, cancelar seria precedido de um salvamento — a ação faria o oposto do que promete. O contrato IL5 tem guarda própria para isso, e ela clica no ✕ de verdade.

67.3 Os contratos IL1–IL14#

# Contrato Por quê Descartado
IL1 O valor em repouso é um botão, e o nome diz a ação e o valor — “Editar Descrição da ordem: Inspeção termográfica do QGBT” Texto com onclick não é alcançável por Tab nem anunciado como acionável. E “Inspeção termográfica…” sozinho não diz que dá para editar <div onclick> (invisível ao teclado); contenteditable no próprio texto (estado de edição sem fronteira visível, e sem lugar para confirmar/cancelar)
IL2 Entra por clique simples e por Enter/Espaço SC 2.1.1. O botão nativo já dispara click nas duas teclas — não se acrescenta keydown paralelo, que abriria duas vezes Duplo clique como caminho único (sem equivalente de teclado); ícone de lápis separado como único gatilho (alvo minúsculo ao lado de um alvo grande inerte)
IL3 Ao entrar, o foco vai ao campo e o texto fica selecionado Substituir é o caso comum em campo de lista. Cursor no fim cobra uma seleção extra a cada edição Cursor no fim (mais teclas para o caso comum)
IL4 Enter confirma · Esc cancela e restaura · clicar fora CONFIRMA Ver 67.2 blur cancela (perda irreversível); pedir confirmação em diálogo (mata a vantagem de editar em linha)
IL5 Confirmar e cancelar também existem como botões visíveis durante a edição Toque não tem Esc. Teclado tem Enter/Esc; ponteiro e toque têm ✓ e ✕. Dois caminhos, a mesma mutação — a mesma lei do CP30 Só teclado (exclui toque); botões sempre visíveis mesmo em repouso (numa lista de 20 linhas, 40 botões de ruído)
IL6 Sem salto de layout: a caixa de edição mantém a altura da linha (tolerância 2px, declarada) Numa lista longa, abrir a edição empurraria tudo o que está abaixo e a pessoa perde o lugar na tela. Medido: 49,0 → 49,0px, deslocamento 0,0px Campo maior que o texto “para caber melhor” (empurra a lista)
IL7 Confirmar devolve o foco ao gatilho e anuncia o resultado Componente que troca o próprio DOM sem devolver o foco larga o usuário no body — defeito clássico. E o anúncio é "Responsável alterada para X": resultado, não percurso (PN28) Foco no próximo campo (decide pelo usuário); nenhum anúncio
IL8 Erro de validação não sai do modo de edição Fechar a edição no erro descarta o que a pessoa digitou — o mesmo dano que o blur cancela, agora causado pelo sistema. A mensagem se liga por aria-describedby (R2/Semrush) Fechar e mostrar toast (o texto se perde)
IL9 “Salvando” e “salvo” declarados, e o valor não pisca de volta ao antigo Mutação otimista, herdada do PN27: o gesto aplica na hora, na tela. Ver o valor voltar e avançar de novo lê como falha Esperar o servidor para desenhar (o campo trava); nenhum estado (a pessoa não sabe se gravou)
IL10 A affordance aparece no hover E no foco — nunca só no hover Quem navega por teclado não passa o mouse. Medido: borda #788F9D, 3,38 no claro e 4,50 no escuro contra o fundo Só hover (exclui teclado); borda permanente (a lista vira grade de caixas)
IL11 Digitar não salva a cada tecla e não move o foco sozinho SC 3.2.2: mudança automática exige aviso prévio descrito. Auto-avanço sem aviso é o mesmo defeito das caixinhas de OTP do §66 Salvar a cada tecla (grava lixo intermediário e enche o histórico)
IL12 Alvo do gatilho ≥ 44px de altura Piso do projeto desde o §1, acima do SC 2.5.8 (24px). Medido: 784×44px 32px “por densidade” (o alvo é o que se erra, não o que se vê)
IL13 O controle da edição é o do domínio — §59 · §60 · §61 · §62 · §63 Sem isso o componente vira campo de texto universal, e a data volta a ser string livre. A tabela de delegação está impressa na bancada Texto livre para tudo (perde máscara, teclado e validação de cada domínio)
IL14 Campo que não se edita não vira gatilho — e diz por quê Herda o PN29: alça que existe e não obedece é botão morto; trava invisível vira bug aos olhos de quem usa. Sem button, sem tabindex, com o motivo ao lado disabled mudo (a pessoa clica e nada acontece, e ela não sabe se é bug)

67.4 A galeria de estados, e por que ela é contrato#

O catálogo operante mostra um estado por vez — é assim que o componente funciona. Mas a lei CP31 diz que bancada imprime os estados lado a lado, e ela existe por um motivo prático: avaliar o estado de erro não pode exigir que o avaliador reproduza o erro — gate que depende de reprodução não acontece.

Os seis estados — repouso · hover/foco · em edição · erro · salvando · bloqueado — são impressos juntos, e são cópias estáticas. Isso não é detalhe de implementação: um <button> de verdade impresso ali seria um botão morto, a classe de defeito que o projeto persegue desde a v1.4. A galeria não tem button, não tem input e não tem tabindexe a suíte mede essa ausência (guarda CP31), assim como o gerador aborta se a marcação da galeria contiver qualquer um dos três.

67.5 A suíte#

suite-edicao-linha.mjs — 20 PASS · 0 FAIL · 1 medida. Doze das vinte guardas agem:

Guarda O que ela faz de fato
IL6 mede o retângulo da linha antes e depois de abrir, e o deslocamento da linha seguinte
IL3 confere que o foco está no input e que o texto está selecionado (selectionStart/End)
IL4-esc digita, aperta Esc e confere valor restaurado, foco de volta e anúncio
IL4-enter digita, aperta Enter e confere valor, foco, nome acessível atualizado e anúncio de resultado
IL4-blur digita e clica fora: prova que grava
IL5 digita e clica no ✕: prova que cancela mesmo com o blur disparando antes
IL5-b digita e clica no ✓: prova que confirma
IL8 esvazia e confirma: a edição continua aberta, com aria-invalid e aria-describedby
IL9 espera as duas fases e confere salvando → salvo sem o valor piscar
IL11 digita e confere que o gatilho ainda mostra o valor antigo e o foco não fugiu
IL2 foca e aperta Enter no gatilho
CP31 conta os estados impressos e procura controles mortos entre eles

67.6 Pendências#

# Pendência Por que fica aberta
IL-P1 FECHADA — gate visual APROVADO em 2026-08-17, sem achado próprio. A seção é promovida a estável
IL-P2 FECHADA — EXECUTADA em 2026-08-19. E os defeitos eram SETE, não três: o pior — a grade era INALCANÇÁVEL POR TECLADO (56 células em tabindex="-1", nenhuma em "0"; 40 Tabs sem entrar) — não estava escrito na pendência. A grade passa a cumprir o padrão grid da ARIA e o §67; o contrato IL15 e a guarda que o mede por COMPORTAMENTO estão no §67.7
IL-P3 O desfazer de 8 segundos que sustenta a decisão do blur não existe nesta bancada Ele é contrato do §48 (PN28) e vive no painel. A decisão do 67.2 depende dele: sem desfazer, blur confirma deixa de ser o lado seguro. Isso está dito aqui para não virar suposição — quem consumir o §67 fora do painel precisa levar o desfazer junto
IL-P4 Edição em linha de valor de domínio não foi exercida O IL13 delega, e delegação declarada não é delegação medida. Exercitar exigiria montar §59/§60/§61/§62 dentro da bancada — trabalho de composição, não de spec

67.7 IL15 — a grade do §48 em USO: o padrão grid da ARIA, e o defeito que ninguém tinha medido#

Escrito em 2026-08-19, ao executar a IL-P2. Seção autossuficiente: presume um leitor que nunca viu a conversa que a gerou.

67.7.1 O que é a grade, e o que estava errado#

O §48 (tela-painel, dispositivo PN37) desenha uma planilha: tabela com célula editável, setas que navegam e alça que preenche para baixo. O §67 já especifica como se edita um valor em linha — e a grade tinha editor próprio. Essa é a IL-P2, decidida pelo Rafael em 2026-08-17 junto com a SI-P4 ("unificar é melhor… precisamos manter o mesmo padrão, isso é inegociável").

A pendência listava TRÊS divergências. Medido em 2026-08-19, eram SETE — e a mais grave não estava escrita:

# Defeito medido Norma
1 A GRADE ERA INALCANÇÁVEL POR TECLADO. As 56 células tinham tabindex="-1" e nenhuma tinha "0". Partindo do seletor "selecionar todas" da própria tabela e teclando Tab 40 vezes, o foco nunca entrava numa célula. Só o clique abria a grade SC 2.1.1
2 a célula era <td> sem papel nem nome, e não <button> com o nome do IL1 SC 4.1.2
3 sem nome acessível na forma "Editar <rótulo>: <valor>" SC 4.1.2 · 2.4.6
4 sem a affordance de lápis do IL10 IL10
5 sem role="grid"tabindex em <td> solto não é o padrão ARIA SC 1.3.1
6 o title da alça de preencher entrava no nome acessível da célula. Medido: "Ana Lima arraste para copiar para baixo" SC 4.1.2
7 faltavam Home/End, Ctrl+Home/Ctrl+End e F2 padrão grid

A lição, e ela é a mesma da SI-P4 vista de outro ângulo: PENDÊNCIA ESCRITA É HIPÓTESE, NÃO CENSO. A IL-P2 estava escrita desde 2026-08-17 com três itens de SEMÂNTICA. O defeito que realmente impedia uma pessoa de usar a grade era de TECLADO, e ele só apareceu quando alguém teclou Tab de verdade. Guarda que pergunta "tem este atributo?" nunca teria achado: foi preciso PRESSIONAR a tecla.

67.7.2 RITO — três rodadas encadeadas#

  • R1 — canon (padrão grid da ARIA / APG). O padrão admite duas formas: "a célula contém UM widget cuja operação não exige as setas, e as teclas de navegação da grade põem o foco NESSE widget" ou "a célula contém texto ou um único gráfico e as teclas de navegação põem o foco na CÉLULA". As duas exigem os papéis grid/row/gridcell. Teclado nomeado pelo padrão: setas · Home/End · Ctrl+Home/Ctrl+End · Enter ou F2 para editar · Esc para cancelar · tabindex rotativo.
  • R2 — mercado/stack. Partir de uma <table> semântica e acrescentar role="grid" preserva as relações cabeçalho↔célula pelos <th scope>; quando a célula tem um controle, o tabindex rotativo mora no controle, não na célula; e o editor precisa de nome acessível próprio, porque o cabeçalho de coluna deixa de bastar no instante em que o texto da célula vira um campo nu.
  • R3 — normas. SC 2.1.1 (teclado) · 1.3.1 (relações) · 4.1.2 (nome, papel, valor) · 2.4.6 (rótulos) · 3.2.2 (sem mudança automática) · 2.5.8 (tamanho de alvo).

VEREDITO: o IL1 do §67 é exatamente a forma (a) do padrão, e fica CONFIRMADO. O RITO não revogou o que estava escrito — corrigiu o peso: a pendência tratava role="grid" como "agravante", e ele é a PRECONDIÇÃO; sem o papel, nenhuma das duas formas existe.

ALTERNATIVA DESCARTADA: a forma (b) — célula focável com texto dentro. É legítima na ARIA e seria menos código, mas contradiz o IL1, que o Rafael já aprovou, e deixaria a célula sem nome de ação: "Ana Lima" não diz que dá para editar.

67.7.3 O contrato IL15#

# Cláusula O que a guarda faz de fato
IL15-a a tabela declara role="grid" e tem cabeçalhos de coluna lê o papel e conta th[scope="col"]
IL15-b toda célula editável carrega UM gatilho (forma (a)) conta gatilhos contra células
IL15-c tabindex rotativo: exatamente um gatilho na sequência de Tab conta os tabindex="0"
IL15-d a grade é ALCANÇÁVEL por Tab pressiona Tab até 25 vezes a partir do seletor "selecionar todas" e vê se o foco entra
IL15-e/f seta direita anda uma coluna · seta baixo anda uma linha tecla e lê a coordenada do foco
IL15-g/h End e Home vão às pontas da LINHA tecla e lê
IL15-i/j Ctrl+End e Ctrl+Home vão às pontas da GRADE tecla e lê
IL15-k o tabindex="0" acompanha o foco conta depois de navegar
IL15-l nome do gatilho na forma "Editar <rótulo>: <valor>" lê o nome acessível
IL15-m/o F2 e Enter entram na edição tecla e confere que o foco caiu num campo
IL15-n Esc cancela e devolve o foco ao gatilho (IL7) tecla e lê onde o foco parou
IL15-p a alça de preencher é aria-hidden — o title dela não entra no nome lê o atributo
IL15-q a affordance de lápis aparece no foco, não só no hover (IL10) foca e lê a opacidade computada
IL15-r célula travada não tem gatilho e diz o motivo (IL14) conta gatilhos e motivos nas travadas

validacao/guarda-il15.mjsALVO DE PASTA: varre todo *.html da raiz e mede todo artefato com table.planilha; arquivo sem grade sai [n/a] nomeado. Ela troca a lente para "tabela" antes de medir, porque a grade só existe nessa lente.

PROVA DE REPROVAÇÃO: rodada sobre a cópia anterior do tela-painel.html, reprova 6 cláusulasIL15-a (sem papel), IL15-b (0 gatilhos em 56 células), IL15-c (0 de 0), IL15-d (NUNCA em 25 pressionamentos), IL15-p (alça visível ao leitor de tela) e IL15-q (sem gatilho, logo sem lápis).

PLACAR: 1 PASS · 0 FAIL · 50 [n/a], em seis execuções idênticas.

DEFEITO DE MEDIÇÃO CONSERTADO NA PRÓPRIA SESSÃO EM QUE A GUARDA NASCEU. A primeira versão lia a opacidade do lápis logo após dar o foco, e a transição ainda estava correndo: o valor voltava 0.999599 e a guarda reprovava um artefato correto em 3 de 6 execuções. Guarda intermitente é pior que guarda ausente: ela ensina a ignorar o placar. A transição é desligada antes da leitura, e o que se mede passa a ser o valor de DESTINO.

67.7.4 O que mudou no artefato, e o que ficou aberto#

O tela-painel é gerado: a mudança foi no molde validacao/painel-template.html e o artefato foi regerado. A suite-painel reprovou o bloco novo no primeiro segundotransition: opacity .12s tinha duração solta, e a guarda PN21-11 exige token. Trocado por var(--seed-dur-productive-fast).

Placares depois: suite-painel 146 PASS · 0 FAIL · guarda-il15 1 · 0 · 50 · contraste 2 · 0 a 1440px e 2 · 0 a 390px · forced-colors FC1/FC2 2 · 0 cada · reflow BT7 3 · 0 · 1.

# Pendência que nasce Por que fica aberta
PN-P6 FECHADA em 2026-08-19 pelo gate. Decisão do Rafael, verbatim: "sobe para 44". A altura mínima da célula (.planilha .cel-edit) foi de 40px para 44px no molde validacao/painel-template.html, e o painel foi regerado. Medido depois: a guarda-il15 imprime o alvo em 234×44px — a mesma régua que produziu a pendência. Custo medido, e é o único: no mesmo recorte de 360px de altura cabe uma linha a menos (recorte B2 da folha render-audit/gate-v134/fechamento.html). ALTERNATIVA DESCARTADA: manter 40px e declarar a planilha como exceção de densidade — descartada porque toda exclusão declarada é uma dívida com juros, e porque a linha inteira é o alvo, então os 4px não compram densidade real. Aplicado à célula inteira, não só à coluna medida: altura por coluna quebraria o alinhamento horizontal da planilha. Placar depois: suite-painel 146 · 0, guarda-il15 1 · 0 · 50, contraste 2 · 0 nos dois temas.
CC-P7 O contraste do tela-painel é medido na lente padrão (lista). Nenhum instrumento troca a lente antes de medir, então as outras sete lentes — inclusive a grade — seguem não medidas por contraste. Ausência de medição não é aprovação
BancadaSEED Design System v2 · banco-edicao-linha (§67 · edição em linha) — preview v0.2abrir em página própria ↗

Também cita o §67: tela-painel.

Esc