fokus-styles 2.0.0 → 2.4.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 (137) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +4 -3
  3. package/dist/css/components.css +532 -2
  4. package/dist/css/components.css.map +1 -1
  5. package/dist/css/components.min.css +1 -1
  6. package/dist/css/components.min.css.map +1 -1
  7. package/dist/css/fokus-components.css +4072 -0
  8. package/dist/css/fokus-components.css.map +1 -0
  9. package/dist/css/fokus-components.min.css +2 -0
  10. package/dist/css/fokus-components.min.css.map +1 -0
  11. package/dist/css/fokus-core.css +1585 -0
  12. package/dist/css/fokus-core.css.map +1 -0
  13. package/dist/css/fokus-core.min.css +2 -0
  14. package/dist/css/fokus-core.min.css.map +1 -0
  15. package/dist/css/fokus-dark.css +314 -0
  16. package/dist/css/fokus-dark.css.map +1 -0
  17. package/dist/css/fokus-dark.min.css +2 -0
  18. package/dist/css/fokus-dark.min.css.map +1 -0
  19. package/dist/css/fokus-rtl.css +8552 -0
  20. package/dist/css/fokus-rtl.css.map +1 -0
  21. package/dist/css/fokus-rtl.min.css +2 -0
  22. package/dist/css/fokus-rtl.min.css.map +1 -0
  23. package/dist/css/fokus-utilities.css +4198 -0
  24. package/dist/css/fokus-utilities.css.map +1 -0
  25. package/dist/css/fokus-utilities.min.css +2 -0
  26. package/dist/css/fokus-utilities.min.css.map +1 -0
  27. package/dist/css/fokus.css +1361 -53
  28. package/dist/css/fokus.css.map +1 -1
  29. package/dist/css/fokus.min.css +1 -1
  30. package/dist/css/fokus.min.css.map +1 -1
  31. package/dist/css/forms.css +137 -2
  32. package/dist/css/forms.css.map +1 -1
  33. package/dist/css/forms.min.css +1 -1
  34. package/dist/css/forms.min.css.map +1 -1
  35. package/dist/css/helpers.css +398 -2
  36. package/dist/css/helpers.css.map +1 -1
  37. package/dist/css/helpers.min.css +1 -1
  38. package/dist/css/helpers.min.css.map +1 -1
  39. package/dist/css/layout.css +582 -2
  40. package/dist/css/layout.css.map +1 -1
  41. package/dist/css/layout.min.css +1 -1
  42. package/dist/css/layout.min.css.map +1 -1
  43. package/dist/js/fokus.js +347 -12
  44. package/dist/js/fokus.js.map +4 -4
  45. package/dist/js/fokus.min.js +17 -17
  46. package/dist/js/fokus.min.js.map +4 -4
  47. package/docs/components/accordion.md +3 -0
  48. package/docs/components/avatar.md +13 -0
  49. package/docs/components/button-group.md +13 -0
  50. package/docs/components/close-button.md +13 -0
  51. package/docs/components/code.md +13 -0
  52. package/docs/components/icon-link.md +13 -0
  53. package/docs/components/list-group.md +13 -0
  54. package/docs/components/modal.md +3 -0
  55. package/docs/components/navbar.md +3 -0
  56. package/docs/components/pagination.md +3 -0
  57. package/docs/components/placeholder.md +13 -0
  58. package/docs/components/ratio.md +13 -0
  59. package/docs/components/scrollspy.md +13 -0
  60. package/docs/components/skeleton.md +3 -0
  61. package/docs/components/table.md +3 -0
  62. package/docs/guides/javascript-api.md +9 -0
  63. package/docs/guides/rtl-and-system-preferences.md +28 -0
  64. package/docs/guides/utility-api.md +9 -0
  65. package/docs/reference/size-baseline.json +13 -13
  66. package/mockup/assets/example-theme.css +3 -1
  67. package/mockup/assets/example-theme.js +2 -0
  68. package/mockup/assets/showcase-contracts.js +2 -2
  69. package/mockup/assets/showcase.css +4 -2
  70. package/mockup/assets/showcase.js +2 -0
  71. package/mockup/examples/js-foundation.html +25 -0
  72. package/mockup/examples/tables-navbar.html +12 -8
  73. package/mockup/examples/theming.html +2 -1
  74. package/mockup/foundations.html +2 -2
  75. package/package.json +15 -1
  76. package/packages/fokus-cli/bin/fokus.mjs +18 -1
  77. package/packages/fokus-cli/lib/build.mjs +12 -2
  78. package/packages/fokus-components/scss/components/_accordion.scss +19 -0
  79. package/packages/fokus-components/scss/components/_avatar.scss +22 -0
  80. package/packages/fokus-components/scss/components/_button-group.scss +14 -0
  81. package/packages/fokus-components/scss/components/_close-button.scss +22 -0
  82. package/packages/fokus-components/scss/components/_code.scss +19 -0
  83. package/packages/fokus-components/scss/components/_icon-link.scss +8 -0
  84. package/packages/fokus-components/scss/components/_index.scss +10 -0
  85. package/packages/fokus-components/scss/components/_list-group.scss +26 -0
  86. package/packages/fokus-components/scss/components/_modal.scss +36 -0
  87. package/packages/fokus-components/scss/components/_navbar.scss +48 -0
  88. package/packages/fokus-components/scss/components/_offcanvas.scss +19 -0
  89. package/packages/fokus-components/scss/components/_pagination.scss +10 -0
  90. package/packages/fokus-components/scss/components/_placeholder.scss +13 -0
  91. package/packages/fokus-components/scss/components/_progress.scss +8 -0
  92. package/packages/fokus-components/scss/components/_ratio.scss +10 -0
  93. package/packages/fokus-components/scss/components/_scrollspy.scss +5 -0
  94. package/packages/fokus-components/scss/components/_skeleton.scss +19 -0
  95. package/packages/fokus-components/scss/components/_spinner.scss +9 -53
  96. package/packages/fokus-components/scss/components/_tables.scss +20 -0
  97. package/packages/fokus-components/scss/forms/_forms.scss +29 -0
  98. package/packages/fokus-core/scss/base/_accessibility.scss +59 -0
  99. package/packages/fokus-core/scss/base/_index.scss +1 -0
  100. package/packages/fokus-core/scss/layout/_grid.scss +18 -0
  101. package/packages/fokus-core/scss/settings/_config.scss +43 -0
  102. package/packages/fokus-core/scss/settings/_index.scss +1 -0
  103. package/packages/fokus-core/scss/themes/_dark.scss +38 -2
  104. package/packages/fokus-core/scss/tokens/_root.scss +25 -0
  105. package/packages/fokus-core/scss/tools/_mixins.scss +8 -0
  106. package/packages/fokus-js/js/accordion.js +7 -1
  107. package/packages/fokus-js/js/core/focus.js +20 -0
  108. package/packages/fokus-js/js/core/overlay.d.ts +2 -0
  109. package/packages/fokus-js/js/core/overlay.js +10 -0
  110. package/packages/fokus-js/js/core/register.js +4 -2
  111. package/packages/fokus-js/js/focus-trap.d.ts +3 -0
  112. package/packages/fokus-js/js/focus-trap.js +1 -0
  113. package/packages/fokus-js/js/fokus.d.ts +7 -0
  114. package/packages/fokus-js/js/fokus.js +7 -0
  115. package/packages/fokus-js/js/form-validation.d.ts +7 -0
  116. package/packages/fokus-js/js/form-validation.js +20 -0
  117. package/packages/fokus-js/js/modal.js +16 -2
  118. package/packages/fokus-js/js/navbar.d.ts +10 -0
  119. package/packages/fokus-js/js/navbar.js +27 -0
  120. package/packages/fokus-js/js/offcanvas.d.ts +4 -0
  121. package/packages/fokus-js/js/offcanvas.js +16 -2
  122. package/packages/fokus-js/js/pagination.d.ts +7 -0
  123. package/packages/fokus-js/js/pagination.js +38 -0
  124. package/packages/fokus-js/js/scrollspy.d.ts +7 -0
  125. package/packages/fokus-js/js/scrollspy.js +26 -0
  126. package/packages/fokus-js/js/spinner.d.ts +9 -0
  127. package/packages/fokus-js/js/spinner.js +18 -0
  128. package/packages/fokus-js/js/theme.d.ts +9 -0
  129. package/packages/fokus-js/js/theme.js +19 -0
  130. package/packages/fokus-js/js/toast.js +4 -0
  131. package/packages/fokus-utilities/scss/utilities/_api.scss +48 -0
  132. package/packages/fokus-utilities/scss/utilities/_index.scss +2 -0
  133. package/packages/fokus-utilities/scss/utilities/_states.scss +19 -0
  134. package/packages/fokus-utilities/scss/utilities/_visibility.scss +24 -0
  135. package/scss/entries/core-entry.scss +5 -0
  136. package/scss/entries/dark-entry.scss +3 -0
  137. package/scss/entries/rtl-entry.scss +11 -0
