mithril-materialized 3.11.0 → 3.13.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,610 @@
1
+ @use 'sass:color';
2
+ @use "variables";
3
+
4
+ /* Likert Scale Component
5
+ ========================================================================== */
6
+
7
+ // Likert scale component variables
8
+ $likert-color-primary: var(--mm-primary-color, variables.$primary-color) !default;
9
+ $likert-color-radio-empty: var(--mm-text-hint, #9e9e9e) !default;
10
+ $likert-color-radio-checked: var(--mm-primary-color, variables.$primary-color) !default;
11
+ $likert-color-disabled: var(--mm-text-disabled, rgba(0, 0, 0, 0.38)) !default;
12
+ $likert-color-text: var(--mm-text-primary, rgba(0, 0, 0, 0.87)) !default;
13
+ $likert-color-text-secondary: var(--mm-text-secondary, rgba(0, 0, 0, 0.54)) !default;
14
+
15
+ // Size variants for radio buttons
16
+ $likert-radio-size-small: 16px !default;
17
+ $likert-radio-size-medium: 20px !default;
18
+ $likert-radio-size-large: 24px !default;
19
+
20
+ // Text size variants
21
+ $likert-text-size-small: 14px !default;
22
+ $likert-text-size-medium: 16px !default;
23
+ $likert-text-size-large: 18px !default;
24
+
25
+ // Density spacing (gap between items)
26
+ $likert-gap-compact: 4px !default;
27
+ $likert-gap-standard: 10px !default;
28
+ $likert-gap-comfortable: 16px !default;
29
+
30
+ // Tooltip
31
+ $likert-tooltip-bg: rgba(0, 0, 0, 0.8) !default;
32
+ $likert-tooltip-text: white !default;
33
+
34
+ // Container
35
+ .likert-scale {
36
+ position: relative;
37
+ display: flex;
38
+ align-items: center;
39
+ outline: none;
40
+ gap: 16px;
41
+ transition: all 0.2s ease;
42
+ margin-bottom: 20px;
43
+
44
+ // Focus state
45
+ &:focus-visible {
46
+ outline: 2px solid var(--mm-primary-color, #{variables.$primary-color});
47
+ outline-offset: 2px;
48
+ border-radius: 4px;
49
+ }
50
+
51
+ // Read-only state
52
+ &--readonly {
53
+ .likert-scale__item {
54
+ cursor: default;
55
+ }
56
+ }
57
+
58
+ // Disabled state
59
+ &--disabled {
60
+ opacity: 0.6;
61
+
62
+ .likert-scale__item {
63
+ cursor: not-allowed;
64
+ }
65
+ }
66
+
67
+ // Aligned layout for multi-question surveys
68
+ &--aligned {
69
+ .likert-scale__question-label {
70
+ min-width: 250px;
71
+ max-width: 50%;
72
+ }
73
+
74
+ .likert-scale__scale-container {
75
+ flex: 0 0 auto;
76
+ min-width: 300px;
77
+ }
78
+ }
79
+ }
80
+
81
+ // Question label (left side)
82
+ .likert-scale__question-label {
83
+ flex: 1 1 auto;
84
+ display: flex;
85
+ flex-direction: column;
86
+ min-width: 0; // Allow text wrapping
87
+
88
+ span {
89
+ font-size: 1rem;
90
+ font-weight: 400;
91
+ color: $likert-color-text;
92
+ line-height: 1.4;
93
+ word-wrap: break-word;
94
+ }
95
+ }
96
+
97
+ .likert-scale__description {
98
+ font-size: 0.875rem;
99
+ color: $likert-color-text-secondary;
100
+ margin-top: 4px;
101
+ line-height: 1.3;
102
+ }
103
+
104
+ // Scale container (right side with fixed width)
105
+ .likert-scale__scale-container {
106
+ flex: 0 0 auto;
107
+ display: flex;
108
+ flex-direction: column;
109
+ align-items: stretch;
110
+ }
111
+
112
+ // Scale items row
113
+ .likert-scale__scale {
114
+ display: flex;
115
+ align-items: flex-start;
116
+ justify-content: space-between;
117
+ position: relative;
118
+ }
119
+
120
+ // Individual scale item
121
+ .likert-scale__item {
122
+ display: flex;
123
+ flex-direction: column;
124
+ align-items: center;
125
+ justify-content: flex-start;
126
+ position: relative;
127
+ cursor: pointer;
128
+ transition: transform 0.15s ease;
129
+ flex: 1 1 0;
130
+
131
+ &:hover:not(.likert-scale__item--disabled):not(.likert-scale__item--readonly) {
132
+ transform: scale(1.05);
133
+ }
134
+
135
+ // Checked state - radio button styling handled by label pseudo-elements
136
+ &--checked {
137
+ .likert-scale__label::before {
138
+ border-color: $likert-color-radio-checked;
139
+ }
140
+ .likert-scale__label::after {
141
+ background-color: $likert-color-radio-checked;
142
+ transform: scale(1);
143
+ }
144
+ }
145
+
146
+ // Disabled state
147
+ &--disabled {
148
+ cursor: not-allowed;
149
+ opacity: 0.6;
150
+
151
+ .likert-scale__label::before {
152
+ border-color: $likert-color-disabled;
153
+ }
154
+ }
155
+
156
+ // Readonly state
157
+ &--readonly {
158
+ cursor: default;
159
+ }
160
+ }
161
+
162
+ // Number label above radio button
163
+ .likert-scale__number {
164
+ font-size: $likert-text-size-medium;
165
+ font-weight: 500;
166
+ color: $likert-color-text;
167
+ margin-bottom: 4px;
168
+ user-select: none;
169
+ text-align: center;
170
+ }
171
+
172
+ // Hidden radio input - same as RadioButtons
173
+ .likert-scale__input {
174
+ position: absolute;
175
+ opacity: 0;
176
+ pointer-events: none;
177
+ }
178
+
179
+ // Custom radio button label - uses EXACT same style as RadioButtons
180
+ .likert-scale__label {
181
+ position: relative;
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: center;
185
+ min-width: 48px;
186
+ min-height: 48px;
187
+ cursor: pointer;
188
+ user-select: none;
189
+
190
+ // Before and after pseudo-elements - EXACT RadioButtons styling
191
+ &::before,
192
+ &::after {
193
+ content: '';
194
+ position: absolute;
195
+ left: 50%;
196
+ top: 50%;
197
+ margin-left: -8px;
198
+ margin-top: -8px;
199
+ width: 16px;
200
+ height: 16px;
201
+ z-index: 0;
202
+ transition: .28s ease;
203
+ border-radius: 50%;
204
+ }
205
+
206
+ // Unchecked state - both before and after have border
207
+ &::before,
208
+ &::after {
209
+ border: 2px solid var(--mm-text-secondary, $likert-color-radio-empty);
210
+ }
211
+
212
+ // Unchecked - after element is scaled to 0
213
+ &::after {
214
+ transform: scale(0);
215
+ }
216
+ }
217
+
218
+ // Checked state - same as RadioButtons
219
+ .likert-scale__input:checked + .likert-scale__label {
220
+ &::before {
221
+ border: 2px solid transparent;
222
+ }
223
+
224
+ &::after {
225
+ border: 2px solid var(--mm-primary-color, $likert-color-radio-checked);
226
+ background-color: var(--mm-primary-color, $likert-color-radio-checked);
227
+ transform: scale(1.02);
228
+ }
229
+ }
230
+
231
+ // Hover state
232
+ .likert-scale__item:hover:not(.likert-scale__item--disabled):not(.likert-scale__item--readonly) .likert-scale__label {
233
+ &::before {
234
+ border-color: var(--mm-primary-color, $likert-color-radio-checked);
235
+ }
236
+ }
237
+
238
+ // Focus state
239
+ .likert-scale__input:focus + .likert-scale__label::before {
240
+ box-shadow: 0 0 0 10px rgba(0,0,0,.1);
241
+ }
242
+
243
+ // Disabled state
244
+ .likert-scale__input:disabled + .likert-scale__label {
245
+ &::before {
246
+ background-color: transparent;
247
+ border-color: var(--mm-text-disabled, $likert-color-disabled);
248
+ }
249
+ }
250
+
251
+ .likert-scale__input:disabled:checked + .likert-scale__label::after {
252
+ background-color: var(--mm-text-disabled, $likert-color-disabled);
253
+ border-color: var(--mm-text-disabled, $likert-color-disabled);
254
+ }
255
+
256
+ // Tooltip
257
+ .likert-scale__tooltip {
258
+ position: absolute;
259
+ bottom: calc(100% + 8px);
260
+ left: 50%;
261
+ transform: translateX(-50%);
262
+ padding: 4px 8px;
263
+ background: $likert-tooltip-bg;
264
+ color: $likert-tooltip-text;
265
+ font-size: 12px;
266
+ border-radius: 4px;
267
+ white-space: nowrap;
268
+ opacity: 0;
269
+ pointer-events: none;
270
+ transition: opacity 0.2s ease;
271
+ z-index: 1000;
272
+
273
+ // Arrow
274
+ &::after {
275
+ content: '';
276
+ position: absolute;
277
+ top: 100%;
278
+ left: 50%;
279
+ transform: translateX(-50%);
280
+ border: 4px solid transparent;
281
+ border-top-color: $likert-tooltip-bg;
282
+ }
283
+ }
284
+
285
+ .likert-scale__item:hover .likert-scale__tooltip {
286
+ opacity: 1;
287
+ }
288
+
289
+ // Scale anchors (below the radio buttons)
290
+ .likert-scale__anchors {
291
+ display: flex;
292
+ justify-content: space-between;
293
+ align-items: flex-start;
294
+ font-size: 0.875rem;
295
+ color: $likert-color-text-secondary;
296
+ position: relative;
297
+ }
298
+
299
+ .likert-scale__anchor {
300
+ flex: 1 1 0;
301
+ text-align: center;
302
+ line-height: 1.2;
303
+ padding: 0 4px;
304
+
305
+ &--start {
306
+ text-align: left;
307
+ }
308
+
309
+ &--middle {
310
+ text-align: center;
311
+ }
312
+
313
+ &--end {
314
+ text-align: right;
315
+ }
316
+ }
317
+
318
+ // Layout variants
319
+ .likert-scale--horizontal {
320
+ flex-direction: row;
321
+ align-items: center;
322
+
323
+ .likert-scale__scale {
324
+ flex-direction: row;
325
+ }
326
+ }
327
+
328
+ .likert-scale--vertical {
329
+ flex-direction: column;
330
+ align-items: stretch;
331
+
332
+ .likert-scale__question-label {
333
+ margin-bottom: 12px;
334
+ }
335
+
336
+ .likert-scale__scale-container {
337
+ width: 100%;
338
+ }
339
+
340
+ .likert-scale__scale {
341
+ flex-direction: column;
342
+ align-items: stretch;
343
+ }
344
+
345
+ .likert-scale__item {
346
+ flex-direction: row;
347
+ justify-content: flex-start;
348
+ padding: 4px 0;
349
+ width: 100%;
350
+ }
351
+
352
+ .likert-scale__number {
353
+ margin-bottom: 0;
354
+ margin-right: 12px;
355
+ min-width: 24px;
356
+ text-align: left;
357
+ }
358
+
359
+ .likert-scale__anchors {
360
+ flex-direction: column;
361
+ margin-top: 0;
362
+ margin-left: 60px;
363
+ }
364
+
365
+ .likert-scale__anchor {
366
+ margin: 4px 0;
367
+ text-align: left;
368
+ flex: 0 0 auto;
369
+
370
+ &--start,
371
+ &--middle,
372
+ &--end {
373
+ text-align: left;
374
+ }
375
+ }
376
+ }
377
+
378
+ .likert-scale--responsive {
379
+ // Default: horizontal on desktop
380
+ flex-direction: row;
381
+ align-items: center;
382
+
383
+ .likert-scale__scale {
384
+ flex-direction: row;
385
+ }
386
+
387
+ // Vertical on mobile
388
+ @media #{variables.$small-and-down} {
389
+ flex-direction: column;
390
+ align-items: stretch;
391
+
392
+ .likert-scale__question-label {
393
+ margin-bottom: 12px;
394
+ }
395
+
396
+ .likert-scale__scale-container {
397
+ width: 100%;
398
+ }
399
+
400
+ .likert-scale__scale {
401
+ flex-direction: column;
402
+ align-items: stretch;
403
+ }
404
+
405
+ .likert-scale__item {
406
+ flex-direction: row;
407
+ justify-content: flex-start;
408
+ padding: 4px 0;
409
+ width: 100%;
410
+ }
411
+
412
+ .likert-scale__number {
413
+ margin-bottom: 0;
414
+ margin-right: 12px;
415
+ min-width: 24px;
416
+ text-align: left;
417
+ }
418
+
419
+ .likert-scale__anchors {
420
+ flex-direction: column;
421
+ margin-top: 0;
422
+ margin-left: 60px;
423
+ }
424
+
425
+ .likert-scale__anchor {
426
+ margin: 4px 0;
427
+ text-align: left;
428
+ flex: 0 0 auto;
429
+
430
+ &--start,
431
+ &--middle,
432
+ &--end {
433
+ text-align: left;
434
+ }
435
+ }
436
+ }
437
+ }
438
+
439
+ // Density variants (spacing between items and overall spacing)
440
+ .likert-scale--compact {
441
+ margin-bottom: 12px;
442
+ gap: 12px;
443
+
444
+ .likert-scale__scale {
445
+ gap: $likert-gap-compact;
446
+ }
447
+
448
+ .likert-scale__anchors {
449
+ margin-top: 4px;
450
+ }
451
+ }
452
+
453
+ .likert-scale--standard {
454
+ margin-bottom: 20px;
455
+ gap: 16px;
456
+
457
+ .likert-scale__scale {
458
+ gap: $likert-gap-standard;
459
+ }
460
+ }
461
+
462
+ .likert-scale--comfortable {
463
+ margin-bottom: 28px;
464
+ gap: 20px;
465
+
466
+ .likert-scale__scale {
467
+ gap: $likert-gap-comfortable;
468
+ }
469
+
470
+ .likert-scale__anchors {
471
+ margin-top: 12px;
472
+ }
473
+ }
474
+
475
+ // Size variants (affect touch targets, spacing, and number text)
476
+ .likert-scale--small {
477
+ .likert-scale__number {
478
+ font-size: $likert-text-size-small;
479
+ margin-bottom: 2px;
480
+ }
481
+
482
+ .likert-scale__label {
483
+ min-width: 36px;
484
+ min-height: 36px;
485
+ }
486
+
487
+ .likert-scale__anchor {
488
+ font-size: 0.75rem;
489
+ }
490
+ }
491
+
492
+ .likert-scale--medium {
493
+ .likert-scale__number {
494
+ font-size: $likert-text-size-medium;
495
+ margin-bottom: 4px;
496
+ }
497
+
498
+ .likert-scale__label {
499
+ min-width: 48px;
500
+ min-height: 48px;
501
+ }
502
+
503
+ .likert-scale__anchor {
504
+ font-size: 0.875rem;
505
+ }
506
+ }
507
+
508
+ .likert-scale--large {
509
+ .likert-scale__number {
510
+ font-size: $likert-text-size-large;
511
+ margin-bottom: 6px;
512
+ }
513
+
514
+ .likert-scale__label {
515
+ min-width: 56px;
516
+ min-height: 56px;
517
+ }
518
+
519
+ .likert-scale__anchor {
520
+ font-size: 1rem;
521
+ }
522
+ }
523
+
524
+ // Screen reader only content
525
+ .likert-scale__sr-only {
526
+ position: absolute;
527
+ width: 1px;
528
+ height: 1px;
529
+ padding: 0;
530
+ margin: -1px;
531
+ overflow: hidden;
532
+ clip: rect(0, 0, 0, 0);
533
+ white-space: nowrap;
534
+ border: 0;
535
+ }
536
+
537
+ // Material Design touch target (minimum 48x48dp)
538
+ @media (pointer: coarse) {
539
+ .likert-scale__label {
540
+ min-width: 48px;
541
+ min-height: 48px;
542
+ }
543
+ }
544
+
545
+ // RTL support
546
+ [dir="rtl"] {
547
+ .likert-scale__tooltip {
548
+ &::after {
549
+ transform: translateX(50%);
550
+ }
551
+ }
552
+
553
+ .likert-scale--vertical {
554
+ .likert-scale__number {
555
+ margin-right: 0;
556
+ margin-left: 12px;
557
+ }
558
+
559
+ .likert-scale__anchors {
560
+ margin-left: 0;
561
+ margin-right: 60px;
562
+ }
563
+
564
+ .likert-scale__item {
565
+ justify-content: flex-end;
566
+ }
567
+ }
568
+
569
+ .likert-scale--aligned {
570
+ .likert-scale__question-label {
571
+ text-align: right;
572
+ }
573
+ }
574
+ }
575
+
576
+ // High contrast mode support
577
+ @media (prefers-contrast: high) {
578
+ .likert-scale__label {
579
+ &::before {
580
+ border-width: 3px;
581
+ }
582
+ }
583
+ }
584
+
585
+ // Dark theme adjustments
586
+ [data-theme="dark"] {
587
+ .likert-scale__tooltip {
588
+ background: rgba(255, 255, 255, 0.9);
589
+ color: rgba(0, 0, 0, 0.87);
590
+
591
+ &::after {
592
+ border-top-color: rgba(255, 255, 255, 0.9);
593
+ }
594
+ }
595
+ }
596
+
597
+ // Reduced motion support
598
+ @media (prefers-reduced-motion: reduce) {
599
+ .likert-scale,
600
+ .likert-scale__item,
601
+ .likert-scale__label,
602
+ .likert-scale__tooltip {
603
+ transition: none !important;
604
+ animation: none !important;
605
+ }
606
+
607
+ .likert-scale__item:hover:not(.likert-scale__item--disabled):not(.likert-scale__item--readonly) {
608
+ transform: none;
609
+ }
610
+ }
@@ -53,8 +53,8 @@
53
53
  @use "components/masonry";
54
54
  @use "components/image-list";
55
55
  @use 'components/rating';
56
+ @use 'components/likert-scale';
56
57
  @use 'components/toggle-group';
57
58
  @use 'components/circular-progress';
58
59
  @use 'components/linear-progress';
59
60
  @use 'components/badge-component';
60
-