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.
Files changed (101) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/css/components.css +583 -83
  3. package/dist/css/components.css.map +1 -1
  4. package/dist/css/components.min.css +1 -1
  5. package/dist/css/components.min.css.map +1 -1
  6. package/dist/css/fokus-components.css +583 -83
  7. package/dist/css/fokus-components.css.map +1 -1
  8. package/dist/css/fokus-components.min.css +1 -1
  9. package/dist/css/fokus-components.min.css.map +1 -1
  10. package/dist/css/fokus-core.css +22 -0
  11. package/dist/css/fokus-core.css.map +1 -1
  12. package/dist/css/fokus-core.min.css +1 -1
  13. package/dist/css/fokus-core.min.css.map +1 -1
  14. package/dist/css/fokus-dark.css +10 -0
  15. package/dist/css/fokus-dark.css.map +1 -1
  16. package/dist/css/fokus-dark.min.css +1 -1
  17. package/dist/css/fokus-dark.min.css.map +1 -1
  18. package/dist/css/fokus-rtl.css +9166 -0
  19. package/dist/css/fokus-rtl.css.map +1 -0
  20. package/dist/css/fokus-rtl.min.css +2 -0
  21. package/dist/css/fokus-rtl.min.css.map +1 -0
  22. package/dist/css/fokus-utilities.css +158 -0
  23. package/dist/css/fokus-utilities.css.map +1 -1
  24. package/dist/css/fokus-utilities.min.css +1 -1
  25. package/dist/css/fokus-utilities.min.css.map +1 -1
  26. package/dist/css/fokus.css +1018 -258
  27. package/dist/css/fokus.css.map +1 -1
  28. package/dist/css/fokus.min.css +1 -1
  29. package/dist/css/fokus.min.css.map +1 -1
  30. package/dist/css/forms.css +322 -176
  31. package/dist/css/forms.css.map +1 -1
  32. package/dist/css/forms.min.css +1 -1
  33. package/dist/css/forms.min.css.map +1 -1
  34. package/dist/css/helpers.css +158 -0
  35. package/dist/css/helpers.css.map +1 -1
  36. package/dist/css/helpers.min.css +1 -1
  37. package/dist/css/helpers.min.css.map +1 -1
  38. package/dist/css/layout.css +22 -0
  39. package/dist/css/layout.css.map +1 -1
  40. package/dist/css/layout.min.css +1 -1
  41. package/dist/css/layout.min.css.map +1 -1
  42. package/dist/js/fokus.js +270 -25
  43. package/dist/js/fokus.js.map +2 -2
  44. package/dist/js/fokus.min.js +18 -18
  45. package/dist/js/fokus.min.js.map +3 -3
  46. package/docs/components/alert.md +69 -24
  47. package/docs/components/badge.md +23 -4
  48. package/docs/components/checkbox.md +16 -3
  49. package/docs/components/popover.md +20 -7
  50. package/docs/components/radio.md +11 -1
  51. package/docs/components/responsive.md +19 -0
  52. package/docs/components/switch.md +30 -8
  53. package/docs/components/tag.md +19 -4
  54. package/docs/components/toast.md +72 -59
  55. package/docs/components/tooltip.md +38 -2
  56. package/docs/guides/accessibility.md +7 -0
  57. package/docs/guides/rtl-and-system-preferences.md +28 -0
  58. package/docs/prompts/prompt-plan.md +4 -4
  59. package/docs/reference/accessibility-matrix.md +7 -7
  60. package/docs/reference/contrast-report.md +4 -0
  61. package/docs/reference/definitions.md +5 -1
  62. package/docs/reference/design-tokens.md +14 -0
  63. package/docs/reference/size-baseline.json +13 -13
  64. package/mockup/assets/example-theme.css +11 -0
  65. package/mockup/assets/showcase-contracts.js +6 -6
  66. package/mockup/examples/alerts.html +105 -31
  67. package/mockup/examples/badges-alerts.html +91 -59
  68. package/mockup/examples/check-radio-switch.html +575 -99
  69. package/mockup/examples/popover.html +81 -0
  70. package/mockup/examples/tag.html +97 -87
  71. package/mockup/examples/toast.html +113 -0
  72. package/mockup/examples/tooltip.html +68 -0
  73. package/mockup/forms.html +1 -1
  74. package/mockup/overlays-commands.html +2 -2
  75. package/package.json +2 -1
  76. package/packages/fokus-components/scss/components/_alerts.scss +128 -6
  77. package/packages/fokus-components/scss/components/_badges.scss +26 -10
  78. package/packages/fokus-components/scss/components/_index.scss +1 -0
  79. package/packages/fokus-components/scss/components/_popover.scss +131 -21
  80. package/packages/fokus-components/scss/components/_responsive.scss +23 -0
  81. package/packages/fokus-components/scss/components/_tag.scss +37 -14
  82. package/packages/fokus-components/scss/components/_toasts.scss +156 -11
  83. package/packages/fokus-components/scss/components/_tooltips.scss +70 -18
  84. package/packages/fokus-components/scss/forms/_check-radio-switch.scss +313 -215
  85. package/packages/fokus-components/scss/forms/_forms.scss +16 -0
  86. package/packages/fokus-core/scss/base/_accessibility.scss +14 -0
  87. package/packages/fokus-core/scss/tokens/_root.scss +11 -0
  88. package/packages/fokus-js/js/carousel.d.ts +4 -0
  89. package/packages/fokus-js/js/carousel.js +8 -0
  90. package/packages/fokus-js/js/core/positioning.js +18 -9
  91. package/packages/fokus-js/js/dropdown.d.ts +4 -0
  92. package/packages/fokus-js/js/dropdown.js +7 -0
  93. package/packages/fokus-js/js/popover.js +26 -1
  94. package/packages/fokus-js/js/tabs.d.ts +3 -0
  95. package/packages/fokus-js/js/tabs.js +5 -0
  96. package/packages/fokus-js/js/tag.js +17 -0
  97. package/packages/fokus-js/js/toast.js +77 -3
  98. package/packages/fokus-js/js/tooltip.d.ts +8 -1
  99. package/packages/fokus-js/js/tooltip.js +106 -13
  100. package/packages/fokus-utilities/scss/utilities/_api.scss +48 -0
  101. package/scss/entries/rtl-entry.scss +11 -0
