@styloviz/badge 0.1.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.
- package/LICENSE +21 -0
- package/README.md +61 -0
- package/fesm2022/styloviz-badge.mjs +190 -0
- package/fesm2022/styloviz-badge.mjs.map +1 -0
- package/package.json +50 -0
- package/types/styloviz-badge.d.ts +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 StyloViz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @styloviz/badge
|
|
2
|
+
|
|
3
|
+
> Compact status and category labels with 7 semantic variants and 3 visual styles.
|
|
4
|
+
|
|
5
|
+
Part of the **StyloViz UI Kit** — a premium Angular 21 + Tailwind CSS 4 dashboard component library. Standalone, `OnPush`, strongly typed, dark-mode ready.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @styloviz/core @styloviz/badge
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires `@angular/core` and `@angular/common` >= 21. `@styloviz/core` is a peer dependency shared by every component. Prefer everything at once? `@styloviz/all` installs the whole free tier in one command.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { SvBadgeComponent } from '@styloviz/badge';
|
|
19
|
+
|
|
20
|
+
@Component({
|
|
21
|
+
standalone: true,
|
|
22
|
+
imports: [SvBadgeComponent],
|
|
23
|
+
template: `
|
|
24
|
+
<sv-badge label="Active" variant="success" />
|
|
25
|
+
`,
|
|
26
|
+
})
|
|
27
|
+
export class DemoComponent {}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Inputs
|
|
31
|
+
|
|
32
|
+
| Input | Type | Default | Description |
|
|
33
|
+
| --- | --- | --- | --- |
|
|
34
|
+
| `variant` | `BadgeVariant` | `'primary'` | Semantic color/intent (primary, success, warning, danger…). |
|
|
35
|
+
| `badgeStyle` | `BadgeStyle` | `'soft'` | Visual treatment: solid, soft or outline. |
|
|
36
|
+
| `shape` | `BadgeShape` | `'pill'` | Corner style: pill, rounded or square. |
|
|
37
|
+
| `size` | `BadgeSize` | `'md'` | Badge size: sm, md or lg. |
|
|
38
|
+
| `label` | `string` | `''` | Badge text. Omit when using count mode or projecting content. |
|
|
39
|
+
| `dot` | `boolean` | `false` | Show status dot. |
|
|
40
|
+
| `pulseDot` | `boolean` | `false` | Animate dot with ping. |
|
|
41
|
+
| `count` | `number` | `0` | When > 0, renders count mode (overrides label). |
|
|
42
|
+
| `maxCount` | `number` | `99` | Cap for count display (shows "N+"). |
|
|
43
|
+
| `iconPath` | `string` | `''` | SVG path `d` for leading icon. |
|
|
44
|
+
| `dismissible` | `boolean` | `false` | Show dismiss button. |
|
|
45
|
+
| `customClass` | `string` | `''` | Extra CSS classes merged on root. |
|
|
46
|
+
| `ariaLabel` | `string` | `''` | aria-label override — replaces the visible text as the accessible name. |
|
|
47
|
+
| `live` | `boolean` | `false` | Announce the badge as a polite ARIA live region (`role="status"`). Enable for dynamic notification counts/statuses that update in place so assistive tech is notified of changes. Leave `false` for static labels and tags to avoid noisy announcements. |
|
|
48
|
+
|
|
49
|
+
## Outputs
|
|
50
|
+
|
|
51
|
+
| Output | Type | Description |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `dismissed` | `void` | Emitted when the dismiss button is clicked. |
|
|
54
|
+
|
|
55
|
+
## Documentation
|
|
56
|
+
|
|
57
|
+
Full API reference and live demos: https://styloviz.dev/docs/badge
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
MIT
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, output, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { NgClass } from '@angular/common';
|
|
4
|
+
|
|
5
|
+
// ─── Component ───────────────────────────────────────────────────────────────
|
|
6
|
+
/**
|
|
7
|
+
* SvBadgeComponent — Compact, accessible label for statuses, counts, and tags.
|
|
8
|
+
*
|
|
9
|
+
* Install: npm install @styloviz/badge
|
|
10
|
+
* Import: import { SvBadgeComponent } from '@styloviz/badge';
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - 7 variants × 3 styles × 3 shapes × 3 sizes
|
|
14
|
+
* - Optional status dot with pulse animation
|
|
15
|
+
* - Count mode (notification badge)
|
|
16
|
+
* - Leading icon slot
|
|
17
|
+
* - Dismiss button
|
|
18
|
+
* - Full dark mode + OnPush
|
|
19
|
+
*/
|
|
20
|
+
class SvBadgeComponent {
|
|
21
|
+
// ── Inputs ────────────────────────────────────────────────────────────────
|
|
22
|
+
/** Semantic color/intent (primary, success, warning, danger…). @default 'primary' */
|
|
23
|
+
variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
24
|
+
/** Visual treatment: solid, soft or outline. @default 'soft' */
|
|
25
|
+
badgeStyle = input('soft', ...(ngDevMode ? [{ debugName: "badgeStyle" }] : /* istanbul ignore next */ []));
|
|
26
|
+
/** Corner style: pill, rounded or square. @default 'pill' */
|
|
27
|
+
shape = input('pill', ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
|
|
28
|
+
/** Badge size: sm, md or lg. @default 'md' */
|
|
29
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
30
|
+
/** Badge text. Omit when using count mode or projecting content. */
|
|
31
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
32
|
+
/** Show status dot. @default false */
|
|
33
|
+
dot = input(false, ...(ngDevMode ? [{ debugName: "dot" }] : /* istanbul ignore next */ []));
|
|
34
|
+
/** Animate dot with ping. @default false */
|
|
35
|
+
pulseDot = input(false, ...(ngDevMode ? [{ debugName: "pulseDot" }] : /* istanbul ignore next */ []));
|
|
36
|
+
/**
|
|
37
|
+
* When > 0, renders count mode (overrides label).
|
|
38
|
+
* @default 0
|
|
39
|
+
*/
|
|
40
|
+
count = input(0, ...(ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []));
|
|
41
|
+
/** Cap for count display (shows "N+"). @default 99 */
|
|
42
|
+
maxCount = input(99, ...(ngDevMode ? [{ debugName: "maxCount" }] : /* istanbul ignore next */ []));
|
|
43
|
+
/** SVG path `d` for leading icon. */
|
|
44
|
+
iconPath = input('', ...(ngDevMode ? [{ debugName: "iconPath" }] : /* istanbul ignore next */ []));
|
|
45
|
+
/** Show dismiss button. @default false */
|
|
46
|
+
dismissible = input(false, ...(ngDevMode ? [{ debugName: "dismissible" }] : /* istanbul ignore next */ []));
|
|
47
|
+
/** Extra CSS classes merged on root. */
|
|
48
|
+
customClass = input('', ...(ngDevMode ? [{ debugName: "customClass" }] : /* istanbul ignore next */ []));
|
|
49
|
+
/** aria-label override — replaces the visible text as the accessible name. */
|
|
50
|
+
ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
51
|
+
/**
|
|
52
|
+
* Announce the badge as a polite ARIA live region (`role="status"`).
|
|
53
|
+
* Enable for dynamic notification counts/statuses that update in place so
|
|
54
|
+
* assistive tech is notified of changes. Leave `false` for static labels
|
|
55
|
+
* and tags to avoid noisy announcements. @default false
|
|
56
|
+
*/
|
|
57
|
+
live = input(false, ...(ngDevMode ? [{ debugName: "live" }] : /* istanbul ignore next */ []));
|
|
58
|
+
// ── Outputs ───────────────────────────────────────────────────────────────
|
|
59
|
+
/** Emitted when the dismiss button is clicked. */
|
|
60
|
+
dismissed = output();
|
|
61
|
+
// ── Computed ──────────────────────────────────────────────────────────────
|
|
62
|
+
resolvedAriaLabel = computed(() => this.ariaLabel() || this.label(), ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
|
|
63
|
+
/**
|
|
64
|
+
* Host ARIA role. A live badge is a polite status region; an aria-label
|
|
65
|
+
* override exposes the badge as a single labelled image; otherwise the
|
|
66
|
+
* visible text is the accessible name and no role is needed.
|
|
67
|
+
*/
|
|
68
|
+
hostRole = computed(() => {
|
|
69
|
+
if (this.live())
|
|
70
|
+
return 'status';
|
|
71
|
+
if (this.ariaLabel())
|
|
72
|
+
return 'img';
|
|
73
|
+
return null;
|
|
74
|
+
}, ...(ngDevMode ? [{ debugName: "hostRole" }] : /* istanbul ignore next */ []));
|
|
75
|
+
isCountMode = computed(() => this.count() > 0, ...(ngDevMode ? [{ debugName: "isCountMode" }] : /* istanbul ignore next */ []));
|
|
76
|
+
displayCount = computed(() => {
|
|
77
|
+
const n = this.count(), max = this.maxCount();
|
|
78
|
+
return n > max ? `${max}+` : `${n}`;
|
|
79
|
+
}, ...(ngDevMode ? [{ debugName: "displayCount" }] : /* istanbul ignore next */ []));
|
|
80
|
+
rootClasses = computed(() => [
|
|
81
|
+
'inline-flex items-center font-medium select-none transition-colors duration-150',
|
|
82
|
+
this._sizeClasses(),
|
|
83
|
+
this._shapeClasses(),
|
|
84
|
+
this._colorClasses(),
|
|
85
|
+
this.customClass(),
|
|
86
|
+
].filter(Boolean).join(' '), ...(ngDevMode ? [{ debugName: "rootClasses" }] : /* istanbul ignore next */ []));
|
|
87
|
+
_sizeClasses = computed(() => {
|
|
88
|
+
const cm = this.isCountMode();
|
|
89
|
+
switch (this.size()) {
|
|
90
|
+
case 'sm': return cm ? 'h-5 min-w-5 px-1 text-[10px] justify-center gap-1' : 'px-2.5 py-1 text-[11px] gap-1';
|
|
91
|
+
case 'lg': return cm ? 'h-7 min-w-7 px-2 text-sm justify-center gap-2' : 'px-4 py-1.5 text-sm gap-2';
|
|
92
|
+
default: return cm ? 'h-6 min-w-6 px-1.5 text-xs justify-center gap-1.5' : 'px-3 py-1 text-xs gap-1.5';
|
|
93
|
+
}
|
|
94
|
+
}, ...(ngDevMode ? [{ debugName: "_sizeClasses" }] : /* istanbul ignore next */ []));
|
|
95
|
+
_shapeClasses = computed(() => {
|
|
96
|
+
switch (this.shape()) {
|
|
97
|
+
case 'square': return 'rounded-none';
|
|
98
|
+
case 'rounded': return 'rounded-md';
|
|
99
|
+
default: return 'rounded-full';
|
|
100
|
+
}
|
|
101
|
+
}, ...(ngDevMode ? [{ debugName: "_shapeClasses" }] : /* istanbul ignore next */ []));
|
|
102
|
+
_colorClasses = computed(() => {
|
|
103
|
+
const map = {
|
|
104
|
+
primary: {
|
|
105
|
+
filled: 'bg-blue-600 text-white dark:bg-blue-600',
|
|
106
|
+
soft: 'bg-blue-50 text-blue-700 ring-1 ring-blue-100 dark:bg-blue-950/60 dark:text-blue-300 dark:ring-blue-900/50',
|
|
107
|
+
outline: 'bg-transparent text-blue-700 ring-1 ring-inset ring-blue-400 dark:text-blue-400 dark:ring-blue-700',
|
|
108
|
+
},
|
|
109
|
+
secondary: {
|
|
110
|
+
filled: 'bg-gray-700 text-white dark:bg-gray-500',
|
|
111
|
+
soft: 'bg-gray-100 text-gray-700 ring-1 ring-gray-200 dark:bg-gray-800/70 dark:text-gray-300 dark:ring-gray-700/60',
|
|
112
|
+
outline: 'bg-transparent text-gray-600 ring-1 ring-inset ring-gray-300 dark:text-gray-400 dark:ring-gray-600',
|
|
113
|
+
},
|
|
114
|
+
success: {
|
|
115
|
+
filled: 'bg-emerald-600 text-white dark:bg-emerald-600',
|
|
116
|
+
soft: 'bg-emerald-50 text-emerald-700 ring-1 ring-emerald-100 dark:bg-emerald-950/60 dark:text-emerald-300 dark:ring-emerald-900/50',
|
|
117
|
+
outline: 'bg-transparent text-emerald-700 ring-1 ring-inset ring-emerald-400 dark:text-emerald-400 dark:ring-emerald-700',
|
|
118
|
+
},
|
|
119
|
+
warning: {
|
|
120
|
+
filled: 'bg-amber-500 text-white dark:bg-amber-500',
|
|
121
|
+
soft: 'bg-amber-50 text-amber-700 ring-1 ring-amber-100 dark:bg-amber-950/60 dark:text-amber-300 dark:ring-amber-900/50',
|
|
122
|
+
outline: 'bg-transparent text-amber-700 ring-1 ring-inset ring-amber-400 dark:text-amber-400 dark:ring-amber-700',
|
|
123
|
+
},
|
|
124
|
+
danger: {
|
|
125
|
+
filled: 'bg-red-600 text-white dark:bg-red-600',
|
|
126
|
+
soft: 'bg-red-50 text-red-700 ring-1 ring-red-100 dark:bg-red-950/60 dark:text-red-300 dark:ring-red-900/50',
|
|
127
|
+
outline: 'bg-transparent text-red-700 ring-1 ring-inset ring-red-400 dark:text-red-400 dark:ring-red-700',
|
|
128
|
+
},
|
|
129
|
+
info: {
|
|
130
|
+
filled: 'bg-sky-600 text-white dark:bg-sky-600',
|
|
131
|
+
soft: 'bg-sky-50 text-sky-700 ring-1 ring-sky-100 dark:bg-sky-950/60 dark:text-sky-300 dark:ring-sky-900/50',
|
|
132
|
+
outline: 'bg-transparent text-sky-700 ring-1 ring-inset ring-sky-400 dark:text-sky-400 dark:ring-sky-700',
|
|
133
|
+
},
|
|
134
|
+
neutral: {
|
|
135
|
+
filled: 'bg-gray-900 text-white dark:bg-gray-200 dark:text-gray-900',
|
|
136
|
+
soft: 'bg-gray-100 text-gray-600 ring-1 ring-gray-200 dark:bg-gray-800/80 dark:text-gray-400 dark:ring-gray-700/60',
|
|
137
|
+
outline: 'bg-transparent text-gray-600 ring-1 ring-inset ring-gray-300 dark:text-gray-400 dark:ring-gray-600',
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
return map[this.variant()][this.badgeStyle()];
|
|
141
|
+
}, ...(ngDevMode ? [{ debugName: "_colorClasses" }] : /* istanbul ignore next */ []));
|
|
142
|
+
dotColorClass = computed(() => {
|
|
143
|
+
const map = {
|
|
144
|
+
primary: 'bg-blue-500 dark:bg-blue-400',
|
|
145
|
+
secondary: 'bg-gray-500 dark:bg-gray-400',
|
|
146
|
+
success: 'bg-emerald-500 dark:bg-emerald-400',
|
|
147
|
+
warning: 'bg-amber-500 dark:bg-amber-400',
|
|
148
|
+
danger: 'bg-red-500 dark:bg-red-400',
|
|
149
|
+
info: 'bg-sky-500 dark:bg-sky-400',
|
|
150
|
+
neutral: 'bg-zinc-500 dark:bg-zinc-400',
|
|
151
|
+
};
|
|
152
|
+
return map[this.variant()];
|
|
153
|
+
}, ...(ngDevMode ? [{ debugName: "dotColorClass" }] : /* istanbul ignore next */ []));
|
|
154
|
+
dismissColorClass = computed(() => {
|
|
155
|
+
if (this.badgeStyle() === 'filled') {
|
|
156
|
+
return 'text-white/70 hover:text-white hover:bg-white/20';
|
|
157
|
+
}
|
|
158
|
+
const map = {
|
|
159
|
+
primary: 'text-blue-500 hover:text-blue-700 hover:bg-blue-100 dark:text-blue-400 dark:hover:text-blue-200 dark:hover:bg-blue-800/40',
|
|
160
|
+
secondary: 'text-gray-400 hover:text-gray-600 hover:bg-gray-200 dark:text-gray-500 dark:hover:text-gray-200 dark:hover:bg-gray-700',
|
|
161
|
+
success: 'text-emerald-500 hover:text-emerald-700 hover:bg-emerald-100 dark:text-emerald-400 dark:hover:text-emerald-200 dark:hover:bg-emerald-800/40',
|
|
162
|
+
warning: 'text-amber-500 hover:text-amber-700 hover:bg-amber-100 dark:text-amber-400 dark:hover:text-amber-200 dark:hover:bg-amber-800/40',
|
|
163
|
+
danger: 'text-red-500 hover:text-red-700 hover:bg-red-100 dark:text-red-400 dark:hover:text-red-200 dark:hover:bg-red-800/40',
|
|
164
|
+
info: 'text-sky-500 hover:text-sky-700 hover:bg-sky-100 dark:text-sky-400 dark:hover:text-sky-200 dark:hover:bg-sky-800/40',
|
|
165
|
+
neutral: 'text-zinc-500 hover:text-zinc-700 hover:bg-zinc-200 dark:text-zinc-400 dark:hover:text-zinc-200 dark:hover:bg-zinc-700',
|
|
166
|
+
};
|
|
167
|
+
return map[this.variant()];
|
|
168
|
+
}, ...(ngDevMode ? [{ debugName: "dismissColorClass" }] : /* istanbul ignore next */ []));
|
|
169
|
+
onDismiss(event) {
|
|
170
|
+
event.stopPropagation();
|
|
171
|
+
this.dismissed.emit();
|
|
172
|
+
}
|
|
173
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SvBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
174
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: SvBadgeComponent, isStandalone: true, selector: "sv-badge", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, badgeStyle: { classPropertyName: "badgeStyle", publicName: "badgeStyle", isSignal: true, isRequired: false, transformFunction: null }, shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, dot: { classPropertyName: "dot", publicName: "dot", isSignal: true, isRequired: false, transformFunction: null }, pulseDot: { classPropertyName: "pulseDot", publicName: "pulseDot", isSignal: true, isRequired: false, transformFunction: null }, count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null }, maxCount: { classPropertyName: "maxCount", publicName: "maxCount", isSignal: true, isRequired: false, transformFunction: null }, iconPath: { classPropertyName: "iconPath", publicName: "iconPath", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null }, customClass: { classPropertyName: "customClass", publicName: "customClass", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, live: { classPropertyName: "live", publicName: "live", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, ngImport: i0, template: "<span\n [ngClass]=\"rootClasses()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.role]=\"hostRole()\"\n [attr.aria-live]=\"live() ? 'polite' : null\"\n>\n @if (dot()) {\n <span\n class=\"relative inline-flex shrink-0 rounded-full\"\n [ngClass]=\"[\n size() === 'sm' ? 'h-1.5 w-1.5' : size() === 'lg' ? 'h-2.5 w-2.5' : 'h-2 w-2',\n dotColorClass()\n ]\"\n aria-hidden=\"true\"\n >\n @if (pulseDot()) {\n <span\n class=\"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75\"\n [ngClass]=\"dotColorClass()\"\n ></span>\n }\n </span>\n }\n\n @if (iconPath()) {\n <svg\n class=\"shrink-0\"\n [ngClass]=\"size() === 'sm' ? 'h-3 w-3' : size() === 'lg' ? 'h-4.5 w-4.5' : 'h-3.5 w-3.5'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path [attr.d]=\"iconPath()\" />\n </svg>\n }\n\n @if (isCountMode()) {\n <span class=\"tabular-nums leading-none\">{{ displayCount() }}</span>\n } @else if (label()) {\n <span class=\"leading-none whitespace-nowrap\">{{ label() }}</span>\n }\n\n @if (dismissible() && !isCountMode()) {\n <button\n type=\"button\"\n class=\"inline-flex shrink-0 items-center justify-center rounded-full transition-colors\n duration-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-current\"\n [ngClass]=\"[\n size() === 'sm' ? 'h-3 w-3 -mr-0.5' : size() === 'lg' ? 'h-4.5 w-4.5 -mr-0.5' : 'h-3.5 w-3.5 -mr-0.5',\n dismissColorClass()\n ]\"\n (click)=\"onDismiss($event)\"\n [attr.aria-label]=\"'Remove ' + (label() || ariaLabel() || 'badge')\"\n >\n <svg class=\"h-full w-full\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M3 3l8 8M11 3l-8 8\" />\n </svg>\n </button>\n }\n</span>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
175
|
+
}
|
|
176
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SvBadgeComponent, decorators: [{
|
|
177
|
+
type: Component,
|
|
178
|
+
args: [{ selector: 'sv-badge', standalone: true, imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span\n [ngClass]=\"rootClasses()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.role]=\"hostRole()\"\n [attr.aria-live]=\"live() ? 'polite' : null\"\n>\n @if (dot()) {\n <span\n class=\"relative inline-flex shrink-0 rounded-full\"\n [ngClass]=\"[\n size() === 'sm' ? 'h-1.5 w-1.5' : size() === 'lg' ? 'h-2.5 w-2.5' : 'h-2 w-2',\n dotColorClass()\n ]\"\n aria-hidden=\"true\"\n >\n @if (pulseDot()) {\n <span\n class=\"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75\"\n [ngClass]=\"dotColorClass()\"\n ></span>\n }\n </span>\n }\n\n @if (iconPath()) {\n <svg\n class=\"shrink-0\"\n [ngClass]=\"size() === 'sm' ? 'h-3 w-3' : size() === 'lg' ? 'h-4.5 w-4.5' : 'h-3.5 w-3.5'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path [attr.d]=\"iconPath()\" />\n </svg>\n }\n\n @if (isCountMode()) {\n <span class=\"tabular-nums leading-none\">{{ displayCount() }}</span>\n } @else if (label()) {\n <span class=\"leading-none whitespace-nowrap\">{{ label() }}</span>\n }\n\n @if (dismissible() && !isCountMode()) {\n <button\n type=\"button\"\n class=\"inline-flex shrink-0 items-center justify-center rounded-full transition-colors\n duration-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-current\"\n [ngClass]=\"[\n size() === 'sm' ? 'h-3 w-3 -mr-0.5' : size() === 'lg' ? 'h-4.5 w-4.5 -mr-0.5' : 'h-3.5 w-3.5 -mr-0.5',\n dismissColorClass()\n ]\"\n (click)=\"onDismiss($event)\"\n [attr.aria-label]=\"'Remove ' + (label() || ariaLabel() || 'badge')\"\n >\n <svg class=\"h-full w-full\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M3 3l8 8M11 3l-8 8\" />\n </svg>\n </button>\n }\n</span>\n" }]
|
|
179
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], badgeStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeStyle", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], dot: [{ type: i0.Input, args: [{ isSignal: true, alias: "dot", required: false }] }], pulseDot: [{ type: i0.Input, args: [{ isSignal: true, alias: "pulseDot", required: false }] }], count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }], maxCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxCount", required: false }] }], iconPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPath", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], customClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "customClass", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], live: [{ type: i0.Input, args: [{ isSignal: true, alias: "live", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }] } });
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @styloviz/badge — Public API
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Generated bundle index. Do not edit.
|
|
187
|
+
*/
|
|
188
|
+
|
|
189
|
+
export { SvBadgeComponent };
|
|
190
|
+
//# sourceMappingURL=styloviz-badge.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styloviz-badge.mjs","sources":["../../../../projects/badge/src/lib/badge.component.ts","../../../../projects/badge/src/lib/badge.component.html","../../../../projects/badge/src/public-api.ts","../../../../projects/badge/src/styloviz-badge.ts"],"sourcesContent":["import {\n Component,\n input,\n output,\n computed,\n ChangeDetectionStrategy,\n} from '@angular/core';\nimport { NgClass } from '@angular/common';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport type BadgeVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'neutral';\nexport type BadgeSize = 'sm' | 'md' | 'lg';\nexport type BadgeStyle = 'filled' | 'soft' | 'outline';\nexport type BadgeShape = 'rounded' | 'pill' | 'square';\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\n/**\n * SvBadgeComponent — Compact, accessible label for statuses, counts, and tags.\n *\n * Install: npm install @styloviz/badge\n * Import: import { SvBadgeComponent } from '@styloviz/badge';\n *\n * Features:\n * - 7 variants × 3 styles × 3 shapes × 3 sizes\n * - Optional status dot with pulse animation\n * - Count mode (notification badge)\n * - Leading icon slot\n * - Dismiss button\n * - Full dark mode + OnPush\n */\n@Component({\n selector: 'sv-badge',\n standalone: true,\n imports: [NgClass],\n templateUrl: './badge.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SvBadgeComponent {\n // ── Inputs ────────────────────────────────────────────────────────────────\n\n /** Semantic color/intent (primary, success, warning, danger…). @default 'primary' */\n variant = input<BadgeVariant>('primary');\n /** Visual treatment: solid, soft or outline. @default 'soft' */\n badgeStyle = input<BadgeStyle>('soft');\n /** Corner style: pill, rounded or square. @default 'pill' */\n shape = input<BadgeShape>('pill');\n /** Badge size: sm, md or lg. @default 'md' */\n size = input<BadgeSize>('md');\n /** Badge text. Omit when using count mode or projecting content. */\n label = input<string>('');\n /** Show status dot. @default false */\n dot = input<boolean>(false);\n /** Animate dot with ping. @default false */\n pulseDot = input<boolean>(false);\n /**\n * When > 0, renders count mode (overrides label).\n * @default 0\n */\n count = input<number>(0);\n /** Cap for count display (shows \"N+\"). @default 99 */\n maxCount = input<number>(99);\n /** SVG path `d` for leading icon. */\n iconPath = input<string>('');\n /** Show dismiss button. @default false */\n dismissible = input<boolean>(false);\n /** Extra CSS classes merged on root. */\n customClass = input<string>('');\n /** aria-label override — replaces the visible text as the accessible name. */\n ariaLabel = input<string>('');\n /**\n * Announce the badge as a polite ARIA live region (`role=\"status\"`).\n * Enable for dynamic notification counts/statuses that update in place so\n * assistive tech is notified of changes. Leave `false` for static labels\n * and tags to avoid noisy announcements. @default false\n */\n live = input<boolean>(false);\n\n // ── Outputs ───────────────────────────────────────────────────────────────\n\n /** Emitted when the dismiss button is clicked. */\n dismissed = output<void>();\n\n // ── Computed ──────────────────────────────────────────────────────────────\n\n resolvedAriaLabel = computed(() => this.ariaLabel() || this.label());\n /**\n * Host ARIA role. A live badge is a polite status region; an aria-label\n * override exposes the badge as a single labelled image; otherwise the\n * visible text is the accessible name and no role is needed.\n */\n hostRole = computed<'status' | 'img' | null>(() => {\n if (this.live()) return 'status';\n if (this.ariaLabel()) return 'img';\n return null;\n });\n isCountMode = computed(() => this.count() > 0);\n displayCount = computed(() => {\n const n = this.count(), max = this.maxCount();\n return n > max ? `${max}+` : `${n}`;\n });\n\n rootClasses = computed(() => [\n 'inline-flex items-center font-medium select-none transition-colors duration-150',\n this._sizeClasses(),\n this._shapeClasses(),\n this._colorClasses(),\n this.customClass(),\n ].filter(Boolean).join(' '));\n\n private _sizeClasses = computed<string>(() => {\n const cm = this.isCountMode();\n switch (this.size()) {\n case 'sm': return cm ? 'h-5 min-w-5 px-1 text-[10px] justify-center gap-1' : 'px-2.5 py-1 text-[11px] gap-1';\n case 'lg': return cm ? 'h-7 min-w-7 px-2 text-sm justify-center gap-2' : 'px-4 py-1.5 text-sm gap-2';\n default: return cm ? 'h-6 min-w-6 px-1.5 text-xs justify-center gap-1.5' : 'px-3 py-1 text-xs gap-1.5';\n }\n });\n\n private _shapeClasses = computed<string>(() => {\n switch (this.shape()) {\n case 'square': return 'rounded-none';\n case 'rounded': return 'rounded-md';\n default: return 'rounded-full';\n }\n });\n\n private _colorClasses = computed<string>(() => {\n const map: Record<BadgeVariant, Record<BadgeStyle, string>> = {\n primary: {\n filled: 'bg-blue-600 text-white dark:bg-blue-600',\n soft: 'bg-blue-50 text-blue-700 ring-1 ring-blue-100 dark:bg-blue-950/60 dark:text-blue-300 dark:ring-blue-900/50',\n outline: 'bg-transparent text-blue-700 ring-1 ring-inset ring-blue-400 dark:text-blue-400 dark:ring-blue-700',\n },\n secondary: {\n filled: 'bg-gray-700 text-white dark:bg-gray-500',\n soft: 'bg-gray-100 text-gray-700 ring-1 ring-gray-200 dark:bg-gray-800/70 dark:text-gray-300 dark:ring-gray-700/60',\n outline: 'bg-transparent text-gray-600 ring-1 ring-inset ring-gray-300 dark:text-gray-400 dark:ring-gray-600',\n },\n success: {\n filled: 'bg-emerald-600 text-white dark:bg-emerald-600',\n soft: 'bg-emerald-50 text-emerald-700 ring-1 ring-emerald-100 dark:bg-emerald-950/60 dark:text-emerald-300 dark:ring-emerald-900/50',\n outline: 'bg-transparent text-emerald-700 ring-1 ring-inset ring-emerald-400 dark:text-emerald-400 dark:ring-emerald-700',\n },\n warning: {\n filled: 'bg-amber-500 text-white dark:bg-amber-500',\n soft: 'bg-amber-50 text-amber-700 ring-1 ring-amber-100 dark:bg-amber-950/60 dark:text-amber-300 dark:ring-amber-900/50',\n outline: 'bg-transparent text-amber-700 ring-1 ring-inset ring-amber-400 dark:text-amber-400 dark:ring-amber-700',\n },\n danger: {\n filled: 'bg-red-600 text-white dark:bg-red-600',\n soft: 'bg-red-50 text-red-700 ring-1 ring-red-100 dark:bg-red-950/60 dark:text-red-300 dark:ring-red-900/50',\n outline: 'bg-transparent text-red-700 ring-1 ring-inset ring-red-400 dark:text-red-400 dark:ring-red-700',\n },\n info: {\n filled: 'bg-sky-600 text-white dark:bg-sky-600',\n soft: 'bg-sky-50 text-sky-700 ring-1 ring-sky-100 dark:bg-sky-950/60 dark:text-sky-300 dark:ring-sky-900/50',\n outline: 'bg-transparent text-sky-700 ring-1 ring-inset ring-sky-400 dark:text-sky-400 dark:ring-sky-700',\n },\n neutral: {\n filled: 'bg-gray-900 text-white dark:bg-gray-200 dark:text-gray-900',\n soft: 'bg-gray-100 text-gray-600 ring-1 ring-gray-200 dark:bg-gray-800/80 dark:text-gray-400 dark:ring-gray-700/60',\n outline: 'bg-transparent text-gray-600 ring-1 ring-inset ring-gray-300 dark:text-gray-400 dark:ring-gray-600',\n },\n };\n return map[this.variant()][this.badgeStyle()];\n });\n\n dotColorClass = computed<string>(() => {\n const map: Record<BadgeVariant, string> = {\n primary: 'bg-blue-500 dark:bg-blue-400',\n secondary: 'bg-gray-500 dark:bg-gray-400',\n success: 'bg-emerald-500 dark:bg-emerald-400',\n warning: 'bg-amber-500 dark:bg-amber-400',\n danger: 'bg-red-500 dark:bg-red-400',\n info: 'bg-sky-500 dark:bg-sky-400',\n neutral: 'bg-zinc-500 dark:bg-zinc-400',\n };\n return map[this.variant()];\n });\n\n dismissColorClass = computed<string>(() => {\n if (this.badgeStyle() === 'filled') {\n return 'text-white/70 hover:text-white hover:bg-white/20';\n }\n const map: Record<BadgeVariant, string> = {\n primary: 'text-blue-500 hover:text-blue-700 hover:bg-blue-100 dark:text-blue-400 dark:hover:text-blue-200 dark:hover:bg-blue-800/40',\n secondary: 'text-gray-400 hover:text-gray-600 hover:bg-gray-200 dark:text-gray-500 dark:hover:text-gray-200 dark:hover:bg-gray-700',\n success: 'text-emerald-500 hover:text-emerald-700 hover:bg-emerald-100 dark:text-emerald-400 dark:hover:text-emerald-200 dark:hover:bg-emerald-800/40',\n warning: 'text-amber-500 hover:text-amber-700 hover:bg-amber-100 dark:text-amber-400 dark:hover:text-amber-200 dark:hover:bg-amber-800/40',\n danger: 'text-red-500 hover:text-red-700 hover:bg-red-100 dark:text-red-400 dark:hover:text-red-200 dark:hover:bg-red-800/40',\n info: 'text-sky-500 hover:text-sky-700 hover:bg-sky-100 dark:text-sky-400 dark:hover:text-sky-200 dark:hover:bg-sky-800/40',\n neutral: 'text-zinc-500 hover:text-zinc-700 hover:bg-zinc-200 dark:text-zinc-400 dark:hover:text-zinc-200 dark:hover:bg-zinc-700',\n };\n return map[this.variant()];\n });\n\n onDismiss(event: MouseEvent): void {\n event.stopPropagation();\n this.dismissed.emit();\n }\n}\n","<span\n [ngClass]=\"rootClasses()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.role]=\"hostRole()\"\n [attr.aria-live]=\"live() ? 'polite' : null\"\n>\n @if (dot()) {\n <span\n class=\"relative inline-flex shrink-0 rounded-full\"\n [ngClass]=\"[\n size() === 'sm' ? 'h-1.5 w-1.5' : size() === 'lg' ? 'h-2.5 w-2.5' : 'h-2 w-2',\n dotColorClass()\n ]\"\n aria-hidden=\"true\"\n >\n @if (pulseDot()) {\n <span\n class=\"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75\"\n [ngClass]=\"dotColorClass()\"\n ></span>\n }\n </span>\n }\n\n @if (iconPath()) {\n <svg\n class=\"shrink-0\"\n [ngClass]=\"size() === 'sm' ? 'h-3 w-3' : size() === 'lg' ? 'h-4.5 w-4.5' : 'h-3.5 w-3.5'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path [attr.d]=\"iconPath()\" />\n </svg>\n }\n\n @if (isCountMode()) {\n <span class=\"tabular-nums leading-none\">{{ displayCount() }}</span>\n } @else if (label()) {\n <span class=\"leading-none whitespace-nowrap\">{{ label() }}</span>\n }\n\n @if (dismissible() && !isCountMode()) {\n <button\n type=\"button\"\n class=\"inline-flex shrink-0 items-center justify-center rounded-full transition-colors\n duration-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-current\"\n [ngClass]=\"[\n size() === 'sm' ? 'h-3 w-3 -mr-0.5' : size() === 'lg' ? 'h-4.5 w-4.5 -mr-0.5' : 'h-3.5 w-3.5 -mr-0.5',\n dismissColorClass()\n ]\"\n (click)=\"onDismiss($event)\"\n [attr.aria-label]=\"'Remove ' + (label() || ariaLabel() || 'badge')\"\n >\n <svg class=\"h-full w-full\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M3 3l8 8M11 3l-8 8\" />\n </svg>\n </button>\n }\n</span>\n","/**\n * @styloviz/badge — Public API\n */\nexport { SvBadgeComponent } from './lib/badge.component';\nexport type {\n BadgeVariant,\n BadgeSize,\n BadgeStyle,\n BadgeShape,\n} from './lib/badge.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@styloviz/badge",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Compact status and category labels with 7 semantic variants and 3 visual styles.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"tailwind",
|
|
8
|
+
"ui-kit",
|
|
9
|
+
"badge",
|
|
10
|
+
"styloviz"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "sazzad-bs23",
|
|
14
|
+
"homepage": "https://styloviz.dev",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/rhossain/angular-tailwind-dashboard-components.git",
|
|
18
|
+
"directory": "projects/badge"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/rhossain/angular-tailwind-dashboard-components/issues"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@angular/common": ">=21.0.0",
|
|
25
|
+
"@angular/core": ">=21.0.0",
|
|
26
|
+
"@styloviz/core": ">=0.1.0"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
|
33
|
+
},
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"module": "fesm2022/styloviz-badge.mjs",
|
|
36
|
+
"typings": "types/styloviz-badge.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
"./package.json": {
|
|
39
|
+
"default": "./package.json"
|
|
40
|
+
},
|
|
41
|
+
".": {
|
|
42
|
+
"types": "./types/styloviz-badge.d.ts",
|
|
43
|
+
"default": "./fesm2022/styloviz-badge.mjs"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"type": "module",
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"tslib": "^2.3.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
|
|
3
|
+
type BadgeVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'neutral';
|
|
4
|
+
type BadgeSize = 'sm' | 'md' | 'lg';
|
|
5
|
+
type BadgeStyle = 'filled' | 'soft' | 'outline';
|
|
6
|
+
type BadgeShape = 'rounded' | 'pill' | 'square';
|
|
7
|
+
/**
|
|
8
|
+
* SvBadgeComponent — Compact, accessible label for statuses, counts, and tags.
|
|
9
|
+
*
|
|
10
|
+
* Install: npm install @styloviz/badge
|
|
11
|
+
* Import: import { SvBadgeComponent } from '@styloviz/badge';
|
|
12
|
+
*
|
|
13
|
+
* Features:
|
|
14
|
+
* - 7 variants × 3 styles × 3 shapes × 3 sizes
|
|
15
|
+
* - Optional status dot with pulse animation
|
|
16
|
+
* - Count mode (notification badge)
|
|
17
|
+
* - Leading icon slot
|
|
18
|
+
* - Dismiss button
|
|
19
|
+
* - Full dark mode + OnPush
|
|
20
|
+
*/
|
|
21
|
+
declare class SvBadgeComponent {
|
|
22
|
+
/** Semantic color/intent (primary, success, warning, danger…). @default 'primary' */
|
|
23
|
+
variant: _angular_core.InputSignal<BadgeVariant>;
|
|
24
|
+
/** Visual treatment: solid, soft or outline. @default 'soft' */
|
|
25
|
+
badgeStyle: _angular_core.InputSignal<BadgeStyle>;
|
|
26
|
+
/** Corner style: pill, rounded or square. @default 'pill' */
|
|
27
|
+
shape: _angular_core.InputSignal<BadgeShape>;
|
|
28
|
+
/** Badge size: sm, md or lg. @default 'md' */
|
|
29
|
+
size: _angular_core.InputSignal<BadgeSize>;
|
|
30
|
+
/** Badge text. Omit when using count mode or projecting content. */
|
|
31
|
+
label: _angular_core.InputSignal<string>;
|
|
32
|
+
/** Show status dot. @default false */
|
|
33
|
+
dot: _angular_core.InputSignal<boolean>;
|
|
34
|
+
/** Animate dot with ping. @default false */
|
|
35
|
+
pulseDot: _angular_core.InputSignal<boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* When > 0, renders count mode (overrides label).
|
|
38
|
+
* @default 0
|
|
39
|
+
*/
|
|
40
|
+
count: _angular_core.InputSignal<number>;
|
|
41
|
+
/** Cap for count display (shows "N+"). @default 99 */
|
|
42
|
+
maxCount: _angular_core.InputSignal<number>;
|
|
43
|
+
/** SVG path `d` for leading icon. */
|
|
44
|
+
iconPath: _angular_core.InputSignal<string>;
|
|
45
|
+
/** Show dismiss button. @default false */
|
|
46
|
+
dismissible: _angular_core.InputSignal<boolean>;
|
|
47
|
+
/** Extra CSS classes merged on root. */
|
|
48
|
+
customClass: _angular_core.InputSignal<string>;
|
|
49
|
+
/** aria-label override — replaces the visible text as the accessible name. */
|
|
50
|
+
ariaLabel: _angular_core.InputSignal<string>;
|
|
51
|
+
/**
|
|
52
|
+
* Announce the badge as a polite ARIA live region (`role="status"`).
|
|
53
|
+
* Enable for dynamic notification counts/statuses that update in place so
|
|
54
|
+
* assistive tech is notified of changes. Leave `false` for static labels
|
|
55
|
+
* and tags to avoid noisy announcements. @default false
|
|
56
|
+
*/
|
|
57
|
+
live: _angular_core.InputSignal<boolean>;
|
|
58
|
+
/** Emitted when the dismiss button is clicked. */
|
|
59
|
+
dismissed: _angular_core.OutputEmitterRef<void>;
|
|
60
|
+
resolvedAriaLabel: _angular_core.Signal<string>;
|
|
61
|
+
/**
|
|
62
|
+
* Host ARIA role. A live badge is a polite status region; an aria-label
|
|
63
|
+
* override exposes the badge as a single labelled image; otherwise the
|
|
64
|
+
* visible text is the accessible name and no role is needed.
|
|
65
|
+
*/
|
|
66
|
+
hostRole: _angular_core.Signal<"status" | "img" | null>;
|
|
67
|
+
isCountMode: _angular_core.Signal<boolean>;
|
|
68
|
+
displayCount: _angular_core.Signal<string>;
|
|
69
|
+
rootClasses: _angular_core.Signal<string>;
|
|
70
|
+
private _sizeClasses;
|
|
71
|
+
private _shapeClasses;
|
|
72
|
+
private _colorClasses;
|
|
73
|
+
dotColorClass: _angular_core.Signal<string>;
|
|
74
|
+
dismissColorClass: _angular_core.Signal<string>;
|
|
75
|
+
onDismiss(event: MouseEvent): void;
|
|
76
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SvBadgeComponent, never>;
|
|
77
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SvBadgeComponent, "sv-badge", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "badgeStyle": { "alias": "badgeStyle"; "required": false; "isSignal": true; }; "shape": { "alias": "shape"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "dot": { "alias": "dot"; "required": false; "isSignal": true; }; "pulseDot": { "alias": "pulseDot"; "required": false; "isSignal": true; }; "count": { "alias": "count"; "required": false; "isSignal": true; }; "maxCount": { "alias": "maxCount"; "required": false; "isSignal": true; }; "iconPath": { "alias": "iconPath"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; "customClass": { "alias": "customClass"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "live": { "alias": "live"; "required": false; "isSignal": true; }; }, { "dismissed": "dismissed"; }, never, never, true, never>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { SvBadgeComponent };
|
|
81
|
+
export type { BadgeShape, BadgeSize, BadgeStyle, BadgeVariant };
|