-
Notifications
You must be signed in to change notification settings - Fork 1
Styling pt BR
🌐 Esta página em: English · Português
O eQuantic.UI entrega uma experiência de desenvolvimento (DX) inspirada no Flutter enquanto aproveita a força inteira de cada alvo de renderização. A arquitetura de estilo se apoia em três pilares:
- Abstração: componentes autoram o que estilizar, como valores C# tipados, nunca strings CSS.
- Uma semântica, dois alvos: o mesmo vocabulário de estilo comanda valores em dp no nativo (Photon) e CSS no web.
- Performance: geração e deduplicação de classes em tempo de build, sem custo de runtime CSS-in-JS.
O estilo de um componente é autorado inteiramente em C# tipado (BoxStyle, StyleDiff, tokens de
design) e rebaixado pelo motor de estilo atômico: cada declaração comum vira UMA classe atômica
deduplicada, idêntica byte a byte entre o SSR (C#) e a hidratação (TS); cores de tema referenciam as
custom properties var(--eq-color-*). Estados de hover/foco, adaptação por classe de tamanho de
janela, posicionamento sticky e transforms fazem todos parte do vocabulário, com zero JavaScript
envolvido.
Desde 0.2.0-preview.24
A paleta de variante continua com cinco sub-tokens; o hover resolve por DERIVAÇÃO: o
VariantColors.Hover é o ponto médio canal a canal de Base → Pressed
(ColorToken.MidpointWith, a mesma cor onde color-mix(in srgb, Base 50%, Pressed) cai), e
variantes discretas fazem hover em SurfaceSubtle. Componentes autoram isso como um diff comum de
BoxStyle.Hover, então os dois realizadores já sabiam pintá-lo: o web como uma regra atômica
:hover, o Photon pelo pipeline de ponteiro.
Duas regras acompanham a própria emissão. Toda regra atômica :hover é embrulhada em
@media (hover: hover), para que o hover emulado e grudento de um browser de toque não ache regra
nenhuma, e a cerca embrulha a regra, nunca o hash, então SSR e hidratação continuam comparando strings
de classe idênticas. E no Photon, o hover é rastreado por CAMINHO de layout, como uma CADEIA de tudo
que está sob o ponteiro, porque o :hover do CSS casa com todo ancestral: passar sobre o gatilho de
um tooltip também faz hover no tooltip, e uma reconstrução de componente, que troca cada instância
de nó, deixou de perder o hover que ela mesma repintou.
Desde 0.2.0-preview.23
O Photon pinta em ORDEM DE FILHO: um irmão posterior fica por cima, e não é preciso dizer nada. O CSS para de funcionar assim no momento em que caixas adquirem contextos de empilhamento, então o realizador web soletra o que o nativo dá de graça, nas palavras do design system, nunca nas do CSS.
Elevation decide o que está acima, não só quão profunda é a sombra. Ela desenhava uma sombra e
nada mais, o que é meia frase: uma superfície elevada que qualquer coisa pintada depois cobre não
está elevada. Os níveis 1–5 são o plano de CONTEÚDO, e são os únicos números que um autor escreve.
Chrome é um plano, não um cartão elevado. Qualquer coisa fixada (um cabeçalho Sticky,
flutuante ou no fluxo) fica acima de toda elevação de conteúdo. Antes ela ficava um passo acima de
nada, o que é um número competindo com outros números: dê à elevação a faixa 1–5 e um cartão
meramente elevado passaria a empilhar acima do cabeçalho e rolaria por cima dele.
É por isso que Sticky não tem ZIndex e nunca vai ter. Um z-index é vocabulário CSS, e um autor
que precisa escolher um está sendo obrigado a saber quais números todo o resto escolheu. A elevação
diz quão alto, o realizador decide como isso se soletra, e chrome não está na mesma escala que
conteúdo.
Uma exceção ao uma declaração, uma classe, e ela deixa de ser exceção assim que é nomeada: um
prefixo de fabricante não é uma declaração própria, é a mesma escrita para outro motor. O par
divide uma classe cuja regra nomeia os dois, com a propriedade padrão por último. Sozinho numa regra,
o -webkit-backdrop-filter é descartado inteiro por um motor que só aceita o nome padrão (o
insertRule deixa uma regra VAZIA no Chromium, medido), então a classe era computada, hasheada,
emitida, posta no elemento, e não fazia nada. Desde 0.2.0-preview.21.
Desde 0.2.0-preview.7
Um trecho monoespaçado (Text com Mono, um trecho rico, um CodeBlock) desenha numa pilha que o
framework possui, e ela cai numa classe atômica, que vence uma regra body { font-family }, e
cujo nome é um hash de conteúdo que muda entre builds. Então não havia onde pendurar a sua própria
face de código. O gancho é uma variável:
:root { --eq-font-mono: 'JetBrains Mono', ui-monospace, monospace; }Todo trecho mono a segue, com a pilha da plataforma como fallback quando ninguém a define.
O medidor lê a mesma variável, e isso não é um detalhe de implementação que dá para ignorar se
você publica um editor de código: o CodeEditor posiciona o cursor a partir de um avanço de coluna
medido, então medir numa face e desenhar em outra põe o cursor ao lado do caractere em que ele está,
em vez de embaixo dele.
O motor completo (leis, pseudo-estados, classes de tamanho, a folha de estilo gerada) está
documentado em DesignSystem. O vocabulário abstrato em si (Box,
Row/Column, Grid, Stack, …) está documentado em
Componentes write-once.
Temas também são C# tipado (cores como pares ColorToken claro/escuro, papéis de tipo, escala de
forma, elevação) selecionados numa linha e ponteados do SSR para o cliente:
builder.Services.AddUI(options =>
{
options.ScanAssembly(typeof(Program).Assembly)
.UseTheme(PhotonTheme.Instance); // ou MaterialTheme.FromSeed(color)
});Duas implementações vêm na caixa: PhotonTheme (o padrão) e MaterialTheme (Material 3 de
verdade, incluindo cor dinâmica a partir de uma semente). Troque o tema e todo componente se
rebranda, servidor e cliente, web e nativo. A troca claro/escuro em tempo de execução é um serviço
(IThemeController); veja DesignSystem.
Desde 0.2.0-preview.13
new BoxStyle
{
BorderWidth = 1,
BorderColor = theme.Border,
BorderSides = BorderSides.Top, // um filete acima de uma seção
}
new BoxStyle
{
BorderWidth = 3,
BorderColor = theme.Colors(Variant.Primary).Base,
BorderSides = BorderSides.Start, // uma barra de acento ao lado de um destaque
}BorderSides.All por padrão, então toda caixa escrita antes disso renderiza byte por byte igual: uma
borda completa continua emitindo o atalho de uma declaração e a sua classe atômica única.
Nenhuma dessas é um Divider. Um Divider é um irmão entre duas coisas; estas pertencem à
própria caixa, e o único jeito de desenhar uma era um Row embrulhando um Box de um dp, o que é
uma mentira de layout sobre o que o design queria dizer.
Start e End em vez de Left e Right, casando com EdgeInsets: eles espelham numa leitura da
direita para a esquerda, e uma barra de acento que fica à esquerda quando o texto flui para o outro
lado está do lado errado dele.
Cerca. Com raio de canto, uma borda parcial difere levemente entre os alvos no canto onde uma aresta presente encontra uma ausente: o web faz meia-esquadria, o Photon deixa quadrado. Em raio 0 (um filete, uma barra de acento, uma célula de tabela, que é para o que bordas parciais servem) os dois são idênticos. Use
BorderSides.Allpara um contorno arredondado.
A camada web de baixo nível (eQuantic.UI.Core) espelha o DOM 1:1. Todo HtmlElement expõe os
atributos que o browser tem:
public abstract class HtmlElement : IComponent {
/// <summary>Classes CSS cruas (separadas por espaço).</summary>
public string? ClassName { get; set; }
/// <summary>Estilos inline para valores dinâmicos (ex.: coordenadas, cores vindas do banco).</summary>
public HtmlStyle? Style { get; set; }
}Esse contrato significa que a camada web não impõe nenhum framework CSS, ela renderiza atributos
HTML. O DynamicElement vai além e renderiza qualquer tag com quaisquer atributos. Classes CSS
padrão de qualquer folha de estilo funcionam nativamente:
new DynamicElement("aside") { ClassName = "my-sidebar" }O framework publica exatamente um motor de estilo, o pipeline C# tipado acima. Não há framework
CSS embutido nem camada de adaptação: uma página que precisa de markup escrito à mão usa a saída de
emergência (HtmlElement/DynamicElement + ClassName), e qualquer folha de estilo que o app traga
(o CSS dele, um framework utilitário que ele mesmo constrói) é referenciada como em qualquer projeto
web:
builder.Services.AddUI(options =>
{
options.ConfigureHtmlShell(shell => shell.AddStylesheet("/css/app.css"));
});O framework não gera nem processa esse CSS; é assunto do build do próprio app.
| Pacote | Propósito |
|---|---|
| eQuantic.UI.Primitives | Estilos tipados, tokens de design, o vocabulário abstrato: a fonte da verdade do estilo. |
| eQuantic.UI.Core | A camada espelho do DOM: HtmlElement, ClassName, HtmlStyle, DynamicElement. |
| eQuantic.UI.Web | O realizador web + o motor de estilo atômico (StyleAtomizer) + a folha de estilo gerada. |
🌐 English · Português
🏁 Comece aqui
📱 Write-once
- Componentes write-once
- Superfície declarativa
- Motor Photon
- Design System
- Capacidades
- Armazenamento
- Formulários
- Editor de código
- Markdown
- Mermaid
- Renderização de Email
🏗️ Arquitetura
⚙️ Compilação
- Compilador
- Avaliação em tempo de compilação
- Recursos C# suportados
- Resolução de tipos externos
- Fluxo de build
- Diagnósticos
⚡ Runtime
🔌 Servidor
🎨 Ecossistema
🚀 Desenvolvimento