@abstraks-dev/ui-library 1.0.1

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 (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +708 -0
  3. package/dist/__tests__/Anchor.test.js +145 -0
  4. package/dist/__tests__/ArrowRight.test.js +91 -0
  5. package/dist/__tests__/Avatar.test.js +123 -0
  6. package/dist/__tests__/Button.test.js +82 -0
  7. package/dist/__tests__/Card.test.js +198 -0
  8. package/dist/__tests__/CheckCircle.test.js +98 -0
  9. package/dist/__tests__/Checkbox.test.js +161 -0
  10. package/dist/__tests__/ChevronDown.test.js +73 -0
  11. package/dist/__tests__/Close.test.js +98 -0
  12. package/dist/__tests__/EditSquare.test.js +99 -0
  13. package/dist/__tests__/Error.test.js +74 -0
  14. package/dist/__tests__/Footer.test.js +66 -0
  15. package/dist/__tests__/Heading.test.js +227 -0
  16. package/dist/__tests__/Hero.test.js +74 -0
  17. package/dist/__tests__/Label.test.js +123 -0
  18. package/dist/__tests__/Loader.test.js +115 -0
  19. package/dist/__tests__/MenuHover.test.js +137 -0
  20. package/dist/__tests__/Paragraph.test.js +93 -0
  21. package/dist/__tests__/PlusCircle.test.js +99 -0
  22. package/dist/__tests__/Radio.test.js +153 -0
  23. package/dist/__tests__/Select.test.js +187 -0
  24. package/dist/__tests__/Tabs.test.js +162 -0
  25. package/dist/__tests__/TextArea.test.js +127 -0
  26. package/dist/__tests__/TextInput.test.js +181 -0
  27. package/dist/__tests__/Toggle.test.js +120 -0
  28. package/dist/__tests__/TrashX.test.js +99 -0
  29. package/dist/__tests__/useHeadingAccessibility.test.js +144 -0
  30. package/dist/components/Anchor.js +131 -0
  31. package/dist/components/Animation.js +129 -0
  32. package/dist/components/AnimationGroup.js +207 -0
  33. package/dist/components/AnimationToggle.js +216 -0
  34. package/dist/components/Avatar.js +153 -0
  35. package/dist/components/Button.js +218 -0
  36. package/dist/components/Card.js +222 -0
  37. package/dist/components/Checkbox.js +305 -0
  38. package/dist/components/Crud.js +564 -0
  39. package/dist/components/DragAndDrop.js +337 -0
  40. package/dist/components/Error.js +206 -0
  41. package/dist/components/Footer.js +99 -0
  42. package/dist/components/Form.js +412 -0
  43. package/dist/components/Header.js +372 -0
  44. package/dist/components/Heading.js +134 -0
  45. package/dist/components/Hero.js +181 -0
  46. package/dist/components/Label.js +256 -0
  47. package/dist/components/Loader.js +302 -0
  48. package/dist/components/MenuHover.js +114 -0
  49. package/dist/components/Paragraph.js +128 -0
  50. package/dist/components/Prompt.js +61 -0
  51. package/dist/components/Radio.js +254 -0
  52. package/dist/components/Select.js +422 -0
  53. package/dist/components/SideMenu.js +313 -0
  54. package/dist/components/Tabs.js +297 -0
  55. package/dist/components/TextArea.js +370 -0
  56. package/dist/components/TextInput.js +286 -0
  57. package/dist/components/Toggle.js +186 -0
  58. package/dist/components/crudFiles/CrudEditBase.js +150 -0
  59. package/dist/components/crudFiles/CrudViewBase.js +39 -0
  60. package/dist/components/crudFiles/crudDevelopment.js +118 -0
  61. package/dist/components/crudFiles/crudEditHandlers.js +50 -0
  62. package/dist/constants/animation.js +30 -0
  63. package/dist/icons/ArrowIcon.js +32 -0
  64. package/dist/icons/ArrowRight.js +33 -0
  65. package/dist/icons/CheckCircle.js +33 -0
  66. package/dist/icons/ChevronDown.js +28 -0
  67. package/dist/icons/Close.js +33 -0
  68. package/dist/icons/EditSquare.js +33 -0
  69. package/dist/icons/Ellipses.js +34 -0
  70. package/dist/icons/Hamburger.js +39 -0
  71. package/dist/icons/LoadingSpinner.js +42 -0
  72. package/dist/icons/PlusCircle.js +33 -0
  73. package/dist/icons/SaveIcon.js +32 -0
  74. package/dist/icons/TrashX.js +33 -0
  75. package/dist/icons/__tests__/CheckCircle.test.js +9 -0
  76. package/dist/icons/__tests__/ChevronDown.test.js +9 -0
  77. package/dist/icons/__tests__/Close.test.js +9 -0
  78. package/dist/icons/__tests__/EditSquare.test.js +9 -0
  79. package/dist/icons/__tests__/PlusCircle.test.js +9 -0
  80. package/dist/icons/__tests__/TrashX.test.js +9 -0
  81. package/dist/icons/index.js +89 -0
  82. package/dist/index.js +332 -0
  83. package/dist/setupTests.js +3 -0
  84. package/dist/styles/_variables.scss +286 -0
  85. package/dist/styles/anchor.scss +40 -0
  86. package/dist/styles/animation-accessibility.scss +96 -0
  87. package/dist/styles/animation-toggle.scss +233 -0
  88. package/dist/styles/animation.scss +3781 -0
  89. package/dist/styles/avatar.scss +285 -0
  90. package/dist/styles/button.scss +430 -0
  91. package/dist/styles/card.scss +210 -0
  92. package/dist/styles/checkbox.scss +160 -0
  93. package/dist/styles/crud.scss +474 -0
  94. package/dist/styles/dragAndDrop.scss +312 -0
  95. package/dist/styles/error.scss +232 -0
  96. package/dist/styles/footer.scss +58 -0
  97. package/dist/styles/form.scss +420 -0
  98. package/dist/styles/grid.scss +29 -0
  99. package/dist/styles/header.scss +276 -0
  100. package/dist/styles/heading.scss +118 -0
  101. package/dist/styles/hero.scss +185 -0
  102. package/dist/styles/htmlElements.scss +20 -0
  103. package/dist/styles/image.scss +9 -0
  104. package/dist/styles/label.scss +340 -0
  105. package/dist/styles/list-item.scss +5 -0
  106. package/dist/styles/loader.scss +354 -0
  107. package/dist/styles/logo.scss +19 -0
  108. package/dist/styles/main.css +9056 -0
  109. package/dist/styles/main.css.map +1 -0
  110. package/dist/styles/main.scss +0 -0
  111. package/dist/styles/menu-hover.scss +30 -0
  112. package/dist/styles/paragraph.scss +88 -0
  113. package/dist/styles/prompt.scss +51 -0
  114. package/dist/styles/radio.scss +202 -0
  115. package/dist/styles/select.scss +363 -0
  116. package/dist/styles/side-menu.scss +334 -0
  117. package/dist/styles/tabs.scss +540 -0
  118. package/dist/styles/text-area.scss +388 -0
  119. package/dist/styles/text-input.scss +171 -0
  120. package/dist/styles/toggle.scss +0 -0
  121. package/dist/styles/unordered-list.scss +8 -0
  122. package/dist/utils/ScrollHandler.js +30 -0
  123. package/dist/utils/accessibility.js +128 -0
  124. package/dist/utils/heroUtils.js +316 -0
  125. package/dist/utils/index.js +104 -0
  126. package/dist/utils/inputValidation.js +29 -0
  127. package/dist/utils/keyboardNavigation.js +536 -0
  128. package/dist/utils/labelUtils.js +708 -0
  129. package/dist/utils/loaderUtils.js +387 -0
  130. package/dist/utils/menuUtils.js +575 -0
  131. package/dist/utils/useHeadingAccessibility.js +298 -0
  132. package/dist/utils/useRadioGroup.js +260 -0
  133. package/dist/utils/useSelectAccessibility.js +426 -0
  134. package/dist/utils/useTabsAccessibility.js +278 -0
  135. package/dist/utils/useTextAreaAccessibility.js +255 -0
  136. package/dist/utils/useTextInputAccessibility.js +295 -0
  137. package/dist/utils/useTypographyAccessibility.js +168 -0
  138. package/dist/utils/useWindowSize.js +32 -0
  139. package/dist/utils/utils/ScrollHandler.js +26 -0
  140. package/dist/utils/utils/accessibility.js +133 -0
  141. package/dist/utils/utils/heroUtils.js +348 -0
  142. package/dist/utils/utils/index.js +9 -0
  143. package/dist/utils/utils/inputValidation.js +22 -0
  144. package/dist/utils/utils/keyboardNavigation.js +664 -0
  145. package/dist/utils/utils/labelUtils.js +772 -0
  146. package/dist/utils/utils/loaderUtils.js +436 -0
  147. package/dist/utils/utils/menuUtils.js +651 -0
  148. package/dist/utils/utils/useHeadingAccessibility.js +334 -0
  149. package/dist/utils/utils/useRadioGroup.js +311 -0
  150. package/dist/utils/utils/useSelectAccessibility.js +498 -0
  151. package/dist/utils/utils/useTabsAccessibility.js +316 -0
  152. package/dist/utils/utils/useTextAreaAccessibility.js +303 -0
  153. package/dist/utils/utils/useTextInputAccessibility.js +338 -0
  154. package/dist/utils/utils/useTypographyAccessibility.js +180 -0
  155. package/dist/utils/utils/useWindowSize.js +26 -0
  156. package/dist/utils/utils/validation.js +131 -0
  157. package/dist/utils/validation.js +139 -0
  158. package/package.json +90 -0
@@ -0,0 +1,420 @@
1
+ /* ==========================================================================
2
+ Form Component Styles
3
+ ========================================================================== */
4
+
5
+ @use 'variables' as *;
6
+
7
+ /* Base Form Styles
8
+ ========================================================================== */
9
+
10
+ .form {
11
+ display: block;
12
+ width: 100%;
13
+ max-width: 100%;
14
+ margin: 0;
15
+ padding: 0;
16
+ background: none;
17
+ border: none;
18
+ font-family: $font-family-body;
19
+ font-size: $font-size-base;
20
+ line-height: $line-height-base;
21
+ color: $text-color;
22
+ }
23
+
24
+ /* Form States
25
+ ========================================================================== */
26
+
27
+ .form--disabled {
28
+ opacity: 0.6;
29
+ pointer-events: none;
30
+ cursor: not-allowed;
31
+ }
32
+
33
+ .form--submitting {
34
+ position: relative;
35
+ pointer-events: none;
36
+ }
37
+
38
+ .form--submitting::before {
39
+ content: '';
40
+ position: absolute;
41
+ top: 0;
42
+ left: 0;
43
+ right: 0;
44
+ bottom: 0;
45
+ background: rgba(255, 255, 255, 0.8);
46
+ z-index: $z-index-base;
47
+ cursor: wait;
48
+ }
49
+
50
+ .form--has-errors {
51
+ border-color: $error-border;
52
+ }
53
+
54
+ /* Form Layout Utilities
55
+ ========================================================================== */
56
+
57
+ .form__fieldset {
58
+ border: 1px solid $border-color;
59
+ border-radius: $border-radius;
60
+ padding: $spacing-lg;
61
+ margin: 0 0 $spacing-lg 0;
62
+ min-width: 0;
63
+ background: $background-color;
64
+ }
65
+
66
+ .form__legend {
67
+ font-weight: $font-weight-semibold;
68
+ font-size: $font-size-lg;
69
+ color: $text-color;
70
+ padding: 0 $spacing-sm;
71
+ margin-bottom: $spacing-md;
72
+ }
73
+
74
+ .form__field-group {
75
+ margin-bottom: $spacing-lg;
76
+ }
77
+
78
+ .form__field-group:last-child {
79
+ margin-bottom: 0;
80
+ }
81
+
82
+ .form__field-row {
83
+ display: flex;
84
+ gap: $spacing-md;
85
+ align-items: flex-start;
86
+ flex-wrap: wrap;
87
+ }
88
+
89
+ .form__field-row > * {
90
+ flex: 1;
91
+ min-width: 0;
92
+ }
93
+
94
+ /* Form Actions
95
+ ========================================================================== */
96
+
97
+ .form__actions {
98
+ display: flex;
99
+ gap: $spacing-md;
100
+ align-items: center;
101
+ justify-content: flex-end;
102
+ flex-wrap: wrap;
103
+ margin-top: $spacing-xl;
104
+ padding-top: $spacing-lg;
105
+ border-top: 1px solid $border-color;
106
+ }
107
+
108
+ .form__actions--left {
109
+ justify-content: flex-start;
110
+ }
111
+
112
+ .form__actions--center {
113
+ justify-content: center;
114
+ }
115
+
116
+ .form__actions--spread {
117
+ justify-content: space-between;
118
+ }
119
+
120
+ /* Error Summary Styles
121
+ ========================================================================== */
122
+
123
+ .form__errors-summary {
124
+ background: $error-background;
125
+ border: 1px solid $error-border;
126
+ border-radius: $border-radius;
127
+ padding: $spacing-md $spacing-lg;
128
+ margin-bottom: $spacing-lg;
129
+ color: $error-text;
130
+ }
131
+
132
+ .form__errors-title {
133
+ font-weight: $font-weight-semibold;
134
+ font-size: $font-size-sm;
135
+ margin: 0 0 $spacing-sm 0;
136
+ color: $error-text;
137
+ }
138
+
139
+ .form__errors-list {
140
+ list-style: none;
141
+ margin: 0;
142
+ padding: 0;
143
+ }
144
+
145
+ .form__error-item {
146
+ font-size: $font-size-sm;
147
+ line-height: $line-height-tight;
148
+ margin-bottom: $spacing-xs;
149
+ color: $error-text;
150
+ }
151
+
152
+ .form__error-item:last-child {
153
+ margin-bottom: 0;
154
+ }
155
+
156
+ .form__error-item strong {
157
+ font-weight: $font-weight-semibold;
158
+ }
159
+
160
+ /* Loading States
161
+ ========================================================================== */
162
+
163
+ .form__loading-indicator {
164
+ display: flex;
165
+ align-items: center;
166
+ gap: $spacing-sm;
167
+ font-size: $font-size-sm;
168
+ color: $text-muted;
169
+ margin-top: $spacing-md;
170
+ }
171
+
172
+ .form__loading-spinner {
173
+ width: 16px;
174
+ height: 16px;
175
+ border: 2px solid $border-color;
176
+ border-top: 2px solid $primary-color;
177
+ border-radius: 50%;
178
+ animation: spin 1s linear infinite;
179
+ }
180
+
181
+ @keyframes spin {
182
+ 0% {
183
+ transform: rotate(0deg);
184
+ }
185
+ 100% {
186
+ transform: rotate(360deg);
187
+ }
188
+ }
189
+
190
+ /* Screen Reader Only Styles
191
+ ========================================================================== */
192
+
193
+ .sr-only {
194
+ position: absolute;
195
+ width: 1px;
196
+ height: 1px;
197
+ padding: 0;
198
+ margin: -1px;
199
+ overflow: hidden;
200
+ clip: rect(0, 0, 0, 0);
201
+ white-space: nowrap;
202
+ border: 0;
203
+ }
204
+
205
+ /* Responsive Design
206
+ ========================================================================== */
207
+
208
+ @media (max-width: 768px) {
209
+ .form__field-row {
210
+ flex-direction: column;
211
+ gap: $spacing-md;
212
+ }
213
+
214
+ .form__field-row > * {
215
+ flex: none;
216
+ }
217
+
218
+ .form__actions {
219
+ flex-direction: column;
220
+ align-items: stretch;
221
+ gap: $spacing-sm;
222
+ }
223
+
224
+ .form__actions--spread {
225
+ justify-content: stretch;
226
+ }
227
+
228
+ .form__fieldset {
229
+ padding: $spacing-md;
230
+ }
231
+ }
232
+
233
+ @media (max-width: 480px) {
234
+ .form__fieldset {
235
+ padding: $spacing-sm;
236
+ margin-bottom: $spacing-md;
237
+ }
238
+
239
+ .form__legend {
240
+ font-size: $font-size-base;
241
+ padding: 0 $spacing-xs;
242
+ }
243
+
244
+ .form__errors-summary {
245
+ padding: $spacing-sm $spacing-md;
246
+ }
247
+ }
248
+
249
+ /* High Contrast Mode Support
250
+ ========================================================================== */
251
+
252
+ @media (prefers-contrast: high) {
253
+ .form__fieldset {
254
+ border-width: 2px;
255
+ border-color: $text-color;
256
+ }
257
+
258
+ .form__errors-summary {
259
+ border-width: 2px;
260
+ border-color: $error-text;
261
+ background: $background-color;
262
+ }
263
+
264
+ .form--submitting::before {
265
+ background: $background-color;
266
+ opacity: 0.9;
267
+ }
268
+ }
269
+
270
+ /* Reduced Motion Support
271
+ ========================================================================== */
272
+
273
+ @media (prefers-reduced-motion: reduce) {
274
+ .form__loading-spinner {
275
+ animation: none;
276
+ }
277
+
278
+ .form--submitting::before {
279
+ transition: none;
280
+ }
281
+
282
+ // Scope animation overrides to form elements only for better performance
283
+ .form input,
284
+ .form textarea,
285
+ .form select,
286
+ .form button,
287
+ .form input::before,
288
+ .form input::after,
289
+ .form textarea::before,
290
+ .form textarea::after,
291
+ .form select::before,
292
+ .form select::after,
293
+ .form button::before,
294
+ .form button::after {
295
+ animation-duration: 0.01ms !important;
296
+ animation-iteration-count: 1 !important;
297
+ transition-duration: 0.01ms !important;
298
+ }
299
+ }
300
+
301
+ /* Focus Management
302
+ ========================================================================== */
303
+
304
+ /* Print Styles
305
+ ========================================================================== */
306
+
307
+ @media print {
308
+ .form--submitting::before {
309
+ display: none;
310
+ }
311
+
312
+ .form__loading-indicator,
313
+ .form__loading-spinner {
314
+ display: none;
315
+ }
316
+
317
+ .form__actions {
318
+ display: none;
319
+ }
320
+
321
+ .form__errors-summary {
322
+ border: 2px solid #000;
323
+ background: #fff;
324
+ color: #000;
325
+ }
326
+ }
327
+
328
+ /* Theme Variations
329
+ ========================================================================== */
330
+
331
+ .form--inline .form__field-group {
332
+ display: inline-flex;
333
+ align-items: center;
334
+ gap: $spacing-sm;
335
+ margin-right: $spacing-md;
336
+ margin-bottom: $spacing-sm;
337
+ }
338
+
339
+ .form--compact .form__field-group {
340
+ margin-bottom: $spacing-md;
341
+ }
342
+
343
+ .form--compact .form__fieldset {
344
+ padding: $spacing-md;
345
+ }
346
+
347
+ .form--compact .form__actions {
348
+ margin-top: $spacing-lg;
349
+ padding-top: $spacing-md;
350
+ }
351
+
352
+ /* Dark Theme Support
353
+ ========================================================================== */
354
+
355
+ @media (prefers-color-scheme: dark) {
356
+ .form--submitting::before {
357
+ background: rgba(0, 0, 0, 0.8);
358
+ }
359
+ }
360
+
361
+ /* Interactive States
362
+ ========================================================================== */
363
+
364
+ .form__fieldset:hover:not(.form--disabled) {
365
+ border-color: $border-color-hover;
366
+ }
367
+
368
+ .form__fieldset:focus-within {
369
+ border-color: $focus-ring-color;
370
+ box-shadow: 0 0 0 1px $focus-ring-color;
371
+ outline: none;
372
+ }
373
+
374
+ /* Validation States
375
+ ========================================================================== */
376
+
377
+ .form--has-errors .form__fieldset {
378
+ border-color: $error-border;
379
+ }
380
+
381
+ .form--valid .form__fieldset {
382
+ border-color: $success-border;
383
+ }
384
+
385
+ /* Form Layout Modifiers
386
+ ========================================================================== */
387
+
388
+ .form--horizontal .form__field-group {
389
+ display: grid;
390
+ grid-template-columns: 1fr 2fr;
391
+ gap: $spacing-md;
392
+ align-items: start;
393
+ }
394
+
395
+ .form--stacked .form__field-group {
396
+ display: flex;
397
+ flex-direction: column;
398
+ gap: $spacing-xs;
399
+ }
400
+
401
+ /* Utility Classes
402
+ ========================================================================== */
403
+
404
+ .form__help-text {
405
+ font-size: $font-size-sm;
406
+ color: $text-muted;
407
+ margin-top: $spacing-xs;
408
+ line-height: $line-height-tight;
409
+ }
410
+
411
+ .form__required-indicator {
412
+ color: $error-text;
413
+ font-weight: $font-weight-bold;
414
+ }
415
+
416
+ .form__optional-indicator {
417
+ color: $text-muted;
418
+ font-size: $font-size-sm;
419
+ font-style: italic;
420
+ }
@@ -0,0 +1,29 @@
1
+
2
+ .container {
3
+ margin-right: auto;
4
+ margin-left: auto;
5
+ }
6
+
7
+ *,
8
+ :after,
9
+ :before {
10
+ box-sizing: border-box
11
+ }
12
+
13
+ @media (min-width: 768px) {
14
+ .container {
15
+ width: 750px
16
+ }
17
+ }
18
+
19
+ @media (min-width: 992px) {
20
+ .container {
21
+ width: 970px
22
+ }
23
+ }
24
+
25
+ @media (min-width: 1200px) {
26
+ .container {
27
+ width: 1170px
28
+ }
29
+ }
@@ -0,0 +1,276 @@
1
+ @use 'variables' as *;
2
+
3
+ .header {
4
+ width: 100%;
5
+ display: flex;
6
+ align-items: center;
7
+ flex-direction: row;
8
+ padding: 15px;
9
+ background-color: $color-white;
10
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
11
+
12
+ // Improve focus indicators for accessibility
13
+ *:focus {
14
+ outline: 2px solid $focus-color;
15
+ outline-offset: 2px;
16
+ }
17
+
18
+ // High contrast mode support
19
+ @media (prefers-contrast: high) {
20
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.3);
21
+ border-bottom: 1px solid $color-black;
22
+ }
23
+
24
+ .container-large {
25
+ width: 100%;
26
+ display: flex;
27
+ flex-direction: row;
28
+ align-items: center;
29
+
30
+ .navigation {
31
+ margin-left: auto;
32
+ }
33
+ }
34
+
35
+ .container-mobile {
36
+ width: 100%;
37
+ display: flex;
38
+ align-items: center;
39
+
40
+ .side-menu {
41
+ width: 50%;
42
+ display: inline-flex;
43
+ justify-content: flex-end;
44
+
45
+ .overlay {
46
+ background-color: $color-white;
47
+ }
48
+
49
+ .menu {
50
+ .wrapper-content {
51
+ display: flex;
52
+ flex-direction: column;
53
+ width: 100%;
54
+ background-color: $color-white;
55
+
56
+ .menu-item {
57
+ margin: 15px 0;
58
+ }
59
+ }
60
+
61
+ .wrapper-header {
62
+ background-color: $color-white;
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ // Mobile menu trigger button styling
69
+ .mobile-menu-trigger,
70
+ .mobile-menu-close {
71
+ background: none;
72
+ border: none;
73
+ padding: 8px;
74
+ cursor: pointer;
75
+ border-radius: 4px;
76
+ transition: background-color 0.2s ease;
77
+
78
+ &:hover {
79
+ background-color: rgba(0, 0, 0, 0.05);
80
+ }
81
+
82
+ &:focus {
83
+ outline: 2px solid $focus-color;
84
+ outline-offset: 2px;
85
+ }
86
+ }
87
+
88
+ .navigation {
89
+ @media #{$medium} {
90
+ display: inline-flex;
91
+ justify-content: flex-end;
92
+ }
93
+
94
+ .unordered-list {
95
+ display: flex;
96
+ flex-direction: column;
97
+
98
+ @media #{$medium} {
99
+ display: inline-flex;
100
+ flex-direction: row;
101
+ align-items: center;
102
+ justify-content: flex-end;
103
+ padding: 0;
104
+ margin: 0;
105
+ }
106
+
107
+ &.auth-menu {
108
+ border-top: 1px solid $gray-200;
109
+
110
+ @media #{$medium} {
111
+ border-left: 1px solid $gray-200;
112
+ border-top: none;
113
+ }
114
+
115
+ .head {
116
+ .ellipses {
117
+ background: none;
118
+ border: none;
119
+ padding: 4px;
120
+ cursor: pointer;
121
+ border-radius: 50%;
122
+ position: relative;
123
+ transition: background-color 0.2s ease;
124
+
125
+ &:hover {
126
+ background-color: rgba(0, 0, 0, 0.05);
127
+ }
128
+
129
+ &:focus {
130
+ outline: 2px solid $focus-color;
131
+ outline-offset: 2px;
132
+ }
133
+
134
+ &[aria-expanded='true'] {
135
+ background-color: rgba(0, 0, 0, 0.1);
136
+ }
137
+
138
+ .ellipses-content {
139
+ display: flex;
140
+ z-index: $z-index-dropdown;
141
+ position: absolute;
142
+ width: 200px;
143
+ right: 0;
144
+ top: 100%;
145
+ margin-top: 8px;
146
+ border-radius: 8px;
147
+ box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 5px -3px,
148
+ rgba(0, 0, 0, 0.14) 0px 8px 10px 1px,
149
+ rgba(0, 0, 0, 0.12) 0px 3px 14px 2px;
150
+ background-color: $color-white;
151
+ border: 1px solid rgba(0, 0, 0, 0.1);
152
+ padding: 8px 0;
153
+ opacity: 1;
154
+ transform: none;
155
+ transition: opacity 226ms cubic-bezier(0.4, 0, 0.2, 1),
156
+ transform 151ms cubic-bezier(0.4, 0, 0.2, 1);
157
+
158
+ // High contrast mode
159
+ @media (prefers-contrast: high) {
160
+ border: 2px solid $color-black;
161
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);
162
+ }
163
+
164
+ .unordered-list {
165
+ align-items: flex-start;
166
+ flex-direction: column;
167
+ width: 100%;
168
+
169
+ .list-item {
170
+ width: 100%;
171
+ padding: 0;
172
+
173
+ [role='menuitem'] {
174
+ display: block;
175
+ padding: 12px 16px;
176
+ width: 100%;
177
+ color: $color-font-body;
178
+ text-decoration: none;
179
+ transition: background-color 0.2s ease;
180
+
181
+ &:hover,
182
+ &:focus {
183
+ background-color: rgba(0, 0, 0, 0.05);
184
+ color: $color-primary;
185
+ }
186
+
187
+ &:focus {
188
+ outline: 2px solid $focus-color;
189
+ outline-offset: -2px;
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
197
+ }
198
+
199
+ .list-item {
200
+ display: flex;
201
+
202
+ @media #{$medium} {
203
+ display: inline-flex;
204
+ padding: 0 15px;
205
+ }
206
+
207
+ // Menu item styling
208
+ [role='menuitem'] {
209
+ display: inline-block;
210
+ padding: 8px 12px;
211
+ border-radius: 4px;
212
+ transition: background-color 0.2s ease, color 0.2s ease;
213
+
214
+ &:focus {
215
+ outline: 2px solid $focus-color;
216
+ outline-offset: 2px;
217
+ }
218
+ }
219
+ }
220
+ }
221
+
222
+ .anchor {
223
+ color: $gray-600;
224
+ text-decoration: none;
225
+ transition: color 0.2s ease;
226
+
227
+ &:hover {
228
+ color: $color-font-body;
229
+ }
230
+
231
+ &:focus {
232
+ color: $color-primary;
233
+ outline: 2px solid $focus-color;
234
+ outline-offset: 2px;
235
+ }
236
+
237
+ // High contrast mode
238
+ @media (prefers-contrast: high) {
239
+ &:hover,
240
+ &:focus {
241
+ color: $color-black;
242
+ text-decoration: underline;
243
+ }
244
+ }
245
+ }
246
+ }
247
+
248
+ // Responsive breakpoint adjustments
249
+ @media #{$large} {
250
+ padding: 20px;
251
+
252
+ .container-large {
253
+ max-width: 1200px;
254
+ margin: 0 auto;
255
+ }
256
+ }
257
+
258
+ @media #{$xlarge} {
259
+ padding: 24px;
260
+
261
+ .container-large {
262
+ max-width: 1400px;
263
+ }
264
+ }
265
+
266
+ // Reduce motion for accessibility
267
+ @media (prefers-reduced-motion: reduce) {
268
+ *,
269
+ *::before,
270
+ *::after {
271
+ animation-duration: 0.01ms !important;
272
+ animation-iteration-count: 1 !important;
273
+ transition-duration: 0.01ms !important;
274
+ }
275
+ }
276
+ }