@justin_evo/evo-ui 1.1.0 → 1.2.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 (80) hide show
  1. package/README.md +3 -3
  2. package/dist/TopNav/TopNav.d.ts +19 -0
  3. package/dist/declarations.d.ts +6 -6
  4. package/dist/evo-ui.css +1 -1
  5. package/dist/index.cjs.js +1 -1
  6. package/dist/index.es.js +3301 -3197
  7. package/package.json +52 -52
  8. package/src/Alert/Alert.tsx +49 -49
  9. package/src/AutoComplete/AutoComplete.tsx +810 -810
  10. package/src/Badge/Badge.tsx +53 -53
  11. package/src/Breadcrumb/Breadcrumb.tsx +53 -53
  12. package/src/Button/Button.tsx +125 -125
  13. package/src/Card/Card.tsx +257 -257
  14. package/src/Checkbox/Checkbox.tsx +59 -59
  15. package/src/CommandPalette/CommandPalette.tsx +185 -185
  16. package/src/Container/Container.tsx +31 -31
  17. package/src/Divider/Divider.tsx +31 -31
  18. package/src/Form/Form.tsx +185 -185
  19. package/src/Grid/Grid.tsx +66 -66
  20. package/src/ImageCropper/ImageCropper.tsx +911 -911
  21. package/src/Input/Input.tsx +74 -74
  22. package/src/Modal/Modal.tsx +77 -77
  23. package/src/Nav/Nav.tsx +708 -708
  24. package/src/Notification/Notification.tsx +1503 -1503
  25. package/src/Pagination/Pagination.tsx +76 -76
  26. package/src/Radio/Radio.tsx +69 -69
  27. package/src/RichTextArea/RichTextArea.tsx +886 -869
  28. package/src/Select/Select.tsx +515 -515
  29. package/src/Skeleton/Skeleton.tsx +70 -70
  30. package/src/Stack/Stack.tsx +52 -52
  31. package/src/Table/Table.tsx +335 -335
  32. package/src/Tabs/Tabs.tsx +90 -90
  33. package/src/Theme/ThemeProvider.tsx +253 -253
  34. package/src/Theme/ThemeToggle.tsx +79 -79
  35. package/src/Toggle/Toggle.tsx +48 -48
  36. package/src/Tooltip/Tooltip.tsx +38 -38
  37. package/src/TopNav/TopNav.tsx +1163 -994
  38. package/src/TreeSelect/TreeSelect.tsx +825 -825
  39. package/src/css/alert.module.scss +93 -93
  40. package/src/css/autocomplete.module.scss +416 -416
  41. package/src/css/badge.module.scss +82 -82
  42. package/src/css/base/_color.scss +159 -159
  43. package/src/css/base/_theme.scss +237 -237
  44. package/src/css/base/_variables.scss +161 -161
  45. package/src/css/breadcrumb.module.scss +50 -50
  46. package/src/css/button.module.scss +385 -385
  47. package/src/css/card.module.scss +217 -217
  48. package/src/css/checkbox.module.scss +123 -120
  49. package/src/css/commandpalette.module.scss +211 -211
  50. package/src/css/container.module.scss +18 -18
  51. package/src/css/divider.module.scss +41 -41
  52. package/src/css/form.module.scss +245 -245
  53. package/src/css/imagecropper.module.scss +397 -397
  54. package/src/css/input.module.scss +89 -89
  55. package/src/css/modal.module.scss +105 -105
  56. package/src/css/nav.module.scss +494 -494
  57. package/src/css/notification.module.scss +691 -691
  58. package/src/css/pagination.module.scss +63 -63
  59. package/src/css/radio.module.scss +89 -89
  60. package/src/css/richtextarea.module.scss +307 -307
  61. package/src/css/select.module.scss +525 -525
  62. package/src/css/skeleton.module.scss +30 -30
  63. package/src/css/table.module.scss +386 -386
  64. package/src/css/tabs.module.scss +63 -63
  65. package/src/css/theme-toggle.module.scss +83 -83
  66. package/src/css/toggle.module.scss +54 -54
  67. package/src/css/tooltip.module.scss +97 -97
  68. package/src/css/topnav.module.scss +568 -396
  69. package/src/css/treeselect.module.scss +558 -558
  70. package/src/css/utilities/_borders.scss +111 -111
  71. package/src/css/utilities/_colors.scss +66 -66
  72. package/src/css/utilities/_effects.scss +216 -216
  73. package/src/css/utilities/_layout.scss +181 -181
  74. package/src/css/utilities/_position.scss +75 -75
  75. package/src/css/utilities/_sizing.scss +138 -138
  76. package/src/css/utilities/_spacing.scss +99 -99
  77. package/src/css/utilities/_typography.scss +121 -121
  78. package/src/css/utilities/index.scss +24 -24
  79. package/src/declarations.d.ts +6 -6
  80. package/src/index.ts +60 -60
