Ir ao conteúdo
SEED engenhariaDesign System

Componentes

61. Data, intervalo e hora

estávelseed-componentes.md v1.43 · §61seção 67 de 9861-data-intervalo-e-hora-estavel-f7-5-promovida-em.md · MD5 f5784b55

Título completo no canon: Data, intervalo e hora — estável (F7.5 · promovida em 2026-08-17 por gate declarado, verbatim "aprovo. siga" · RE-GATE OBSERVADO em 2026-08-17: a BT-P1 e a DH-P6 FECHAM — insumo nomeado, ver §64.10.1) · DH1–DH18 · fecha C1 e C2 · bancada banco-data.html v0.4 (errata corrigida: este cabeçalho declarava v0.5, versão que nem o artefato, nem o gerador, nem o MANIFESTO, nem o mapa de cobertura têm — §64.10.3) · suite-data.mjs 31 · 0 · 1 [n/a] · BT7 consertado em 2026-08-17 (178px de excesso a 390px: o calendário empilha os atalhos abaixo de 470px, com exceção declarada ao piso de 44px na célula do dia)

Rodada zero: NÃO VISITADO — e a visita mudou a seção. O dispositivo existe no produto de referência (o §13 já tinha lido a data renderizada — C80, cor por estado), mas o seletor nunca tinha sido aberto. Navegação autorizada, modo somente leitura: o seletor foi aberto, lido e fechado; nenhuma data foi escolhida, alterada ou limpa. Oito dispositivos observados, C117–C124, no §15 do estudo-clickup-completo.md.

E a volta estreou um método que rendeu na primeira tentativa. Além da captura de tela, foi lida a árvore de acessibilidade da mesma região. As duas não coincidem — e o achado é o C122, negativo: cada dia é um button cujo nome acessível é só o número (button "2"), sem role="grid", sem gridcell, sem columnheader, e sem aria-selected no dia escolhido. Na tela o dia 31 tem fundo sólido; na árvore ele não carrega estado nenhum.

Copiar a forma teria copiado o defeito, porque o defeito não aparece na captura.

Base (3 rodadas, 2026-08-16), e o canon diverge em TRÊS. (a) ARIA APG — calendário é role="grid" sobre <table> (row/columnheader/gridcell vêm implícitos de tr/th/td); cabeçalho de coluna com abbr trazendo o dia por extenso; aria-selected="true" na célula escolhida; com campo vazio, o foco entra no dia de hoje; teclado ←/→ dia, ↑/↓ semana, Home/End na semana, PageUp/PageDown mês, Shift+PageUp/Down ano; e o campo de texto recebe aria-describedby apontando para a descrição do formato. (b) GOV.UK / NHSnão use calendário quando o usuário já sabe a data: use campos de texto, com inputmode="numeric" e autocomplete (bday-day/bday-month/bday-year) para o SC 1.3.5. O calendário é para quando a data não é sabida. (c) USWDS — faz os dois (campo + botão de calendário), e monta o intervalo como dois seletores independentes, com data-min-date/data-max-date. Admite duas coisas: que não valida a coerência entre início e fim, e que o componente passa no SC 3.3.2 com ressalva — falta instrução visível de como usar o botão de calendário.

R3 normas: SC 3.3.2 (o formato esperado tem de estar visível, não só no placeholder) · SC 1.3.5 (identificar o propósito do campo) · SC 3.3.7 Redundant Entry, nível A (o que o usuário já informou na sessão não se pede de novo).

61.1 A régua: pergunte se o usuário JÁ SABE a data#

A divergência não tem "jeito certo" — tem dois problemas diferentes que a mesma forma serve, e foi assim que o §60 se resolveu. Aqui a pergunta é outra:

Se o usuário… Então o caminho primário é… E o outro…
já sabe a data (nota fiscal, nascimento, prazo em contrato) digitar — teclado é mais rápido que caçar num calendário o calendário fica disponível, e ninguém é obrigado a abri-lo
não sabe e precisa do contexto (que dia da semana? quantos dias faltam? cai no fim de semana?) o calendário — a pergunta que ele responde não cabe num campo de texto o campo continua lá, aceitando digitação

Os dois existem SEMPRE, e nenhum é opcional. O GOV.UK está certo sobre a data sabida e o APG está certo sobre a data descoberta; escolher um dos dois seria acertar metade dos casos. No ERP da SEED os dois casos convivem na mesma tela: a data de emissão de uma nota o usuário sabe e digita; o agendamento de uma OS depende de que dia da semana cai e de quem está livre.

61.2 Os contratos#