@@ -0,0 +1,22 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ .fs-avatar {
4
+ display: inline-flex;
5
+ flex: 0 0 auto;
6
+ align-items: center;
7
+ justify-content: center;
8
+ width: 2.5rem;
9
+ height: 2.5rem;
10
+ overflow: hidden;
11
+ color: var(--fs-color-on-primary);
12
+ font-weight: 600;
13
+ background: var(--fs-color-primary);
14
+ border-radius: 50%;
15
+ object-fit: cover;
16
+ }
17
+
18
+ .fs-avatar-sm { width: 2rem; height: 2rem; font-size: .8125rem; }
19
+ .fs-avatar-lg { width: 3.5rem; height: 3.5rem; font-size: 1.25rem; }
20
+ .fs-avatar-square { border-radius: var(--fs-radius-md); }
21
+ .fs-avatar img { width: 100%; height: 100%; object-fit: cover; }
22
+ }
@@ -0,0 +1,14 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ .fs-button-group {
4
+ display: inline-flex;
5
+ vertical-align: middle;
6
+ }
7
+
8
+ .fs-button-group > .fs-btn { border-radius: 0; }
9
+ .fs-button-group > .fs-btn:first-child { border-start-start-radius: var(--fs-radius-sm); border-end-start-radius: var(--fs-radius-sm); }
10
+ .fs-button-group > .fs-btn:last-child { border-start-end-radius: var(--fs-radius-sm); border-end-end-radius: var(--fs-radius-sm); }
11
+ .fs-button-group > .fs-btn + .fs-btn { margin-inline-start: -1px; }
12
+ .fs-button-group-vertical { flex-direction: column; align-items: flex-start; }
13
+ .fs-button-group-vertical > .fs-btn { width: 100%; }
14
+ }
@@ -0,0 +1,22 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ .fs-close {
4
+ display: inline-grid;
5
+ width: 2rem;
6
+ height: 2rem;
7
+ place-items: center;
8
+ padding: 0;
9
+ color: currentcolor;
10
+ font-size: 1.5rem;
11
+ line-height: 1;
12
+ background: transparent;
13
+ border: 0;
14
+ border-radius: 50%;
15
+ cursor: pointer;
16
+ opacity: .72;
17
+ }
18
+
19
+ .fs-close::before { content: "×"; }
20
+ .fs-close:hover { opacity: 1; background: var(--fs-color-subtle); }
21
+ .fs-close:focus-visible { outline: var(--fs-focus-width) solid var(--fs-focus-color); outline-offset: var(--fs-focus-offset); }
22
+ }
@@ -0,0 +1,19 @@
1
+ @layer components {
2
+ .fs-code {
3
+ padding: .125em .35em;
4
+ color: var(--fs-color-danger);
5
+ background: var(--fs-color-subtle);
6
+ border-radius: var(--fs-radius-sm);
7
+ }
8
+
9
+ .fs-pre {
10
+ display: block;
11
+ max-width: 100%;
12
+ padding: var(--fs-space-4);
13
+ overflow: auto;
14
+ color: var(--fs-color-text);
15
+ background: var(--fs-color-subtle);
16
+ border: 1px solid var(--fs-color-border);
17
+ border-radius: var(--fs-radius-md);
18
+ }
19
+ }
@@ -0,0 +1,8 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ .fs-icon-link { display: inline-flex; gap: .5em; align-items: center; }
4
+ .fs-icon-link svg { width: 1em; height: 1em; flex: 0 0 auto; }
5
+ .fs-icon-link:hover svg { transform: translateX(.15em); }
6
+
7
+ @media (prefers-reduced-motion: reduce) { .fs-icon-link svg { transition: none; } }
8
+ }
@@ -34,3 +34,13 @@
34
34
  @use "notification-center";
