@raintonic/formaui 0.2.1 → 0.3.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 (169) hide show
  1. package/CHANGELOG.md +100 -3
  2. package/LICENSE +21 -0
  3. package/README.md +80 -26
  4. package/fesm2022/raintonic-formaui-components-accordion.mjs +2 -2
  5. package/fesm2022/raintonic-formaui-components-accordion.mjs.map +1 -1
  6. package/fesm2022/raintonic-formaui-components-alert.mjs +24 -5
  7. package/fesm2022/raintonic-formaui-components-alert.mjs.map +1 -1
  8. package/fesm2022/raintonic-formaui-components-autocomplete.mjs +38 -9
  9. package/fesm2022/raintonic-formaui-components-autocomplete.mjs.map +1 -1
  10. package/fesm2022/raintonic-formaui-components-badge.mjs +45 -31
  11. package/fesm2022/raintonic-formaui-components-badge.mjs.map +1 -1
  12. package/fesm2022/raintonic-formaui-components-big-menu.mjs +23 -5
  13. package/fesm2022/raintonic-formaui-components-big-menu.mjs.map +1 -1
  14. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs +24 -7
  15. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs.map +1 -1
  16. package/fesm2022/raintonic-formaui-components-button-group.mjs +6 -6
  17. package/fesm2022/raintonic-formaui-components-button-group.mjs.map +1 -1
  18. package/fesm2022/raintonic-formaui-components-button.mjs +63 -17
  19. package/fesm2022/raintonic-formaui-components-button.mjs.map +1 -1
  20. package/fesm2022/raintonic-formaui-components-card.mjs +8 -8
  21. package/fesm2022/raintonic-formaui-components-card.mjs.map +1 -1
  22. package/fesm2022/raintonic-formaui-components-checkbox.mjs +2 -2
  23. package/fesm2022/raintonic-formaui-components-checkbox.mjs.map +1 -1
  24. package/fesm2022/raintonic-formaui-components-data-table.mjs +67 -9
  25. package/fesm2022/raintonic-formaui-components-data-table.mjs.map +1 -1
  26. package/fesm2022/raintonic-formaui-components-date-picker.mjs +63 -16
  27. package/fesm2022/raintonic-formaui-components-date-picker.mjs.map +1 -1
  28. package/fesm2022/raintonic-formaui-components-drawer.mjs +19 -4
  29. package/fesm2022/raintonic-formaui-components-drawer.mjs.map +1 -1
  30. package/fesm2022/raintonic-formaui-components-file-upload.mjs +25 -5
  31. package/fesm2022/raintonic-formaui-components-file-upload.mjs.map +1 -1
  32. package/fesm2022/raintonic-formaui-components-form-field.mjs +21 -6
  33. package/fesm2022/raintonic-formaui-components-form-field.mjs.map +1 -1
  34. package/fesm2022/raintonic-formaui-components-icon.mjs +2 -2
  35. package/fesm2022/raintonic-formaui-components-icon.mjs.map +1 -1
  36. package/fesm2022/raintonic-formaui-components-input.mjs +1 -1
  37. package/fesm2022/raintonic-formaui-components-input.mjs.map +1 -1
  38. package/fesm2022/raintonic-formaui-components-list.mjs +4 -4
  39. package/fesm2022/raintonic-formaui-components-list.mjs.map +1 -1
  40. package/fesm2022/raintonic-formaui-components-menu.mjs +4 -4
  41. package/fesm2022/raintonic-formaui-components-menu.mjs.map +1 -1
  42. package/fesm2022/raintonic-formaui-components-number-input.mjs +20 -5
  43. package/fesm2022/raintonic-formaui-components-number-input.mjs.map +1 -1
  44. package/fesm2022/raintonic-formaui-components-paginator.mjs +27 -7
  45. package/fesm2022/raintonic-formaui-components-paginator.mjs.map +1 -1
  46. package/fesm2022/raintonic-formaui-components-password-input.mjs +23 -5
  47. package/fesm2022/raintonic-formaui-components-password-input.mjs.map +1 -1
  48. package/fesm2022/raintonic-formaui-components-popover.mjs +2 -2
  49. package/fesm2022/raintonic-formaui-components-popover.mjs.map +1 -1
  50. package/fesm2022/raintonic-formaui-components-progressbar.mjs +32 -7
  51. package/fesm2022/raintonic-formaui-components-progressbar.mjs.map +1 -1
  52. package/fesm2022/raintonic-formaui-components-radio.mjs +4 -4
  53. package/fesm2022/raintonic-formaui-components-radio.mjs.map +1 -1
  54. package/fesm2022/raintonic-formaui-components-select.mjs +19 -4
  55. package/fesm2022/raintonic-formaui-components-select.mjs.map +1 -1
  56. package/fesm2022/raintonic-formaui-components-side-panel.mjs +19 -4
  57. package/fesm2022/raintonic-formaui-components-side-panel.mjs.map +1 -1
  58. package/fesm2022/raintonic-formaui-components-sidebar.mjs +23 -5
  59. package/fesm2022/raintonic-formaui-components-sidebar.mjs.map +1 -1
  60. package/fesm2022/raintonic-formaui-components-skeleton.mjs +2 -2
  61. package/fesm2022/raintonic-formaui-components-skeleton.mjs.map +1 -1
  62. package/fesm2022/raintonic-formaui-components-slider.mjs +23 -5
  63. package/fesm2022/raintonic-formaui-components-slider.mjs.map +1 -1
  64. package/fesm2022/raintonic-formaui-components-spinner.mjs +24 -7
  65. package/fesm2022/raintonic-formaui-components-spinner.mjs.map +1 -1
  66. package/fesm2022/raintonic-formaui-components-stepper.mjs +2 -2
  67. package/fesm2022/raintonic-formaui-components-stepper.mjs.map +1 -1
  68. package/fesm2022/raintonic-formaui-components-tab.mjs +2 -2
  69. package/fesm2022/raintonic-formaui-components-tab.mjs.map +1 -1
  70. package/fesm2022/raintonic-formaui-components-tag.mjs +21 -4
  71. package/fesm2022/raintonic-formaui-components-tag.mjs.map +1 -1
  72. package/fesm2022/raintonic-formaui-components-time-picker.mjs +26 -7
  73. package/fesm2022/raintonic-formaui-components-time-picker.mjs.map +1 -1
  74. package/fesm2022/raintonic-formaui-components-toggle.mjs +2 -2
  75. package/fesm2022/raintonic-formaui-components-toggle.mjs.map +1 -1
  76. package/fesm2022/raintonic-formaui-components-toolbar.mjs +41 -7
  77. package/fesm2022/raintonic-formaui-components-toolbar.mjs.map +1 -1
  78. package/fesm2022/raintonic-formaui-components-tooltip.mjs +2 -2
  79. package/fesm2022/raintonic-formaui-components-tooltip.mjs.map +1 -1
  80. package/fesm2022/raintonic-formaui-components-tree-table.mjs +35 -6
  81. package/fesm2022/raintonic-formaui-components-tree-table.mjs.map +1 -1
  82. package/fesm2022/raintonic-formaui-components-tree.mjs +23 -5
  83. package/fesm2022/raintonic-formaui-components-tree.mjs.map +1 -1
  84. package/fesm2022/raintonic-formaui-core.mjs +25 -1
  85. package/fesm2022/raintonic-formaui-core.mjs.map +1 -1
  86. package/fesm2022/raintonic-formaui-services-dialog.mjs +3 -3
  87. package/fesm2022/raintonic-formaui-services-dialog.mjs.map +1 -1
  88. package/fesm2022/raintonic-formaui-services-notification.mjs +2 -2
  89. package/fesm2022/raintonic-formaui-services-notification.mjs.map +1 -1
  90. package/fesm2022/raintonic-formaui-services-theme.mjs +3 -3
  91. package/fesm2022/raintonic-formaui-services-theme.mjs.map +1 -1
  92. package/fesm2022/raintonic-formaui-test-utils.mjs +21 -16
  93. package/fesm2022/raintonic-formaui-test-utils.mjs.map +1 -1
  94. package/fesm2022/raintonic-formaui.mjs +1 -1
  95. package/fesm2022/raintonic-formaui.mjs.map +1 -1
  96. package/llms-full.txt +33 -25
  97. package/llms.txt +1 -2
  98. package/package.json +1 -5
  99. package/styles/index.scss +2 -2
  100. package/styles/partials/_motion.scss +25 -0
  101. package/styles/partials/_theme.scss +6 -5
  102. package/styles/partials/components/_button.scss +361 -367
  103. package/styles/partials/themes/_dark.scss +14 -0
  104. package/styles/partials/themes/_light.scss +14 -0
  105. package/types/raintonic-formaui-components-alert.d.ts +11 -1
  106. package/types/raintonic-formaui-components-alert.d.ts.map +1 -1
  107. package/types/raintonic-formaui-components-autocomplete.d.ts +25 -7
  108. package/types/raintonic-formaui-components-autocomplete.d.ts.map +1 -1
  109. package/types/raintonic-formaui-components-badge.d.ts +20 -9
  110. package/types/raintonic-formaui-components-badge.d.ts.map +1 -1
  111. package/types/raintonic-formaui-components-big-menu.d.ts +12 -1
  112. package/types/raintonic-formaui-components-big-menu.d.ts.map +1 -1
  113. package/types/raintonic-formaui-components-breadcrumb.d.ts +11 -2
  114. package/types/raintonic-formaui-components-breadcrumb.d.ts.map +1 -1
  115. package/types/raintonic-formaui-components-button-group.d.ts +6 -6
  116. package/types/raintonic-formaui-components-button.d.ts +9 -7
  117. package/types/raintonic-formaui-components-button.d.ts.map +1 -1
  118. package/types/raintonic-formaui-components-card.d.ts +4 -4
  119. package/types/raintonic-formaui-components-checkbox.d.ts +1 -1
  120. package/types/raintonic-formaui-components-data-table.d.ts +56 -16
  121. package/types/raintonic-formaui-components-data-table.d.ts.map +1 -1
  122. package/types/raintonic-formaui-components-date-picker.d.ts +32 -4
  123. package/types/raintonic-formaui-components-date-picker.d.ts.map +1 -1
  124. package/types/raintonic-formaui-components-drawer.d.ts +10 -1
  125. package/types/raintonic-formaui-components-drawer.d.ts.map +1 -1
  126. package/types/raintonic-formaui-components-file-upload.d.ts +12 -1
  127. package/types/raintonic-formaui-components-file-upload.d.ts.map +1 -1
  128. package/types/raintonic-formaui-components-form-field.d.ts +12 -2
  129. package/types/raintonic-formaui-components-form-field.d.ts.map +1 -1
  130. package/types/raintonic-formaui-components-input.d.ts +1 -1
  131. package/types/raintonic-formaui-components-number-input.d.ts +11 -2
  132. package/types/raintonic-formaui-components-number-input.d.ts.map +1 -1
  133. package/types/raintonic-formaui-components-paginator.d.ts +13 -1
  134. package/types/raintonic-formaui-components-paginator.d.ts.map +1 -1
  135. package/types/raintonic-formaui-components-password-input.d.ts +12 -2
  136. package/types/raintonic-formaui-components-password-input.d.ts.map +1 -1
  137. package/types/raintonic-formaui-components-progressbar.d.ts +14 -1
  138. package/types/raintonic-formaui-components-progressbar.d.ts.map +1 -1
  139. package/types/raintonic-formaui-components-select.d.ts.map +1 -1
  140. package/types/raintonic-formaui-components-side-panel.d.ts +10 -1
  141. package/types/raintonic-formaui-components-side-panel.d.ts.map +1 -1
  142. package/types/raintonic-formaui-components-sidebar.d.ts +12 -1
  143. package/types/raintonic-formaui-components-sidebar.d.ts.map +1 -1
  144. package/types/raintonic-formaui-components-slider.d.ts +12 -1
  145. package/types/raintonic-formaui-components-slider.d.ts.map +1 -1
  146. package/types/raintonic-formaui-components-spinner.d.ts +12 -2
  147. package/types/raintonic-formaui-components-spinner.d.ts.map +1 -1
  148. package/types/raintonic-formaui-components-tag.d.ts +10 -1
  149. package/types/raintonic-formaui-components-tag.d.ts.map +1 -1
  150. package/types/raintonic-formaui-components-time-picker.d.ts +14 -2
  151. package/types/raintonic-formaui-components-time-picker.d.ts.map +1 -1
  152. package/types/raintonic-formaui-components-toggle.d.ts +1 -1
  153. package/types/raintonic-formaui-components-toolbar.d.ts +22 -4
  154. package/types/raintonic-formaui-components-toolbar.d.ts.map +1 -1
  155. package/types/raintonic-formaui-components-tree-table.d.ts +29 -4
  156. package/types/raintonic-formaui-components-tree-table.d.ts.map +1 -1
  157. package/types/raintonic-formaui-components-tree.d.ts +12 -1
  158. package/types/raintonic-formaui-components-tree.d.ts.map +1 -1
  159. package/types/raintonic-formaui-core.d.ts +19 -2
  160. package/types/raintonic-formaui-core.d.ts.map +1 -1
  161. package/types/raintonic-formaui-services-dialog.d.ts +1 -1
  162. package/types/raintonic-formaui-services-theme.d.ts +3 -3
  163. package/types/raintonic-formaui-test-utils.d.ts +15 -2
  164. package/types/raintonic-formaui-test-utils.d.ts.map +1 -1
  165. package/types/raintonic-formaui.d.ts +1 -1
  166. package/fesm2022/raintonic-formaui-components-dynamic-form.mjs +0 -266
  167. package/fesm2022/raintonic-formaui-components-dynamic-form.mjs.map +0 -1
  168. package/types/raintonic-formaui-components-dynamic-form.d.ts +0 -412
  169. package/types/raintonic-formaui-components-dynamic-form.d.ts.map +0 -1
