minora 0.1.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.
@@ -0,0 +1,616 @@
1
+ /* ============================================================
2
+ ELEGANT MINIMALIST UI KIT — Select & Multiselect Components
3
+ select.css
4
+
5
+ ANATOMY — SINGLE SELECT
6
+ ─────────────────────────────────────────────────────────────
7
+ Structure:
8
+ <div class="select select-md" data-select>
9
+ <label class="input-label">Category</label>
10
+ <div class="select-trigger" role="combobox" aria-expanded="false">
11
+ <span class="select-placeholder">Choose...</span>
12
+ <span class="select-value" hidden>Selected value</span>
13
+ <svg class="select-chevron">...</svg>
14
+ </div>
15
+ <!-- Hidden native select for form submission -->
16
+ <select name="category" hidden></select>
17
+ <div class="select-dropdown" role="listbox">
18
+ <div class="select-search-wrapper">
19
+ <input class="select-search-input" type="text" placeholder="Search..." />
20
+ </div>
21
+ <div class="select-options">
22
+ <div class="select-option" role="option" data-value="a">
23
+ <span>Option A</span>
24
+ <svg class="select-check">...</svg>
25
+ </div>
26
+ <!-- Group separator -->
27
+ <div class="select-group-label">Group Name</div>
28
+ <div class="select-option" role="option" data-value="b">
29
+ <span>Option B</span>
30
+ <svg class="select-check">...</svg>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ <span class="input-helper">Helper text</span>
35
+ </div>
36
+
37
+ Class layers:
38
+ 1. .select → Wrapper, layout
39
+ 2. .select-{size} → Height, font-size
40
+ 3. .select-trigger → Visible button (fake select)
41
+ 4. .select-dropdown → Dropdown panel (hidden by default)
42
+ 5. .select-open → Modifier: dropdown is visible
43
+ 6. .select-disabled → Modifier: non-interactive
44
+ 7. .select-error → Modifier: error state
45
+ 8. .select-success → Modifier: success state
46
+ 9. .select-option → Individual option
47
+ 10. .select-option-selected → Selected option style
48
+ 11. .select-group-label → Group separator
49
+ 12. .select-chevron → Dropdown arrow (rotates on open)
50
+ ─────────────────────────────────────────────────────────────
51
+
52
+ ANATOMY — MULTISELECT
53
+ ─────────────────────────────────────────────────────────────
54
+ Structure:
55
+ <div class="multiselect multiselect-md" data-multiselect>
56
+ <label class="input-label">Tags</label>
57
+ <div class="select-trigger" role="combobox" aria-expanded="false">
58
+ <div class="multiselect-tags">
59
+ <span class="multiselect-tag" data-value="x">
60
+ <span class="multiselect-tag-label">Tag X</span>
61
+ <button class="multiselect-tag-remove" type="button">
62
+ <svg>×</svg>
63
+ </button>
64
+ </span>
65
+ <span class="multiselect-counter">+5</span>
66
+ <input class="multiselect-search-input" placeholder="Search..." />
67
+ </div>
68
+ <svg class="select-chevron">...</svg>
69
+ </div>
70
+ <select name="tags" multiple hidden></select>
71
+ <div class="select-dropdown" role="listbox">
72
+ <div class="multiselect-actions">
73
+ <button class="multiselect-select-all">Select All</button>
74
+ <button class="multiselect-clear-all">Clear All</button>
75
+ </div>
76
+ <!-- options same as single select -->
77
+ </div>
78
+ </div>
79
+ ─────────────────────────────────────────────────────────────
80
+ ============================================================ */
81
+
82
+ /* ═══════════════════════════════════════════════════════════
83
+ SELECT — Base wrapper
84
+ ═══════════════════════════════════════════════════════════ */
85
+
86
+ .select,
87
+ .multiselect {
88
+ display: flex;
89
+ flex-direction: column;
90
+ gap: var(--space-1-5);
91
+ width: 100%;
92
+ position: relative;
93
+ }
94
+
95
+ /* ═══════════════════════════════════════════════════════════
96
+ SELECT — Trigger (visible button)
97
+ ═══════════════════════════════════════════════════════════ */
98
+
99
+ .select-trigger {
100
+ display: flex;
101
+ align-items: center;
102
+ justify-content: space-between;
103
+ width: 100%;
104
+ border: var(--border-width) solid var(--border-color);
105
+ border-radius: var(--radius-sm);
106
+ background-color: var(--select-bg);
107
+ cursor: pointer;
108
+ user-select: none;
109
+ -webkit-user-select: none;
110
+ position: relative;
111
+ transition: border-color var(--duration-fast) var(--ease-in-out),
112
+ box-shadow var(--duration-fast) var(--ease-out);
113
+ overflow: hidden;
114
+ }
115
+
116
+ .select-trigger:hover:not(:disabled) {
117
+ border-color: var(--border-color-strong);
118
+ }
119
+
120
+ /* Chevron icon */
121
+ .select-chevron {
122
+ flex-shrink: 0;
123
+ width: var(--space-4);
124
+ height: var(--space-4);
125
+ margin-right: var(--space-3);
126
+ color: var(--input-icon-color);
127
+ transition: transform var(--duration-normal) var(--ease-in-out);
128
+ }
129
+
130
+ .select-chevron svg {
131
+ width: 100%;
132
+ height: 100%;
133
+ }
134
+
135
+ /* Rotate chevron on open */
136
+ .select-open .select-chevron {
137
+ transform: rotate(180deg);
138
+ }
139
+
140
+ /* Placeholder / value display */
141
+ .select-placeholder,
142
+ .select-value {
143
+ flex: 1;
144
+ min-width: 0;
145
+ overflow: hidden;
146
+ text-overflow: ellipsis;
147
+ white-space: nowrap;
148
+ font-family: var(--font-sans);
149
+ font-size: var(--text-sm);
150
+ line-height: var(--leading-none);
151
+ }
152
+
153
+ .select-placeholder {
154
+ color: var(--input-placeholder-color);
155
+ }
156
+
157
+ .select-value {
158
+ color: var(--input-text-color);
159
+ }
160
+
161
+ /* ═══════════════════════════════════════════════════════════
162
+ SELECT — Sizes
163
+ ═══════════════════════════════════════════════════════════ */
164
+
165
+ .select-sm .select-trigger {
166
+ min-height: var(--select-sm-height);
167
+ padding: var(--space-1) var(--space-3);
168
+ font-size: var(--text-sm);
169
+ }
170
+
171
+ .select-md .select-trigger {
172
+ min-height: var(--select-md-height);
173
+ padding: var(--space-2) var(--space-4);
174
+ font-size: var(--text-sm);
175
+ }
176
+
177
+ .select-lg .select-trigger {
178
+ min-height: var(--select-lg-height);
179
+ padding: var(--space-2-5) var(--space-4);
180
+ font-size: var(--text-base);
181
+ }
182
+
183
+ /* ═══════════════════════════════════════════════════════════
184
+ SELECT — Dropdown panel
185
+ ═══════════════════════════════════════════════════════════ */
186
+
187
+ .select-dropdown {
188
+ position: absolute;
189
+ top: calc(100% + var(--space-1));
190
+ left: 0;
191
+ width: 100%;
192
+ max-height: var(--select-dropdown-max-height);
193
+ background-color: var(--select-bg);
194
+ border: var(--border-width) solid var(--border-color);
195
+ border-radius: var(--radius-sm);
196
+ box-shadow: var(--select-dropdown-shadow);
197
+ z-index: var(--z-dropdown);
198
+ opacity: 0;
199
+ transform: translateY(-4px);
200
+ pointer-events: none;
201
+ transition: opacity var(--duration-normal) var(--ease-out),
202
+ transform var(--duration-normal) var(--ease-out);
203
+ overflow: hidden;
204
+ display: flex;
205
+ flex-direction: column;
206
+ }
207
+
208
+ /* Flip above if .select-flip-up is set by JS */
209
+ .select-flip-up {
210
+ top: auto;
211
+ bottom: calc(100% + var(--space-1));
212
+ transform: translateY(4px);
213
+ }
214
+
215
+ .select-open .select-dropdown {
216
+ opacity: 1;
217
+ transform: translateY(0);
218
+ pointer-events: auto;
219
+ }
220
+
221
+ .select-flip-up.select-open .select-dropdown {
222
+ transform: translateY(0);
223
+ }
224
+
225
+ /* Options container with scroll */
226
+ .select-options {
227
+ overflow-y: auto;
228
+ max-height: var(--select-dropdown-max-height);
229
+ padding: var(--space-1) 0;
230
+ }
231
+
232
+ /* ═══════════════════════════════════════════════════════════
233
+ SELECT — Search input inside dropdown
234
+ ═══════════════════════════════════════════════════════════ */
235
+
236
+ .select-search-wrapper {
237
+ padding: var(--space-2) var(--space-2) var(--space-1);
238
+ border-bottom: var(--border-width) solid var(--color-neutral-100);
239
+ }
240
+
241
+ .select-search-input {
242
+ width: 100%;
243
+ border: var(--border-width) solid var(--select-search-border);
244
+ border-radius: var(--radius-sm);
245
+ padding: var(--space-1-5) var(--space-2-5);
246
+ font-family: var(--font-sans);
247
+ font-size: var(--text-sm);
248
+ color: var(--input-text-color);
249
+ background-color: var(--color-neutral-50);
250
+ outline: none;
251
+ transition: border-color var(--duration-fast) var(--ease-in-out);
252
+ }
253
+
254
+ .select-search-input::placeholder {
255
+ color: var(--input-placeholder-color);
256
+ }
257
+
258
+ .select-search-input:focus {
259
+ border-color: var(--input-focus-color);
260
+ }
261
+
262
+ /* ═══════════════════════════════════════════════════════════
263
+ SELECT — Individual option
264
+ ═══════════════════════════════════════════════════════════ */
265
+
266
+ .select-option {
267
+ display: flex;
268
+ align-items: center;
269
+ justify-content: space-between;
270
+ gap: var(--space-2);
271
+ padding: var(--space-2) var(--space-3);
272
+ min-height: var(--select-option-height);
273
+ font-family: var(--font-sans);
274
+ font-size: var(--text-sm);
275
+ color: var(--input-text-color);
276
+ cursor: pointer;
277
+ transition: background-color var(--duration-fast) var(--ease-in-out),
278
+ color var(--duration-fast) var(--ease-in-out);
279
+ user-select: none;
280
+ -webkit-user-select: none;
281
+ }
282
+
283
+ .select-option:hover {
284
+ background-color: var(--select-option-hover-bg);
285
+ }
286
+
287
+ .select-option:active {
288
+ background-color: var(--select-option-active-bg);
289
+ }
290
+
291
+ /* Keyboard-focused option */
292
+ .select-option.is-focused {
293
+ background-color: var(--select-option-hover-bg);
294
+ outline: var(--focus-ring-width) solid var(--focus-ring-color);
295
+ outline-offset: 0;
296
+ }
297
+
298
+ /* Selected option */
299
+ .select-option.is-selected {
300
+ background-color: var(--select-option-active-bg);
301
+ color: var(--input-text-color);
302
+ font-weight: var(--font-medium);
303
+ }
304
+
305
+ /* Checkmark (hidden until selected) */
306
+ .select-check {
307
+ flex-shrink: 0;
308
+ width: var(--space-4);
309
+ height: var(--space-4);
310
+ color: var(--input-focus-color);
311
+ opacity: 0;
312
+ transform: scale(0.8);
313
+ transition: opacity var(--duration-fast) var(--ease-in-out),
314
+ transform var(--duration-fast) var(--ease-out);
315
+ }
316
+
317
+ .select-option.is-selected .select-check {
318
+ opacity: 1;
319
+ transform: scale(1);
320
+ }
321
+
322
+ /* Hidden option (filtered out by search) */
323
+ .select-option.is-hidden {
324
+ display: none;
325
+ }
326
+
327
+ /* Disabled option */
328
+ .select-option.is-disabled {
329
+ opacity: 0.4;
330
+ cursor: not-allowed;
331
+ pointer-events: none;
332
+ }
333
+
334
+ /* ═══════════════════════════════════════════════════════════
335
+ SELECT — Group label separator
336
+ ═══════════════════════════════════════════════════════════ */
337
+
338
+ .select-group-label {
339
+ padding: var(--space-1-5) var(--space-3);
340
+ font-family: var(--font-sans);
341
+ font-size: var(--text-xs);
342
+ font-weight: var(--font-semibold);
343
+ color: var(--select-group-label-color);
344
+ text-transform: uppercase;
345
+ letter-spacing: var(--tracking-wider);
346
+ border-top: var(--border-width) solid var(--color-neutral-100);
347
+ margin-top: var(--space-1);
348
+ }
349
+
350
+ .select-group-label:first-child {
351
+ margin-top: 0;
352
+ border-top: none;
353
+ }
354
+
355
+ /* ═══════════════════════════════════════════════════════════
356
+ SELECT — States
357
+ ═══════════════════════════════════════════════════════════ */
358
+
359
+ /* Disabled */
360
+ .select-disabled .select-trigger {
361
+ opacity: var(--input-disabled-opacity);
362
+ cursor: var(--input-disabled-cursor);
363
+ pointer-events: none;
364
+ }
365
+
366
+ .select-disabled .select-chevron {
367
+ opacity: 0.5;
368
+ }
369
+
370
+ /* Error */
371
+ .select-error .select-trigger {
372
+ border-color: var(--color-error);
373
+ }
374
+
375
+ .select-error.select-open .select-trigger {
376
+ border-color: var(--input-focus-error);
377
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--input-focus-error);
378
+ }
379
+
380
+ .select-error .select-chevron {
381
+ color: var(--color-error);
382
+ }
383
+
384
+ /* Success */
385
+ .select-success .select-trigger {
386
+ border-color: var(--color-success);
387
+ }
388
+
389
+ .select-success.select-open .select-trigger {
390
+ border-color: var(--input-focus-success);
391
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--input-focus-success);
392
+ }
393
+
394
+ .select-success .select-chevron {
395
+ color: var(--color-success);
396
+ }
397
+
398
+ /* ═══════════════════════════════════════════════════════════
399
+ MULTISELECT — Trigger with tags
400
+ ═══════════════════════════════════════════════════════════ */
401
+
402
+ .multiselect-tags {
403
+ display: flex;
404
+ align-items: center;
405
+ flex-wrap: wrap;
406
+ gap: var(--space-1);
407
+ flex: 1;
408
+ min-width: 0;
409
+ padding: var(--space-0-5) 0;
410
+ }
411
+
412
+ /* Tag inside multiselect */
413
+ .multiselect-tag {
414
+ display: inline-flex;
415
+ align-items: center;
416
+ gap: var(--space-0-5);
417
+ padding: var(--space-0-25) var(--space-1-5) var(--space-0-25) var(--space-2);
418
+ font-family: var(--font-sans);
419
+ font-size: var(--text-xs);
420
+ font-weight: var(--font-medium);
421
+ color: var(--color-neutral-700);
422
+ background-color: var(--color-neutral-100);
423
+ border-radius: var(--radius-sm);
424
+ line-height: var(--leading-none);
425
+ white-space: nowrap;
426
+ animation: tag-fade-in var(--duration-normal) var(--ease-out);
427
+ }
428
+
429
+ @keyframes tag-fade-in {
430
+ from {
431
+ opacity: 0;
432
+ transform: scale(0.9);
433
+ }
434
+ to {
435
+ opacity: 1;
436
+ transform: scale(1);
437
+ }
438
+ }
439
+
440
+ .multiselect-tag-label {
441
+ max-width: var(--space-32);
442
+ overflow: hidden;
443
+ text-overflow: ellipsis;
444
+ white-space: nowrap;
445
+ }
446
+
447
+ /* Remove button on tag */
448
+ .multiselect-tag-remove {
449
+ display: inline-flex;
450
+ align-items: center;
451
+ justify-content: center;
452
+ width: var(--space-3-5);
453
+ height: var(--space-3-5);
454
+ border: none;
455
+ border-radius: var(--radius-sm);
456
+ background: transparent;
457
+ color: var(--color-neutral-400);
458
+ cursor: pointer;
459
+ padding: 0;
460
+ transition: color var(--duration-fast) var(--ease-in-out),
461
+ background-color var(--duration-fast) var(--ease-in-out);
462
+ }
463
+
464
+ .multiselect-tag-remove:hover {
465
+ color: var(--color-neutral-700);
466
+ background-color: var(--color-neutral-200);
467
+ }
468
+
469
+ .multiselect-tag-remove svg {
470
+ width: var(--space-3);
471
+ height: var(--space-3);
472
+ }
473
+
474
+ /* Counter badge for overflow tags */
475
+ .multiselect-counter {
476
+ display: inline-flex;
477
+ align-items: center;
478
+ justify-content: center;
479
+ min-width: var(--select-counter-min-width);
480
+ height: var(--select-counter-height);
481
+ padding: 0 var(--space-1);
482
+ font-family: var(--font-sans);
483
+ font-size: var(--text-xs);
484
+ font-weight: var(--font-medium);
485
+ color: var(--color-neutral-600);
486
+ background-color: var(--select-counter-bg);
487
+ border-radius: var(--radius-pill);
488
+ line-height: var(--leading-none);
489
+ white-space: nowrap;
490
+ font-variant-numeric: tabular-nums;
491
+ -moz-font-feature-settings: 'tnum';
492
+ font-feature-settings: 'tnum';
493
+ }
494
+
495
+ /* Search input inside multiselect trigger */
496
+ .multiselect-search-input {
497
+ border: none;
498
+ outline: none;
499
+ background: transparent;
500
+ font-family: var(--font-sans);
501
+ font-size: var(--text-sm);
502
+ color: var(--input-text-color);
503
+ min-width: var(--select-search-min-width);
504
+ flex: 1;
505
+ padding: var(--space-1) 0;
506
+ line-height: var(--leading-none);
507
+ }
508
+
509
+ .multiselect-search-input::placeholder {
510
+ color: var(--input-placeholder-color);
511
+ }
512
+
513
+ /* ═══════════════════════════════════════════════════════════
514
+ MULTISELECT — Select All / Clear All actions
515
+ ═══════════════════════════════════════════════════════════ */
516
+
517
+ .multiselect-actions {
518
+ display: flex;
519
+ align-items: center;
520
+ justify-content: space-between;
521
+ padding: var(--space-1) var(--space-2);
522
+ border-bottom: var(--border-width) solid var(--color-neutral-100);
523
+ gap: var(--space-2);
524
+ }
525
+
526
+ .multiselect-actions button {
527
+ font-family: var(--font-sans);
528
+ font-size: var(--text-xs);
529
+ font-weight: var(--font-medium);
530
+ color: var(--input-focus-color);
531
+ background: transparent;
532
+ border: none;
533
+ cursor: pointer;
534
+ padding: var(--space-1) var(--space-1-5);
535
+ border-radius: var(--radius-sm);
536
+ transition: background-color var(--duration-fast) var(--ease-in-out),
537
+ color var(--duration-fast) var(--ease-in-out);
538
+ }
539
+
540
+ .multiselect-actions button:hover {
541
+ background-color: var(--color-accent-50);
542
+ }
543
+
544
+ .multiselect-actions button:active {
545
+ background-color: var(--color-accent-100);
546
+ }
547
+
548
+ .multiselect-actions .multiselect-clear-all {
549
+ color: var(--color-error);
550
+ }
551
+
552
+ .multiselect-actions .multiselect-clear-all:hover {
553
+ background-color: var(--color-error-light);
554
+ }
555
+
556
+ /* ═══════════════════════════════════════════════════════════
557
+ MULTISELECT — Sizes
558
+ ═══════════════════════════════════════════════════════════ */
559
+
560
+ .multiselect-sm .select-trigger {
561
+ min-height: var(--select-sm-height);
562
+ padding: var(--space-1) var(--space-3);
563
+ font-size: var(--text-sm);
564
+ }
565
+
566
+ .multiselect-md .select-trigger {
567
+ min-height: var(--select-md-height);
568
+ padding: var(--space-2) var(--space-4);
569
+ font-size: var(--text-sm);
570
+ }
571
+
572
+ .multiselect-lg .select-trigger {
573
+ min-height: var(--select-lg-height);
574
+ padding: var(--space-2-5) var(--space-4);
575
+ font-size: var(--text-base);
576
+ }
577
+
578
+ /* ═══════════════════════════════════════════════════════════
579
+ MULTISELECT — States
580
+ ═══════════════════════════════════════════════════════════ */
581
+
582
+ .select-disabled.multiselect .select-trigger {
583
+ opacity: var(--input-disabled-opacity);
584
+ cursor: var(--input-disabled-cursor);
585
+ pointer-events: none;
586
+ }
587
+
588
+ .select-error.multiselect .select-trigger {
589
+ border-color: var(--color-error);
590
+ }
591
+
592
+ .select-error.multiselect.select-open .select-trigger {
593
+ border-color: var(--input-focus-error);
594
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--input-focus-error);
595
+ }
596
+
597
+ .select-success.multiselect .select-trigger {
598
+ border-color: var(--color-success);
599
+ }
600
+
601
+ .select-success.multiselect.select-open .select-trigger {
602
+ border-color: var(--input-focus-success);
603
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--input-focus-success);
604
+ }
605
+
606
+ /* ═══════════════════════════════════════════════════════════
607
+ UTILITY: No results message
608
+ ═══════════════════════════════════════════════════════════ */
609
+
610
+ .select-no-results {
611
+ padding: var(--space-4) var(--space-3);
612
+ text-align: center;
613
+ font-size: var(--text-sm);
614
+ color: var(--color-neutral-400);
615
+ font-style: italic;
616
+ }