35
35
  @use "nested-menu";
36
36
  @use "tile";
37
+ @use "avatar";
38
+ @use "button-group";
39
+ @use "close-button";
40
+ @use "list-group";
41
+ @use "code";
42
+ @use "ratio";
43
+ @use "icon-link";
44
+ @use "placeholder";
45
+ @use "progress";
46
+ @use "scrollspy";
@@ -0,0 +1,26 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ .fs-list-group {
4
+ display: flex;
5
+ flex-direction: column;
6
+ padding: 0;
7
+ margin: 0;
8
+ list-style: none;
9
+ border: 1px solid var(--fs-color-border);
10
+ border-radius: var(--fs-radius-md);
11
+ }
12
+
13
+ .fs-list-group-item {
14
+ position: relative;
15
+ display: block;
16
+ padding: var(--fs-space-3) var(--fs-space-4);
17
+ color: var(--fs-color-text);
18
+ background: var(--fs-color-surface);
19
+ border-block-end: 1px solid var(--fs-color-border);
20
+ }
21
+
22
+ .fs-list-group-item:last-child { border-block-end: 0; }
23
+ button.fs-list-group-item, a.fs-list-group-item { width: 100%; text-align: start; cursor: pointer; }
24
+ .fs-list-group-item:hover { background: var(--fs-color-subtle); }
25
+ .fs-list-group-item.is-active { color: var(--fs-color-on-primary); background: var(--fs-color-primary); }
26
+ }
@@ -29,6 +29,15 @@
29
29
  max-width: 720px;
