fokus-styles 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/dist/css/components.css +583 -83
- package/dist/css/components.css.map +1 -1
- package/dist/css/components.min.css +1 -1
- package/dist/css/components.min.css.map +1 -1
- package/dist/css/fokus-components.css +583 -83
- package/dist/css/fokus-components.css.map +1 -1
- package/dist/css/fokus-components.min.css +1 -1
- package/dist/css/fokus-components.min.css.map +1 -1
- package/dist/css/fokus-core.css +22 -0
- package/dist/css/fokus-core.css.map +1 -1
- package/dist/css/fokus-core.min.css +1 -1
- package/dist/css/fokus-core.min.css.map +1 -1
- package/dist/css/fokus-dark.css +10 -0
- package/dist/css/fokus-dark.css.map +1 -1
- package/dist/css/fokus-dark.min.css +1 -1
- package/dist/css/fokus-dark.min.css.map +1 -1
- package/dist/css/fokus-rtl.css +9166 -0
- package/dist/css/fokus-rtl.css.map +1 -0
- package/dist/css/fokus-rtl.min.css +2 -0
- package/dist/css/fokus-rtl.min.css.map +1 -0
- package/dist/css/fokus-utilities.css +158 -0
- package/dist/css/fokus-utilities.css.map +1 -1
- package/dist/css/fokus-utilities.min.css +1 -1
- package/dist/css/fokus-utilities.min.css.map +1 -1
- package/dist/css/fokus.css +1018 -258
- package/dist/css/fokus.css.map +1 -1
- package/dist/css/fokus.min.css +1 -1
- package/dist/css/fokus.min.css.map +1 -1
- package/dist/css/forms.css +322 -176
- package/dist/css/forms.css.map +1 -1
- package/dist/css/forms.min.css +1 -1
- package/dist/css/forms.min.css.map +1 -1
- package/dist/css/helpers.css +158 -0
- package/dist/css/helpers.css.map +1 -1
- package/dist/css/helpers.min.css +1 -1
- package/dist/css/helpers.min.css.map +1 -1
- package/dist/css/layout.css +22 -0
- package/dist/css/layout.css.map +1 -1
- package/dist/css/layout.min.css +1 -1
- package/dist/css/layout.min.css.map +1 -1
- package/dist/js/fokus.js +270 -25
- package/dist/js/fokus.js.map +2 -2
- package/dist/js/fokus.min.js +18 -18
- package/dist/js/fokus.min.js.map +3 -3
- package/docs/components/alert.md +69 -24
- package/docs/components/badge.md +23 -4
- package/docs/components/checkbox.md +16 -3
- package/docs/components/popover.md +20 -7
- package/docs/components/radio.md +11 -1
- package/docs/components/responsive.md +19 -0
- package/docs/components/switch.md +30 -8
- package/docs/components/tag.md +19 -4
- package/docs/components/toast.md +72 -59
- package/docs/components/tooltip.md +38 -2
- package/docs/guides/accessibility.md +7 -0
- package/docs/guides/rtl-and-system-preferences.md +28 -0
- package/docs/prompts/prompt-plan.md +4 -4
- package/docs/reference/accessibility-matrix.md +7 -7
- package/docs/reference/contrast-report.md +4 -0
- package/docs/reference/definitions.md +5 -1
- package/docs/reference/design-tokens.md +14 -0
- package/docs/reference/size-baseline.json +13 -13
- package/mockup/assets/example-theme.css +11 -0
- package/mockup/assets/showcase-contracts.js +6 -6
- package/mockup/examples/alerts.html +105 -31
- package/mockup/examples/badges-alerts.html +91 -59
- package/mockup/examples/check-radio-switch.html +575 -99
- package/mockup/examples/popover.html +81 -0
- package/mockup/examples/tag.html +97 -87
- package/mockup/examples/toast.html +113 -0
- package/mockup/examples/tooltip.html +68 -0
- package/mockup/forms.html +1 -1
- package/mockup/overlays-commands.html +2 -2
- package/package.json +2 -1
- package/packages/fokus-components/scss/components/_alerts.scss +128 -6
- package/packages/fokus-components/scss/components/_badges.scss +26 -10
- package/packages/fokus-components/scss/components/_index.scss +1 -0
- package/packages/fokus-components/scss/components/_popover.scss +131 -21
- package/packages/fokus-components/scss/components/_responsive.scss +23 -0
- package/packages/fokus-components/scss/components/_tag.scss +37 -14
- package/packages/fokus-components/scss/components/_toasts.scss +156 -11
- package/packages/fokus-components/scss/components/_tooltips.scss +70 -18
- package/packages/fokus-components/scss/forms/_check-radio-switch.scss +313 -215
- package/packages/fokus-components/scss/forms/_forms.scss +16 -0
- package/packages/fokus-core/scss/base/_accessibility.scss +14 -0
- package/packages/fokus-core/scss/tokens/_root.scss +11 -0
- package/packages/fokus-js/js/carousel.d.ts +4 -0
- package/packages/fokus-js/js/carousel.js +8 -0
- package/packages/fokus-js/js/core/positioning.js +18 -9
- package/packages/fokus-js/js/dropdown.d.ts +4 -0
- package/packages/fokus-js/js/dropdown.js +7 -0
- package/packages/fokus-js/js/popover.js +26 -1
- package/packages/fokus-js/js/tabs.d.ts +3 -0
- package/packages/fokus-js/js/tabs.js +5 -0
- package/packages/fokus-js/js/tag.js +17 -0
- package/packages/fokus-js/js/toast.js +77 -3
- package/packages/fokus-js/js/tooltip.d.ts +8 -1
- package/packages/fokus-js/js/tooltip.js +106 -13
- package/packages/fokus-utilities/scss/utilities/_api.scss +48 -0
- package/scss/entries/rtl-entry.scss +11 -0
|
@@ -25,7 +25,13 @@ marcação manualmente — só o elemento de referência com `title`/`data-fs="t
|
|
|
25
25
|
## Variações
|
|
26
26
|
|
|
27
27
|
`data-placement` (`top` — padrão, `bottom`, `left`, `right`) no elemento
|
|
28
|
-
de referência. Reposiciona automaticamente se não couber.
|
|
28
|
+
de referência. Reposiciona automaticamente se não couber. A posição efetiva
|
|
29
|
+
fica em `data-placement` no Tooltip gerado.
|
|
30
|
+
|
|
31
|
+
Também são aceitos alinhamentos compostos, como `top-start`, `top-end`,
|
|
32
|
+
`bottom-start`, `bottom-end`, `left-start` e `right-end`. A forma manual
|
|
33
|
+
equivalente é `{ placement: "top", align: "start" }`. Use `data-offset` ou
|
|
34
|
+
`offset` para controlar a distância entre o gatilho e a dica.
|
|
29
35
|
|
|
30
36
|
```html
|
|
31
37
|
<button class="fs-btn" data-fs="tooltip" data-placement="right" title="Mais opções">⋮</button>
|
|
@@ -36,6 +42,25 @@ de referência. Reposiciona automaticamente se não couber.
|
|
|
36
42
|
`.is-open` — controlado pelo JS ao mostrar/esconder; não defina
|
|
37
43
|
manualmente.
|
|
38
44
|
|
|
45
|
+
### Delays e touch
|
|
46
|
+
|
|
47
|
+
Use `data-show-delay` e `data-hide-delay` para evitar abertura acidental:
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<button data-fs="tooltip" data-show-delay="300" data-hide-delay="100"
|
|
51
|
+
title="Ajuda complementar">Ajuda</button>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
O Tooltip também responde a foco e ponteiro. Em touch, toque fora fecha a dica.
|
|
55
|
+
Escape fecha sem mover o foco. Tooltips concorrentes são fechados quando uma
|
|
56
|
+
nova dica é aberta.
|
|
57
|
+
|
|
58
|
+
Sem configuração, a abertura é imediata; use `data-show-delay` para evitar
|
|
59
|
+
aberturas acidentais em interações com ponteiro. O foco de teclado abre
|
|
60
|
+
imediatamente. Elementos `disabled` não
|
|
61
|
+
recebem foco nem eventos nativos: envolva-os em um elemento focável quando
|
|
62
|
+
precisar explicar seu estado.
|
|
63
|
+
|
|
39
64
|
## A11y
|
|
40
65
|
|
|
41
66
|
O JS aplica `aria-describedby` no elemento de referência, apontando pro
|
|
@@ -68,10 +93,21 @@ de outro lugar, não de um atributo estático; é assim que
|
|
|
68
93
|
|
|
69
94
|
`--fs-tooltip-bg`, `--fs-tooltip-text`, `--fs-radius-sm`.
|
|
70
95
|
|
|
96
|
+
O componente também expõe tokens locais como `--fs-tooltip-max-width`,
|
|
97
|
+
`--fs-tooltip-padding-block`, `--fs-tooltip-padding-inline`,
|
|
98
|
+
`--fs-tooltip-radius`, `--fs-tooltip-shadow` e `--fs-tooltip-arrow-size`.
|
|
99
|
+
Eles podem ser sobrescritos por instância sem alterar tokens globais.
|
|
100
|
+
|
|
71
101
|
## Exemplo
|
|
72
102
|
|
|
73
103
|
```html
|
|
74
104
|
<button type="button" class="fs-btn-close" data-fs="tooltip" title="Fechar" aria-label="Fechar"></button>
|
|
75
105
|
```
|
|
76
106
|
|
|
77
|
-
|
|
107
|
+
O Tooltip não deve conter links ou botões e não substitui label, texto de erro
|
|
108
|
+
ou instrução essencial; nesses casos use conteúdo visível ou Popover.
|
|
109
|
+
|
|
110
|
+
Quando o gatilho já possui `aria-describedby`, o Tooltip acrescenta somente o
|
|
111
|
+
próprio ID e restaura a lista original ao executar `dispose()`.
|
|
112
|
+
|
|
113
|
+
Mockup: [laboratório independente do componente](../../mockup/examples/tooltip.html).
|
|
@@ -84,6 +84,13 @@ para que leitores de tela anunciem a mensagem ao focar o campo. O
|
|
|
84
84
|
framework não injeta esse atributo automaticamente, porque o `id` do texto
|
|
85
85
|
de apoio é definido por você.
|
|
86
86
|
|
|
87
|
+
Para Checkbox, Radio e Switch, mantenha o input nativo e associe o texto com
|
|
88
|
+
`for`/`id`. Opções relacionadas devem ficar em `fieldset` com `legend`.
|
|
89
|
+
Mensagens de ajuda e erro devem ser referenciadas por `aria-describedby`, e
|
|
90
|
+
um campo inválido pode usar `aria-invalid="true"` junto de `.is-invalid`.
|
|
91
|
+
Switch não recebe `role="switch"` automaticamente; a semântica oficial é a
|
|
92
|
+
do checkbox nativo, inclusive para a tecla `Space`.
|
|
93
|
+
|
|
87
94
|
## Testes automatizados
|
|
88
95
|
|
|
89
96
|
A regressão visual (`npm run test:visual`, Playwright) cobre
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# RTL e preferências do sistema
|
|
2
|
+
|
|
3
|
+
## Visão geral
|
|
4
|
+
|
|
5
|
+
O Fokus Styles 2.4 mantém os componentes em fluxo lógico e oferece o preset
|
|
6
|
+
`fokus-styles/rtl.css` para documentos com `dir="rtl"`. O preset complementa
|
|
7
|
+
a folha principal e preserva `margin-inline`, `padding-inline`, `inset-inline`
|
|
8
|
+
e `border-inline-*`.
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<html dir="rtl" data-fs-theme="auto">
|
|
12
|
+
<link rel="stylesheet" href="fokus-styles/dist/css/fokus.css">
|
|
13
|
+
<link rel="stylesheet" href="fokus-styles/dist/css/fokus-rtl.css">
|
|
14
|
+
</html>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Estados de sistema
|
|
18
|
+
|
|
19
|
+
O framework respeita `prefers-reduced-motion`, `prefers-contrast: more`,
|
|
20
|
+
`forced-colors: active` e `prefers-color-scheme`. Em alto contraste, bordas e
|
|
21
|
+
foco passam a usar espessuras maiores; em forced colors, ações preservam
|
|
22
|
+
`ButtonText` e o foco usa `Highlight`.
|
|
23
|
+
|
|
24
|
+
## A11y
|
|
25
|
+
|
|
26
|
+
O atributo `dir` deve ser aplicado ao documento ou ao contêiner que define o
|
|
27
|
+
fluxo de leitura. Use `dir="auto"` quando a direção do texto inserido não for
|
|
28
|
+
conhecida.
|
|
@@ -5,12 +5,12 @@ Copie o texto abaixo e substitua os campos entre colchetes antes de usar.
|
|
|
5
5
|
```text
|
|
6
6
|
Atue como responsável pelo planejamento técnico e de design do Fokus Styles.
|
|
7
7
|
|
|
8
|
-
Quero criar um plano, sem implementar ainda, para o componente
|
|
8
|
+
Quero criar um plano, sem implementar ainda, para o componente abaixo:
|
|
9
9
|
|
|
10
|
-
## Contexto do pedido
|
|
10
|
+
## Contexto do pedido 8011827-28.2026
|
|
11
11
|
|
|
12
|
-
- Objetivo: [REFINAMENTO VISUAL DO COMPONENTE
|
|
13
|
-
Sugira correções, alterações e implementações de códigos, funcionalidades de mudanças de visual para algo com maior qualidade e usabilidade]
|
|
12
|
+
- Objetivo: [REFINAMENTO VISUAL DO COMPONENTE TOOLTIP;
|
|
13
|
+
Sugira correções, alterações e implementações de códigos, funcionalidades de mudanças de visual para algo com maior qualidade, responsividade, acessibilidade, criatividade e usabilidade]
|
|
14
14
|
|
|
15
15
|
Antes de propor o plano, investigue o repositório e use a documentação como fonte de verdade. Não presuma que o componente está isolado: determine suas dependências, impactos visuais, comportamentais, públicos e de manutenção.
|
|
16
16
|
|
|
@@ -19,13 +19,13 @@ renderizado de fato nos mockups (via o gate axe).
|
|
|
19
19
|
|---|---|---|---|---|---|
|
|
20
20
|
| [Accordion](../components/accordion.md) | Nativo (`<button>`) | Automático | — | ✓ | Sim |
|
|
21
21
|
| [Alert Dialog](../components/alert-dialog.md) | Herdado do Modal | Herdado do Modal | Focus trap + devolve ao gatilho | ✓ | Sim |
|
|
22
|
-
| [Alert](../components/alert.md) |
|
|
22
|
+
| [Alert](../components/alert.md) | Nativo quando houver link/botão | Manual (`role="alert"`/`"status"`) | Nenhuma automática | ✓ | Sim |
|
|
23
23
|
| [Badge](../components/badge.md) | N/A (decorativo) | N/A | — | ✓ | Sim |
|
|
24
24
|
| [Breadcrumb](../components/breadcrumb.md) | Nativo (links) | Manual (`<nav aria-label>`) | — | ✓ | Sim |
|
|
25
25
|
| [Button](../components/button.md) | Nativo | Manual (`aria-label` em só-ícone) | Foco visível padrão | ✓ | Sim |
|
|
26
26
|
| [Card](../components/card.md) | Nativo (stretched-link) | — | Foco no link real | ✓ | Sim |
|
|
27
27
|
| [Carousel](../components/carousel.md) | Automático (setas/Home/End e arraste) | Automático (`aria-hidden`, `aria-current`, toggle) | Recebe foco no contêiner; autoplay pausável | ✓ | Sim |
|
|
28
|
-
| [Checkbox](../components/checkbox.md) | Nativo | Nativo |
|
|
28
|
+
| [Checkbox](../components/checkbox.md) | Nativo (Space) | Nativo + `aria-describedby` manual | Foco visível no controle | ✓ | Sim |
|
|
29
29
|
| [Collapse](../components/collapse.md) | Nativo (gatilho) | Automático | — | ✓ | Sim |
|
|
30
30
|
| [Divider](../components/divider.md) | N/A | Implícito (`<hr>`) | — | ✓ | Sim |
|
|
31
31
|
| [Dropdown](../components/dropdown.md) | Automático (setas/Escape) | Automático | Primeiro item ao abrir; devolve ao gatilho | ✓ | Sim |
|
|
@@ -41,20 +41,20 @@ renderizado de fato nos mockups (via o gate axe).
|
|
|
41
41
|
| [Pagination](../components/pagination.md) | Nativo (links) | Manual (`<nav aria-label>`, `aria-current`) | — | ✓ | Sim |
|
|
42
42
|
| [Popover](../components/popover.md) | Automático (Escape) | Automático | Devolve ao gatilho | ✓ | Sim |
|
|
43
43
|
| [Spinner / Progress](../components/progress.md) | N/A | Manual (`role`+`aria-label`/`aria-valuenow`) | — | ✓ | Sim |
|
|
44
|
-
| [Radio](../components/radio.md) | Nativo (setas no grupo) | Nativo |
|
|
44
|
+
| [Radio](../components/radio.md) | Nativo (setas no grupo) | Nativo + `fieldset/legend` manual | Foco visível no controle | ✓ | Sim |
|
|
45
45
|
| [Rating](../components/rating.md) | Nativo (setas no grupo) | Manual (`aria-label` por estrela) | — | ✓ | Sim |
|
|
46
46
|
| [Segmented Control](../components/segmented-control.md) | Nativo (setas no grupo) | Nativo | — | ✓ | Sim |
|
|
47
47
|
| [Select (custom)](../components/select.md) | Herdado do Dropdown | Automático (`role="listbox"`) | Herdado do Dropdown | ✓ | Sim |
|
|
48
48
|
| [Skeleton](../components/skeleton.md) | N/A | Manual (`aria-busy` opcional) | — | ✓ | Sim |
|
|
49
49
|
| [Stepper](../components/stepper.md) | Automático (passos clicáveis) | Automático (`aria-current="step"`) | — | ✓ | Sim |
|
|
50
|
-
| [Switch](../components/switch.md) | Nativo |
|
|
50
|
+
| [Switch](../components/switch.md) | Nativo (Space) | Checkbox nativo; nome manual sem texto | Foco visível no trilho | ✓ | Sim |
|
|
51
51
|
| [Table](../components/table.md) | Nativo | Manual (`scope`, `<caption>`) | — | ✓ | Sim |
|
|
52
52
|
| [Tabs](../components/tabs.md) | Automático (roving tabindex) | Automático (`role="tab"`/`"tabpanel"`) | — | ✓ | Sim |
|
|
53
|
-
| [Tag](../components/tag.md) | Nativo (botão de fechar) | Manual (`aria-label` descritivo) |
|
|
53
|
+
| [Tag](../components/tag.md) | Nativo (botão de fechar) | Manual (`aria-label` descritivo, `aria-busy`) | Foco preservado/transferido após dismiss | ✓ | Sim |
|
|
54
54
|
| [Tile](../components/tile.md) | Nativo (link real) | — | Foco no link, não no `::after` | ✓ | Sim |
|
|
55
55
|
| [Timeline](../components/timeline.md) | N/A (sem interação própria) | — | — | ✓ | Sim |
|
|
56
|
-
| [Toast](../components/toast.md) |
|
|
57
|
-
| [Tooltip](../components/tooltip.md) | Nativo (`focus`/`blur
|
|
56
|
+
| [Toast](../components/toast.md) | Nativo em fechamento e ações | Automático (`role="status"`, `aria-live="polite"`) | Nenhuma automática; pausa em foco/hover | ✓ | Sim |
|
|
57
|
+
| [Tooltip](../components/tooltip.md) | Nativo (`focus`/`blur`, ponteiro e Escape) | Automático (`role="tooltip"`, `aria-describedby`) | Nenhuma; foco permanece no gatilho | ✓ | Sim |
|
|
58
58
|
|
|
59
59
|
## Legenda
|
|
60
60
|
|
|
@@ -20,6 +20,10 @@ e AAA:
|
|
|
20
20
|
para o texto de botões sólidos, que é sempre bold/UI, não corpo de leitura).
|
|
21
21
|
- **7:1** — AAA, opcional.
|
|
22
22
|
|
|
23
|
+
Checkbox, Radio e Switch reutilizam esses tokens semânticos para bordas,
|
|
24
|
+
superfícies, estados de ação e validação. O relatório visual dos laboratórios
|
|
25
|
+
também deve ser executado após qualquer ajuste nos tokens locais dos controles.
|
|
26
|
+
|
|
23
27
|
`npm run contrast -- --strict` sai com código de erro se algum par ficar
|
|
24
28
|
abaixo do mínimo AA — é o comando rodado pelo gate `contrast:check` do CI
|
|
25
29
|
(`.github/workflows/ci.yml`).
|
|
@@ -527,7 +527,7 @@ abas habilitadas (`role="tablist"`/`"tab"`/`"tabpanel"`, `aria-selected`,
|
|
|
527
527
|
`tabindex` roving), disparando `fs:tab:changed`.
|
|
528
528
|
|
|
529
529
|
**Toast** (`.fs-toast-container`/`.fs-toast`/`.fs-toast-header`/`.fs-toast-body`,
|
|
530
|
-
variantes de cor de estado via `.fs-toast-#{nome}`,
|
|
530
|
+
slots opcionais de ícone, ações e progresso, variantes de cor de estado via `.fs-toast-#{nome}`,
|
|
531
531
|
`packages/fokus-components/scss/components/_toasts.scss`): `packages/fokus-js/js/toast.js` usa `expand()`/`collapse()`
|
|
532
532
|
para mostrar/esconder, com timer de auto-dismiss configurável (`data-delay`,
|
|
533
533
|
`data-autohide="false"` para desativar) e dismiss via
|
|
@@ -810,6 +810,10 @@ Tag removível (`.fs-tag`, `packages/fokus-components/scss/components/_tag.scss`
|
|
|
810
810
|
tamanho do botão de fechar (14×14px) para caber num badge. Precisa de
|
|
811
811
|
JavaScript, mas de forma mínima:
|
|
812
812
|
`packages/fokus-js/js/tag.js` (`FokusStyles.Tag`) só ouve o clique em `[data-fs-dismiss="tag"]`.
|
|
813
|
+
Tags suportam ícones decorativos iniciais ou de estado finais em
|
|
814
|
+
`.fs-tag-icon`/`.fs-tag-icon-end`; esses ícones não substituem o texto
|
|
815
|
+
acessível. Quando o botão focado remove uma Tag de um grupo, o foco é
|
|
816
|
+
transferido para a próxima Tag ou, na ausência dela, para a anterior.
|
|
813
817
|
Antes de remover o elemento do DOM, dispara o evento **cancelável**
|
|
814
818
|
`fs:tag:dismissed` (mesmo espírito de `fs:stepper:beforechange`) —
|
|
815
819
|
`preventDefault()` bloqueia a remoção.
|
|
@@ -88,6 +88,20 @@ legendas possam ser ajustados por instância: `--fs-carousel-radius`,
|
|
|
88
88
|
`--fs-carousel-caption-scrim`. Consulte a [página do Carousel](../components/carousel.md)
|
|
89
89
|
para os nomes completos e seus fallbacks.
|
|
90
90
|
|
|
91
|
+
### Check, Radio e Switch
|
|
92
|
+
|
|
93
|
+
Os controles nativos de seleção expõem tokens locais, sempre com fallback
|
|
94
|
+
para a escala semântica do framework:
|
|
95
|
+
|
|
96
|
+
| Família | Tokens |
|
|
97
|
+
|---|---|
|
|
98
|
+
| Checkbox | `--fs-check-size`, `--fs-check-border-width`, `--fs-check-radius`, `--fs-check-gap`, `--fs-check-mark-color` |
|
|
99
|
+
| Radio | `--fs-radio-size`, `--fs-radio-dot-size`, `--fs-radio-radius`, `--fs-radio-gap` |
|
|
100
|
+
| Switch | `--fs-switch-track-width`, `--fs-switch-track-height`, `--fs-switch-thumb-width`, `--fs-switch-thumb-height`, `--fs-switch-thumb-offset`, `--fs-switch-on-offset`, `--fs-switch-radius`, `--fs-switch-thumb-radius`, `--fs-switch-gap`, `--fs-switch-track-bg`, `--fs-switch-track-border`, `--fs-switch-track-checked-bg`, `--fs-switch-thumb-bg`, `--fs-switch-thumb-border`, `--fs-switch-thumb-shadow`, `--fs-switch-track-shadow`, `--fs-switch-hover-ring`, `--fs-switch-hover-shadow`, `--fs-switch-active-scale` |
|
|
101
|
+
|
|
102
|
+
Eles podem ser sobrescritos no wrapper do controle sem `!important`. As
|
|
103
|
+
variantes `sm` e `lg` alteram os valores desses tokens.
|
|
104
|
+
|
|
91
105
|
## Tipografia
|
|
92
106
|
|
|
93
107
|
| Token | Valor | Uso |
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
{
|
|
2
|
-
"measuredAt": "2026-09-
|
|
2
|
+
"measuredAt": "2026-09-08T15:45:28.076Z",
|
|
3
3
|
"unit": "bytes",
|
|
4
4
|
"files": {
|
|
5
5
|
"css/layout.min.css": {
|
|
6
|
-
"bytes":
|
|
7
|
-
"gzipBytes":
|
|
6
|
+
"bytes": 28993,
|
|
7
|
+
"gzipBytes": 6049
|
|
8
8
|
},
|
|
9
9
|
"css/forms.min.css": {
|
|
10
|
-
"bytes":
|
|
11
|
-
"gzipBytes":
|
|
10
|
+
"bytes": 40484,
|
|
11
|
+
"gzipBytes": 7974
|
|
12
12
|
},
|
|
13
13
|
"css/components.min.css": {
|
|
14
|
-
"bytes":
|
|
15
|
-
"gzipBytes":
|
|
14
|
+
"bytes": 104877,
|
|
15
|
+
"gzipBytes": 18264
|
|
16
16
|
},
|
|
17
17
|
"css/helpers.min.css": {
|
|
18
|
-
"bytes":
|
|
19
|
-
"gzipBytes":
|
|
18
|
+
"bytes": 63446,
|
|
19
|
+
"gzipBytes": 11044
|
|
20
20
|
},
|
|
21
21
|
"css/fonts.min.css": {
|
|
22
22
|
"bytes": 1505,
|
|
23
23
|
"gzipBytes": 409
|
|
24
24
|
},
|
|
25
25
|
"css/fokus.min.css": {
|
|
26
|
-
"bytes":
|
|
27
|
-
"gzipBytes":
|
|
26
|
+
"bytes": 184593,
|
|
27
|
+
"gzipBytes": 28935
|
|
28
28
|
},
|
|
29
29
|
"js/fokus.min.js": {
|
|
30
|
-
"bytes":
|
|
31
|
-
"gzipBytes":
|
|
30
|
+
"bytes": 115015,
|
|
31
|
+
"gzipBytes": 24623
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -6,3 +6,14 @@ html[data-fs-theme="dark"] body {
|
|
|
6
6
|
color: var(--fs-color-text);
|
|
7
7
|
background-color: var(--fs-color-surface);
|
|
8
8
|
}
|
|
9
|
+
|
|
10
|
+
/* Textos de contrato aparecem sobre superfícies escuras nos laboratórios. */
|
|
11
|
+
html[data-theme="dark"] :is(.demo-eyebrow, .showcase-eyebrow),
|
|
12
|
+
html[data-fs-theme="dark"] :is(.demo-eyebrow, .showcase-eyebrow) {
|
|
13
|
+
color: var(--fs-alert-primary-text);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
html[data-theme="dark"] .demo-reference code,
|
|
17
|
+
html[data-fs-theme="dark"] .demo-reference code {
|
|
18
|
+
color: var(--fs-alert-primary-text);
|
|
19
|
+
}
|
|
@@ -43,9 +43,9 @@ window.showcaseContracts = {
|
|
|
43
43
|
},
|
|
44
44
|
alert: {
|
|
45
45
|
use: [{ label: "Feedback contextual", text: "Use para sucesso, aviso, erro ou informação persistente relacionada à região afetada." }],
|
|
46
|
-
api: [{ label: ".fs-alert", code: true, text: "contêiner-base da mensagem." }, { label: ".fs-alert-{primary|secondary|success|warning|danger|info}", code: true, text: "seleciona intenção visual." }, { label: ".fs-alert-heading / .fs-alert-link", code: true, text: "
|
|
47
|
-
a11y: [{ label: "Urgência", text: "use role=alert somente para mensagem
|
|
48
|
-
states: [{ label: "Conteúdo", text: "teste
|
|
46
|
+
api: [{ label: ".fs-alert", code: true, text: "contêiner-base da mensagem persistente." }, { label: ".fs-alert-{primary|secondary|success|warning|danger|info}", code: true, text: "seleciona intenção visual." }, { label: ".fs-alert-group / .fs-alert-inline", code: true, text: "organizam mensagens relacionadas e versões compactas." }, { label: ".fs-alert-icon / -content / -heading / -text", code: true, text: "organizam ícone, título e descrição opcionais." }, { label: ".fs-alert-actions / -link / -close", code: true, text: "compõem ações, link contextual e fechamento visual manual." }],
|
|
47
|
+
a11y: [{ label: "Urgência", text: "use role=alert somente para mensagem urgente e role=status para atualização calma; o componente não injeta ARIA nem move foco." }],
|
|
48
|
+
states: [{ label: "Conteúdo", text: "teste grupo, inline, loading com aria-busy, ícone decorativo, ações, fechamento manual, forced colors e telas estreitas." }],
|
|
49
49
|
},
|
|
50
50
|
input: { use: [{ label: "Dado curto", text: "Use para texto, e-mail, senha ou número quando a pessoa deve digitar um valor identificável." }], api: [{ label: ".fs-form-control", code: true, text: "estiliza input e textarea nativos." }, { label: ".is-valid / .is-invalid", code: true, text: "aplicam feedback visual de validação." }, { label: "disabled / readonly / aria-describedby", code: true, text: "controlam disponibilidade, edição e associação com ajuda ou erro." }], a11y: [{ label: "Rótulo", text: "associe label ao id; placeholder não substitui o nome persistente." }, { label: "Erro", text: "conecte ajuda e mensagem de erro com aria-describedby." }], states: [{ label: "Validação", text: "teste foco, readonly, disabled, sucesso e erro com mensagem longa." }] },
|
|
51
51
|
select: { use: [{ label: "Opções conhecidas", text: "Use select nativo para listas curtas; use Combobox quando a busca reduzir esforço." }], api: [{ label: ".fs-select", code: true, text: "aplica acabamento FokusStyles ao select nativo." }, { label: "required / disabled / multiple", code: true, text: "mantêm comportamento nativo de obrigatoriedade, indisponibilidade e múltipla escolha." }], a11y: [{ label: "Nome", text: "forneça label visível e não simule select com div sem necessidade." }], states: [{ label: "Opções", text: "teste placeholder, selecionado, disabled, erro e teclado nativo." }] },
|
|
@@ -72,13 +72,13 @@ window.showcaseContracts = {
|
|
|
72
72
|
"nested-menu": { use: [{ label: "Navegação hierárquica", text: "Use para poucos níveis de destinos relacionados; não esconda arquitetura complexa em menus profundos." }], api: [{ label: ".fs-nested-menu + data-fs=\"nested-menu\"", code: true, text: "raiz e auto-init." }, { label: "[data-fs-nested-menu-toggle] / [data-fs-nested-menu-submenu]", code: true, text: "identificam gatilho e submenu." }], a11y: [{ label: "Expansão", text: "o toggle precisa de nome e aria-expanded atualizado; preserve Escape e foco." }], states: [{ label: "Subnível", text: "teste aberto, fechado, item ativo, teclado e clique externo." }] },
|
|
73
73
|
"tree-view": { use: [{ label: "Estrutura aninhada", text: "Use para arquivos, permissões ou categorias com relação pai-filho explícita." }], api: [{ label: ".fs-tree / .fs-tree-item", code: true, text: "lista e nó da árvore." }, { label: ".fs-tree-toggle / .fs-tree-children", code: true, text: "controle de expansão e grupo filho." }], a11y: [{ label: "Hierarquia", text: "mantenha rótulos, níveis e estado expandido disponíveis; controles precisam de nome." }], states: [{ label: "Nó", text: "teste expandido, recolhido, selecionado, foco e nomes longos." }] },
|
|
74
74
|
dropdown: { use: [{ label: "Ações contextuais", text: "Use para agrupar poucas ações secundárias ligadas a um gatilho." }], api: [{ label: "data-fs=\"dropdown\"", code: true, text: "inicializa o grupo." }, { label: "[data-fs-dropdown-toggle] / .fs-dropdown-menu", code: true, text: "gatilho e menu." }], a11y: [{ label: "Foco", text: "aria-expanded, Escape e retorno de foco são geridos; cada item precisa de texto claro." }], states: [{ label: "Menu", text: "teste aberto, fechado, teclado, borda de viewport e disabled." }] },
|
|
75
|
-
tooltip: { use: [{ label: "Dica curta", text: "Use para explicar ícone ou termo; não esconda instrução necessária exclusivamente no hover." }], api: [{ label: "data-fs=\"tooltip\" + title", code: true, text: "inicializa e fornece o texto da dica." }, { label: "data-
|
|
75
|
+
tooltip: { use: [{ label: "Dica curta", text: "Use para explicar ícone ou termo; não esconda instrução necessária exclusivamente no hover." }], api: [{ label: "data-fs=\"tooltip\" + title/data-title", code: true, text: "inicializa e fornece o texto da dica." }, { label: "data-placement + data-show-delay/data-hide-delay", code: true, text: "define posição e atrasos opcionais." }], a11y: [{ label: "Alternativa", text: "a dica aparece por foco, usa aria-describedby e não é a única fonte de informação essencial." }], states: [{ label: "Posição", text: "teste hover, foco, Escape, touch, fallback, RTL, viewport e conteúdo longo." }] },
|
|
76
76
|
"hover-card": { use: [{ label: "Prévia rica", text: "Use para contexto adicional associado a link ou botão, sem interromper a tarefa principal." }], api: [{ label: "data-fs=\"hover-card\"", code: true, text: "inicializa o gatilho." }, { label: "data-fs-hover-card-content / -placement", code: true, text: "define conteúdo e posição." }], a11y: [{ label: "Foco", text: "o conteúdo deve poder ser alcançado por foco quando contiver ações." }], states: [{ label: "Sobreposição", text: "teste hover, foco, atraso, Escape e limite da viewport." }] },
|
|
77
|
-
popover: { use: [{ label: "Informação ou ação curta", text: "Use para conteúdo acionado explicitamente; prefira Modal para tarefa extensa." }], api: [{ label: "data-fs=\"popover\"", code: true, text: "inicializa gatilho." }, { label: "data-fs-popover-
|
|
77
|
+
popover: { use: [{ label: "Informação ou ação curta", text: "Use para conteúdo acionado explicitamente; prefira Modal para tarefa extensa." }], api: [{ label: "data-fs=\"popover\" / data-fs-target", code: true, text: "inicializa o gatilho e associa o painel." }, { label: "data-trigger / data-placement / data-align", code: true, text: "configuram interação, posição e alinhamento." }, { label: ".fs-popover-icon / -heading / -text / -close", code: true, text: "slots opcionais para conteúdo rico." }], a11y: [{ label: "Controle", text: "aria-expanded e aria-controls acompanham o gatilho; Escape devolve foco e Popover não cria focus trap." }], states: [{ label: "Visibilidade", text: "teste aberto, fechado, foco interno, clique externo, hover, fallback de viewport e RTL." }] },
|
|
78
78
|
offcanvas: { use: [{ label: "Painel lateral", text: "Use para navegação, filtros ou contexto secundário sem abandonar a página." }], api: [{ label: "data-fs=\"offcanvas\" + data-fs-target=\"#id\"", code: true, text: "gatilho e painel." }, { label: ".fs-offcanvas / .fs-offcanvas-start|end", code: true, text: "estrutura e lado de entrada." }], a11y: [{ label: "Diálogo", text: "foco é contido no painel e Escape o fecha; título deve nomear o contexto." }], states: [{ label: "Painel", text: "teste aberto, backdrop, Escape, foco e viewport estreito." }] },
|
|
79
79
|
modal: { use: [{ label: "Tarefa concentrada", text: "Use para confirmação, formulário curto ou detalhe que exige atenção temporária." }], api: [{ label: "data-fs=\"modal\" + data-fs-target=\"#id\"", code: true, text: "gatilho e diálogo." }, { label: ".fs-modal / .fs-modal-dialog / .fs-modal-content", code: true, text: "camadas estruturais." }], a11y: [{ label: "Foco", text: "role=dialog, aria-modal, título e retorno de foco são essenciais." }], states: [{ label: "Diálogo", text: "teste abrir, fechar, backdrop, Escape, formulário e conteúdo alto." }] },
|
|
80
80
|
"alert-dialog": { use: [{ label: "Confirmação crítica", text: "Use antes de ação destrutiva ou irreversível; mantenha a consequência explícita." }], api: [{ label: "data-fs=\"alert-dialog\"", code: true, text: "inicializa o diálogo de alerta." }, { label: "data-fs-alert-dialog-confirm", code: true, text: "identifica a ação de confirmação." }], a11y: [{ label: "Urgência", text: "use role=alertdialog, texto descritivo e foco inicial na opção segura." }], states: [{ label: "Decisão", text: "teste confirmar, cancelar, Escape quando permitido e foco restaurado." }] },
|
|
81
81
|
"command-palette": { use: [{ label: "Atalho de comandos", text: "Use para navegação e ações frequentes de usuários avançados; mantenha alternativas visíveis." }], api: [{ label: "data-fs=\"command-palette\"", code: true, text: "inicializa gatilho e paleta." }, { label: "data-fs-command-palette-input / -list", code: true, text: "identificam busca e resultados." }], a11y: [{ label: "Diálogo", text: "foco, Escape, navegação por setas e anúncio de resultados devem ser preservados." }], states: [{ label: "Busca", text: "teste fechada, aberta, filtrada, vazia, teclado e comandos desabilitados." }] },
|
|
82
|
-
toast: { use: [{ label: "Feedback transitório", text: "Use para confirmação breve que não exige decisão imediata; erros críticos devem persistir em contexto." }], api: [{ label: ".fs-toast-container / .fs-toast", code: true, text: "região empilhada e mensagem." }, { label: "data-fs=\"toast\" / data-autohide", code: true, text: "
|
|
82
|
+
toast: { use: [{ label: "Feedback transitório", text: "Use para confirmação breve que não exige decisão imediata; erros críticos devem persistir em contexto." }], api: [{ label: ".fs-toast-container / .fs-toast", code: true, text: "região fixa, empilhada e mensagem flutuante." }, { label: ".fs-toast-icon / -heading / -actions / -progress", code: true, text: "slots opcionais para ícone, título, ações e indicador de tempo." }, { label: "data-fs=\"toast\" / data-delay / data-autohide / data-toast-progress", code: true, text: "inicializam e configuram duração, persistência e progresso." }], a11y: [{ label: "Anúncio", text: "role=status e aria-live=polite são aplicados automaticamente; foco não é movido e hover/foco pausam o timer." }], states: [{ label: "Tempo", text: "teste entrada, auto-dismiss, pausa por hover/foco, progresso, empilhamento, RTL e fechamento manual." }] },
|
|
83
83
|
"notification-center": { use: [{ label: "Histórico de notificações", text: "Use quando mensagens precisam ser revisitadas, filtradas ou marcadas como lidas." }], api: [{ label: "data-fs=\"notification-center\"", code: true, text: "inicializa o painel." }, { label: "data-fs-notification-toggle / -list", code: true, text: "gatilho e lista de notificações." }], a11y: [{ label: "Contagem", text: "o botão deve expor contagem e estado expandido; itens precisam de ações nomeadas." }], states: [{ label: "Lista", text: "teste vazia, não lida, lida, aberta, teclado e marcação em lote." }] },
|
|
84
84
|
};
|
|
@@ -1,41 +1,115 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="pt-BR">
|
|
3
3
|
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<style>
|
|
11
|
-
.theme-panel { padding: 24px; }
|
|
12
|
-
|
|
13
|
-
html[data-theme="dark"] .theme-panel {
|
|
14
|
-
color: var(--fs-color-text);
|
|
15
|
-
background-color: var(--fs-color-surface);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.fs-alert { max-width: 480px; }
|
|
19
|
-
</style>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Fokus Styles — Alerts</title>
|
|
7
|
+
<link rel="stylesheet" href="../../dist/css/fonts.css">
|
|
8
|
+
<link rel="stylesheet" href="../../dist/css/components.css">
|
|
9
|
+
<link rel="stylesheet" href="../../dist/css/helpers.css">
|
|
20
10
|
<link rel="stylesheet" href="../assets/example-theme.css">
|
|
21
11
|
<script src="../assets/example-theme.js"></script>
|
|
12
|
+
<style>
|
|
13
|
+
:root { --demo-max-width: 1080px; --demo-panel-bg: var(--fs-color-surface); --demo-soft-bg: var(--fs-color-subtle); --demo-panel-border: var(--fs-color-border); --demo-accent: var(--fs-color-primary); }
|
|
14
|
+
* { box-sizing: border-box; }
|
|
15
|
+
body { min-block-size: 100vh; margin: 0; color: var(--fs-color-text); background: var(--fs-color-bg-subtle); }
|
|
16
|
+
.demo-page { max-inline-size: var(--demo-max-width); margin-inline: auto; padding: clamp(20px, 4vw, 56px) clamp(16px, 4vw, 40px) 64px; }
|
|
17
|
+
.demo-hero { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 24px; margin-block-end: 32px; }
|
|
18
|
+
.demo-eyebrow { margin: 0 0 8px; color: var(--demo-accent); font-size: .75rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
|
|
19
|
+
html[data-fs-theme="dark"] .demo-eyebrow { color: var(--fs-color-text); }
|
|
20
|
+
.demo-title { max-inline-size: 760px; margin: 0; font-size: clamp(2rem, 4vw, 3.5rem); line-height: 1.05; letter-spacing: -.04em; }
|
|
21
|
+
.demo-lead { max-inline-size: 720px; margin: 16px 0 0; color: var(--fs-color-muted); font-size: 1.05rem; line-height: 1.6; }
|
|
22
|
+
.demo-alert-row, .demo-action-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
|
|
23
|
+
.demo-alert-row { margin-block-start: 20px; }
|
|
24
|
+
.demo-toolbar { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px; margin-block: 24px; padding: 12px; border: var(--fs-border-width) solid var(--demo-panel-border); border-radius: var(--fs-radius-md); background: var(--demo-panel-bg); }
|
|
25
|
+
.demo-section { margin-block-start: 32px; }
|
|
26
|
+
.demo-section-heading { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 12px; margin-block-end: 14px; }
|
|
27
|
+
.demo-section-heading h2, .demo-card h3, .demo-reference h2, .demo-playground h3 { margin: 0; }
|
|
28
|
+
.demo-section-heading p, .demo-card p, .demo-reference p, .demo-status p { color: var(--fs-color-muted); }
|
|
29
|
+
.demo-section-heading p { max-inline-size: 620px; margin: 0; font-size: .9rem; }
|
|
30
|
+
.demo-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
|
|
31
|
+
.demo-card, .demo-playground, .demo-reference { border: var(--fs-border-width) solid var(--demo-panel-border); border-radius: var(--fs-radius-md); background: var(--demo-panel-bg); box-shadow: var(--fs-shadow-sm); }
|
|
32
|
+
.demo-card { min-block-size: 190px; padding: 20px; }
|
|
33
|
+
.demo-card p { margin: 10px 0 20px; line-height: 1.55; }
|
|
34
|
+
.demo-card-icon { display: grid; inline-size: 36px; block-size: 36px; place-items: center; margin-block-end: 16px; border-radius: var(--fs-radius-sm); color: var(--fs-color-primary); background: var(--demo-soft-bg); font-size: 1.2rem; font-weight: 700; }
|
|
35
|
+
.demo-playground { padding: clamp(18px, 3vw, 28px); }
|
|
36
|
+
.demo-playground-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(240px, .65fr); gap: 28px; }
|
|
37
|
+
.demo-demo-group + .demo-demo-group { margin-block-start: 28px; }
|
|
38
|
+
.demo-demo-group h3 { font-size: 1rem; }
|
|
39
|
+
.demo-demo-group > p { margin: 6px 0 14px; color: var(--fs-color-muted); font-size: .9rem; }
|
|
40
|
+
.demo-sample { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 16px; border: var(--fs-border-width) solid var(--demo-panel-border); border-radius: var(--fs-radius-sm); background: var(--demo-soft-bg); }
|
|
41
|
+
.demo-sample + .demo-sample { margin-block-start: 10px; }
|
|
42
|
+
.demo-sample-label { flex: 1 1 150px; color: var(--fs-color-muted); font-size: .82rem; }
|
|
43
|
+
.demo-status { display: flex; flex-direction: column; gap: 16px; padding: 20px; border-radius: var(--fs-radius-sm); background: var(--demo-soft-bg); }
|
|
44
|
+
.demo-status h3 { margin: 0; }
|
|
45
|
+
.demo-status p { margin: 8px 0 0; font-size: .9rem; line-height: 1.5; }
|
|
46
|
+
.demo-status-output { margin: 0; padding: 12px; border-inline-start: 3px solid var(--demo-accent); color: var(--fs-color-text) !important; background: var(--demo-panel-bg); font-size: .85rem !important; }
|
|
47
|
+
.demo-code { margin: 0; padding: 14px; overflow: auto; border-radius: var(--fs-radius-sm); color: var(--fs-color-text); background: var(--demo-panel-bg); font: .76rem/1.6 var(--fs-font-mono, ui-monospace, monospace); white-space: pre-wrap; }
|
|
48
|
+
.demo-reference { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; padding: clamp(18px, 3vw, 28px); }
|
|
49
|
+
.demo-reference p { margin: 8px 0 16px; line-height: 1.5; }
|
|
50
|
+
.demo-reference ul { margin: 0; padding-inline-start: 20px; color: var(--fs-color-muted); line-height: 1.8; }
|
|
51
|
+
.demo-reference code { color: var(--fs-color-primary); }
|
|
52
|
+
.demo-note { margin-block-start: 14px !important; font-size: .85rem; }
|
|
53
|
+
html[data-demo-forced-colors] .demo-page { --demo-panel-bg: Canvas; --demo-soft-bg: Canvas; --demo-panel-border: CanvasText; color: CanvasText; background: Canvas; }
|
|
54
|
+
@media (max-width: 760px) { .demo-hero, .demo-playground-grid, .demo-reference { grid-template-columns: 1fr; } .demo-hero { align-items: start; } .demo-grid { grid-template-columns: 1fr; } }
|
|
55
|
+
</style>
|
|
22
56
|
</head>
|
|
23
57
|
<body>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
58
|
+
<main class="demo-page">
|
|
59
|
+
<header class="demo-hero">
|
|
60
|
+
<div>
|
|
61
|
+
<p class="demo-eyebrow">Fokus Styles · mensagem persistente</p>
|
|
62
|
+
<h1 class="demo-title">Alertas que explicam estados e orientam próximas ações.</h1>
|
|
63
|
+
<p class="demo-lead">Use Alert para feedback contextual que precisa permanecer visível. Ícones, títulos e ações são opcionais; o texto continua sendo a fonte principal do significado.</p>
|
|
64
|
+
<div class="demo-alert-row" aria-label="Exemplos rápidos"><span class="fs-badge fs-badge-soft-info">Informação</span><span class="fs-badge fs-badge-soft-success">Sucesso</span><span class="fs-badge fs-badge-soft-warning">Atenção</span><span class="fs-badge fs-badge-soft-danger">Erro</span></div>
|
|
65
|
+
</div>
|
|
66
|
+
<span class="fs-badge fs-badge-outline-primary">CSS-only</span>
|
|
67
|
+
</header>
|
|
68
|
+
|
|
69
|
+
<nav class="demo-toolbar" aria-label="Controles da demonstração"><div class="demo-action-row"><button class="fs-btn fs-btn-primary fs-btn-sm" type="button" id="reset-demo">Restaurar demonstração</button><button class="fs-btn fs-btn-outline-primary fs-btn-sm" type="button" id="toggle-direction" aria-pressed="false">Testar RTL</button><button class="fs-btn fs-btn-outline-secondary fs-btn-sm" type="button" id="toggle-forced-colors" aria-pressed="false">Testar alto contraste</button></div><span class="fs-form-text">Compare variantes, composições e estados sem depender apenas de cor.</span></nav>
|
|
70
|
+
|
|
71
|
+
<section class="demo-section" aria-labelledby="why-title">
|
|
72
|
+
<div class="demo-section-heading"><div><h2 id="why-title">Escolha o padrão certo</h2><p>Badge resume, Tag gerencia uma seleção, Alert explica contexto e Toast comunica algo transitório.</p></div></div>
|
|
73
|
+
<div class="demo-grid">
|
|
74
|
+
<article class="demo-card"><span class="demo-card-icon" aria-hidden="true">#</span><h3>Badge informa</h3><p>Status e classificação são curtos e complementam um item que já tem contexto.</p><span class="fs-badge fs-badge-success">Ativo</span></article>
|
|
75
|
+
<article class="demo-card"><span class="demo-card-icon" aria-hidden="true">!</span><h3>Alert explica</h3><p>Quando existe consequência, instrução ou próxima ação, use uma mensagem persistente.</p><div class="fs-alert fs-alert-warning" role="status">Revise o cadastro antes de publicar.</div></article>
|
|
76
|
+
<article class="demo-card"><span class="demo-card-icon" aria-hidden="true">↗</span><h3>Toast avisa</h3><p>Para confirmação breve que não exige leitura prolongada, prefira uma mensagem transitória.</p><span class="fs-badge fs-badge-outline-info">Temporário</span></article>
|
|
77
|
+
</div>
|
|
78
|
+
</section>
|
|
79
|
+
|
|
80
|
+
<section class="demo-section" aria-labelledby="playground-title">
|
|
81
|
+
<div class="demo-section-heading"><div><h2 id="playground-title">Laboratório de Alertas</h2><p>Compare variantes, anatomia, ações, fechamento manual, grupos, inline, loading e mensagens longas.</p></div><span class="fs-badge fs-badge-outline-success">ao vivo</span></div>
|
|
82
|
+
<div class="demo-playground"><div class="demo-playground-grid"><div>
|
|
83
|
+
<div class="demo-demo-group"><h3>Variantes semânticas</h3><p>O texto comunica a intenção; a barra lateral reforça a hierarquia visual.</p><div class="demo-sample"><span class="demo-sample-label">Neutro e informação</span><div class="fs-alert">Informação neutra para o contexto atual.</div><div class="fs-alert fs-alert-info" role="status">Há uma nova versão pronta para revisão.</div></div><div class="demo-sample"><span class="demo-sample-label">Sucesso, atenção e erro</span><div class="fs-alert fs-alert-success" role="status">Operação concluída com sucesso.</div><div class="fs-alert fs-alert-warning" role="status">Revise antes de continuar.</div><div class="fs-alert fs-alert-danger" role="alert">Não foi possível salvar.</div></div></div>
|
|
84
|
+
<div class="demo-demo-group"><h3>Anatomia e ações</h3><p>Ícone, título, descrição, link, botão e fechamento são slots opcionais e composicionais.</p><div class="demo-sample"><span class="demo-sample-label">Mensagem rica</span><div class="fs-alert fs-alert-warning" role="status"><span class="fs-alert-icon" aria-hidden="true"><svg class="fs-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m12 3 9 17H3L12 3Z"/><path d="M12 9v4m0 3h.01"/></svg></span><div class="fs-alert-content"><h3 class="fs-alert-heading">Sessão expirando</h3><p class="fs-alert-text">Salve seu trabalho para não perder alterações.</p><div class="fs-alert-actions"><button class="fs-btn fs-btn-warning fs-btn-sm" type="button">Continuar sessão</button><a class="fs-alert-link" href="#ajuda">Saiba mais</a></div></div></div></div><div class="demo-sample"><span class="demo-sample-label">Fechamento manual</span><div class="fs-alert fs-alert-success"><div class="fs-alert-content"><h3 class="fs-alert-heading">Convite enviado</h3><p class="fs-alert-text">A pessoa receberá um e-mail para entrar no projeto.</p></div><button class="fs-btn-close fs-alert-close" type="button" aria-label="Fechar aviso de convite enviado"></button></div></div></div>
|
|
85
|
+
<div class="demo-demo-group"><h3>Densidade, grupos e loading</h3><p>Use a variante inline perto de campos e aria-busy durante operações assíncronas.</p><div class="demo-sample"><span class="demo-sample-label">Inline</span><div class="fs-alert fs-alert-inline fs-alert-warning" role="status"><span class="fs-alert-icon" aria-hidden="true">!</span><div class="fs-alert-content"><p class="fs-alert-text">Campo obrigatório.</p></div></div></div><div class="demo-sample"><span class="demo-sample-label">Grupo</span><div class="fs-alert-group" aria-label="Mensagens do projeto"><div class="fs-alert fs-alert-info">A sincronização será iniciada em instantes.</div><div class="fs-alert fs-alert-success">Última sincronização concluída.</div></div></div><div class="demo-sample"><span class="demo-sample-label">Loading</span><div class="fs-alert fs-alert-info" role="status" aria-busy="true"><span class="fs-spinner fs-spinner-sm" aria-hidden="true"></span><div class="fs-alert-content"><p class="fs-alert-text">Atualizando dados…</p></div></div></div></div>
|
|
86
|
+
<div class="demo-demo-group"><h3>Mensagem longa e responsiva</h3><p>Conteúdo, links e ações quebram sem causar overflow horizontal em telas estreitas.</p><div class="demo-sample"><span class="demo-sample-label">Responsivo</span><div class="fs-alert fs-alert-primary" role="status"><div class="fs-alert-content"><h3 class="fs-alert-heading">Mensagem com várias linhas</h3><p class="fs-alert-text">Alertas preservam a leitura em telas estreitas e permitem que títulos, descrições e links quebrem livremente.</p><div class="fs-alert-actions"><a class="fs-alert-link" href="#documentacao">Abrir documentação com endereço longo</a></div></div></div></div></div>
|
|
87
|
+
</div><aside class="demo-status" aria-labelledby="status-title"><div><h3 id="status-title">Contrato do Alert</h3><p>Alert permanece no contexto, não move foco e não fecha sozinho. O fechamento visual depende da lógica da aplicação.</p></div><p class="demo-status-output" id="demo-status" role="status" aria-live="polite">Demonstração pronta.</p><pre class="demo-code"><code>.fs-alert
|
|
88
|
+
.fs-alert-{color}
|
|
89
|
+
.fs-alert-icon
|
|
90
|
+
.fs-alert-content
|
|
91
|
+
.fs-alert-actions
|
|
92
|
+
.fs-alert-close
|
|
93
|
+
.fs-alert-group
|
|
94
|
+
.fs-alert-inline
|
|
95
|
+
|
|
96
|
+
/* tokens locais */
|
|
97
|
+
--fs-alert-radius
|
|
98
|
+
--fs-alert-gap
|
|
99
|
+
--fs-alert-icon-size</code></pre></aside></div></div>
|
|
100
|
+
</section>
|
|
27
101
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
102
|
+
<section class="demo-section" aria-labelledby="a11y-title"><div class="demo-section-heading"><div><h2 id="a11y-title">Contratos preservados</h2><p>O significado permanece disponível sem depender de cor, ícone, foco automático ou desaparecimento temporizado.</p></div></div><div class="demo-reference"><div><h2>Uso acessível</h2><ul><li>Use <code>role="status"</code> para atualização calma e <code>role="alert"</code> somente para urgência.</li><li>Ícones decorativos usam <code>aria-hidden="true"</code>.</li><li>Botões e links mantêm nomes e foco visível.</li><li>Loading usa <code>aria-busy="true"</code> e texto compreensível.</li></ul></div><div><h2>Limites do componente</h2><ul><li>Alert não injeta ARIA nem move foco.</li><li>Não use Alert para decisões críticas; prefira Alert Dialog.</li><li>Não use Alert para feedback temporário; prefira Toast.</li><li>RTL, dark mode e forced colors preservam a leitura.</li></ul></div></div></section>
|
|
103
|
+
</main>
|
|
104
|
+
<script>
|
|
105
|
+
const page = document.querySelector(".demo-page");
|
|
106
|
+
const status = document.getElementById("demo-status");
|
|
107
|
+
const directionButton = document.getElementById("toggle-direction");
|
|
108
|
+
const forcedColorsButton = document.getElementById("toggle-forced-colors");
|
|
109
|
+
document.querySelectorAll(".fs-alert-close").forEach((button) => button.addEventListener("click", () => { button.closest(".fs-alert")?.remove(); status.textContent = "Alert removido manualmente da demonstração."; }));
|
|
110
|
+
document.getElementById("reset-demo").addEventListener("click", () => { location.reload(); });
|
|
111
|
+
directionButton.addEventListener("click", () => { const rtl = page.getAttribute("dir") !== "rtl"; page.setAttribute("dir", rtl ? "rtl" : "ltr"); directionButton.setAttribute("aria-pressed", String(rtl)); directionButton.textContent = rtl ? "Voltar para LTR" : "Testar RTL"; status.textContent = rtl ? "Direção RTL ativada." : "Direção LTR ativada."; });
|
|
112
|
+
forcedColorsButton.addEventListener("click", () => { const active = forcedColorsButton.getAttribute("aria-pressed") !== "true"; forcedColorsButton.setAttribute("aria-pressed", String(active)); forcedColorsButton.textContent = active ? "Voltar ao tema" : "Testar alto contraste"; document.documentElement.toggleAttribute("data-demo-forced-colors", active); status.textContent = active ? "Modo de alto contraste demonstrativo ativado." : "Modo de alto contraste demonstrativo desativado."; });
|
|
113
|
+
</script>
|
|
40
114
|
</body>
|
|
41
115
|
</html>
|