Componentes
62. Seletor de pessoa
seed-componentes.md v1.43 · §62seção 68 de 9862-seletor-de-pessoa-estavel-f7-5-promovida-em.md · MD5 25ea53b3Título completo no canon: Seletor de pessoa — estável (F7.5 · promovida em 2026-08-17 por gate declarado, verbatim "aprovo. siga" · GATE OBSERVADO em 2026-08-17: a PS-P4 FECHA — insumo nomeado, ver §64.10.1) · PS1–PS16 · fecha C4 · C5 e C8 com bloqueio nomeado (PS-P2, que segue ABERTA) · bancada banco-pessoa.html v0.1 (errata corrigida: este cabeçalho declarava v0.2, versão que nem o artefato, nem o gerador, nem o MANIFESTO, nem o mapa de cobertura têm — §64.10.3) · suite-pessoa.mjs 44 · 0 · 1 [n/a] · BT7 consertado em 2026-08-17
Rodada zero: NÃO VISITADO. O §13 tinha lido o avatar renderizado (C85) e o cartão de pessoa (C115), mas nenhum seletor tinha sido aberto. Navegação autorizada, modo somente leitura: menus abertos, lidos e fechados; nenhuma atribuição feita. Seis dispositivos, C125–C130, no §16 do
estudo-clickup-completo.md. LGPD: a lista traz nomes reais de colaboradores; nenhum foi transcrito.E o achado principal é o mesmo da volta anterior, noutro componente. Na árvore de acessibilidade, cada pessoa da lista é
generic— semrole="listbox", semrole="option", semaria-selectedem quem já está escolhido —, e o campo de busca é umtextboxsimples, semrole="combobox", semaria-expanded, semaria-controls. Na tela a lista é exemplar: agrupada, com avatares, com o escolhido destacado. Na árvore é um bloco de nomes soltos.Dois de dois seletores auditados repetem o padrão (C122 no calendário, C130 aqui). A regra da quinta volta — onde o dispositivo é de ESCOLHA, leia a ÁRVORE junto com a TELA — deixou de ser precaução e virou expectativa.
Base (3 rodadas, 2026-08-16). R1 · ARIA APG (combobox): o campo é
role="combobox"comaria-controlsapontando o popup earia-expanded; o foco do DOM permanece no campo e o foco da tecnologia assistiva anda poraria-activedescendant; a opção escolhida levaaria-selected="true"; teclado ↓/↑ para andar,Escpara fechar sem alterar,Enterpara aceitar. Para grupos, o APG traz o exemplo de listbox com opções agrupadas —role="group"com nome próprio. R2 · mercado: o produto de referência agrupa em "Responsáveis" e "Pessoas", põe "Eu" no topo, e usa o mesmo campo para buscar e convidar. R3 · normas: SC 4.1.2 (nome, papel e valor) é o que o C130 viola; SC 2.4.3 (ordem de foco) é o que oaria-activedescendantpreserva.
62.1 A régua: quem escolhe pessoa está escolhendo RESPONSABILIDADE#
Um seletor de pessoa num ERP de engenharia não é um select bonito: atribuir é transferir
responsabilidade técnica. Isso muda três coisas em relação a um seletor genérico — quem pode
aparecer na lista, o que acontece quando a pessoa sai da empresa, e o fato de que a escolha
precisa ser desfazível e visível a quem audita.
62.2 Os contratos#
| # | Contrato | O que ele descarta, e por quê |
|---|---|---|
| PS1 | O campo é role="combobox" com aria-expanded e aria-controls apontando a lista |
textbox solto ao lado de uma lista sem vínculo. É o C130 medido: sem o vínculo, quem não vê não sabe que existe lista |
| PS2 | A lista é listbox; cada item é option com aria-selected |
Itens generic. Sem papel, o leitor de tela anuncia nomes soltos em vez de "lista de 8, 1 selecionada" |
| PS3 | O foco do DOM fica no campo; a AT anda por aria-activedescendant |
Mover o foco real para dentro da lista. Isso quebra a digitação contínua, que é o modo natural de filtrar |
| PS4 | Grupos são role="group" com nome próprio ("Já atribuídos", "Equipe") |
Cabeçalho só visual. O agrupamento é informação; sem papel ele é decoração |
| PS5 | Multi-select produz CHIPS removíveis — herda SG9–SG13 do §60, inclusive o teto e o "+N" |
Reinventar. A família de chips já é canon |
| PS6 | Teclado: ↓/↑ anda · Enter escolhe · Esc fecha SEM alterar · Backspace no campo vazio remove o último chip |
Fechar aplicando. Esc que confirma é a armadilha clássica de picker |
| PS7 | O avatar é aria-hidden; quem informa é o NOME |
Concatenar. Herda o SG8 e o defeito real do ✋ Mover |
| PS8 | Avatar sem foto cai para INICIAIS sobre fundo derivado do nome — determinístico, nunca aleatório | Cor sorteada. A mesma pessoa mudaria de cor entre telas |
| PS9 | O indicador de presença, quando existe, tem rótulo textual | Bolinha muda. Cor sozinha não diz "disponível" |
| PS10 | "Eu" aparece primeiro, e é rotulado como tal | Só o nome próprio. C127: o atalho para si mesmo é o caso mais frequente |
| PS11 | Buscar e CONVIDAR são ações distintas, ainda que no mesmo campo: convidar exige confirmação explícita | Convidar por Enter. C126 mostra os dois no mesmo campo; num ERP, convidar cria acesso — não pode ser efeito colateral de digitar |
| PS12 | Pessoa INATIVA continua exibível onde já foi atribuída, marcada como inativa; e não é oferecida para novas atribuições | Sumir com quem saiu. O histórico de quem assinou o quê é registro técnico — herda o VD16: ausência e vazio não são a mesma coisa |
| PS13 | A lista carrega em página, com estado de carregando declarado; nunca corta em silêncio | Cortar em N sem dizer. Herda a regra do teto declarado (SG11) |
| PS14 | Vazio de busca diz o que fazer ("Ninguém com esse nome. Digite um e-mail para convidar.") | "Nenhum resultado" |
| PS15 | Remover uma pessoa anuncia quem saiu e quantos restam | Remoção silenciosa. Herda o SG12 |
| PS16 | Alvo de 44px por linha da lista, e a linha inteira é clicável | Alvo só no nome |
62.3 A fronteira, e os dois bloqueios nomeados#
- C5 · seletor de entidade colorida (espaço/lista com glifo) — o seletor vive atrás da ação mover, que é escrita. A entidade renderizada foi vista; o seletor não. Bloqueio nomeado: só se alcança escrevendo.
- C8 · campo de menção
@— abrir a lista de menção exige digitar no compositor de comentário, e o produto persiste rascunho. Mesmo bloqueio.
Achado negativo é achado. Os dois não são "não deu tempo": são inalcançáveis no modo autorizado, e ficam assim registrados. Quando a spec deles for escrita, ou o modo muda, ou a base é canon + norma sem leitura — declarado, como o DH12.
Também fora: permissão (quem pode ser atribuído é regra de produto) · notificação ao atribuir · carga de trabalho (A15, bloqueado por ambiente desde a quarta volta).
62.4 Números — a MEDIR na bancada#
Altura da linha · diâmetro do avatar e sua escala de tipo para as iniciais · alvo do X do chip (herda os 44px do SG10) · contraste das iniciais sobre os fundos derivados, em todos os fundos que a derivação puder gerar · altura máxima da lista antes de rolar. Nenhuma medida é afirmada aqui.
62.5 Pendências — a lista de origem (2026-08-16, manhã)#
| # | Pendência | Por que nasceu |
|---|---|---|
| PS-P1 | Bancada banco-pessoa.html, com gerador, molde e suíte |
Nível de prova ao escrever a spec: nenhum — não havia consumidor no acervo |
| PS-P2 | C5 e C8 sem leitura | Bloqueio nomeado: só se alcançam escrevendo |
| PS-P3 | A derivação de cor das iniciais | O contraste tem de passar em todas as cores que a função puder gerar, não numa amostra. É medição de classe, não de caso |
O estado ATUAL de cada uma está em §62.7, abaixo — esta tabela fica como registro de origem.
62.6 A bancada banco-pessoa.html — e a decisão que torna a PS-P3 DEMONSTRÁVEL#
A bancada nasceu em 2026-08-16 com 44 PASS · 0 FAIL · 1 [n/a] em suite-pessoa.mjs, cobrindo
PS1–PS16 mais sete guardas de operabilidade (PS-OP1…PS-OP7), duas de forced-colors e a guarda
transversal GI2/BT3 do §64.
Por que sete guardas de operabilidade, e não só as de estrutura. Em 2026-08-16 a
banco-data.htmlv0.1 passou em 25 PASS · 0 FAIL com o calendário inoperante — nenhuma data clicável. Quem reprovou foi o olho do Rafael, não o placar. Desde então, guarda de componente de escolha clica, digita e tecla antes de aprovar: aqui, ↓ move o cursor, o clique na extremidade da linha escolhe,Escfecha,Backspaceremove, o filtro filtra, o"+N"abre e a carga em página carrega.
A paleta das iniciais é FECHADA — e é isso que fecha a PS-P3#
O PS8 manda que o avatar sem foto caia para iniciais sobre fundo derivado do nome, determinístico. A PS-P3 exigia mais: o contraste tem de passar em todas as cores que a função puder gerar, não numa amostra.
Alternativa descartada — e é a que a maioria dos produtos usa: hash do nome → matiz livre (HSL). Ela gera uma classe infinita de cores. Contraste de classe infinita não se mede: se torce para dar certo, e no dia em que um nome cair num amarelo claro com tinta clara ninguém vai saber por quê.
Decisão (2026-08-16): o hash indexa um conjunto FECHADO de oito pares (fundo, tinta), com os dois lados na mesma família da rampa. Duas consequências que se ganham juntas:
- A PS-P3 vira demonstrável por ENUMERAÇÃO — oito pares se medem; classe infinita, não.
- O par não se rompe na inversão de tema (contrato BT3 do §64), porque fundo e tinta são do mesmo par fixo. É o caso que o BT4 tolera de propósito — primitiva em superfície de identidade —, com o número impresso no placar em vez de tolerado em silêncio.
| Par | Fundo | Tinta | Contraste medido |
|---|---|---|---|
| turquesa claro | --seed-turquesa-100 |
--seed-turquesa-900 |
11,37 |
| turquesa médio | --seed-turquesa-200 |
--seed-turquesa-900 |
9,35 |
| amarelo claro | --seed-amarelo-100 |
--seed-amarelo-900 |
11,54 |
| amarelo médio | --seed-amarelo-200 |
--seed-amarelo-900 |
9,73 |
| azul claro | --seed-azul-100 |
--seed-azul-900 |
11,50 |
| azul médio | --seed-azul-200 |
--seed-azul-900 |
9,38 |
| cinza claro | --seed-cinza-100 |
--seed-cinza-900 |
11,49 |
| cinza médio | --seed-cinza-200 |
--seed-cinza-900 |
9,33 (o pior) |
Piso do projeto para texto: 4,50. Medido nos dois temas — os valores não mudam, e é essa estabilidade que o BT4 exige que seja impressa.
Detalhe de implementação que é contrato, não gosto: a derivação não pode usar o
hash()do Python — ele é randomizado por processo (PYTHONHASHSEED), então a mesma pessoa mudaria de cor entre duas gerações do mesmo arquivo, que é exatamente o defeito que o PS8 proíbe. A derivação usa soma de códigos de ponto: estável, reproduzível em JS, e portanto igual no gerador e em produção.
O estado ABERTO é impresso EM FLUXO — e isso é decisão de bancada#
A primeira versão da página imprimia os quatro seletores abertos com o popup em
position:absolute — que é o comportamento real do componente. Resultado observado no render:
cada popup cobriu o cartão vizinho e as duas seções seguintes, e a bancada ficou ilegível
justamente nos estados que ela existe para mostrar.
Regra que fica: bancada é catálogo de estados lado a lado (CP31); sobreposição é
comportamento de tela. Os estados impressos abertos vão em fluxo (.sel--fluxo), e a
sobreposição real continua exercida pelo Estado 1, que abre no clique.
Décimo quinto defeito de instrumento — coordenada de elemento recortado#
A guarda PS-OP2 (a linha inteira é clicável) pegava o retângulo da última opção e clicava em
right − 6 sem rolar antes. A lista tem max-height:264px; overflow:auto, e a última opção
estava em y=865, fora da área visível do popup, que termina em y=782. O clique caiu na página,
não no controle, e a guarda reprovou um artefato correto com "o alvo é só o texto".
Regra nova: coordenada de elemento recortado por contêiner rolável não é a coordenada do controle. Rola-se primeiro, mede-se depois — e a guarda agora verifica que o ponto medido cai sobre a opção antes de emitir veredito.
62.7 Pendências — atualizadas em 2026-08-16#
Aviso de supersede (2026-08-17): a linha PS-P4 desta tabela está SUPERSEDIDA pelo §64.10.4 — ela FECHOU com o gate observado da
banco-pessoav0.1. A PS-P2 segue ABERTA e não foi tocada. A tabela abaixo fica como histórico; o estado vigente é o do §64.10.4.
| # | Pendência | Estado |
|---|---|---|
| PS-P1 | Bancada banco-pessoa.html, com gerador, molde e suíte |
✅ FECHADA — 44 · 0 · 1. Nível de prova: 2 (bancada). Continua sem consumidor em produção, e isso está dito: quem escreve o teste escreve o caso |
| PS-P3 | A derivação de cor das iniciais | ✅ FECHADA por DECISÃO + ENUMERAÇÃO — paleta fechada de 8 pares, medida nos dois temas, pior par 9,33 contra piso 4,50 |
| PS-P2 | C5 e C8 sem leitura | ABERTA — bloqueio nomeado: os dois só se alcançam escrevendo no produto de referência, e o modo autorizado é somente leitura |
| PS-P4 | Gate visual da banco-pessoa.html v0.1 |
NOVA, e ABERTA — quatro camadas verdes não substituem o olho. Foi o gate que reprovou a banco-data v0.1 com 25 PASS |
62.8 PS-P5 — REVOGADA PELA MEDIÇÃO: o .mini-avatar não é avatar de pessoa#
Escrito em 2026-08-19, ao executar a PS-P5. Seção autossuficiente, e ela supersede formalmente a linha PS-P5 do §64.13.4 e do §69.6.
O que a pendência mandava fazer. A PS-P5 nasceu em 2026-08-17, da auditoria transversal do §69, com
este enunciado: "o .mini-avatar, círculo de iniciais de PESSOA, pinta-se com a paleta de ENTIDADE,
quando o §62 fechou paleta própria de 8 pares". A decisão do Rafael foi migrá-lo para a paleta de
PESSOA, "não a de entidade do CP23".
O que a medição encontrou, em 2026-08-19, antes de tocar em qualquer coisa:
| tela | quantos .mini-avatar |
o que as iniciais são | o que a cor é | o que mais tem |
|---|---|---|---|---|
tela-lista |
ZERO no DOM | — | — | folha de estilo sem consumidor: .pessoa, .mini-avatar e cinco posições de cor, mantidas por cópia entre telas |
tela-tabela |
6, na coluna Cliente | MA = Metalúrgica Andrade · FB = Fazenda Boa Vista · HS = Hospital Santa Rita | posição de ENTIDADE (1 a 5) | um ponto de presença (disponivel / ocupado / ausente) |
tela-referencia |
5, na coluna Cliente | idem | idem | idem |
Ou seja: ele NÃO é um avatar de pessoa. Ele carrega o CLIENTE, que é uma ENTIDADE, com as iniciais do cliente. A paleta que ele usa — a de entidade — é a paleta certa para o que ele representa. Migrar para a paleta de PESSOA seria pintar uma empresa com a cor de uma pessoa.
A PS-P5, como escrita, está REVOGADA. Não se executa uma decisão cuja premissa a medição derrubou. É o mesmo movimento de 2026-08-18, quando o RITO reprovou o conserto que a própria pendência CD-P9 mandava aplicar. O que a auditoria viu foi o NOME da classe —
pessoa,mini-avatar—, e o nome mentia sobre o dado.
O que a medição achou de verdade, e vira pendência nova:
| # | Pendência que nasce | O que está medido |
|---|---|---|
| PS-P6 | Um CLIENTE está desenhado com a anatomia de uma PESSOA. Círculo de 26px com INICIAIS e ponto de presença, na coluna Cliente de duas telas estáveis. Três problemas, e os três são de PRODUTO: (a) o SI1 do §65 descartou explicitamente "inicial da palavra sobre cor" como identidade de entidade — "duas entidades com a mesma letra e cores próximas ficam idênticas, e a inicial não sobrevive a renome" —, e é exatamente o que está em uso; (b) o ponto de presença é estado de PESSOA: uma empresa não fica "ocupada"; (c) o elemento inteiro é aria-hidden, então a presença é comunicada só por cor e para ninguém — ela não está escrita em lugar nenhum da linha. Vai a gate com recorte, não se conserta por conta própria |
O que FOI feito, e é inerte: o tela-lista teve o bloco .pessoa / .mini-avatar removido —
eram zero elementos no DOM, zero em class="pessoa" e zero menções em script. Prova de inércia: 0
de 3.294.000 pixels em 4 comparações, duas execuções.
Regra que fica: REGRA DE ESTILO SEM ELEMENTO É DRIFT ESPERANDO DATA. Ela não pinta hoje e pintaria errado amanhã, e foi por cópia entre telas que ela chegou ali. Foi essa mesma folha morta que fez a auditoria contar o
.mini-avatarem três telas quando ele existe em duas.
Também cita o §62: banco-edicao-linha, banco-identidade, tela-lista.