30
30
  }
31
31
 
32
+ .fs-modal-dialog.fs-modal-xl {
33
+ max-width: 1140px;
34
+ }
35
+
36
+ .fs-modal-dialog.fs-modal-fullscreen {
37
+ max-width: none;
38
+ height: 100%;
39
+ }
40
+
32
41
  .fs-modal-content {
33
42
  display: flex;
34
43
  flex-direction: column;
@@ -59,6 +68,33 @@
59
68
  overflow-y: auto;
60
69
  }
61
70
 
71
+ .fs-modal-scrollable .fs-modal-content {
72
+ overflow: hidden;
73
+ }
74
+
75
+ .fs-modal-scrollable .fs-modal-body {
76
+ overflow-y: auto;
77
+ }
78
+
79
+ @media (width < 640px) {
80
+ .fs-modal {
81
+ align-items: flex-end;
82
+ padding: 0;
83
+ }
84
+
85
+ .fs-modal-dialog,
86
+ .fs-modal-dialog.fs-modal-sm,
87
+ .fs-modal-dialog.fs-modal-lg,
88
+ .fs-modal-dialog.fs-modal-xl {
89
+ max-width: none;
90
+ }
91
+
92
+ .fs-modal-content {
93
+ max-height: calc(100dvh - var(--fs-safe-area-top));
94
+ border-radius: var(--fs-radius-md) var(--fs-radius-md) 0 0;
95
+ }
96
+ }
97
+
62
98
  .fs-modal-footer {
63
99
  display: flex;
64
100
  align-items: center;
@@ -29,6 +29,54 @@
29
29
  list-style: none;
30
30
  }
31
31
 
32
+ .fs-navbar-toggler {
33
+ display: inline-flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ min-width: 44px;
37
+ min-height: 44px;
38
+ padding: 8px;
39
+ color: var(--fs-color-text);
40
+ background: transparent;
41
+ border: 1px solid var(--fs-color-border);
42
+ border-radius: var(--fs-radius-sm);
43
+ cursor: pointer;
44
+ }
45
+
46
+ .fs-navbar-collapse {
47
+ flex-basis: 100%;
48
+ width: 100%;
49
+ }
50
+
51
+ .fs-navbar-collapse:not(.is-open) {
52
+ display: none;
53
+ }
54
+
55
+ .fs-navbar-collapse.is-open .fs-navbar-nav {
56
+ flex-direction: column;
57
+ align-items: stretch;
58
+ }
59
+
60
+ @media (width >= 768px) {
61
+ .fs-navbar-toggler {
62
+ display: none;
63
+ }
64
+
65
+ .fs-navbar-collapse,
66
+ .fs-navbar-collapse:not(.is-open),
67
+ .fs-navbar-collapse[hidden] {
68
+ display: flex;
69
+ flex: 1 1 auto;
70
+ align-items: center;
71
+ justify-content: flex-end;
72
+ width: auto;
73
+ }
74
+
75
+ .fs-navbar-collapse .fs-navbar-nav {
76
+ flex-direction: row;
77
+ }
78
+ }
79
+
32
80
  .fs-nav-link {
33
81
  display: inline-flex;
34
82
  align-items: center;
@@ -92,6 +92,25 @@
92
92
  border-top: 1px solid var(--fs-color-border);
93
93
  }