# Contrato O que ele descarta, e por quê
DH1 O campo de TEXTO existe sempre e aceita digitação. O calendário é complemento, nunca substituto Calendário sozinho. Para data sabida, obriga a navegar meses para chegar onde a digitação chegaria em 8 teclas
DH2 O calendário existe sempre e é alcançável por teclado. Gatilho com nome próprio, não um ícone mudo Campo de texto sozinho. Ele não responde "que dia da semana é" nem "quantos dias faltam"
DH3 O formato esperado é VISÍVEL (SC 3.3.2) — em texto de apoio, não só no placeholder, que some ao digitar justamente quando o usuário mais precisa dele Formato só no placeholder. É a ressalva que o próprio USWDS registrou contra si
DH4 pt-BR: entrada em dd/mm/aaaa, inputmode="numeric", e o parser aceita separador /, . ou -. Exibição pode ser compacta; entrada não Aceitar mm/dd. Herda o VD5 — em pt-BR 1240.5 é doze mil quatrocentos e cinco, e a mesma armadilha de locale vale para data
DH5 A grade é role="grid" sobre <table>, com <th> para os dias da semana e abbr com o nome por extenso Pilha de <button>. É exatamente o que o produto de referência faz (C122)
DH6 O nome acessível de cada dia é COMPLETO — dia, mês, ano e dia da semana —, nunca só o número button "2". Contraexemplo medido no C122: o leitor de tela anuncia "botão 2", sem mês, sem ano, sem saber o que já está escolhido
DH7 aria-selected="true" só na célula escolhida; hoje se marca por aria-current="date" — são coisas diferentes e precisam de marcas diferentes Marcar hoje e o escolhido do mesmo jeito. Quem não vê perde a diferença entre "onde estou" e "o que escolhi"
DH8 Teclado do APG, inteiro: ←/→ dia · ↑/↓ semana · Home/End na semana · PageUp/PageDown mês · Shift+PageUp/Down ano · Enter/Espaço escolhe · Esc fecha sem escolher Só setas. Sem PageUp/Down, mudar de ano custa dezenas de teclas
DH9 A grade tem UM tab stop (roving), como o SG1 Um tab stop por dia. Quarenta e dois tab stops para atravessar um calendário
DH10 Intervalo é UM controle: dois campos de texto e UM calendário compartilhado Dois seletores independentes (USWDS). Separados, ninguém é dono da relação — e o próprio USWDS admite que não valida a coerência entre início e fim
DH11 A coerência início ≤ fim é validada, e a mensagem diz QUAL dos dois corrigir e sugere a correção "Intervalo inválido". Herda o VD11: erro que identifica o problema E sugere a saída
DH12 O vão entre os extremos é DESENHADO na grade, e os dois extremos se distinguem do meio Marcar só as pontas. Contrato decidido sem leitura — ver §61.4
DH13 A hora é campo SEPARADO e opt-in; não existir hora não é erro, e existir o campo não a torna obrigatória Data e hora no mesmo campo. C118: no produto de referência a hora é um terceiro campo de texto, e a data não a carrega por padrão
DH14 ISO 8601 na camada de dado; a string ISO NUNCA passa por new Date(string) Confiar no parser do agente de usuário. Regra já canônica do projeto — new Date("2026-08-16") desloca por UTC e devolve o dia anterior a oeste de Greenwich
DH15 Atalho relativo mostra a data ABSOLUTA que resolve, ao lado do rótulo "2 semanas" sozinho. C119: o relativo é ambíguo, e o produto responde mostrando o resultado antes do clique. Irmão do FC5 — o número é a prova de que o comando fez o que diz
DH16 "Hoje" é o hoje do USUÁRIO, e o fuso fica declarado quando o dado é compartilhado Hoje do servidor. Numa empresa em MG, ES e BA o fuso é o mesmo, mas o dado que sai em relatório não pode depender disso
DH17 Recorrência NÃO é deste componente Regra de recorrência dentro do seletor. C124: até o produto de referência a põe atrás de um passo a mais
DH18 Data já informada na sessão não se pede de novo (SC 3.3.7, nível A): o segundo campo pré-carrega ou oferece o valor Redigitar. É critério de nível A, o mais baixo — falhar nele é falhar no piso

61.3 A fronteira: o que este componente NÃO decide#

  • Regra de negócio de prazo — o que conta como atraso, se sábado é dia útil, qual feriado vale. O componente exibe e coleta; quem decide é o produto.
  • Recorrência (DH17) · fuso como configuração · calendário de trabalho.
  • Conversão de unidade de tempo — herdado do VD15: conversão é regra de engenharia.

61.4 O contrato que nasce SEM LEITURA, e isso está dito#