@@ -1,8 +1,8 @@
1
1
  <!doctype html><html lang="pt-BR"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>FokusStyles — Overlays</title><link rel="stylesheet" href="../dist/css/fonts.css"><link rel="stylesheet" href="../dist/css/components.css"><link rel="stylesheet" href="../dist/css/forms.css"><link rel="stylesheet" href="../dist/css/helpers.css"><link rel="stylesheet" href="assets/showcase.css"></head><body><main class="showcase-shell"><header class="showcase-hero"><p class="showcase-eyebrow">Fokus Styles · laboratório</p><h1 class="showcase-title">Overlays, comandos e notificações</h1><p class="showcase-lead">Componentes que sobrepõem conteúdo ou respondem a uma ação imediata. O foco, Escape e clique externo fazem parte do contrato de cada exemplo.</p></header><div class="showcase-toolbar"><button class="fs-btn fs-btn-primary" type="button" data-showcase-theme>Usar tema escuro</button><a class="fs-btn" href="README.md">Índice dos laboratórios</a></div><nav class="showcase-nav" aria-label="Componentes desta página" data-showcase-navigation></nav><div data-showcase-sections></div></main><script id="showcase-catalog" type="application/json">[
2
2
  {"id":"dropdown","title":"Dropdown","description":"Menu contextual acionado por botão ou controle equivalente.","use":"Use para ações secundárias e compactas relacionadas a um mesmo gatilho.","api":".fs-dropdown, toggle, menu, data-align e item.","a11y":"Gerencie aria-expanded, foco inicial, setas e Escape.","states":"Alinhamento, aberto, item disabled e clique externo.","source":"examples/dropdown-tooltip.html","height":880},
3
- {"id":"tooltip","title":"Tooltip","description":"Ajuda curta e complementar mostrada ao foco ou hover.","use":"Explique ícones ou termos sem esconder informação essencial.","api":".fs-tooltip e data-placement.","a11y":"Disponibilize no foco e não dependa só de hover.","states":"Posições, hover, foco e fechamento.","source":"examples/dropdown-tooltip.html","height":880},
3
+ {"id":"tooltip","title":"Tooltip","description":"Ajuda curta e complementar mostrada ao foco ou hover.","use":"Explique ícones ou termos sem esconder informação essencial.","api":".fs-tooltip, data-placement, data-align e offset.","a11y":"Disponibilize no foco e não dependa só de hover.","states":"Posições, alinhamentos, offset, hover, foco, delay, RTL e fallback.","source":"examples/tooltip.html","height":1450},
4
4
  {"id":"hover-card","title":"Hover card","description":"Prévia rica de informação associada a um gatilho.","use":"Use como complemento opcional; conteúdo essencial deve permanecer acessível sem hover.","api":".fs-hover-card e gatilho associado.","a11y":"Mantenha foco, fechamento previsível e conteúdo alcançável.","states":"Hover, foco, posicionamento e saída do ponteiro.","source":"examples/hover-card.html","height":720},
5
- {"id":"popover","title":"Popover","description":"Painel contextual acionado por clique ou hover.","use":"Use para conteúdo curto que depende de um elemento próximo.","api":".fs-popover, data-fs-target e modos de acionamento.","a11y":"Controle foco e fechamento por Escape/clique externo quando aplicável.","states":"Clique, hover, aberto, fora do painel e alinhamento.","source":"examples/offcanvas-popover.html","height":1080},
5
+ {"id":"popover","title":"Popover","description":"Painel contextual acionado por clique ou hover.","use":"Use para conteúdo curto que depende de um elemento próximo.","api":".fs-popover, data-fs-target e modos de acionamento.","a11y":"Controle foco e fechamento por Escape/clique externo quando aplicável.","states":"Clique, hover, manual, foco, RTL e alinhamento responsivo.","source":"examples/popover.html","height":1180},
6
6
  {"id":"offcanvas","title":"Offcanvas","description":"Painel lateral para navegação ou tarefas auxiliares.","use":"Use para contexto complementar sem trocar de página.","api":".fs-offcanvas, data-fs-target, dismiss e data-backdrop.","a11y":"Prenda foco, bloqueie scroll e devolva foco ao gatilho.","states":"Lados, aberto, backdrop estático, Escape e dismiss.","source":"examples/offcanvas-popover.html","height":1080},
7
7
  {"id":"modal","title":"Modal","description":"Diálogo para decisão ou tarefa que exige atenção temporária.","use":"Use com parcimônia; não esconda fluxo longo em modal.","api":".fs-modal, data-fs-target, dismiss e data-backdrop=static.","a11y":"Use diálogo nomeado, focus trap, Escape e foco de retorno.","states":"Tamanhos, aberto, backdrop estático e confirmação.","source":"examples/modal-select.html","height":900},
8
8
  {"id":"alert-dialog","title":"Alert dialog","description":"Confirmação de ação crítica com escolhas explícitas.","use":"Use para consequências relevantes, como exclusão ou perda de dados.","api":"FokusStyles.confirm() e estrutura .fs-alert-dialog.","a11y":"Destaque consequência, foco inicial seguro e retorno ao gatilho.","states":"Confirmação, cancelamento, destrutivo e teclado.","source":"examples/alert-dialog.html","height":650},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fokus-styles",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "description": "Fokus Styles is a complete CSS framework with components, utilities, vanilla JavaScript, icons, React wrappers, and a CLI.",
5
5
  "keywords": [
6
6
  "css",
@@ -52,6 +52,7 @@
52
52
  "./components": "./dist/css/fokus-components.css",
53
53
  "./utilities": "./dist/css/fokus-utilities.css",
54
54
  "./themes": "./dist/css/fokus-dark.css",
55
+ "./rtl.css": "./dist/css/fokus-rtl.css",
55
56
  "./config": "./packages/fokus-core/scss/settings/_config.scss",
56
57
  "./js/theme": {
57
58
  "types": "./packages/fokus-js/js/theme.d.ts",
@@ -2,23 +2,145 @@
2
2
 
3
3
  @layer components {
4
4
  .fs-alert {
5
+ --fs-alert-padding-block: 12px;
6
+ --fs-alert-padding-inline: 16px;
7
+ --fs-alert-gap: 12px;
8
+ --fs-alert-radius: var(--fs-radius-md, 6px);
9
+ --fs-alert-border-width: 1px;
10
+ --fs-alert-accent-width: 4px;
11
+ --fs-alert-icon-size: 20px;
12
+ --fs-alert-heading-gap: 4px;
13
+ --fs-alert-actions-gap: 8px;
14
+
5
15
  display: flex;
6
16
  align-items: flex-start;
7
- gap: 8px;
8
- padding: 12px 16px;
9
- border: 1px solid var(--fs-color-border);
10
- border-left: 5px solid var(--fs-color-border);
11
- border-radius: 0;
17
+ gap: var(--fs-alert-gap);
18
+ min-inline-size: 0;
19
+ padding-block: var(--fs-alert-padding-block);
20
+ padding-inline: var(--fs-alert-padding-inline);
21
+ border: var(--fs-alert-border-width) solid var(--fs-color-border);
22
+ border-inline-start: var(--fs-alert-accent-width) solid var(--fs-color-border);
23
+ border-radius: var(--fs-alert-radius);
12
24
  color: var(--fs-color-text);
13
25
  background-color: var(--fs-color-surface-raised);
14
26
  font-size: $font-size-sm;
15
27
  }
16
28
 
29
+ .fs-alert-inline {
30
+ --fs-alert-padding-block: 8px;
31
+ --fs-alert-padding-inline: 12px;
32
+ --fs-alert-gap: 8px;
33
+ --fs-alert-accent-width: 3px;
34
+ --fs-alert-icon-size: 16px;
35
+ }
36
+
37
+ .fs-alert-group {
38
+ display: grid;
39
+ gap: 12px;
40
+ min-inline-size: 0;
41
+ }
42
+
43
+ .fs-alert[aria-busy="true"],
44
+ .fs-alert.is-loading {
45
+ cursor: progress;
46
+ }
47
+
48
+ .fs-alert[aria-busy="true"] .fs-alert-actions,
49
+ .fs-alert.is-loading .fs-alert-actions {
50
+ opacity: 0.75;
51
+ }
52
+
53
+ .fs-alert .fs-spinner {
54
+ flex: 0 0 auto;
55
+ align-self: flex-start;
56
+ margin-block: 2px;
57
+ }
58
+
59
+ .fs-alert-icon {
60
+ display: inline-flex;
61
+ flex: 0 0 var(--fs-alert-icon-size);
62
+ align-items: center;
63
+ justify-content: center;
64
+ inline-size: var(--fs-alert-icon-size);
65
+ block-size: var(--fs-alert-icon-size);
66
+ color: currentcolor;
67
+ }
68
+
69
+ .fs-alert-icon .fs-icon,
70
+ .fs-alert-icon > svg {
71
+ inline-size: 100%;
72
+ block-size: 100%;
73
+ }
74
+
75
+ .fs-alert-content {
76
+ flex: 1 1 auto;
77
+ min-inline-size: 0;
78
+ }
79
+
80
+ .fs-alert-heading {
81
+ margin: 0 0 var(--fs-alert-heading-gap);
82
+ color: inherit;
83
+ font-size: inherit;
84
+ font-weight: $font-weight-semibold;
85
+ line-height: 1.35;
86
+ }
87
+
88
+ .fs-alert-text {
89
+ margin: 0;
90
+ line-height: 1.5;
91
+ }
92
+
93
+ .fs-alert-actions {
94
+ display: flex;
95
+ flex-wrap: wrap;
96
+ gap: var(--fs-alert-actions-gap);
97
+ align-items: center;
98
+ margin-block-start: var(--fs-alert-actions-gap);
99
+ }
100
+
101
+ .fs-alert-link {
102
+ color: inherit;
103
+ font-weight: $font-weight-medium;
104
+ text-decoration: underline;
105
+ text-underline-offset: 2px;
106
+ }
107
+
108
+ .fs-alert-close {
109
+ flex: 0 0 auto;
110
+ margin-inline-start: auto;
111
+ color: inherit;
112
+ }
113
+
17
114
  @each $name, $color in $theme-colors {
18
115
  .fs-alert-#{$name} {
19
116
  color: var(--fs-alert-#{$name}-text);
20
117
  background-color: var(--fs-alert-#{$name}-bg);
21
- border-color: var(--fs-color-#{$name});
118
+ border-color: var(--fs-color-border);
119
+ border-inline-start-color: var(--fs-color-#{$name});
120
+ }
121
+ }
122
+
123
+ @media (width <= 480px) {
124
+ .fs-alert {
125
+ --fs-alert-padding-inline: 12px;
126
+ }
127
+
128
+ .fs-alert-actions {
129
+ align-items: flex-start;
130
+ }
131
+ }
132
+
133
+ @media (forced-colors: active) {
134
+ .fs-alert {
135
+ border-color: CanvasText;
136
+ border-inline-start-color: Highlight;
137
+ color: CanvasText;
138
+ background-color: Canvas;
139
+ }
140
+
141
+ .fs-alert-link,
142
+ .fs-alert .fs-btn {
143
+ forced-color-adjust: none;
22
144
  }
23
145
  }
24
146
  }
@@ -10,7 +10,10 @@
10
10
  --fs-badge-bg: var(--fs-color-subtle);
11
11
  --fs-badge-border: transparent;
12
12
  --fs-badge-height: 22px;
13
- --fs-badge-radius: 0;
13
+ --fs-badge-radius: var(--fs-radius-sm);
14
+ --fs-badge-padding-inline: 8px;
15
+ --fs-badge-padding-block-start: 2px;
16
+ --fs-badge-padding-block-end: 2px;
14
17
 
15
18
  display: inline-flex;
16
19
  align-items: center;
@@ -18,9 +21,8 @@
18
21
  justify-content: center;
19
22
  min-height: var(--fs-badge-height);
20
23
 
21
- // O peso óptico da fonte fica ligeiramente abaixo do centro geométrico.
22
- // Um pixel extra abaixo reposiciona a linha de texto para cima.
23
- padding: 1px 8px 3px;
24
+ // O padding vertical simétrico mantém a linha de texto no centro geométrico.
25
+ padding: var(--fs-badge-padding-block-start) var(--fs-badge-padding-inline) var(--fs-badge-padding-block-end);
24
26
  border: 1px solid var(--fs-badge-border);
25
27
  border-radius: var(--fs-badge-radius);
26
28
  color: var(--fs-badge-color);
@@ -53,15 +55,19 @@
53
55
 
54
56
  .fs-badge-sm {
55
57
  --fs-badge-height: 18px;
58
+ --fs-badge-padding-inline: 6px;
59
+ --fs-badge-padding-block-start: 1px;
60
+ --fs-badge-padding-block-end: 1px;
56
61
 
57
- padding: 0 6px 2px;
58
62
  font-size: $font-size-xs;
59
63
  }
60
64
 
61
65
  .fs-badge-lg {
62
66
  --fs-badge-height: 26px;
67
+ --fs-badge-padding-inline: 10px;
68
+ --fs-badge-padding-block-start: 3px;
69
+ --fs-badge-padding-block-end: 3px;
63
70
 
64
- padding: 2px 10px 4px;
65
71
  font-size: $font-size-md;
66
72
  }
67
73
 
@@ -81,13 +87,20 @@
81
87
  font-variant-numeric: tabular-nums;
82
88
  }
83
89
 
90
+ .fs-badge-count-circle {
91
+ aspect-ratio: 1;
92
+ min-width: var(--fs-badge-height);
93
+ padding-inline: 0;
94
+ border-radius: 50%;
95
+ }
96
+
84
97
  .fs-badge-split {
85
98
  --fs-badge-split-label-bg: var(--fs-color-black);
86
99
  --fs-badge-split-label-color: var(--fs-color-white);
87
100
  --fs-badge-split-value-bg: var(--fs-color-primary);
88
101
  --fs-badge-split-value-color: #{color-contrast(map.get($theme-colors, primary))};
89
102
  --fs-badge-split-height: 22px;
90
- --fs-badge-split-radius: 0;
103
+ --fs-badge-split-radius: var(--fs-radius-sm);
91
104
 
92
105
  display: inline-flex;
93
106
  min-height: var(--fs-badge-split-height);
@@ -105,7 +118,8 @@
105
118
  display: inline-flex;
106
119
  align-items: center;
107
120
  min-height: var(--fs-badge-split-height);
108
- padding: 1px 8px 3px;
121
+ padding-block: 2px;
122
+ padding-inline: 8px;
109
123
  }
110
124
 
111
125
  .fs-badge-split-label {
@@ -143,11 +157,13 @@
143
157
 
144
158
  .fs-badge-split.fs-badge-sm .fs-badge-split-label,
145
159
  .fs-badge-split.fs-badge-sm .fs-badge-split-value {
146
- padding: 0 6px 2px;
160
+ padding-block: 1px;
161
+ padding-inline: 6px;
147
162
  }
148
163
 
149
164
  .fs-badge-split.fs-badge-lg .fs-badge-split-label,
150
165
  .fs-badge-split.fs-badge-lg .fs-badge-split-value {
151
- padding: 2px 10px 4px;
166
+ padding-block: 3px;
167
+ padding-inline: 10px;
152
168
  }
153
169
  }
@@ -44,3 +44,4 @@
44
44
  @use "placeholder";
45
45
  @use "progress";
46
46
  @use "scrollspy";
47
+ @use "responsive";
@@ -9,15 +9,31 @@
9
9
 
10
10
  @layer components {
11
11
  .fs-popover {
12
+ --fs-popover-width: 320px;
13
+ --fs-popover-max-width: min(var(--fs-popover-width), calc(100vw - 32px));
14
+ --fs-popover-padding-block: 12px;
15
+ --fs-popover-padding-inline: 14px;
16
+ --fs-popover-gap: 10px;
17
+ --fs-popover-radius: var(--fs-radius-md, 6px);
18
+ --fs-popover-shadow: var(--fs-shadow-md);
19
+ --fs-popover-icon-size: 20px;
20
+ --fs-popover-heading-gap: 4px;
21
+ --fs-popover-footer-gap: 8px;
22
+ --fs-popover-arrow-size: 8px;
23
+ --fs-popover-border-width: 1px;
24
+
12
25
  position: absolute;
13
26
  z-index: var(--fs-z-offcanvas);
14
27
  display: none;
15
- max-width: 280px;
28
+ inline-size: var(--fs-popover-width);
29
+ max-inline-size: var(--fs-popover-max-width);
30
+ min-inline-size: 0;
16
31
  color: var(--fs-color-text);
17
32
  background-color: var(--fs-color-surface);
18
- border: 1px solid var(--fs-color-border);
19
- border-radius: var(--fs-radius-md);
20
- box-shadow: var(--fs-shadow-md);
33
+ border: var(--fs-popover-border-width) solid var(--fs-color-border);
34
+ border-radius: var(--fs-popover-radius);
35
+ box-shadow: var(--fs-popover-shadow);
36
+ overflow-wrap: anywhere;
21
37
  }
22
38
 
23
39
  .fs-popover.is-open {
@@ -25,32 +41,89 @@
25
41
  }
26
42
 
27
43
  .fs-popover-header {
28
- padding: 10px 14px;
44
+ display: flex;
45
+ align-items: center;
46
+ gap: var(--fs-popover-gap);
47
+ min-inline-size: 0;
48
+ padding-block: var(--fs-popover-padding-block);
49
+ padding-inline: var(--fs-popover-padding-inline);
29
50
  background-color: var(--fs-color-subtle);
30
51
  border-bottom: 1px solid var(--fs-color-border);
31
- border-radius: var(--fs-radius-md) var(--fs-radius-md) 0 0;
52
+ border-radius: var(--fs-popover-radius) var(--fs-popover-radius) 0 0;
32
53
  font-size: $font-size-sm;
33
54
  font-weight: $font-weight-medium;
34
55
  }
35
56
 
36
57
  .fs-popover-body {
37
- padding: 14px;
58
+ min-inline-size: 0;
59
+ padding-block: var(--fs-popover-padding-block);
60
+ padding-inline: var(--fs-popover-padding-inline);
38
61
  font-size: $font-size-sm;
62
+ line-height: 1.5;
63
+ }
64
+
65
+ .fs-popover-icon {
66
+ display: inline-flex;
67
+ flex: 0 0 var(--fs-popover-icon-size);
68
+ align-items: center;
69
+ justify-content: center;
70
+ inline-size: var(--fs-popover-icon-size);
71
+ block-size: var(--fs-popover-icon-size);
72
+ color: currentcolor;
73
+ }
74
+
75
+ .fs-popover-icon .fs-icon,
76
+ .fs-popover-icon > svg {
77
+ inline-size: 100%;
78
+ block-size: 100%;
79
+ }
80
+
81
+ .fs-popover-heading {
82
+ display: flex;
83
+ flex: 1 1 auto;
84
+ flex-wrap: wrap;
85
+ align-items: baseline;
86
+ gap: var(--fs-popover-heading-gap);
87
+ min-inline-size: 0;
88
+ }
89
+
90
+ .fs-popover-title,
91
+ .fs-popover-meta,
92
+ .fs-popover-text {
93
+ min-inline-size: 0;
94
+ }
95
+
96
+ .fs-popover-meta {
97
+ color: var(--fs-color-muted);
98
+ font-size: $font-size-xs;
99
+ font-weight: $font-weight-regular;
100
+ }
101
+
102
+ .fs-popover-text {
103
+ margin: 0;
104
+ }
105
+
106
+ .fs-popover-close {
107
+ flex: 0 0 auto;
108
+ margin-inline-start: auto;
109
+ color: inherit;
39
110
  }
40
111
 
41
112
  .fs-popover-footer {
42
113
  display: flex;
43
114
  align-items: center;
44
115
  justify-content: flex-end;
45
- gap: 8px;
46
- padding: 10px 14px;
116
+ flex-wrap: wrap;
117
+ gap: var(--fs-popover-footer-gap);
118
+ padding-block: var(--fs-popover-padding-block);
119
+ padding-inline: var(--fs-popover-padding-inline);
47
120
  border-top: 1px solid var(--fs-color-border);
48
121
  }
49
122
 
50
123
  .fs-popover-arrow {
51
124
  position: absolute;
52
- width: 8px;
53
- height: 8px;
125
+ inline-size: var(--fs-popover-arrow-size);
126
+ block-size: var(--fs-popover-arrow-size);
54
127
  background-color: var(--fs-color-surface);
55
128
  border: 1px solid var(--fs-color-border);
56
129
  transform: rotate(45deg);
@@ -58,32 +131,32 @@
58
131
 
59
132
  .fs-popover[data-placement="top"] .fs-popover-arrow {
60
133
  bottom: -5px;
61
- left: 50%;
62
- margin-left: -4px;
134
+ inset-inline-start: var(--fs-popover-arrow-offset, 50%);
135
+ margin-inline-start: calc(var(--fs-popover-arrow-size) / -2);
63
136
  border-top: 0;
64
137
  border-left: 0;
65
138
  }
66
139
 
67
140
  .fs-popover[data-placement="bottom"] .fs-popover-arrow {
68
141
  top: -5px;
69
- left: 50%;
70
- margin-left: -4px;
142
+ inset-inline-start: var(--fs-popover-arrow-offset, 50%);
143
+ margin-inline-start: calc(var(--fs-popover-arrow-size) / -2);
71
144
  border-right: 0;
72
145
  border-bottom: 0;
73
146
  }
74
147
 
75
148
  .fs-popover[data-placement="left"] .fs-popover-arrow {
76
- top: 50%;
77
- right: -5px;
78
- margin-top: -4px;
149
+ inset-block-start: var(--fs-popover-arrow-offset, 50%);
150
+ inset-inline-end: calc(var(--fs-popover-arrow-size) / -2 - 1px);
151
+ margin-block-start: calc(var(--fs-popover-arrow-size) / -2);
79
152
  border-bottom: 0;
80
153
  border-left: 0;
81
154
  }
82
155
 
83
156
  .fs-popover[data-placement="right"] .fs-popover-arrow {
84
- top: 50%;
85
- left: -5px;
86
- margin-top: -4px;
157
+ inset-block-start: var(--fs-popover-arrow-offset, 50%);
158
+ inset-inline-start: calc(var(--fs-popover-arrow-size) / -2 - 1px);
159
+ margin-block-start: calc(var(--fs-popover-arrow-size) / -2);
87
160
  border-top: 0;
88
161
  border-right: 0;
89
162
  }
@@ -100,4 +173,41 @@
100
173
  display: flex;
101
174
  gap: 12px;
102
175
  }
176
+
177
+ .fs-popover[aria-busy="true"] {
178
+ cursor: progress;
179
+ }
180
+
181
+ @media (width <= 480px) {
182
+ .fs-popover {
183
+ --fs-popover-padding-inline: 12px;
184
+ --fs-popover-max-width: calc(100vw - 24px);
185
+ }
186
+
187
+ .fs-popover-footer {
188
+ align-items: flex-start;
189
+ }
190
+ }
191
+
192
+ @media (prefers-reduced-motion: reduce) {
193
+ .fs-popover {
194
+ transition: none;
195
+ }
196
+ }
197
+
198
+ @media (forced-colors: active) {
199
+ .fs-popover,
200
+ .fs-popover-arrow {
201
+ border-color: CanvasText;
202
+ color: CanvasText;
203
+ background-color: Canvas;
204
+ box-shadow: none;
205
+ }
206
+
207
+ .fs-popover-header,
208
+ .fs-popover-footer {
209
+ border-color: CanvasText;
210
+ background-color: Canvas;
211
+ }
212
+ }
103
213
  }
@@ -0,0 +1,23 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ .fs-stack { display: flex; flex-direction: column; gap: var(--fs-stack-gap, var(--fs-space-3)); }
4
+ .fs-cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--fs-cluster-gap, var(--fs-space-2)); }
5
+ .fs-responsive-media { width: 100%; height: auto; object-fit: cover; }
6
+
7
+ @media (width <= 639.98px) {
8
+ .fs-modal-dialog, .fs-offcanvas { max-width: 100%; margin-inline: 0; border-radius: 0; }
9
+ .fs-table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; }
10
+ .fs-btn-group-responsive, .fs-btn-group-responsive > .fs-btn { width: 100%; }
11
+ .fs-btn-group-responsive { flex-direction: column; }
12
+ }
13
+
14
+ @media (width >= 640px) {
15
+ .fs-stack-md-row { flex-direction: row; align-items: center; }
16
+ }
17
+
18
+ @media (prefers-reduced-motion: reduce) { .fs-stack, .fs-cluster { scroll-behavior: auto; } }
19
+
20
+ @media (forced-colors: active) {
21
+ .fs-card, .fs-dropdown-menu, .fs-modal-content, .fs-offcanvas, .fs-toast { border: 1px solid CanvasText; box-shadow: none; }
22
+ }
23
+ }
@@ -8,8 +8,18 @@
8
8
  // o texto e o "x". O dismiss em si é feito por js/tag.js (FokusStyles.Tag).
9
9
  @layer components {
10
10
  .fs-tag {
11
+ --fs-tag-icon-size: var(--fs-tag-close-size);
12
+ --fs-tag-icon-glyph-size: 12px;
13
+ --fs-tag-icon-gap: 4px;
14
+ --fs-tag-icon-color: currentcolor;
15
+ --fs-tag-close-size: calc(var(--fs-badge-height) - 2px);
16
+ --fs-tag-close-gap: 4px;
17
+ --fs-tag-padding-inline-start: 8px;
18
+ --fs-tag-padding-inline-end: 2px;
19
+
11
20
  gap: 0;
12
- padding: 0 0 0 8px;
21
+ padding-inline-start: var(--fs-tag-padding-inline-start);
22
+ padding-inline-end: var(--fs-tag-padding-inline-end);
13
23
  }
14
24
 
15
25
  // O texto fica em um elemento próprio quando a tag puder ser truncada. A
@@ -30,25 +40,32 @@
30
40
 
31
41
  .fs-tag-icon {
32
42
  display: inline-grid;
33
- width: 12px;
34
- height: 12px;
35
- flex: 0 0 12px;
36
- margin-right: 4px;
43
+ width: var(--fs-tag-icon-size);
44
+ height: var(--fs-tag-icon-size);
45
+ flex: 0 0 var(--fs-tag-icon-size);
37
46
  place-items: center;
47
+ color: var(--fs-tag-icon-color);
48
+ margin-inline-end: var(--fs-tag-icon-gap);
49
+ }
50
+
51
+ .fs-tag-icon-end {
52
+ margin-inline-start: auto;
53
+ margin-inline-end: var(--fs-tag-icon-gap);
38
54
  }
39
55
 
40
56
  .fs-tag-icon .fs-icon {
41
- width: 12px;
42
- height: 12px;
57
+ display: block;
58
+ width: var(--fs-tag-icon-glyph-size);
59
+ height: var(--fs-tag-icon-glyph-size);
43
60
  stroke: currentcolor;
44
61
  }
45
62
 
46
63
  .fs-tag .fs-btn-close {
47
- width: calc(var(--fs-badge-height) - 2px);
48
- height: calc(var(--fs-badge-height) - 2px);
49
- flex: 0 0 calc(var(--fs-badge-height) - 2px);
50
- margin-left: 4px;
51
- border-radius: 0;
64
+ width: var(--fs-tag-close-size);
65
+ height: var(--fs-tag-close-size);
66
+ flex: 0 0 var(--fs-tag-close-size);
67
+ margin-inline-start: var(--fs-tag-close-gap);
68
+ border-radius: var(--fs-badge-radius);
52
69
  background-color: transparent;
53
70
 
54
71
  // Herda a cor de texto do badge (contraste automático por variante) em vez
@@ -61,7 +78,7 @@
61
78
 
62
79
  .fs-tag .fs-btn-close::before,
63
80
  .fs-tag .fs-btn-close::after {
64
- top: calc(50% + 1px);
81
+ top: 50%;
65
82
  width: 8px;
66
83
  }
67
84
 
@@ -143,6 +160,12 @@
143
160
  background-color: color-mix(in srgb, currentcolor 18%, transparent);
144
161
  }
145
162
 
163
+ // Um ícone inicial ocupa a área reservada à esquerda; reduzir o padding
164
+ // mantém a composição equilibrada sem empurrar o texto para dentro.
165
+ .fs-tag:has(> .fs-tag-icon:not(.fs-tag-icon-end)) {
166
+ --fs-tag-padding-inline-start: 2px;
167
+ }
168
+
146
169
  // Um botão de overflow representa as tags não exibidas. A abertura da lista
147
170
  // ou popover é responsabilidade da composição que o utiliza.
148
171
  .fs-tag-overflow {
@@ -200,7 +223,7 @@
200
223
  display: inline-grid;
201
224
  width: calc(var(--fs-badge-height) - 2px);
202
225
  height: calc(var(--fs-badge-height) - 2px);
203
- margin-left: 4px;
226
+ margin-inline-start: var(--fs-tag-close-gap);
204
227
  place-items: center;
205
228
  }
206
229