94
94
 
95
+ .fs-offcanvas-responsive {
96
+ width: min(100%, 420px);
97
+ }
98
+
99
+ @media (width >= 1024px) {
100
+ .fs-offcanvas-lg {
101
+ position: static;
102
+ width: auto;
103
+ height: auto;
104
+ visibility: visible;
105
+ transform: none;
106
+ box-shadow: none;
107
+ }
108
+
109
+ .fs-offcanvas-lg + .fs-offcanvas-backdrop {
110
+ display: none;
111
+ }
112
+ }
113
+
95
114
  @media (prefers-reduced-motion: reduce) {
96
115
  .fs-offcanvas,
97
116
  .fs-offcanvas-backdrop {
@@ -10,6 +10,16 @@
10
10
  list-style: none;
11
11
  }
12
12
 
13
+ .fs-pagination-scroll {
14
+ max-width: 100%;
15
+ overflow-x: auto;
16
+ padding-block: 2px;
17
+ }
18
+
19
+ .fs-pagination-scroll .fs-pagination {
20
+ width: max-content;
21
+ }
22
+
13
23
  .fs-page-link {
14
24
  display: inline-flex;
15
25
  align-items: center;
@@ -0,0 +1,13 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ .fs-placeholder { display: inline-block; min-height: 1em; vertical-align: middle; cursor: wait; background: currentcolor; opacity: .18; }
4
+ .fs-placeholder-glow { animation: fs-placeholder-glow 1.5s ease-in-out infinite; }
5
+ .fs-placeholder-wave { background: linear-gradient(90deg, transparent, rgb(255 255 255 / 35%), transparent), currentcolor; background-size: 200% 100%; animation: fs-placeholder-wave 1.5s linear infinite; }
6
+ .fs-placeholder-btn { width: 6rem; height: 2.5rem; border-radius: var(--fs-radius-sm); }
7
+
8
+ @keyframes fs-placeholder-glow { 50% { opacity: .08; } }
9
+
10
+ @keyframes fs-placeholder-wave { to { background-position: -200% 0; } }
11
+
12
+ @media (prefers-reduced-motion: reduce) { .fs-placeholder-glow, .fs-placeholder-wave { animation: none; } }
13
+ }
@@ -0,0 +1,8 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ .fs-progress { display: flex; height: .75rem; overflow: hidden; background: var(--fs-color-subtle); border-radius: 999px; }
4
+ .fs-progress-bar { display: flex; align-items: center; justify-content: center; color: var(--fs-color-on-primary); background: var(--fs-color-primary); transition: width var(--fs-motion-duration-normal) var(--fs-motion-ease-standard); }
5
+ .fs-progress-bar-striped { background-image: linear-gradient(45deg, rgb(255 255 255 / 15%) 25%, transparent 25%, transparent 50%, rgb(255 255 255 / 15%) 50%, rgb(255 255 255 / 15%) 75%, transparent 75%); background-size: 1rem 1rem; }
6
+
7
+ @media (prefers-reduced-motion: reduce) { .fs-progress-bar { transition: none; } }
8
+ }
@@ -0,0 +1,10 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ .fs-ratio { position: relative; width: 100%; }
4
+ .fs-ratio::before { display: block; padding-top: var(--fs-ratio, 56.25%); content: ""; }
5
+ .fs-ratio > * { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
6
+ .fs-ratio-1x1 { --fs-ratio: 100%; }
7
+ .fs-ratio-4x3 { --fs-ratio: 75%; }
8
+ .fs-ratio-16x9 { --fs-ratio: 56.25%; }
9
+ .fs-ratio-21x9 { --fs-ratio: 42.857%; }
10
+ }
@@ -0,0 +1,5 @@
1
+ /* stylelint-disable declaration-block-single-line-max-declarations */
2
+ @layer components {
3
+ [data-fs-scrollspy] .is-active { color: var(--fs-color-primary); font-weight: 600; }
4
+ .fs-scrollspy-nav { position: sticky; inset-block-start: var(--fs-space-4); }
5
+ }
@@ -35,6 +35,25 @@
35
35
  border-radius: var(--fs-radius-md);