O DH12 — como o seletor desenha o vão entre início e fim — não pôde ser observado. A tarefa aberta tinha só a data de vencimento, e preencher a data inicial seria escrita, fora do modo autorizado. Não havia outra instância à mão com os dois extremos.

Achado negativo é achado. O DH12 fica marcado como decidido por canon e norma, sem leitura visual — e é o único dos dezoito nessa condição. Se uma volta futura achar uma instância com intervalo preenchido, ele é o primeiro a ser reconferido. Registrar de qual contrato não se tem leitura é o que separa uma spec incompleta de uma spec que não sabe onde está incompleta.

61.5 Números — a MEDIR na produção da bancada#

Método do §55: a seção nasce só com relações. Ficam a medir: altura e alvo da célula de dia · largura da grade · espaçamento entre semanas · o par de cor de hoje, do escolhido, do vão, do hover e do foco, nos dois temas e em forced-colors (herdando o SG6-b) · alvo do gatilho do calendário · e a distinção entre dia do mês corrente e dia vizinho.

Nenhuma medida é afirmada aqui.

61.6 A bancada — e as três decisões que ela obrigou#

banco-data.html · suite-data.mjs 25 PASS · 0 FAIL · 1 [n/a].

(a) O "hoje" da bancada é FIXO, e isso é decisão, não conveniência#

Um calendário que consulta o relógio muda de bytes todo dia. Isso quebraria a âncora (bytes + MD5) que este projeto usa para provar que um arquivo é o que se pensa que ele é, e nenhuma guarda poderia afirmar "o dia 16 está marcado como hoje". A data de referência entra pelo gerador, declarada — nunca de Date.now().

É a mesma razão pela qual as suítes esperam por CONDIÇÃO e não por tempo: estado que depende do relógio não é verificável. O selo da bancada diz qual é o "hoje" dela, na primeira linha.

E o intervalo de exemplo é escolhido por asserção, não por gosto: o gerador aborta se hoje não cair dentro do intervalo, porque é a única forma de provar, na mesma imagem, que "hoje" e "escolhido" têm marcas diferentes (DH7).

(b) Dois alvos abaixo do piso, e o motivo do primeiro vale como regra#

O gatilho do calendário media 40px. A caixa declarava min-height: 44px — mas isso é a altura externa: descontadas as bordas e o alinhamento, o botão ficava com 40. A célula de dia media 42px.

Regra: alvo se mede no retângulo do CONTROLE, não no contêiner que o abriga. Declarar 44 no pai é a versão sutil do defeito do ::before da SG-P7 — o número certo, no elemento errado.

(c) A ambiguidade que o DH15 existe para expor apareceu na própria bancada#

Dois atalhos de nomes diferentes — "Amanhã" e "Próxima segunda" — resolvem para a mesma data, porque o "hoje" fixado cai num domingo. A suíte registra isso como medida, não como falha: é exatamente a ambiguidade que torna a data resolvida necessária. Sem ela, o usuário clicaria em dois botões diferentes esperando resultados diferentes.

61.7 O gate achou um calendário inoperável — com 25 PASS · 0 FAIL#

Verbatim, 2026-08-16: "não consegui ter ação no calendário. não consegui fazer seleção de intervalo de data com o mouse, nem clicar em nenhuma data, quanto mais fazer o teste com tab".

A banco-data.html v0.1 tinha a grade estática, emitida em HTML pelo gerador. O clique num dia movia o foco e escrevia numa live region — nada mudava na tela. Não dava para escolher um intervalo, não dava para mudar de mês, e o gatilho do calendário não abria nada.

Uma grade estática não é um seletor de data — é a FOTO de um. E a foto passou em vinte e cinco guardas, porque todas elas mediam marcação: papel, nome, estado, alvo, teclado sob foco programático. Nenhuma perguntou se o usuário consegue usar.

E a guarda que devia pegar isso tinha sido escrita para não olhar ali#

A suite-data.mjs v0.1 tinha uma guarda BTN"nenhum botão morto", regra do projeto desde sempre. E ela excluía, por escrito:

!b.closest('table[role="grid"]') && !b.closest('.cal__nav') &&
!b.classList.contains('cal__hoje') && !b.classList.contains('cd__gatilho')

Os quatro lugares onde o defeito estava. Eu escrevi a exclusão porque aqueles botões "não são CTA comum" — e com isso removi do exame exatamente o que precisava ser examinado.

Regra nova: guarda escrita para NÃO OLHAR onde o defeito mora é pior que guarda nenhuma. Sem guarda, a pergunta continua aberta. Com uma guarda que desvia o olhar, o verde impede a pergunta. Toda exceção numa guarda precisa de motivo escrito — e o motivo não pode ser "esse caso é chato de medir".