@@ -1,525 +1,525 @@
1
- @use 'base/variables' as *;
2
- @use 'base/color' as *;
3
-
4
- /* =====================================================================
5
- * EvoSelect — Custom dropdown built for dark, modern interfaces.
6
- * Combines design ideas from shadcn/Radix, Linear, Vercel, Apple HIG,
7
- * Material 3, GitHub, Stripe, Notion, Tailwind UI, and Untitled UI.
8
- * ===================================================================== */
9
-
10
- .field {
11
- display: inline-flex;
12
- flex-direction: column;
13
- gap: 0.4rem;
14
- font-family: $font-sans;
15
- min-width: 220px;
16
- }
17
-
18
- .fullWidth { width: 100%; }
19
-
20
- .disabled .trigger {
21
- opacity: 0.5;
22
- cursor: not-allowed;
23
- pointer-events: none;
24
- }
25
-
26
- .label {
27
- font-size: $text-sm;
28
- font-weight: 500;
29
- color: $color-text-primary;
30
- letter-spacing: -0.005em;
31
- }
32
-
33
- /* ---------------- Wrapper (positioning context for menu) ---------------- */
34
- .selectWrapper {
35
- position: relative;
36
- width: 100%;
37
- }
38
-
39
- /* ---------------- Trigger button ---------------- */
40
- .trigger {
41
- display: inline-flex;
42
- align-items: center;
43
- justify-content: space-between;
44
- gap: 0.5rem;
45
- width: 100%;
46
-
47
- background: $color-surface;
48
- border: 1px solid $color-border;
49
- border-radius: $radius-sm;
50
- color: $color-text-primary;
51
- font-family: $font-sans;
52
- font-size: $text-sm;
53
- line-height: 1.4;
54
- cursor: pointer;
55
- user-select: none;
56
- text-align: left;
57
- outline: none;
58
-
59
- transition:
60
- background-color $transition-fast,
61
- border-color $transition-fast,
62
- box-shadow $transition-fast,
63
- transform $transition-fast;
64
-
65
- &:hover:not(:disabled) {
66
- background: $color-surface-hover;
67
- border-color: $color-border-strong;
68
- }
69
-
70
- &:focus-visible {
71
- border-color: $evo-primary-color;
72
- box-shadow:
73
- 0 0 0 3px color-mix(in srgb, $evo-primary-color 18%, transparent),
74
- 0 1px 2px rgb(0 0 0 / 0.15);
75
- }
76
-
77
- &.open {
78
- border-color: $evo-primary-color;
79
- box-shadow:
80
- 0 0 0 3px color-mix(in srgb, $evo-primary-color 18%, transparent),
81
- 0 1px 2px rgb(0 0 0 / 0.15);
82
- }
83
-
84
- &.hasError {
85
- border-color: $evo-danger-color;
86
-
87
- &.open,
88
- &:focus-visible {
89
- box-shadow:
90
- 0 0 0 3px color-mix(in srgb, $evo-danger-color 18%, transparent),
91
- 0 1px 2px rgb(0 0 0 / 0.15);
92
- }
93
- }
94
-
95
- &:disabled {
96
- opacity: 0.5;
97
- cursor: not-allowed;
98
- }
99
- }
100
-
101
- /* ---------------- Sizes ---------------- */
102
- .sm {
103
- padding: 0.375rem 0.625rem;
104
- min-height: 32px;
105
- font-size: $text-xs;
106
- border-radius: $radius-sm;
107
- }
108
-
109
- .md {
110
- padding: 0.5rem 0.75rem;
111
- min-height: 38px;
112
- font-size: $text-sm;
113
- }
114
-
115
- .lg {
116
- padding: 0.625rem 0.875rem;
117
- min-height: 44px;
118
- font-size: $text-base;
119
- }
120
-
121
- /* ---------------- Trigger content ---------------- */
122
- .triggerValue,
123
- .triggerPlaceholder {
124
- display: inline-flex;
125
- align-items: center;
126
- gap: 0.5rem;
127
- min-width: 0;
128
- flex: 1;
129
- }
130
-
131
- /* When the trigger is rendering chips it needs vertical padding to breathe,
132
- * and the row must wrap when many chips are selected. */
133
- .triggerChips {
134
- padding-top: 0.3rem;
135
- padding-bottom: 0.3rem;
136
- height: auto;
137
- align-items: flex-start;
138
- }
139
-
140
- .chipRow {
141
- display: flex;
142
- flex-wrap: wrap;
143
- gap: 0.3rem;
144
- min-width: 0;
145
- flex: 1;
146
- align-items: center;
147
- }
148
-
149
- .chip {
150
- display: inline-flex;
151
- align-items: center;
152
- gap: 0.3rem;
153
- padding: 0.15rem 0.35rem 0.15rem 0.5rem;
154
- background: color-mix(in srgb, $evo-primary-color 14%, transparent);
155
- color: $color-text-primary;
156
- border-radius: 999px;
157
- font-size: $text-xs;
158
- font-weight: 500;
159
- line-height: 1.2;
160
- max-width: 100%;
161
- }
162
-
163
- .chipIcon {
164
- display: inline-flex;
165
- align-items: center;
166
- flex-shrink: 0;
167
- font-size: 1em;
168
- color: $color-text-secondary;
169
- }
170
-
171
- .chipLabel {
172
- overflow: hidden;
173
- text-overflow: ellipsis;
174
- white-space: nowrap;
175
- max-width: 12rem;
176
- }
177
-
178
- .chipRemove {
179
- display: inline-flex;
180
- align-items: center;
181
- justify-content: center;
182
- width: 18px;
183
- height: 18px;
184
- border-radius: 50%;
185
- color: $color-text-muted;
186
- cursor: pointer;
187
- flex-shrink: 0;
188
- transition: color $transition-fast, background-color $transition-fast;
189
-
190
- &:hover {
191
- color: $color-text-primary;
192
- background: color-mix(in srgb, $evo-primary-color 22%, transparent);
193
- }
194
- }
195
-
196
- .countMore {
197
- color: $color-text-muted;
198
- font-weight: 400;
199
- margin-left: 0.15rem;
200
- }
201
-
202
- .triggerPlaceholder {
203
- color: $color-text-muted;
204
- }
205
-
206
- .triggerText {
207
- overflow: hidden;
208
- text-overflow: ellipsis;
209
- white-space: nowrap;
210
- min-width: 0;
211
- }
212
-
213
- .triggerIcon {
214
- display: inline-flex;
215
- align-items: center;
216
- flex-shrink: 0;
217
- color: $color-text-secondary;
218
- font-size: 1em;
219
- }
220
-
221
- .triggerActions {
222
- display: inline-flex;
223
- align-items: center;
224
- gap: 0.25rem;
225
- flex-shrink: 0;
226
- }
227
-
228
- /* ---------------- Clear button ---------------- */
229
- .clearBtn {
230
- display: inline-flex;
231
- align-items: center;
232
- justify-content: center;
233
- width: 18px;
234
- height: 18px;
235
- border-radius: 50%;
236
- color: $color-text-muted;
237
- cursor: pointer;
238
- transition: color $transition-fast, background-color $transition-fast;
239
-
240
- &:hover {
241
- color: $color-text-primary;
242
- background: $color-surface-hover;
243
- }
244
- }
245
-
246
- /* ---------------- Chevron ---------------- */
247
- .chevron {
248
- display: inline-flex;
249
- align-items: center;
250
- justify-content: center;
251
- color: $color-text-muted;
252
- transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1), color $transition-fast;
253
- }
254
-
255
- .chevronOpen {
256
- transform: rotate(180deg);
257
- color: $evo-primary-color;
258
- }
259
-
260
- .trigger:hover:not(:disabled) .chevron {
261
- color: $color-text-secondary;
262
- }
263
-
264
- /* ===================================================================
265
- * Dropdown menu
266
- * =================================================================== */
267
- .menu {
268
- position: absolute;
269
- top: calc(100% + 6px);
270
- left: 0;
271
- right: 0;
272
- z-index: 100;
273
-
274
- background: $color-surface-elevated;
275
- border: 1px solid $color-border;
276
- border-radius: $radius-md;
277
- overflow: hidden;
278
-
279
- box-shadow:
280
- 0 16px 32px -12px rgb(0 0 0 / 0.35),
281
- 0 6px 12px -4px rgb(0 0 0 / 0.18);
282
-
283
- transform-origin: top center;
284
- animation: menuOpen 160ms cubic-bezier(0.16, 1, 0.3, 1);
285
- }
286
-
287
- @keyframes menuOpen {
288
- from {
289
- opacity: 0;
290
- transform: translateY(-6px) scale(0.97);
291
- }
292
- to {
293
- opacity: 1;
294
- transform: translateY(0) scale(1);
295
- }
296
- }
297
-
298
- /* ---------------- In-menu search row ---------------- */
299
- .searchRow {
300
- display: flex;
301
- align-items: center;
302
- gap: 0.5rem;
303
- padding: 0.5rem 0.75rem;
304
- border-bottom: 1px solid $color-border-subtle;
305
- background: $color-surface-sunken;
306
- }
307
-
308
- .searchIconWrap {
309
- display: inline-flex;
310
- color: $color-text-muted;
311
- flex-shrink: 0;
312
- }
313
-
314
- .searchInput {
315
- flex: 1;
316
- background: none;
317
- border: none;
318
- outline: none;
319
- font-family: $font-sans;
320
- font-size: $text-sm;
321
- color: $color-text-primary;
322
- caret-color: $evo-primary-color;
323
- padding: 0;
324
-
325
- &::placeholder { color: $color-text-muted; }
326
- }
327
-
328
- /* ---------------- Multi-select bulk actions row ---------------- */
329
- .bulkRow {
330
- display: flex;
331
- align-items: center;
332
- gap: 0.4rem;
333
- padding: 0.35rem 0.6rem;
334
- border-bottom: 1px solid $color-border-subtle;
335
- background: $color-surface-sunken;
336
- }
337
-
338
- .bulkBtn {
339
- padding: 0.2rem 0.5rem;
340
- background: transparent;
341
- border: 1px solid $color-border;
342
- border-radius: $radius-sm;
343
- color: $color-text-secondary;
344
- font-family: $font-sans;
345
- font-size: $text-xs;
346
- font-weight: 500;
347
- cursor: pointer;
348
- transition: background-color $transition-fast, color $transition-fast, border-color $transition-fast;
349
-
350
- &:hover:not(:disabled) {
351
- background: color-mix(in srgb, $evo-primary-color 10%, transparent);
352
- color: $evo-primary-color;
353
- border-color: $evo-primary-color;
354
- }
355
-
356
- &:disabled {
357
- opacity: 0.4;
358
- cursor: not-allowed;
359
- }
360
- }
361
-
362
- .bulkCount {
363
- margin-left: auto;
364
- font-size: $text-xs;
365
- color: $color-text-muted;
366
- font-variant-numeric: tabular-nums;
367
- }
368
-
369
- /* ---------------- Options list ---------------- */
370
- .list {
371
- max-height: 280px;
372
- overflow-y: auto;
373
- padding: 0.3rem;
374
-
375
- /* Theme-aware scrollbar (slim) */
376
- scrollbar-width: thin;
377
- scrollbar-color: $color-border-strong transparent;
378
-
379
- &::-webkit-scrollbar {
380
- width: 8px;
381
- }
382
- &::-webkit-scrollbar-track {
383
- background: transparent;
384
- }
385
- &::-webkit-scrollbar-thumb {
386
- background: $color-border-strong;
387
- border-radius: 4px;
388
- background-clip: padding-box;
389
- border: 2px solid transparent;
390
- }
391
- &::-webkit-scrollbar-thumb:hover {
392
- background: $color-text-muted;
393
- background-clip: padding-box;
394
- border: 2px solid transparent;
395
- }
396
- }
397
-
398
- .empty {
399
- padding: 1.5rem 0.75rem;
400
- text-align: center;
401
- color: $color-text-muted;
402
- font-size: $text-sm;
403
- }
404
-
405
- /* ---------------- Option ---------------- */
406
- .option {
407
- position: relative;
408
- display: flex;
409
- align-items: center;
410
- gap: 0.625rem;
411
- width: 100%;
412
- padding: 0.5rem 0.625rem;
413
- background: transparent;
414
- border: none;
415
- border-radius: 6px;
416
- color: $color-text-primary;
417
- font-family: $font-sans;
418
- font-size: $text-sm;
419
- text-align: left;
420
- cursor: pointer;
421
- transition: background-color 120ms ease, color 120ms ease;
422
-
423
- & + & { margin-top: 1px; }
424
- }
425
-
426
- .optionActive:not(.optionDisabled) {
427
- background: color-mix(in srgb, $evo-primary-color 12%, transparent);
428
- color: $color-text-primary;
429
- }
430
-
431
- .optionSelected {
432
- color: $evo-primary-color;
433
-
434
- .optionTitle { font-weight: 600; }
435
- }
436
-
437
- .optionDisabled {
438
- opacity: 0.4;
439
- cursor: not-allowed;
440
- }
441
-
442
- .optionIcon {
443
- display: inline-flex;
444
- align-items: center;
445
- justify-content: center;
446
- flex-shrink: 0;
447
- color: $color-text-secondary;
448
- font-size: 1em;
449
- width: 1.1rem;
450
- height: 1.1rem;
451
- }
452
-
453
- .optionLabel {
454
- display: flex;
455
- flex-direction: column;
456
- flex: 1;
457
- min-width: 0;
458
- gap: 1px;
459
- }
460
-
461
- .optionTitle {
462
- overflow: hidden;
463
- text-overflow: ellipsis;
464
- white-space: nowrap;
465
- font-weight: 500;
466
- }
467
-
468
- .optionDesc {
469
- font-size: $text-xs;
470
- color: $color-text-muted;
471
- font-weight: 400;
472
- overflow: hidden;
473
- text-overflow: ellipsis;
474
- white-space: nowrap;
475
- }
476
-
477
- .check {
478
- display: inline-flex;
479
- align-items: center;
480
- justify-content: center;
481
- width: 16px;
482
- height: 16px;
483
- color: $evo-primary-color;
484
- flex-shrink: 0;
485
- }
486
-
487
- /* ---------------- Multi-select inline checkbox ---------------- */
488
- .checkbox {
489
- display: inline-flex;
490
- align-items: center;
491
- justify-content: center;
492
- width: 16px;
493
- height: 16px;
494
- border: 1.5px solid $color-border-strong;
495
- border-radius: 4px;
496
- color: transparent;
497
- background: $color-surface;
498
- flex-shrink: 0;
499
- transition: background-color $transition-fast, border-color $transition-fast, color $transition-fast;
500
- }
501
-
502
- .checkboxChecked {
503
- background: $evo-primary-color;
504
- border-color: $evo-primary-color;
505
- color: $evo-primary-fg;
506
- }
507
-
508
- .option:hover:not(.optionDisabled) .checkbox:not(.checkboxChecked) {
509
- border-color: $evo-primary-color;
510
- }
511
-
512
- /* ---------------- Footer texts ---------------- */
513
- .errorText {
514
- font-size: $text-xs;
515
- color: $evo-danger-color;
516
- margin: 0;
517
- line-height: 1.4;
518
- }
519
-
520
- .helperText {
521
- font-size: $text-xs;
522
- color: $color-text-muted;
523
- margin: 0;
524
- line-height: 1.4;
525
- }
1
+ @use 'base/variables' as *;
2
+ @use 'base/color' as *;
3
+
4
+ /* =====================================================================
5
+ * EvoSelect — Custom dropdown built for dark, modern interfaces.
6
+ * Combines design ideas from shadcn/Radix, Linear, Vercel, Apple HIG,
7
+ * Material 3, GitHub, Stripe, Notion, Tailwind UI, and Untitled UI.
8
+ * ===================================================================== */
9
+
10
+ .field {
11
+ display: inline-flex;
12
+ flex-direction: column;
13
+ gap: 0.4rem;
14
+ font-family: $font-sans;
15
+ min-width: 220px;
16
+ }
17
+
18
+ .fullWidth { width: 100%; }
19
+
20
+ .disabled .trigger {
21
+ opacity: 0.5;
22
+ cursor: not-allowed;
23
+ pointer-events: none;
24
+ }
25
+
26
+ .label {
27
+ font-size: $text-sm;
28
+ font-weight: 500;
29
+ color: $color-text-primary;
30
+ letter-spacing: -0.005em;
31
+ }
32
+
33
+ /* ---------------- Wrapper (positioning context for menu) ---------------- */
34
+ .selectWrapper {
35
+ position: relative;
36
+ width: 100%;
37
+ }
38
+
39
+ /* ---------------- Trigger button ---------------- */
40
+ .trigger {
41
+ display: inline-flex;
42
+ align-items: center;
43
+ justify-content: space-between;
44
+ gap: 0.5rem;
45
+ width: 100%;
46
+
47
+ background: $color-surface;
48
+ border: 1px solid $color-border;
49
+ border-radius: $radius-sm;
50
+ color: $color-text-primary;
51
+ font-family: $font-sans;
52
+ font-size: $text-sm;
53
+ line-height: 1.4;
54
+ cursor: pointer;
55
+ user-select: none;
56
+ text-align: left;
57
+ outline: none;
58
+
59
+ transition:
60
+ background-color $transition-fast,
61
+ border-color $transition-fast,
62
+ box-shadow $transition-fast,
63
+ transform $transition-fast;
64
+
65
+ &:hover:not(:disabled) {
66
+ background: $color-surface-hover;
67
+ border-color: $color-border-strong;
68
+ }
69
+
70
+ &:focus-visible {
71
+ border-color: $evo-primary-color;
72
+ box-shadow:
73
+ 0 0 0 3px color-mix(in srgb, $evo-primary-color 18%, transparent),
74
+ 0 1px 2px rgb(0 0 0 / 0.15);
75
+ }
76
+
77
+ &.open {
78
+ border-color: $evo-primary-color;
79
+ box-shadow:
80
+ 0 0 0 3px color-mix(in srgb, $evo-primary-color 18%, transparent),
81
+ 0 1px 2px rgb(0 0 0 / 0.15);
82
+ }
83
+
84
+ &.hasError {
85
+ border-color: $evo-danger-color;
86
+
87
+ &.open,
88
+ &:focus-visible {
89
+ box-shadow:
90
+ 0 0 0 3px color-mix(in srgb, $evo-danger-color 18%, transparent),
91
+ 0 1px 2px rgb(0 0 0 / 0.15);
92
+ }
93
+ }
94
+
95
+ &:disabled {
96
+ opacity: 0.5;
97
+ cursor: not-allowed;
98
+ }
99
+ }
100
+
101
+ /* ---------------- Sizes ---------------- */
102
+ .sm {
103
+ padding: 0.375rem 0.625rem;
104
+ min-height: 32px;
105
+ font-size: $text-xs;
106
+ border-radius: $radius-sm;
107
+ }
108
+
109
+ .md {
110
+ padding: 0.5rem 0.75rem;
111
+ min-height: 38px;
112
+ font-size: $text-sm;
113
+ }
114
+
115
+ .lg {
116
+ padding: 0.625rem 0.875rem;
117
+ min-height: 44px;
118
+ font-size: $text-base;
119
+ }
120
+
121
+ /* ---------------- Trigger content ---------------- */
122
+ .triggerValue,
123
+ .triggerPlaceholder {
124
+ display: inline-flex;
125
+ align-items: center;
126
+ gap: 0.5rem;
127
+ min-width: 0;
128
+ flex: 1;
129
+ }
130
+
131
+ /* When the trigger is rendering chips it needs vertical padding to breathe,
132
+ * and the row must wrap when many chips are selected. */
133
+ .triggerChips {
134
+ padding-top: 0.3rem;
135
+ padding-bottom: 0.3rem;
136
+ height: auto;
137
+ align-items: flex-start;
138
+ }
139
+
140
+ .chipRow {
141
+ display: flex;
142
+ flex-wrap: wrap;
143
+ gap: 0.3rem;
144
+ min-width: 0;
145
+ flex: 1;
146
+ align-items: center;
147
+ }
148
+
149
+ .chip {
150
+ display: inline-flex;
151
+ align-items: center;
152
+ gap: 0.3rem;
153
+ padding: 0.15rem 0.35rem 0.15rem 0.5rem;
154
+ background: color-mix(in srgb, $evo-primary-color 14%, transparent);
155
+ color: $color-text-primary;
156
+ border-radius: 999px;
157
+ font-size: $text-xs;
158
+ font-weight: 500;
159
+ line-height: 1.2;
160
+ max-width: 100%;
161
+ }
162
+
163
+ .chipIcon {
164
+ display: inline-flex;
165
+ align-items: center;
166
+ flex-shrink: 0;
167
+ font-size: 1em;
168
+ color: $color-text-secondary;
169
+ }
170
+
171
+ .chipLabel {
172
+ overflow: hidden;
173
+ text-overflow: ellipsis;
174
+ white-space: nowrap;
175
+ max-width: 12rem;
176
+ }
177
+
178
+ .chipRemove {
179
+ display: inline-flex;
180
+ align-items: center;
181
+ justify-content: center;
182
+ width: 18px;
183
+ height: 18px;
184
+ border-radius: 50%;
185
+ color: $color-text-muted;
186
+ cursor: pointer;
187
+ flex-shrink: 0;
188
+ transition: color $transition-fast, background-color $transition-fast;
189
+
190
+ &:hover {
191
+ color: $color-text-primary;
192
+ background: color-mix(in srgb, $evo-primary-color 22%, transparent);
193
+ }
194
+ }
195
+
196
+ .countMore {
197
+ color: $color-text-muted;
198
+ font-weight: 400;
199
+ margin-left: 0.15rem;
200
+ }
201
+
202
+ .triggerPlaceholder {
203
+ color: $color-text-muted;
204
+ }
205
+
206
+ .triggerText {
207
+ overflow: hidden;
208
+ text-overflow: ellipsis;
209
+ white-space: nowrap;
210
+ min-width: 0;
211
+ }
212
+
213
+ .triggerIcon {
214
+ display: inline-flex;
215
+ align-items: center;
216
+ flex-shrink: 0;
217
+ color: $color-text-secondary;
218
+ font-size: 1em;
219
+ }
220
+
221
+ .triggerActions {
222
+ display: inline-flex;
223
+ align-items: center;
224
+ gap: 0.25rem;
225
+ flex-shrink: 0;
226
+ }
227
+
228
+ /* ---------------- Clear button ---------------- */
229
+ .clearBtn {
230
+ display: inline-flex;
231
+ align-items: center;
232
+ justify-content: center;
233
+ width: 18px;
234
+ height: 18px;
235
+ border-radius: 50%;
236
+ color: $color-text-muted;
237
+ cursor: pointer;
238
+ transition: color $transition-fast, background-color $transition-fast;
239
+
240
+ &:hover {
241
+ color: $color-text-primary;
242
+ background: $color-surface-hover;
243
+ }
244
+ }
245
+
246
+ /* ---------------- Chevron ---------------- */
247
+ .chevron {
248
+ display: inline-flex;
249
+ align-items: center;
250
+ justify-content: center;
251
+ color: $color-text-muted;
252
+ transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1), color $transition-fast;
253
+ }
254
+
255
+ .chevronOpen {
256
+ transform: rotate(180deg);
257
+ color: $evo-primary-color;
258
+ }
259
+
260
+ .trigger:hover:not(:disabled) .chevron {
261
+ color: $color-text-secondary;
262
+ }
263
+
264
+ /* ===================================================================
265
+ * Dropdown menu
266
+ * =================================================================== */
267
+ .menu {
268
+ position: absolute;
269
+ top: calc(100% + 6px);
270
+ left: 0;
271
+ right: 0;
272
+ z-index: 100;
273
+
274
+ background: $color-surface-elevated;
275
+ border: 1px solid $color-border;
276
+ border-radius: $radius-md;
277
+ overflow: hidden;
278
+
279
+ box-shadow:
280
+ 0 16px 32px -12px rgb(0 0 0 / 0.35),
281
+ 0 6px 12px -4px rgb(0 0 0 / 0.18);
282
+
283
+ transform-origin: top center;
284
+ animation: menuOpen 160ms cubic-bezier(0.16, 1, 0.3, 1);
285
+ }
286
+
287
+ @keyframes menuOpen {
288
+ from {
289
+ opacity: 0;
290
+ transform: translateY(-6px) scale(0.97);
291
+ }
292
+ to {
293
+ opacity: 1;
294
+ transform: translateY(0) scale(1);
295
+ }
296
+ }
297
+
298
+ /* ---------------- In-menu search row ---------------- */
299
+ .searchRow {
300
+ display: flex;
301
+ align-items: center;
302
+ gap: 0.5rem;
303
+ padding: 0.5rem 0.75rem;
304
+ border-bottom: 1px solid $color-border-subtle;
305
+ background: $color-surface-sunken;
306
+ }
307
+
308
+ .searchIconWrap {
309
+ display: inline-flex;
310
+ color: $color-text-muted;
311
+ flex-shrink: 0;
312
+ }
313
+
314
+ .searchInput {
315
+ flex: 1;
316
+ background: none;
317
+ border: none;
318
+ outline: none;
319
+ font-family: $font-sans;
320
+ font-size: $text-sm;
321
+ color: $color-text-primary;
322
+ caret-color: $evo-primary-color;
323
+ padding: 0;
324
+
325
+ &::placeholder { color: $color-text-muted; }
326
+ }
327
+
328
+ /* ---------------- Multi-select bulk actions row ---------------- */
329
+ .bulkRow {
330
+ display: flex;
331
+ align-items: center;
332
+ gap: 0.4rem;
333
+ padding: 0.35rem 0.6rem;
334
+ border-bottom: 1px solid $color-border-subtle;
335
+ background: $color-surface-sunken;
336
+ }
337
+
338
+ .bulkBtn {
339
+ padding: 0.2rem 0.5rem;
340
+ background: transparent;
341
+ border: 1px solid $color-border;
342
+ border-radius: $radius-sm;
343
+ color: $color-text-secondary;
344
+ font-family: $font-sans;
345
+ font-size: $text-xs;
346
+ font-weight: 500;
347
+ cursor: pointer;
348
+ transition: background-color $transition-fast, color $transition-fast, border-color $transition-fast;
349
+
350
+ &:hover:not(:disabled) {
351
+ background: color-mix(in srgb, $evo-primary-color 10%, transparent);
352
+ color: $evo-primary-color;
353
+ border-color: $evo-primary-color;
354
+ }
355
+
356
+ &:disabled {
357
+ opacity: 0.4;
358
+ cursor: not-allowed;
359
+ }
360
+ }
361
+
362
+ .bulkCount {
363
+ margin-left: auto;
364
+ font-size: $text-xs;
365
+ color: $color-text-muted;
366
+ font-variant-numeric: tabular-nums;
367
+ }
368
+
369
+ /* ---------------- Options list ---------------- */
370
+ .list {
371
+ max-height: 280px;
372
+ overflow-y: auto;
373
+ padding: 0.3rem;
374
+
375
+ /* Theme-aware scrollbar (slim) */
376
+ scrollbar-width: thin;
377
+ scrollbar-color: $color-border-strong transparent;
378
+
379
+ &::-webkit-scrollbar {
380
+ width: 8px;
381
+ }
382
+ &::-webkit-scrollbar-track {
383
+ background: transparent;
384
+ }
385
+ &::-webkit-scrollbar-thumb {
386
+ background: $color-border-strong;
387
+ border-radius: 4px;
388
+ background-clip: padding-box;
389
+ border: 2px solid transparent;
390
+ }
391
+ &::-webkit-scrollbar-thumb:hover {
392
+ background: $color-text-muted;
393
+ background-clip: padding-box;
394
+ border: 2px solid transparent;
395
+ }
396
+ }
397
+
398
+ .empty {
399
+ padding: 1.5rem 0.75rem;
400
+ text-align: center;
401
+ color: $color-text-muted;
402
+ font-size: $text-sm;
403
+ }
404
+
405
+ /* ---------------- Option ---------------- */
406
+ .option {
407
+ position: relative;
408
+ display: flex;
409
+ align-items: center;
410
+ gap: 0.625rem;
411
+ width: 100%;
412
+ padding: 0.5rem 0.625rem;
413
+ background: transparent;
414
+ border: none;
415
+ border-radius: 6px;
416
+ color: $color-text-primary;
417
+ font-family: $font-sans;
418
+ font-size: $text-sm;
419
+ text-align: left;
420
+ cursor: pointer;
421
+ transition: background-color 120ms ease, color 120ms ease;
422
+
423
+ & + & { margin-top: 1px; }
424
+ }
425
+
426
+ .optionActive:not(.optionDisabled) {
427
+ background: color-mix(in srgb, $evo-primary-color 12%, transparent);
428
+ color: $color-text-primary;
429
+ }
430
+
431
+ .optionSelected {
432
+ color: $evo-primary-color;
433
+
434
+ .optionTitle { font-weight: 600; }
435
+ }
436
+
437
+ .optionDisabled {
438
+ opacity: 0.4;
439
+ cursor: not-allowed;
440
+ }
441
+
442
+ .optionIcon {
443
+ display: inline-flex;
444
+ align-items: center;
445
+ justify-content: center;
446
+ flex-shrink: 0;
447
+ color: $color-text-secondary;
448
+ font-size: 1em;
449
+ width: 1.1rem;
450
+ height: 1.1rem;
451
+ }
452
+
453
+ .optionLabel {
454
+ display: flex;
455
+ flex-direction: column;
456
+ flex: 1;
457
+ min-width: 0;
458
+ gap: 1px;
459
+ }
460
+
461
+ .optionTitle {
462
+ overflow: hidden;
463
+ text-overflow: ellipsis;
464
+ white-space: nowrap;
465
+ font-weight: 500;
466
+ }
467
+
468
+ .optionDesc {
469
+ font-size: $text-xs;
470
+ color: $color-text-muted;
471
+ font-weight: 400;
472
+ overflow: hidden;
473
+ text-overflow: ellipsis;
474
+ white-space: nowrap;
475
+ }
476
+
477
+ .check {
478
+ display: inline-flex;
479
+ align-items: center;
480
+ justify-content: center;
481
+ width: 16px;
482
+ height: 16px;
483
+ color: $evo-primary-color;
484
+ flex-shrink: 0;
485
+ }
486
+
487
+ /* ---------------- Multi-select inline checkbox ---------------- */
488
+ .checkbox {
489
+ display: inline-flex;
490
+ align-items: center;
491
+ justify-content: center;
492
+ width: 16px;
493
+ height: 16px;
494
+ border: 1.5px solid $color-border-strong;
495
+ border-radius: 4px;
496
+ color: transparent;
497
+ background: $color-surface;
498
+ flex-shrink: 0;
499
+ transition: background-color $transition-fast, border-color $transition-fast, color $transition-fast;
500
+ }
501
+
502
+ .checkboxChecked {
503
+ background: $evo-primary-color;
504
+ border-color: $evo-primary-color;
505
+ color: $evo-primary-fg;
506
+ }
507
+
508
+ .option:hover:not(.optionDisabled) .checkbox:not(.checkboxChecked) {
509
+ border-color: $evo-primary-color;
510
+ }
511
+
512
+ /* ---------------- Footer texts ---------------- */
513
+ .errorText {
514
+ font-size: $text-xs;
515
+ color: $evo-danger-color;
516
+ margin: 0;
517
+ line-height: 1.4;
518
+ }
519
+
520
+ .helperText {
521
+ font-size: $text-xs;
522
+ color: $color-text-muted;
523
+ margin: 0;
524
+ line-height: 1.4;
525
+ }