36
36
  }
37
37
 
38
+ .fs-skeleton-card {
39
+ display: grid;
40
+ gap: var(--fs-space-3);
41
+ min-height: 10rem;
42
+ padding: var(--fs-space-4);
43
+ border-radius: var(--fs-radius-md);
44
+ }
45
+
46
+ .fs-skeleton-table {
47
+ height: 1.25rem;
48
+ margin-block-end: var(--fs-space-2);
49
+ }
50
+
51
+ .fs-skeleton-avatar {
52
+ width: 2.5rem;
53
+ height: 2.5rem;
54
+ border-radius: 50%;
55
+ }
56
+
38
57
  @keyframes fokus-skeleton-pulse {
39
58
  0%,
40
59
  100% {
@@ -1,10 +1,6 @@
1
1
  @use "../../../fokus-core/scss/settings" as *;
2
2
  @use "../../../fokus-core/scss/tools" as *;
3
3
 
4
- // Spinner giratório: trilho discreto + segmento ativo. A cor herda de
5
- // `currentColor`, permitindo usar as variantes semânticas ou utilitários de
6
- // cor de texto.
7
-
8
4
  @layer components {
9
5
  .fs-spinner {
10
6
  --fs-spinner-size: 20px;
@@ -39,14 +35,8 @@
39
35
  }
40
36
  }
41
37
 
42
- @keyframes fokus-spin {
43
- to {
44
- transform: rotate(360deg);
45
- }
46
- }
38
+ @keyframes fokus-spin { to { transform: rotate(360deg); } }
47
39
 
48
- // Barra de progresso linear. A largura do `.fs-progress-bar` é controlada por
49
- // `--fs-progress-value` (0–100) ou diretamente por `style="width"`.
50
40
  .fs-progress {
51
41
  --fs-progress-height: 8px;
52
42
  --fs-progress-track: var(--fs-color-subtle);
@@ -87,6 +77,10 @@
87
77
  }
88
78
  }
89
79
 
80
+ .fs-spinner[data-fs-loading="false"] {
81
+ display: none;
82
+ }
83
+
90
84
  .fs-progress-sm {
91
85
  --fs-progress-height: 4px;
92
86
  }
@@ -100,8 +94,6 @@
100
94
  font-size: $font-size-xs;
101
95
  }
102
96
 
103
- // Cabeçalho externo: preserva o valor legível sem comprimir texto dentro de
104
- // barras compactas.
105
97
  .fs-progress-meta {
106
98
  display: flex;
107
99
  align-items: baseline;
@@ -118,8 +110,6 @@
118
110
  font-variant-numeric: tabular-nums;
119
111
  }
120
112
 
121
- // Processo sem percentual conhecido: um preenchimento curto atravessa o
122
- // trilho. Não combine com aria-valuenow, pois o valor é indeterminado.
123
113
  .fs-progress-indeterminate .fs-progress-bar {
124
114
  width: 36%;
125
115
  animation: fokus-progress-indeterminate 1.25s ease-in-out infinite;
@@ -129,17 +119,8 @@
129
119
  --fs-progress-track: color-mix(in srgb, var(--fs-color-primary) 18%, transparent);
130
120
  }
131
121
 
132
- @keyframes fokus-progress-indeterminate {
133
- from {
134
- transform: translateX(-110%);
135
- }
122
+ @keyframes fokus-progress-indeterminate { from { transform: translateX(-110%); } to { transform: translateX(290%); } }
136
123
 
137
- to {
138
- transform: translateX(290%);
139
- }
140
- }
141
-
142
- // Estados semânticos para operações finalizadas ou interrompidas.
143
124
  .fs-progress-complete .fs-progress-bar {
144
125
  --fs-progress-bar-bg: var(--fs-color-success);
145
126
  --fs-progress-color: #{color-contrast($fokus-color-success)};
@@ -178,8 +159,6 @@
178
159
  color: var(--fs-alert-danger-text);
179
160
  }
180
161
 
181
- // Marca uma meta/SLA no trilho. O valor usa a mesma escala percentual da
182
- // barra e deve ser acompanhado por texto fora do componente.
183
162
  .fs-progress-marker {
184
163
  position: absolute;
185
164
  z-index: 1;
@@ -192,40 +171,17 @@
192
171
  transform: translateX(-1px);
193
172
  }
