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,493 @@
1
+ /* ============================================================
2
+ ELEGANT MINIMALIST UI KIT — Button Component
3
+ button.css
4
+
5
+ ANATOMY OF A BUTTON
6
+ ─────────────────────────────────────────────────────────────
7
+ Structure:
8
+ <button class="btn btn-primary btn-md">
9
+ <!-- optional: <svg class="btn-spinner" ...> -->
10
+ <span class="btn-label">Label</span>
11
+ </button>
12
+
13
+ Class layers:
14
+ 1. .btn → Base reset, layout, typography, interaction
15
+ 2. .btn-{variant} → Color scheme (solid/outline/ghost/destructive)
16
+ 3. .btn-{size} → Padding, font-size, min-height
17
+ 4. .btn-icon → Icon-only modifier (circular)
18
+ 5. .btn-loading → Loading state (disables label, shows spinner)
19
+ 6. :disabled → Disabled visual state
20
+ 7. :focus-visible → Focus ring (accessible, not default outline)
21
+ 8. :active → Pressed state
22
+
23
+ Content model:
24
+ .btn
25
+ ├── .btn-spinner → SVG spinner (hidden by default)
26
+ └── .btn-label → Text or icon content
27
+ ─────────────────────────────────────────────────────────────
28
+ ============================================================ */
29
+
30
+ /* ──────────────────────────────────────────────────────────
31
+ 1. BASE BUTTON RESET & LAYOUT
32
+ ────────────────────────────────────────────────────────── */
33
+ .btn {
34
+ display: inline-flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ gap: var(--space-2);
38
+ position: relative;
39
+ font-family: var(--font-sans);
40
+ font-weight: var(--font-medium);
41
+ letter-spacing: var(--tracking-normal);
42
+ border: var(--border-width) solid transparent;
43
+ border-radius: var(--radius-sm);
44
+ cursor: pointer;
45
+ user-select: none;
46
+ -webkit-user-select: none;
47
+ white-space: nowrap;
48
+ line-height: var(--leading-none);
49
+ text-decoration: none;
50
+
51
+ /* Transisi */
52
+ transition: color var(--duration-fast) var(--ease-in-out),
53
+ background-color var(--duration-fast) var(--ease-in-out),
54
+ border-color var(--duration-fast) var(--ease-in-out),
55
+ box-shadow var(--duration-fast) var(--ease-out),
56
+ opacity var(--duration-fast) var(--ease-in-out),
57
+ transform var(--duration-fast) var(--ease-out);
58
+
59
+ /* Default: tidak ada outline/box-shadow */
60
+ outline: none;
61
+ box-shadow: none;
62
+
63
+ /* Prevent double-tap zoom di mobile */
64
+ touch-action: manipulation;
65
+
66
+ /* Reset default button styles */
67
+ appearance: none;
68
+ -webkit-appearance: none;
69
+ -moz-appearance: none;
70
+ }
71
+
72
+ /* Focus ring — visible, elegant, bukan default browser */
73
+ .btn:focus-visible {
74
+ outline: var(--focus-ring-width) solid var(--focus-ring-color);
75
+ outline-offset: var(--focus-ring-offset);
76
+ }
77
+
78
+ /* Active / pressed state */
79
+ .btn:active:not(:disabled):not(.btn-loading) {
80
+ transform: scale(var(--scale-active));
81
+ }
82
+
83
+ /* Disabled state */
84
+ .btn:disabled {
85
+ opacity: 0.5;
86
+ cursor: not-allowed;
87
+ pointer-events: none;
88
+ }
89
+
90
+ /* ──────────────────────────────────────────────────────────
91
+ 2. SPINNER (Loading state)
92
+ ────────────────────────────────────────────────────────── */
93
+ .btn-spinner {
94
+ display: none;
95
+ width: var(--space-4);
96
+ height: var(--space-4);
97
+ flex-shrink: 0;
98
+ animation: btn-spin 0.6s linear infinite;
99
+ }
100
+
101
+ .btn-loading .btn-spinner {
102
+ display: block;
103
+ }
104
+
105
+ .btn-loading .btn-label {
106
+ opacity: 0.7;
107
+ }
108
+
109
+ @keyframes btn-spin {
110
+ 0% { transform: rotate(0deg); }
111
+ 100% { transform: rotate(360deg); }
112
+ }
113
+
114
+ /* ──────────────────────────────────────────────────────────
115
+ 3. SIZE VARIANTS
116
+ ────────────────────────────────────────────────────────── */
117
+
118
+ /* Small */
119
+ .btn-sm {
120
+ min-height: var(--btn-sm-height);
121
+ padding: var(--space-1-5) var(--space-3);
122
+ font-size: var(--text-sm);
123
+ }
124
+
125
+ .btn-sm.btn-icon {
126
+ width: var(--btn-sm-height);
127
+ height: var(--btn-sm-height);
128
+ padding: var(--space-0);
129
+ }
130
+
131
+ .btn-sm .btn-spinner {
132
+ width: var(--space-3-5);
133
+ height: var(--space-3-5);
134
+ }
135
+
136
+ /* Medium (default) */
137
+ .btn-md {
138
+ min-height: var(--btn-md-height);
139
+ padding: var(--space-2) var(--space-4);
140
+ font-size: var(--text-sm);
141
+ }
142
+
143
+ .btn-md.btn-icon {
144
+ width: var(--btn-md-height);
145
+ height: var(--btn-md-height);
146
+ padding: var(--space-0);
147
+ }
148
+
149
+ .btn-md .btn-spinner {
150
+ width: var(--space-4);
151
+ height: var(--space-4);
152
+ }
153
+
154
+ /* Large */
155
+ .btn-lg {
156
+ min-height: var(--btn-lg-height);
157
+ padding: var(--space-2-5) var(--space-6);
158
+ font-size: var(--text-base);
159
+ }
160
+
161
+ .btn-lg.btn-icon {
162
+ width: var(--btn-lg-height);
163
+ height: var(--btn-lg-height);
164
+ padding: var(--space-0);
165
+ }
166
+
167
+ .btn-lg .btn-spinner {
168
+ width: var(--space-5);
169
+ height: var(--space-5);
170
+ }
171
+
172
+ /* ──────────────────────────────────────────────────────────
173
+ 4. VARIANT: SOLID
174
+ Background penuh, text kontras.
175
+ ────────────────────────────────────────────────────────── */
176
+
177
+ /* Solid — Primary (Accent Gold) */
178
+ .btn-primary {
179
+ color: var(--color-neutral-50);
180
+ background-color: var(--color-accent-500);
181
+ border-color: var(--color-accent-500);
182
+ }
183
+
184
+ .btn-primary:hover:not(:disabled) {
185
+ background-color: var(--color-accent-600);
186
+ border-color: var(--color-accent-600);
187
+ }
188
+
189
+ .btn-primary:focus-visible {
190
+ outline-color: var(--color-accent-500);
191
+ }
192
+
193
+ .btn-primary:active:not(:disabled) {
194
+ background-color: var(--color-accent-700);
195
+ border-color: var(--color-accent-700);
196
+ }
197
+
198
+ /* Solid — Secondary (Neutral) */
199
+ .btn-secondary {
200
+ color: var(--color-neutral-800);
201
+ background-color: var(--color-neutral-200);
202
+ border-color: var(--color-neutral-200);
203
+ }
204
+
205
+ .btn-secondary:hover:not(:disabled) {
206
+ background-color: var(--color-neutral-300);
207
+ border-color: var(--color-neutral-300);
208
+ }
209
+
210
+ .btn-secondary:focus-visible {
211
+ outline-color: var(--color-neutral-500);
212
+ }
213
+
214
+ .btn-secondary:active:not(:disabled) {
215
+ background-color: var(--color-neutral-400);
216
+ border-color: var(--color-neutral-400);
217
+ }
218
+
219
+ /* Solid — Neutral Dark (untuk emphasis lebih tinggi) */
220
+ .btn-neutral {
221
+ color: var(--color-neutral-50);
222
+ background-color: var(--color-neutral-800);
223
+ border-color: var(--color-neutral-800);
224
+ }
225
+
226
+ .btn-neutral:hover:not(:disabled) {
227
+ background-color: var(--color-neutral-700);
228
+ border-color: var(--color-neutral-700);
229
+ }
230
+
231
+ .btn-neutral:focus-visible {
232
+ outline-color: var(--color-neutral-600);
233
+ }
234
+
235
+ .btn-neutral:active:not(:disabled) {
236
+ background-color: var(--color-neutral-600);
237
+ border-color: var(--color-neutral-600);
238
+ }
239
+
240
+ /* ──────────────────────────────────────────────────────────
241
+ 5. VARIANT: OUTLINE
242
+ Border solid, background transparan.
243
+ ────────────────────────────────────────────────────────── */
244
+
245
+ /* Outline — Primary */
246
+ .btn-outline-primary {
247
+ color: var(--color-accent-600);
248
+ background-color: transparent;
249
+ border-color: var(--color-accent-400);
250
+ }
251
+
252
+ .btn-outline-primary:hover:not(:disabled) {
253
+ color: var(--color-neutral-50);
254
+ background-color: var(--color-accent-500);
255
+ border-color: var(--color-accent-500);
256
+ }
257
+
258
+ .btn-outline-primary:focus-visible {
259
+ outline-color: var(--color-accent-500);
260
+ }
261
+
262
+ .btn-outline-primary:active:not(:disabled) {
263
+ color: var(--color-neutral-50);
264
+ background-color: var(--color-accent-600);
265
+ border-color: var(--color-accent-600);
266
+ }
267
+
268
+ /* Outline — Secondary */
269
+ .btn-outline-secondary {
270
+ color: var(--color-neutral-700);
271
+ background-color: transparent;
272
+ border-color: var(--color-neutral-300);
273
+ }
274
+
275
+ .btn-outline-secondary:hover:not(:disabled) {
276
+ color: var(--color-neutral-800);
277
+ background-color: var(--color-neutral-100);
278
+ border-color: var(--color-neutral-400);
279
+ }
280
+
281
+ .btn-outline-secondary:focus-visible {
282
+ outline-color: var(--color-neutral-500);
283
+ }
284
+
285
+ .btn-outline-secondary:active:not(:disabled) {
286
+ color: var(--color-neutral-800);
287
+ background-color: var(--color-neutral-200);
288
+ border-color: var(--color-neutral-500);
289
+ }
290
+
291
+ /* Outline — Neutral */
292
+ .btn-outline-neutral {
293
+ color: var(--color-neutral-800);
294
+ background-color: transparent;
295
+ border-color: var(--color-neutral-400);
296
+ }
297
+
298
+ .btn-outline-neutral:hover:not(:disabled) {
299
+ color: var(--color-neutral-50);
300
+ background-color: var(--color-neutral-800);
301
+ border-color: var(--color-neutral-800);
302
+ }
303
+
304
+ .btn-outline-neutral:focus-visible {
305
+ outline-color: var(--color-neutral-600);
306
+ }
307
+
308
+ .btn-outline-neutral:active:not(:disabled) {
309
+ color: var(--color-neutral-50);
310
+ background-color: var(--color-neutral-700);
311
+ border-color: var(--color-neutral-700);
312
+ }
313
+
314
+ /* ──────────────────────────────────────────────────────────
315
+ 6. VARIANT: GHOST
316
+ Tidak ada border, hanya hover state.
317
+ ────────────────────────────────────────────────────────── */
318
+
319
+ /* Ghost — Primary */
320
+ .btn-ghost-primary {
321
+ color: var(--color-accent-600);
322
+ background-color: transparent;
323
+ border-color: transparent;
324
+ }
325
+
326
+ .btn-ghost-primary:hover:not(:disabled) {
327
+ color: var(--color-accent-700);
328
+ background-color: var(--color-accent-50);
329
+ }
330
+
331
+ .btn-ghost-primary:focus-visible {
332
+ outline-color: var(--color-accent-500);
333
+ }
334
+
335
+ .btn-ghost-primary:active:not(:disabled) {
336
+ color: var(--color-accent-800);
337
+ background-color: var(--color-accent-100);
338
+ }
339
+
340
+ /* Ghost — Secondary */
341
+ .btn-ghost-secondary {
342
+ color: var(--color-neutral-700);
343
+ background-color: transparent;
344
+ border-color: transparent;
345
+ }
346
+
347
+ .btn-ghost-secondary:hover:not(:disabled) {
348
+ color: var(--color-neutral-800);
349
+ background-color: var(--color-neutral-100);
350
+ }
351
+
352
+ .btn-ghost-secondary:focus-visible {
353
+ outline-color: var(--color-neutral-500);
354
+ }
355
+
356
+ .btn-ghost-secondary:active:not(:disabled) {
357
+ color: var(--color-neutral-900);
358
+ background-color: var(--color-neutral-200);
359
+ }
360
+
361
+ /* Ghost — Neutral */
362
+ .btn-ghost-neutral {
363
+ color: var(--color-neutral-600);
364
+ background-color: transparent;
365
+ border-color: transparent;
366
+ }
367
+
368
+ .btn-ghost-neutral:hover:not(:disabled) {
369
+ color: var(--color-neutral-800);
370
+ background-color: var(--color-neutral-100);
371
+ }
372
+
373
+ .btn-ghost-neutral:focus-visible {
374
+ outline-color: var(--color-neutral-500);
375
+ }
376
+
377
+ .btn-ghost-neutral:active:not(:disabled) {
378
+ color: var(--color-neutral-900);
379
+ background-color: var(--color-neutral-200);
380
+ }
381
+
382
+ /* ──────────────────────────────────────────────────────────
383
+ 7. VARIANT: DESTRUCTIVE
384
+ Untuk aksi berbahaya (delete, remove, dst).
385
+ ────────────────────────────────────────────────────────── */
386
+
387
+ /* Destructive — Solid */
388
+ .btn-destructive {
389
+ color: var(--color-neutral-50);
390
+ background-color: var(--color-error);
391
+ border-color: var(--color-error);
392
+ }
393
+
394
+ .btn-destructive:hover:not(:disabled) {
395
+ background-color: var(--color-error-dark);
396
+ border-color: var(--color-error-dark);
397
+ }
398
+
399
+ .btn-destructive:focus-visible {
400
+ outline-color: var(--color-error);
401
+ }
402
+
403
+ .btn-destructive:active:not(:disabled) {
404
+ background-color: var(--color-error-dark);
405
+ border-color: var(--color-error-dark);
406
+ }
407
+
408
+ /* Destructive — Outline */
409
+ .btn-destructive-outline {
410
+ color: var(--color-error);
411
+ background-color: transparent;
412
+ border-color: var(--color-error-border);
413
+ }
414
+
415
+ .btn-destructive-outline:hover:not(:disabled) {
416
+ color: var(--color-neutral-50);
417
+ background-color: var(--color-error);
418
+ border-color: var(--color-error);
419
+ }
420
+
421
+ .btn-destructive-outline:focus-visible {
422
+ outline-color: var(--color-error);
423
+ }
424
+
425
+ .btn-destructive-outline:active:not(:disabled) {
426
+ color: var(--color-neutral-50);
427
+ background-color: var(--color-error-dark);
428
+ border-color: var(--color-error-dark);
429
+ }
430
+
431
+ /* Destructive — Ghost */
432
+ .btn-destructive-ghost {
433
+ color: var(--color-error);
434
+ background-color: transparent;
435
+ border-color: transparent;
436
+ }
437
+
438
+ .btn-destructive-ghost:hover:not(:disabled) {
439
+ color: var(--color-error-dark);
440
+ background-color: var(--color-error-light);
441
+ }
442
+
443
+ .btn-destructive-ghost:focus-visible {
444
+ outline-color: var(--color-error);
445
+ }
446
+
447
+ .btn-destructive-ghost:active:not(:disabled) {
448
+ color: var(--color-error-dark);
449
+ background-color: var(--color-error-border);
450
+ }
451
+
452
+ /* ──────────────────────────────────────────────────────────
453
+ 8. ICON-ONLY BUTTON MODIFIER
454
+ Membuat button bulat (radius-md) untuk icon saja.
455
+ ────────────────────────────────────────────────────────── */
456
+ .btn-icon {
457
+ border-radius: var(--radius-md);
458
+ padding: var(--space-0);
459
+ }
460
+
461
+ /* ──────────────────────────────────────────────────────────
462
+ 9. LOADING STATE OVERRIDE
463
+ Saat loading, cursor tetap not-allowed.
464
+ ────────────────────────────────────────────────────────── */
465
+ .btn.btn-loading {
466
+ cursor: wait;
467
+ pointer-events: auto; /* tetap bisa di-render, tapi tidak trigger aksi */
468
+ }
469
+
470
+ .btn.btn-loading::after {
471
+ content: '';
472
+ position: absolute;
473
+ inset: 0;
474
+ z-index: var(--z-raised);
475
+ cursor: wait;
476
+ }
477
+
478
+ /* ═══════════════════════════════════════════════════════════
479
+ CONTEXTUAL: Button with embedded badge (for badge.html showcase)
480
+ ═══════════════════════════════════════════════════════════ */
481
+
482
+ .btn-with-badge {
483
+ display: inline-flex;
484
+ align-items: center;
485
+ gap: var(--space-2);
486
+ position: relative;
487
+ }
488
+
489
+ .btn-with-badge .badge {
490
+ position: static;
491
+ transform: none;
492
+ border: none;
493
+ }