E há exclusão legítima: a guarda nova exclui [disabled], porque a plataforma define que botão desabilitado não responde. Excluir pelo que o contrato diz é método; excluir por onde o defeito mora é fuga.

As cinco guardas que nascem disso#

# O que mede, AGINDO
DH-OP1 clicar num dia muda estado observável — não só a live region
DH-OP2 o vão é pré-visualizado no ponteiro, antes do segundo clique
DH-OP3 o segundo clique fecha o intervalo e escreve nos campos de texto
DH-OP4 a navegação de mês muda o mês, e "Hoje" volta
DH-OP5 o atalho relativo preenche, não só anuncia

E a BTN passa a clicar em todo botão do componente, zerando a live region antes de cada clique.

Dois defeitos de instrumento a mais, e um de artefato achado pelo teste#

Nono (instrumento): a exclusão da BTN, acima. Décimo (instrumento): a primeira versão da BTN nova media "o texto do anúncio MUDOU" — e dois campos de mesmo rótulo dizem legitimamente a mesma frase. Ela acusou quatro botões corretos de mudos. Comparar com o valor anterior confunde "não respondeu" com "respondeu igual". Agora a região é zerada antes de cada clique: o teste é presença, não diferença.

E um defeito de artefato que só um teste de comportamento acha: a prévia do vão chamava desenha() no mouseenter, e desenha() reescreve o innerHTMLo elemento sob o cursor era destruído, o mouseenter disparava de novo no elemento novo, e o calendário entrava em laço, tremendo. Redesenhar em resposta ao ponteiro destrói o alvo do próprio ponteiro. A prévia passou a mutar atributos das células existentes, sem recriar nada.

E o calendário foi para o TOPO da página#

Ele vinha depois de sete campos de exemplo — cerca de trinta e três tab stops. Agora são quinze, e a grade é a primeira coisa substantiva do arquivo. O que a bancada existe para provar vem primeiro; o catálogo de estados vem depois.

61.8 Nível de prova, declarado#

Aplicando a régua da v10.2 — ao promover, declare o NÍVEL de prova de cada contrato:

Nível Contratos
1 · Consumidor em produção nenhum. Nenhum artefato do acervo tem seletor de data
2 · Bancada DH1–DH16 — provados pela banco-data.html, que nós construímos para prová-los
3 · Ausência de violação DH17 (recorrência não vive no componente)
Fora do componente DH18 — SC 3.3.7 é contrato de TELA: o componente aceita valor inicial; quem o pré-carrega é a tela

A seção segue rascunho, e não é formalidade. Sem consumidor em produção e sem gate visual, o que existe é um componente que passa nos testes que ele mesmo trouxe. Placar verde não diz se o contrato sobreviveu ao mundo ou só ao caso que escrevemos para ele.

61.8 Pendências#

Aviso de supersede (2026-08-17): a linha DH-P6 desta tabela está SUPERSEDIDA pelo §64.10.4 — ela FECHOU com o re-gate observado da banco-data v0.4. A tabela abaixo fica como histórico; o estado vigente é o do §64.10.4.

# Pendência Por que fica aberta
DH-P1 Bancada banco-data.html FECHADA — 25 · 0 · 1 [n/a]. Nível de prova: 2 (bancada)
DH-P5 Gate visual na banco-data.html v0.1 FECHADA — e REPROVOU. "não consegui ter ação no calendário". Cinco guardas de operabilidade nasceram do achado
DH-P6 RE-gate da banco-data.html — hoje v0.4 O calendário funciona e passa em 31 guardas — mas quem disse que a v0.1 estava quebrada foi o olho, não o placar. Além do conserto de operabilidade, a v0.4 traz barra fixa (BT1), seletor de largura (BT2) e o conserto do vão branco no tema escuro, que media 1,02 e passou a medir 10,52 / 7,98 (§64.2). Nada promove antes. Mesma pendência que a BT-P1
DH-P2 DH12 sem leitura visual O vão do intervalo não pôde ser observado sem escrever. Reconferir na próxima volta que achar instância
DH-P3 Calendário de trabalho e feriado Parâmetro do produto, não do DS — irmão do VD-P2 (jornada). Fica nomeado para não voltar como surpresa
DH-P4 Máscara durante a digitação Mesma pendência do VD-P4: a máscara ao vivo não está implementada, e a decisão de fazê-la vale para os dois

BancadaSEED Design System v2 · banco-data (§61 · data, intervalo e hora) — preview v0.4abrir em página própria ↗

Também cita o §61: banco-edicao-linha.

Esc