194
173
 
195
- // Mantém progresso inicial perceptível sem alterar aria-valuenow. Use
196
- // apenas quando o valor real já for maior que zero.
197
174
  .fs-progress-minimum .fs-progress-bar {
198
175
  width: max(calc(var(--fs-progress-value, 0) * 1%), 4px);
199
176
  }
200
177
 
201
- // Faixas diagonais opcionais, animáveis com `.fs-progress-bar-animated`.
202
178
  .fs-progress-bar-striped {
203
- background-image: linear-gradient(
204
- 45deg,
205
- color-mix(in srgb, currentcolor 16%, transparent) 25%,
206
- transparent 25%,
207
- transparent 50%,
208
- color-mix(in srgb, currentcolor 16%, transparent) 50%,
209
- color-mix(in srgb, currentcolor 16%, transparent) 75%,
210
- transparent 75%,
211
- transparent
212
- );
179
+ background-image: linear-gradient(45deg, color-mix(in srgb, currentcolor 16%, transparent) 25%, transparent 25%, transparent 50%, color-mix(in srgb, currentcolor 16%, transparent) 50%, color-mix(in srgb, currentcolor 16%, transparent) 75%, transparent 75%, transparent);
213
180
  background-size: 16px 16px;
214
181
  }
182
+ .fs-progress-bar-animated { animation: fokus-progress-stripes 1s linear infinite; }
215
183
 
216
- .fs-progress-bar-animated {
217
- animation: fokus-progress-stripes 1s linear infinite;
218
- }
219
-
220
- @keyframes fokus-progress-stripes {
221
- from {
222
- background-position: 16px 0;
223
- }
224
-
225
- to {
226
- background-position: 0 0;
227
- }
228
- }
184
+ @keyframes fokus-progress-stripes { from { background-position: 16px 0; } to { background-position: 0 0; } }
229
185
 
230
186
  @media (prefers-reduced-motion: reduce) {
231
187
  .fs-spinner {
@@ -58,4 +58,24 @@
58
58
  .fs-table-responsive {
59
59
  overflow-x: auto;
60
60
  }
61
+
62
+ .fs-table-caption {
63
+ caption-side: top;
64
+ padding: var(--fs-space-2) 0;
65
+ color: var(--fs-color-muted);
66
+ text-align: start;
67
+ }
68
+
69
+ .fs-table-empty {
70
+ padding: var(--fs-space-5);
71
+ color: var(--fs-color-muted);
72
+ text-align: center;
73
+ }
74
+
75
+ @media (width < 640px) {
76
+ .fs-table-priority th:nth-child(n + 4),
77
+ .fs-table-priority td:nth-child(n + 4) {
78
+ display: none;
79
+ }
80
+ }
61
81
  }
@@ -107,6 +107,35 @@
107
107
  cursor: default;
108
108
  }
109
109
 