@@ -1,367 +1,361 @@
1
- // Button component styles aligned with theme tokens
2
- @use '../constants' as *;
3
- @use '../mixins' as mixins;
4
- @use '../motion' as motion;
5
-
6
- .fui-button {
7
- // Component tokens with fallbacks
8
- --fui-button-height: var(--fui-button-height-md);
9
- --fui-button-font-size: var(--fui-font-size-02);
10
- --fui-button-border-radius: var(--fui-border-radius-sm);
11
- --fui-button-padding-x: var(--fui-spacing-05);
12
- --fui-button-padding-y: var(--fui-spacing-03);
13
- --fui-button-gap: var(--fui-spacing-03);
14
- --fui-button-font-weight: var(--fui-font-weight-semibold);
15
- --fui-button-letter-spacing: var(--fui-letter-spacing-wide);
16
-
17
- // Default spinner/text foreground used during loading
18
- @include mixins.fui-button-reset();
19
- @include motion.fui-motion(all, var(--fui-duration-fast-02));
20
-
21
- position: relative;
22
- display: inline-flex;
23
- align-items: center;
24
- justify-content: center;
25
- gap: var(--fui-button-gap);
26
- overflow: hidden;
27
-
28
- font-family: var(--fui-font-family-sans);
29
- font-weight: var(--fui-button-font-weight);
30
- text-decoration: none;
31
- text-align: center;
32
- vertical-align: middle;
33
- white-space: nowrap;
34
- user-select: none;
35
- letter-spacing: var(--fui-button-letter-spacing);
36
- border-radius: var(--fui-button-border-radius);
37
- box-sizing: border-box;
38
- cursor: pointer;
39
- min-height: var(--fui-button-height);
40
-
41
- &:focus-visible {
42
- @include mixins.fui-focus-ring();
43
- }
44
-
45
- // Loading spinner
46
- &__spinner {
47
- position: absolute;
48
- top: 50%;
49
- left: 50%;
50
- transform: translate(-50%, -50%);
51
- display: flex;
52
- align-items: center;
53
- justify-content: center;
54
- }
55
-
56
- &__spinner-icon {
57
- width: var(--fui-icon-size-sm);
58
- height: var(--fui-icon-size-sm);
59
- border: 2px solid var(--fui-text-primary);
60
- border-top-color: transparent;
61
- border-radius: 50%;
62
- animation: fui-spin var(--fui-duration-slow-02) linear infinite;
63
- }
64
-
65
- // WCAG 2.1 AA: ensure minimum 44x44px touch target for smaller sizes
66
- // Uses a pseudo-element so visual size remains unchanged
67
- &::after {
68
- content: '';
69
- position: absolute;
70
- inset: 50% auto auto 50%;
71
- min-width: 44px;
72
- min-height: 44px;
73
- width: 100%;
74
- height: 100%;
75
- transform: translate(-50%, -50%);
76
- }
77
-
78
- // States
79
- &--disabled {
80
- cursor: not-allowed;
81
- opacity: var(--fui-opacity-disabled);
82
- }
83
-
84
- &--loading {
85
- color: transparent !important;
86
- cursor: wait;
87
- }
88
-
89
- &--full-width {
90
- width: 100%;
91
- }
92
-
93
- // Sizes
94
- &--sm {
95
- min-height: var(--fui-button-height-sm);
96
- padding: calc(var(--fui-spacing-03) - 2px) var(--fui-spacing-03);
97
- font-size: var(--fui-font-size-01);
98
-
99
- &.fui-button--icon-only {
100
- width: var(--fui-button-height-sm);
101
- padding: calc(var(--fui-spacing-03) - 2px);
102
- }
103
-
104
- .fui-icon {
105
- width: var(--fui-icon-size-sm);
106
- height: var(--fui-icon-size-sm);
107
- }
108
- }
109
-
110
- &--md {
111
- min-height: var(--fui-button-height-md);
112
- padding: calc(var(--fui-spacing-03) + 2px) var(--fui-spacing-05);
113
- font-size: var(--fui-font-size-02);
114
-
115
- &.fui-button--icon-only {
116
- padding: calc(var(--fui-spacing-03) + 2px);
117
- }
118
-
119
- .fui-icon {
120
- width: var(--fui-icon-size-md);
121
- height: var(--fui-icon-size-md);
122
- }
123
- }
124
-
125
- &--lg {
126
- min-height: var(--fui-button-height-lg);
127
- padding: calc(var(--fui-spacing-04) - 2px) var(--fui-spacing-05);
128
- font-size: var(--fui-font-size-03);
129
-
130
- &.fui-button--icon-only {
131
- width: var(--fui-button-height-lg);
132
- padding: calc(var(--fui-spacing-04) - 2px);
133
- }
134
-
135
- .fui-icon {
136
- width: var(--fui-icon-size-md);
137
- height: var(--fui-icon-size-md);
138
- }
139
- }
140
-
141
- &--xl {
142
- min-height: var(--fui-button-height-xl);
143
- padding: var(--fui-spacing-04) var(--fui-spacing-06);
144
- font-size: var(--fui-font-size-03);
145
-
146
- &.fui-button--icon-only {
147
- width: var(--fui-button-height-xl);
148
- padding: var(--fui-spacing-04);
149
- }
150
-
151
- .fui-icon {
152
- width: var(--fui-icon-size-md);
153
- height: var(--fui-icon-size-md);
154
- }
155
- }
156
-
157
- &--2xl {
158
- min-height: var(--fui-spacing-11);
159
- padding: var(--fui-spacing-05) var(--fui-spacing-06);
160
- font-size: var(--fui-font-size-03);
161
-
162
- &.fui-button--icon-only {
163
- width: var(--fui-spacing-11);
164
- padding: var(--fui-spacing-05);
165
- }
166
-
167
- .fui-icon {
168
- width: var(--fui-icon-size-md);
169
- height: var(--fui-icon-size-md);
170
- }
171
- }
172
-
173
- &--field {
174
- min-height: var(--fui-input-height); // matches form field height
175
- padding: calc(var(--fui-spacing-03) + 2px) var(--fui-spacing-04);
176
- font-size: var(--fui-font-size-02);
177
-
178
- &.fui-button--icon-only {
179
- width: var(--fui-input-height);
180
- padding: calc(var(--fui-spacing-03) + 2px);
181
- }
182
- }
183
-
184
- // Variant and Kind combinations
185
-
186
- // Primary variant
187
- &--primary {
188
- background-color: var(--fui-primary);
189
- color: var(--fui-primary-text);
190
- border-color: transparent;
191
- letter-spacing: var(--fui-letter-spacing-wide);
192
- box-shadow: var(--fui-shadow-02);
193
-
194
- &:hover:not(.fui-button--disabled) {
195
- background-color: var(--fui-primary-hover);
196
- box-shadow: var(--fui-shadow-03);
197
- }
198
-
199
- &:active:not(.fui-button--disabled) {
200
- background-color: var(--fui-primary-hover);
201
- box-shadow: none;
202
- }
203
-
204
- &.fui-button--disabled {
205
- background-color: var(--fui-primary);
206
- }
207
- }
208
-
209
- // Secondary variant
210
- &--secondary {
211
- background-color: var(--fui-secondary-60);
212
- color: var(--fui-text-primary);
213
- border-color: var(--fui-border-color);
214
- letter-spacing: var(--fui-letter-spacing-wide);
215
-
216
- &:hover:not(.fui-button--disabled) {
217
- background-color: var(--fui-secondary-90);
218
- }
219
-
220
- &:active:not(.fui-button--disabled) {
221
- background-color: var(--fui-secondary-90);
222
- }
223
-
224
- &.fui-button--disabled {
225
- background-color: var(--fui-secondary);
226
- }
227
- }
228
-
229
- // Secondary variant
230
- &--outline {
231
- background-color: var(--fui-surface-01);
232
- color: var(--fui-text-primary);
233
- border: var(--fui-border-width-md) solid var(--fui-surface-03);
234
-
235
- &:hover:not(.fui-button--disabled) {
236
- background-color: var(--fui-primary-20);
237
- }
238
-
239
- &:active:not(.fui-button--disabled) {
240
- background-color: var(--fui-primary-20);
241
- }
242
-
243
- &.fui-button--disabled {
244
- background-color: var(--fui-surface-01);
245
- }
246
- }
247
-
248
- // Danger variant
249
- &--danger {
250
- background-color: var(--fui-danger-60);
251
- color: var(--fui-text-primary);
252
- border-color: transparent;
253
- letter-spacing: var(--fui-letter-spacing-wide);
254
-
255
- &:hover:not(.fui-button--disabled) {
256
- background-color: var(--fui-danger-80);
257
- }
258
-
259
- &:active:not(.fui-button--disabled) {
260
- background-color: var(--fui-danger-80);
261
- }
262
-
263
- &.fui-button--disabled {
264
- background-color: var(--fui-danger-60);
265
- }
266
- }
267
-
268
- // Ghost variant (neutral)
269
- &--ghost {
270
- background-color: transparent;
271
- color: var(--fui-text-primary);
272
- border-color: transparent;
273
-
274
- &:hover:not(.fui-button--disabled) {
275
- background-color: var(--fui-surface-02);
276
- }
277
-
278
- &:active:not(.fui-button--disabled) {
279
- background-color: var(--fui-surface-05);
280
- }
281
- }
282
-
283
- &--link {
284
- background-color: transparent;
285
- color: var(--fui-primary);
286
-
287
- &:hover:not(.fui-button--disabled) {
288
- text-decoration: underline;
289
- }
290
-
291
- &:active:not(.fui-button--disabled) {
292
- text-decoration: underline;
293
- }
294
- }
295
-
296
- // Icon variant (ghost-like with circular shape)
297
- &--icon {
298
- background-color: transparent;
299
- color: var(--fui-text-primary);
300
- border-color: transparent;
301
- border-radius: 50%;
302
- aspect-ratio: 1;
303
- padding: 0;
304
-
305
- &:hover:not(.fui-button--disabled) {
306
- background-color: var(--fui-surface-02);
307
- }
308
-
309
- &:active:not(.fui-button--disabled) {
310
- background-color: var(--fui-surface-05);
311
- }
312
- }
313
-
314
- // Icon adjustments
315
- &--icon-only {
316
- gap: 0;
317
-
318
- .fui-icon {
319
- margin: 0;
320
- }
321
- }
322
- }
323
-
324
- // Icon spacing within buttons
325
- .fui-icon {
326
- flex-shrink: 0;
327
-
328
- &[fuiPrefix] {
329
- margin-right: var(--fui-spacing-02);
330
- }
331
-
332
- &[fuiSuffix] {
333
- margin-left: var(--fui-spacing-02);
334
- }
335
- }
336
-
337
- // High contrast mode support
338
- @media (prefers-contrast: more) {
339
- .fui-button {
340
- &--outlined {
341
- border-width: 3px;
342
- }
343
-
344
- &:focus-visible {
345
- outline-width: 3px;
346
- }
347
- }
348
- }
349
-
350
- // Keyframes
351
- @keyframes fui-spin {
352
- from {
353
- transform: rotate(0deg);
354
- }
355
- to {
356
- transform: rotate(360deg);
357
- }
358
- }
359
-
360
- // Print styles
361
- @media print {
362
- .fui-button {
363
- &__spinner {
364
- display: none !important;
365
- }
366
- }
367
- }
1
+ // Button component styles aligned with theme tokens
2
+ @use '../constants' as *;
3
+ @use '../mixins' as mixins;
4
+ @use '../motion' as motion;
5
+
6
+ .fui-button {
7
+ // Component tokens with fallbacks
8
+ --fui-button-height: var(--fui-button-height-md);
9
+ --fui-button-font-size: var(--fui-font-size-02);
10
+ --fui-button-border-radius: var(--fui-border-radius-sm);
11
+ --fui-button-padding-x: var(--fui-spacing-05);
12
+ --fui-button-padding-y: var(--fui-spacing-03);
13
+ --fui-button-gap: var(--fui-spacing-03);
14
+ --fui-button-font-weight: var(--fui-font-weight-semibold);
15
+ --fui-button-letter-spacing: var(--fui-letter-spacing-wide);
16
+
17
+ // Default spinner/text foreground used during loading
18
+ @include mixins.fui-button-reset();
19
+ @include motion.fui-motion(all, var(--fui-duration-fast-02));
20
+
21
+ position: relative;
22
+ display: inline-flex;
23
+ align-items: center;
24
+ justify-content: center;
25
+ gap: var(--fui-button-gap);
26
+ overflow: hidden;
27
+
28
+ font-family: var(--fui-font-family-sans);
29
+ font-weight: var(--fui-button-font-weight);
30
+ text-decoration: none;
31
+ text-align: center;
32
+ vertical-align: middle;
33
+ white-space: nowrap;
34
+ user-select: none;
35
+ letter-spacing: var(--fui-button-letter-spacing);
36
+ border-radius: var(--fui-button-border-radius);
37
+ box-sizing: border-box;
38
+ cursor: pointer;
39
+ min-height: var(--fui-button-height);
40
+
41
+ &:focus-visible {
42
+ @include mixins.fui-focus-ring();
43
+ }
44
+
45
+ // Loading spinner
46
+ &__spinner {
47
+ display: inline-flex;
48
+ align-items: center;
49
+ justify-content: center;
50
+ }
51
+
52
+ &__spinner-icon {
53
+ width: var(--fui-icon-size-sm);
54
+ height: var(--fui-icon-size-sm);
55
+ border: 2px solid currentColor;
56
+ border-top-color: transparent;
57
+ border-radius: 50%;
58
+ animation: fui-spin var(--fui-duration-slow-02) linear infinite;
59
+ }
60
+
61
+ &__leading {
62
+ display: contents;
63
+ }
64
+
65
+ // Ripple effect on click
66
+ &__ripple {
67
+ position: absolute;
68
+ border-radius: 50%;
69
+ background-color: currentColor;
70
+ opacity: 0.35;
71
+ pointer-events: none;
72
+ transform: scale(0);
73
+ animation: fui-button-ripple var(--fui-duration-slow-01, 400ms) ease-out forwards;
74
+ }
75
+
76
+ @media (prefers-reduced-motion: reduce) {
77
+ &__ripple {
78
+ animation: none;
79
+ display: none;
80
+ }
81
+ }
82
+
83
+ // WCAG 2.1 AA: ensure minimum 44x44px touch target for smaller sizes
84
+ // Uses a pseudo-element so visual size remains unchanged
85
+ &::after {
86
+ content: '';
87
+ position: absolute;
88
+ inset: 50% auto auto 50%;
89
+ min-width: 44px;
90
+ min-height: 44px;
91
+ width: 100%;
92
+ height: 100%;
93
+ transform: translate(-50%, -50%);
94
+ }
95
+
96
+ // States
97
+ &--disabled {
98
+ cursor: not-allowed;
99
+ opacity: var(--fui-opacity-disabled);
100
+ }
101
+
102
+ &--loading {
103
+ cursor: wait;
104
+
105
+ .fui-button__leading {
106
+ display: inline-flex;
107
+ align-items: center;
108
+ justify-content: center;
109
+ }
110
+
111
+ // Hide any user-supplied icon child except the spinner
112
+ > .fui-icon:not(.fui-button__spinner),
113
+ > fui-icon:not(.fui-button__spinner) {
114
+ display: none;
115
+ }
116
+ }
117
+
118
+ &--full-width {
119
+ width: 100%;
120
+ }
121
+
122
+ // Sizes
123
+ &--sm {
124
+ min-height: var(--fui-button-height-sm);
125
+ padding: calc(var(--fui-spacing-03) - 2px) var(--fui-spacing-03);
126
+ font-size: var(--fui-font-size-01);
127
+
128
+ &.fui-button--icon-only {
129
+ width: var(--fui-button-height-sm);
130
+ padding: calc(var(--fui-spacing-03) - 2px);
131
+ }
132
+
133
+ .fui-icon {
134
+ width: var(--fui-icon-size-sm);
135
+ height: var(--fui-icon-size-sm);
136
+ }
137
+ }
138
+
139
+ &--md {
140
+ min-height: var(--fui-button-height-md);
141
+ padding: var(--fui-spacing-03) var(--fui-spacing-05);
142
+ font-size: var(--fui-font-size-02);
143
+
144
+ &.fui-button--icon-only {
145
+ width: var(--fui-button-height-md);
146
+ padding: var(--fui-spacing-03);
147
+ }
148
+
149
+ .fui-icon {
150
+ width: var(--fui-icon-size-md);
151
+ height: var(--fui-icon-size-md);
152
+ }
153
+ }
154
+
155
+ &--lg {
156
+ min-height: var(--fui-button-height-lg);
157
+ padding: calc(var(--fui-spacing-04) - 2px) var(--fui-spacing-05);
158
+ font-size: var(--fui-font-size-03);
159
+
160
+ &.fui-button--icon-only {
161
+ width: var(--fui-button-height-lg);
162
+ padding: calc(var(--fui-spacing-04) - 2px);
163
+ }
164
+
165
+ .fui-icon {
166
+ width: var(--fui-icon-size-md);
167
+ height: var(--fui-icon-size-md);
168
+ }
169
+ }
170
+
171
+ &--xl {
172
+ min-height: var(--fui-button-height-xl);
173
+ padding: var(--fui-spacing-04) var(--fui-spacing-06);
174
+ font-size: var(--fui-font-size-03);
175
+
176
+ &.fui-button--icon-only {
177
+ width: var(--fui-button-height-xl);
178
+ padding: var(--fui-spacing-04);
179
+ }
180
+
181
+ .fui-icon {
182
+ width: var(--fui-icon-size-md);
183
+ height: var(--fui-icon-size-md);
184
+ }
185
+ }
186
+
187
+ &--2xl {
188
+ min-height: var(--fui-button-height-2xl);
189
+ padding: var(--fui-spacing-05) var(--fui-spacing-06);
190
+ font-size: var(--fui-font-size-03);
191
+
192
+ &.fui-button--icon-only {
193
+ width: var(--fui-button-height-2xl);
194
+ padding: var(--fui-spacing-05);
195
+ }
196
+
197
+ .fui-icon {
198
+ width: var(--fui-icon-size-md);
199
+ height: var(--fui-icon-size-md);
200
+ }
201
+ }
202
+
203
+ // Variant styles
204
+ // =============================================================================
205
+
206
+ // Primary — solid violet
207
+ &--primary {
208
+ background-color: var(--fui-primary-default);
209
+ color: var(--fui-primary-text);
210
+ border-color: transparent;
211
+ box-shadow: var(--fui-shadow-02);
212
+
213
+ &:hover:not(.fui-button--disabled) {
214
+ background-color: var(--fui-primary-hover);
215
+ box-shadow: var(--fui-shadow-03);
216
+ }
217
+
218
+ &:active:not(.fui-button--disabled) {
219
+ background-color: var(--fui-primary-hover);
220
+ box-shadow: none;
221
+ }
222
+ }
223
+
224
+ // Secondary — white bg with border
225
+ &--secondary {
226
+ background-color: var(--fui-surface-card);
227
+ color: var(--fui-text-primary);
228
+ box-shadow: inset 0 0 0 var(--fui-border-width-md) var(--fui-border-color);
229
+
230
+ &:hover:not(.fui-button--disabled) {
231
+ background-color: var(--fui-surface-02);
232
+ }
233
+
234
+ &:active:not(.fui-button--disabled) {
235
+ background-color: var(--fui-surface-02);
236
+ }
237
+ }
238
+
239
+ // Tertiary — neutral text, no bg/border
240
+ &--tertiary {
241
+ background-color: transparent;
242
+ color: var(--fui-tertiary-text);
243
+ border-color: transparent;
244
+
245
+ &:hover:not(.fui-button--disabled) {
246
+ background-color: var(--fui-tertiary-hover-bg);
247
+ }
248
+
249
+ &:active:not(.fui-button--disabled) {
250
+ background-color: var(--fui-tertiary-hover-bg);
251
+ }
252
+ }
253
+
254
+ // Tertiary-violet — violet text, no bg/border
255
+ &--tertiary-violet {
256
+ background-color: transparent;
257
+ color: var(--fui-tertiary-violet-text);
258
+ border-color: transparent;
259
+
260
+ &:hover:not(.fui-button--disabled) {
261
+ background-color: var(--fui-tertiary-violet-hover-bg);
262
+ }
263
+
264
+ &:active:not(.fui-button--disabled) {
265
+ background-color: var(--fui-tertiary-violet-hover-bg);
266
+ }
267
+ }
268
+
269
+ // Link — underlined violet text on hover
270
+ &--link {
271
+ background-color: transparent;
272
+ color: var(--fui-primary);
273
+
274
+ &:hover:not(.fui-button--disabled) {
275
+ text-decoration: underline;
276
+ }
277
+
278
+ &:active:not(.fui-button--disabled) {
279
+ text-decoration: underline;
280
+ }
281
+ }
282
+
283
+ // Destructive — solid red
284
+ &--destructive {
285
+ background-color: var(--fui-destructive-default);
286
+ color: var(--fui-destructive-text);
287
+ border-color: transparent;
288
+ box-shadow: var(--fui-shadow-02);
289
+
290
+ &:hover:not(.fui-button--disabled) {
291
+ background-color: var(--fui-destructive-hover);
292
+ box-shadow: var(--fui-shadow-03);
293
+ }
294
+
295
+ &:active:not(.fui-button--disabled) {
296
+ background-color: var(--fui-destructive-hover);
297
+ box-shadow: none;
298
+ }
299
+ }
300
+
301
+ // Icon adjustments
302
+ &--icon-only {
303
+ gap: 0;
304
+
305
+ .fui-icon {
306
+ margin: 0;
307
+ }
308
+ }
309
+ }
310
+
311
+ // Icon spacing within buttons
312
+ .fui-icon {
313
+ flex-shrink: 0;
314
+
315
+ &[fuiPrefix] {
316
+ margin-right: var(--fui-spacing-02);
317
+ }
318
+
319
+ &[fuiSuffix] {
320
+ margin-left: var(--fui-spacing-02);
321
+ }
322
+ }
323
+
324
+ // High contrast mode support
325
+ @media (prefers-contrast: more) {
326
+ .fui-button {
327
+ &--secondary {
328
+ border-width: 3px;
329
+ }
330
+
331
+ &:focus-visible {
332
+ outline-width: 3px;
333
+ }
334
+ }
335
+ }
336
+
337
+ // Keyframes
338
+ @keyframes fui-spin {
339
+ from {
340
+ transform: rotate(0deg);
341
+ }
342
+ to {
343
+ transform: rotate(360deg);
344
+ }
345
+ }
346
+
347
+ @keyframes fui-button-ripple {
348
+ to {
349
+ transform: scale(2.5);
350
+ opacity: 0;
351
+ }
352
+ }
353
+
354
+ // Print styles
355
+ @media print {
356
+ .fui-button {
357
+ &__spinner {
358
+ display: none !important;
359
+ }
360
+ }
361
+ }