mithril-materialized 3.9.0 → 3.10.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.
- package/dist/badge.d.ts +129 -0
- package/dist/components.css +227 -0
- package/dist/index.css +227 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +101 -1
- package/dist/index.js +101 -0
- package/dist/index.min.css +1 -1
- package/dist/index.umd.js +101 -0
- package/package.json +1 -1
- package/sass/components/_badge-component.scss +203 -0
- package/sass/materialize.scss +2 -0
package/dist/index.umd.js
CHANGED
|
@@ -509,6 +509,106 @@
|
|
|
509
509
|
};
|
|
510
510
|
};
|
|
511
511
|
|
|
512
|
+
/**
|
|
513
|
+
* Badge component
|
|
514
|
+
*
|
|
515
|
+
* Displays a badge anchored to a child element. Commonly used for notifications,
|
|
516
|
+
* counts, or status indicators. Supports flexible positioning, colors, and variants.
|
|
517
|
+
*
|
|
518
|
+
* @example
|
|
519
|
+
* ```typescript
|
|
520
|
+
* // Basic notification badge
|
|
521
|
+
* m(Badge, { badgeContent: 5 },
|
|
522
|
+
* m('button.btn', 'Messages')
|
|
523
|
+
* )
|
|
524
|
+
*
|
|
525
|
+
* // Dot badge on avatar
|
|
526
|
+
* m(Badge, {
|
|
527
|
+
* variant: 'dot',
|
|
528
|
+
* color: 'green',
|
|
529
|
+
* overlap: 'circular'
|
|
530
|
+
* },
|
|
531
|
+
* m('img.circle', { src: 'avatar.jpg' })
|
|
532
|
+
* )
|
|
533
|
+
* ```
|
|
534
|
+
*/
|
|
535
|
+
const Badge = () => {
|
|
536
|
+
return {
|
|
537
|
+
view: ({ attrs, children }) => {
|
|
538
|
+
const { badgeContent, max, anchorOrigin = { vertical: 'top', horizontal: 'right' }, overlap = 'rectangular', variant = 'standard', color = 'red', colorIntensity, invisible = false, showZero = false, 'aria-label': ariaLabel, badgeClassName = '', className = '' } = attrs, params = __rest(attrs, ["badgeContent", "max", "anchorOrigin", "overlap", "variant", "color", "colorIntensity", "invisible", "showZero", 'aria-label', "badgeClassName", "className"]);
|
|
539
|
+
// === VALIDATION: Single child element ===
|
|
540
|
+
const childArray = Array.isArray(children) ? children : children ? [children] : [];
|
|
541
|
+
if (childArray.length === 0) {
|
|
542
|
+
console.warn('Badge component requires a child element');
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
if (childArray.length > 1) {
|
|
546
|
+
console.warn('Badge component should only wrap a single child element. Using first child only.');
|
|
547
|
+
}
|
|
548
|
+
const child = childArray[0];
|
|
549
|
+
// === VISIBILITY LOGIC ===
|
|
550
|
+
// Hide badge if:
|
|
551
|
+
// 1. invisible prop is true, OR
|
|
552
|
+
// 2. For standard variant: badgeContent is undefined/null OR (badgeContent is 0 AND !showZero)
|
|
553
|
+
const shouldHideBadge = invisible ||
|
|
554
|
+
(variant === 'standard' &&
|
|
555
|
+
(badgeContent === undefined ||
|
|
556
|
+
badgeContent === null ||
|
|
557
|
+
(badgeContent === 0 && !showZero)));
|
|
558
|
+
// === BADGE CONTENT FORMATTING ===
|
|
559
|
+
// Apply max capping: if badgeContent > max, show "max+"
|
|
560
|
+
const getDisplayContent = () => {
|
|
561
|
+
if (variant === 'dot')
|
|
562
|
+
return '';
|
|
563
|
+
if (typeof badgeContent === 'number' && max !== undefined && badgeContent > max) {
|
|
564
|
+
return `${max}+`;
|
|
565
|
+
}
|
|
566
|
+
return String(badgeContent !== null && badgeContent !== void 0 ? badgeContent : '');
|
|
567
|
+
};
|
|
568
|
+
const displayContent = getDisplayContent();
|
|
569
|
+
// === CSS CLASS ASSEMBLY ===
|
|
570
|
+
// Wrapper classes
|
|
571
|
+
const wrapperClasses = ['badge-wrapper', className].filter(Boolean).join(' ').trim() || undefined;
|
|
572
|
+
// Badge element classes - using m-badge prefix to avoid Materialize conflicts
|
|
573
|
+
const positionClass = `m-badge--${anchorOrigin.vertical}-${anchorOrigin.horizontal}`;
|
|
574
|
+
const badgeClasses = [
|
|
575
|
+
'm-badge',
|
|
576
|
+
`m-badge--${variant}`,
|
|
577
|
+
positionClass,
|
|
578
|
+
`m-badge--${overlap}`,
|
|
579
|
+
`m-badge--${color}`,
|
|
580
|
+
colorIntensity ? `m-badge--${colorIntensity}` : '',
|
|
581
|
+
shouldHideBadge ? 'm-badge--invisible' : '',
|
|
582
|
+
badgeClassName,
|
|
583
|
+
]
|
|
584
|
+
.filter(Boolean)
|
|
585
|
+
.join(' ')
|
|
586
|
+
.trim();
|
|
587
|
+
// === ARIA ATTRIBUTES ===
|
|
588
|
+
const badgeAriaLabel = ariaLabel ||
|
|
589
|
+
(variant === 'dot'
|
|
590
|
+
? 'notification indicator'
|
|
591
|
+
: displayContent
|
|
592
|
+
? `${displayContent} notifications`
|
|
593
|
+
: 'notification badge');
|
|
594
|
+
// === RENDER ===
|
|
595
|
+
return m('.badge-wrapper', Object.assign(Object.assign({}, params), { className: wrapperClasses }), [
|
|
596
|
+
// Child element
|
|
597
|
+
child,
|
|
598
|
+
// Badge element - only render if not hidden
|
|
599
|
+
!shouldHideBadge
|
|
600
|
+
? m('span', {
|
|
601
|
+
className: badgeClasses,
|
|
602
|
+
'aria-label': badgeAriaLabel,
|
|
603
|
+
role: 'status',
|
|
604
|
+
'aria-live': 'polite',
|
|
605
|
+
}, variant === 'standard' ? displayContent : null)
|
|
606
|
+
: null,
|
|
607
|
+
]);
|
|
608
|
+
},
|
|
609
|
+
};
|
|
610
|
+
};
|
|
611
|
+
|
|
512
612
|
/**
|
|
513
613
|
* A simple material icon, defined by its icon name.
|
|
514
614
|
*
|
|
@@ -11035,6 +11135,7 @@
|
|
|
11035
11135
|
exports.AnalogClock = AnalogClock;
|
|
11036
11136
|
exports.AnchorItem = AnchorItem;
|
|
11037
11137
|
exports.Autocomplete = Autocomplete;
|
|
11138
|
+
exports.Badge = Badge;
|
|
11038
11139
|
exports.Breadcrumb = Breadcrumb;
|
|
11039
11140
|
exports.BreadcrumbManager = BreadcrumbManager;
|
|
11040
11141
|
exports.Button = Button;
|
package/package.json
CHANGED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
@use 'sass:color';
|
|
2
|
+
@use "variables";
|
|
3
|
+
@use "color-variables";
|
|
4
|
+
|
|
5
|
+
/* Badge Component
|
|
6
|
+
========================================================================== */
|
|
7
|
+
|
|
8
|
+
// Badge component variables
|
|
9
|
+
$badge-size-standard: 20px !default;
|
|
10
|
+
$badge-size-dot: 8px !default;
|
|
11
|
+
$badge-font-size: 12px !default;
|
|
12
|
+
$badge-font-weight: 500 !default;
|
|
13
|
+
$badge-default-color: color-variables.color("red", "base") !default;
|
|
14
|
+
$badge-text-color: #fff !default;
|
|
15
|
+
$badge-border-radius: 10px !default;
|
|
16
|
+
$badge-dot-border-radius: 50% !default;
|
|
17
|
+
|
|
18
|
+
// Wrapper - relative positioning container
|
|
19
|
+
.badge-wrapper {
|
|
20
|
+
position: relative;
|
|
21
|
+
display: inline-flex;
|
|
22
|
+
vertical-align: middle;
|
|
23
|
+
flex-shrink: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Badge element - using .m-badge to avoid conflicts with Materialize's span.badge
|
|
27
|
+
.m-badge {
|
|
28
|
+
position: absolute;
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
font-family: Roboto, sans-serif;
|
|
34
|
+
font-weight: $badge-font-weight;
|
|
35
|
+
line-height: 1;
|
|
36
|
+
white-space: nowrap;
|
|
37
|
+
text-align: center;
|
|
38
|
+
border-radius: $badge-border-radius;
|
|
39
|
+
background-color: $badge-default-color;
|
|
40
|
+
color: $badge-text-color;
|
|
41
|
+
z-index: 1;
|
|
42
|
+
transition: transform 225ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
43
|
+
|
|
44
|
+
// Standard variant (shows content)
|
|
45
|
+
&.m-badge--standard {
|
|
46
|
+
min-width: $badge-size-standard;
|
|
47
|
+
height: $badge-size-standard;
|
|
48
|
+
padding: 0 6px;
|
|
49
|
+
font-size: $badge-font-size;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Dot variant (minimal indicator)
|
|
53
|
+
&.m-badge--dot {
|
|
54
|
+
width: $badge-size-dot;
|
|
55
|
+
height: $badge-size-dot;
|
|
56
|
+
min-width: $badge-size-dot;
|
|
57
|
+
padding: 0;
|
|
58
|
+
border-radius: $badge-dot-border-radius;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Invisible state
|
|
62
|
+
&.m-badge--invisible {
|
|
63
|
+
transform: scale(0);
|
|
64
|
+
opacity: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// === POSITIONING: Top-Right (default) ===
|
|
68
|
+
&.m-badge--top-right {
|
|
69
|
+
top: 0;
|
|
70
|
+
right: 0;
|
|
71
|
+
transform: scale(1) translate(50%, -50%);
|
|
72
|
+
transform-origin: 100% 0%;
|
|
73
|
+
|
|
74
|
+
&.m-badge--rectangular {
|
|
75
|
+
transform: scale(1) translate(50%, -50%);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&.m-badge--circular {
|
|
79
|
+
transform: scale(1) translate(30%, -30%);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
&.m-badge--invisible {
|
|
83
|
+
transform: scale(0) translate(50%, -50%);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// === POSITIONING: Top-Left ===
|
|
88
|
+
&.m-badge--top-left {
|
|
89
|
+
top: 0;
|
|
90
|
+
left: 0;
|
|
91
|
+
transform: scale(1) translate(-50%, -50%);
|
|
92
|
+
transform-origin: 0% 0%;
|
|
93
|
+
|
|
94
|
+
&.m-badge--rectangular {
|
|
95
|
+
transform: scale(1) translate(-50%, -50%);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
&.m-badge--circular {
|
|
99
|
+
transform: scale(1) translate(-30%, -30%);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
&.m-badge--invisible {
|
|
103
|
+
transform: scale(0) translate(-50%, -50%);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// === POSITIONING: Bottom-Right ===
|
|
108
|
+
&.m-badge--bottom-right {
|
|
109
|
+
bottom: 0;
|
|
110
|
+
right: 0;
|
|
111
|
+
transform: scale(1) translate(50%, 50%);
|
|
112
|
+
transform-origin: 100% 100%;
|
|
113
|
+
|
|
114
|
+
&.m-badge--rectangular {
|
|
115
|
+
transform: scale(1) translate(50%, 50%);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&.m-badge--circular {
|
|
119
|
+
transform: scale(1) translate(30%, 30%);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&.m-badge--invisible {
|
|
123
|
+
transform: scale(0) translate(50%, 50%);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// === POSITIONING: Bottom-Left ===
|
|
128
|
+
&.m-badge--bottom-left {
|
|
129
|
+
bottom: 0;
|
|
130
|
+
left: 0;
|
|
131
|
+
transform: scale(1) translate(-50%, 50%);
|
|
132
|
+
transform-origin: 0% 100%;
|
|
133
|
+
|
|
134
|
+
&.m-badge--rectangular {
|
|
135
|
+
transform: scale(1) translate(-50%, 50%);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&.m-badge--circular {
|
|
139
|
+
transform: scale(1) translate(-30%, 30%);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&.m-badge--invisible {
|
|
143
|
+
transform: scale(0) translate(-50%, 50%);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// === COLOR VARIANTS ===
|
|
149
|
+
// Generate color classes for all MaterialColor options
|
|
150
|
+
.m-badge--red { background-color: color-variables.color("red", "base"); }
|
|
151
|
+
.m-badge--pink { background-color: color-variables.color("pink", "base"); }
|
|
152
|
+
.m-badge--purple { background-color: color-variables.color("purple", "base"); }
|
|
153
|
+
.m-badge--deep-purple { background-color: color-variables.color("deep-purple", "base"); }
|
|
154
|
+
.m-badge--indigo { background-color: color-variables.color("indigo", "base"); }
|
|
155
|
+
.m-badge--blue { background-color: color-variables.color("blue", "base"); }
|
|
156
|
+
.m-badge--light-blue { background-color: color-variables.color("light-blue", "base"); }
|
|
157
|
+
.m-badge--cyan { background-color: color-variables.color("cyan", "base"); }
|
|
158
|
+
.m-badge--teal { background-color: color-variables.color("teal", "base"); }
|
|
159
|
+
.m-badge--green { background-color: color-variables.color("green", "base"); }
|
|
160
|
+
.m-badge--light-green { background-color: color-variables.color("light-green", "base"); }
|
|
161
|
+
.m-badge--lime { background-color: color-variables.color("lime", "base"); }
|
|
162
|
+
.m-badge--yellow {
|
|
163
|
+
background-color: color-variables.color("yellow", "base");
|
|
164
|
+
color: #000; // Dark text for light background
|
|
165
|
+
}
|
|
166
|
+
.m-badge--amber { background-color: color-variables.color("amber", "base"); }
|
|
167
|
+
.m-badge--orange { background-color: color-variables.color("orange", "base"); }
|
|
168
|
+
.m-badge--deep-orange { background-color: color-variables.color("deep-orange", "base"); }
|
|
169
|
+
.m-badge--brown { background-color: color-variables.color("brown", "base"); }
|
|
170
|
+
.m-badge--grey { background-color: color-variables.color("grey", "base"); }
|
|
171
|
+
.m-badge--blue-grey { background-color: color-variables.color("blue-grey", "base"); }
|
|
172
|
+
|
|
173
|
+
// === COLOR INTENSITY MODIFIERS ===
|
|
174
|
+
// Use CSS filters for intensity adjustments (matching CircularProgress pattern)
|
|
175
|
+
.m-badge--lighten-5 { filter: brightness(1.4); }
|
|
176
|
+
.m-badge--lighten-4 { filter: brightness(1.3); }
|
|
177
|
+
.m-badge--lighten-3 { filter: brightness(1.2); }
|
|
178
|
+
.m-badge--lighten-2 { filter: brightness(1.1); }
|
|
179
|
+
.m-badge--lighten-1 { filter: brightness(1.05); }
|
|
180
|
+
.m-badge--darken-1 { filter: brightness(0.95); }
|
|
181
|
+
.m-badge--darken-2 { filter: brightness(0.9); }
|
|
182
|
+
.m-badge--darken-3 { filter: brightness(0.8); }
|
|
183
|
+
.m-badge--darken-4 { filter: brightness(0.7); }
|
|
184
|
+
|
|
185
|
+
// === ACCESSIBILITY ===
|
|
186
|
+
// Ensure badge is not announced multiple times by screen readers
|
|
187
|
+
.m-badge[role="status"] {
|
|
188
|
+
// Screen reader will announce changes due to aria-live="polite"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// === REDUCED MOTION ===
|
|
192
|
+
@media (prefers-reduced-motion: reduce) {
|
|
193
|
+
.m-badge {
|
|
194
|
+
transition: none;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// === HIGH CONTRAST MODE ===
|
|
199
|
+
@media (prefers-contrast: high) {
|
|
200
|
+
.m-badge {
|
|
201
|
+
border: 2px solid currentColor;
|
|
202
|
+
}
|
|
203
|
+
}
|