110
+ .fs-floating-label {
111
+ position: relative;
112
+ }
113
+
114
+ .fs-floating-label > .fs-form-control {
115
+ height: 56px;
116
+ padding-top: 20px;
117
+ }
118
+
119
+ .fs-floating-label > .fs-form-label {
120
+ position: absolute;
121
+ z-index: 1;
122
+ top: 8px;
123
+ left: 8px;
124
+ color: var(--fs-color-muted);
125
+ font-size: $font-size-xs;
126
+ pointer-events: none;
127
+ }
128
+
129
+ .fs-form-control[aria-invalid="true"],
130
+ .fs-was-validated .fs-form-control:invalid {
131
+ border-color: var(--fs-color-danger);
132
+ }
133
+
134
+ .fs-form-control[aria-invalid="false"],
135
+ .fs-was-validated .fs-form-control:valid {
136
+ border-color: var(--fs-color-success);
137
+ }
138
+
110
139
  .fs-form-control-sm {
111
140
  height: var(--fs-control-height-sm);
112
141
  font-size: $font-size-xs;
@@ -0,0 +1,59 @@
1
+ /* stylelint-disable property-no-deprecated, selector-not-notation */
2
+ @layer reset {
3
+ :focus-visible {
4
+ outline: var(--fs-focus-width) solid var(--fs-focus-color);
5
+ outline-offset: var(--fs-focus-offset);
6
+ }
7
+
8
+ @media (forced-colors: active) {
9
+ :focus-visible {
10
+ outline: 2px solid CanvasText;
11
+ outline-offset: 2px;
12
+ }
13
+
14
+ button,
15
+ [role="button"],
16
+ input,
17
+ select,
18
+ textarea,
19
+ .fs-btn {
20
+ border-color: ButtonText;
21
+ forced-color-adjust: auto;
22
+ }
23
+
24
+ .fs-u-focus-ring:focus-visible {
25
+ outline: 3px solid Highlight;
26
+ }
27
+ }
28
+ }
29
+
30
+ @layer utilities {
31
+ .fs-u-visually-hidden:not(:focus):not(:focus-within),
32
+ .fs-u-visually-hidden-focusable:not(:focus):not(:focus-within) {
33
+ position: absolute !important;
34
+ width: 1px !important;
35
+ height: 1px !important;
36
+ padding: 0 !important;
37
+ margin: -1px !important;
38
+ overflow: hidden !important;
39
+ clip-path: inset(50%) !important;
40
+ white-space: nowrap !important;
41
+ border: 0 !important;
42
+ }
43
+
44
+ .fs-skip-link {
45
+ position: fixed;
46
+ z-index: 1000;
47
+ inset-block-start: var(--fs-space-2);
48
+ inset-inline-start: var(--fs-space-2);
49
+ transform: translateY(-200%);
50
+ padding: var(--fs-space-2) var(--fs-space-3);
51
+ color: var(--fs-color-on-primary);
52
+ background: var(--fs-color-primary);
53
+ border-radius: var(--fs-radius-sm);
54
+ }
55
+
56
+ .fs-skip-link:focus {
57
+ transform: translateY(0);
58
+ }
59
+ }
@@ -1,3 +1,4 @@
1
1
  @use "reset";
2
2
  @use "typography";
3
3
  @use "motion";
4
+ @use "accessibility";
@@ -31,6 +31,24 @@
31
31
  $infix: breakpoint-infix($breakpoint);
32
32
 
33
33
  @include media-breakpoint-up($breakpoint) {
34
+ .fs-row-cols#{$infix}-auto > * {
35
+ flex: 0 0 auto;
36
+ width: auto;
37
+ }
38
+
39
+ @for $count from 1 through 6 {
40
+ .fs-row-cols#{$infix}-#{$count} > * {
41
+ flex: 0 0 auto;
42
+ width: math.percentage(math.div(1, $count));
43
+ }
44
+ }
45
+
46
+ @for $order from 0 through $grid-columns {
47
+ .fs-order#{$infix}-#{$order} {
48
+ order: $order;
49
+ }
50
+ }
51
+
34
52
  .fs-col#{$infix} {
35
53
  flex: 1 0 0%;
36
54
  }
@@ -0,0 +1,43 @@
1
+ @use "sass:map";
2
+ @use "sass:list";
3
+
4
+ // Configuration centralizada. O mapa pode ser sobrescrito antes de importar
5
+ // qualquer entry-point, mantendo os presets previsíveis para consumidores.
6
+ $fs-config: (
7
+ preset: full,
8
+ components: all,
9
+ utilities: all,
10
+ colors: all,
11
+ spacing: all,
12
+ sizing: all,
13
+ responsive: true,
14
+ states: true,
15
+ pseudo-variants: (responsive, focus-visible, disabled, checked, hover, print),
16
+ fluid-type: true,
17
+ color-modes: true
18
+ ) !default;
19
+
20
+ @function fs-config-list-enabled($key, $item) {
21
+
22
+ $value: fs-config-get($key, all);
23
+
24
+ @if $value == all { @return true; }
25
+
26
+ @if $value == none or $value == false { @return false; }
27
+
28
+ @return list.index($value, $item) != null;
29
+ }
30
+
31
+ @function fs-config-get($key, $fallback: null) {
32
+ @if map.has-key($fs-config, $key) {
33
+ @return map.get($fs-config, $key);
34
+ }
35
+
36
+ @return $fallback;
37
+ }
38
+
39
+ @function fs-feature-enabled($feature, $fallback: true) {
40
+ $value: fs-config-get($feature, $fallback);
41
+
42
+ @return $value != false;
43
+ }
@@ -1,5 +1,6 @@
1
1
  @forward "breakpoints";
2
2
  @forward "colors";
3
+ @forward "config";
3
4
  @forward "container-queries";
4
5
  @forward "spacing";
5
6
  @forward "typography";