@styloviz/button 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 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,79 @@
1
+ # @styloviz/button
2
+
3
+ > Versatile button with semantic variants, sizes, icon slots, loading and block states.
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/button
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 { SvButtonComponent } from '@styloviz/button';
19
+
20
+ @Component({
21
+ standalone: true,
22
+ imports: [SvButtonComponent],
23
+ template: `
24
+ <sv-button />
25
+ `,
26
+ })
27
+ export class DemoComponent {}
28
+ ```
29
+
30
+ ## Inputs
31
+
32
+ | Input | Type | Default | Description |
33
+ | --- | --- | --- | --- |
34
+ | `variant` | `ButtonVariant` | `'primary'` | Semantic color/intent: primary, secondary, success, danger, etc. |
35
+ | `btnStyle` | `ButtonStyle` | `'solid'` | Visual treatment: solid, soft, outline, ghost, link or gradient. |
36
+ | `size` | `ButtonSize` | `'md'` | Button size from xs to xl. |
37
+ | `shape` | `ButtonShape` | `'rounded'` | Corner style: rounded, pill or square. |
38
+ | `block` | `boolean` | `false` | Stretch to 100% width. |
39
+ | `elevated` | `boolean` | `false` | Add drop shadow. |
40
+ | `label` | `string` | `''` | Button text. Omit when projecting custom content. |
41
+ | `iconPath` | `string` | `''` | SVG path for the built-in leading/trailing icon (quick built-in icons, e.g. Heroicons path strings). Ignored when `iconTemplate` is set. |
42
+ | `iconViewBox` | `string` | `'0 0 24 24'` | viewBox for the provided icon paths. |
43
+ | `trailingIconPath` | `string` | `''` | SVG path for the built-in secondary/dual trailing icon. Ignored when `trailingIconTemplate` is set. |
44
+ | `iconTemplate` | `ButtonIconTemplate` | `null` | Custom template for the primary icon — use this to render a third-party icon component (e.g. lucide-angular, ngx-heroicons), an `<img>`, an icon font `<i>`, or arbitrary custom SVG instead of the built-in `iconPath`. Positioned per `iconPosition()`. Takes precedence over `iconPath` when set. |
45
+ | `trailingIconTemplate` | `ButtonIconTemplate` | `null` | Custom template for the secondary/dual trailing icon. Takes precedence over `trailingIconPath` when set. See `iconTemplate` for usage. |
46
+ | `iconPosition` | `ButtonIconPos` | `'leading'` | Where the main icon sits relative to the label. |
47
+ | `counter` | `number \| null` | `null` | Numeric counter badge. null = hidden. |
48
+ | `counterMax` | `number` | `99` | Value above which the counter shows "{max}+". |
49
+ | `counterLabel` | `string` | `''` | Noun describing the counter for screen readers, e.g. "unread". |
50
+ | `type` | `ButtonType` | `'button'` | Native button type when not in link mode. |
51
+ | `disabled` | `boolean` | `false` | Disable interaction and dim the button. |
52
+ | `loading` | `boolean` | `false` | Show a loading indicator and block activation. |
53
+ | `loadingStyle` | `ButtonLoader` | `'spinner'` | Loading indicator style: spinner or dots. |
54
+ | `loadingLabel` | `string` | `''` | Optional text shown beside the loading indicator. |
55
+ | `href` | `string` | `''` | When set, renders an <a> anchor instead of a <button>. |
56
+ | `target` | `string` | `'_self'` | Anchor target (e.g. _blank) when href is set. |
57
+ | `rel` | `string` | `''` | Anchor rel. `noopener noreferrer` is auto-added for target="_blank". |
58
+ | `download` | `string \| null` | `null` | Anchor download attribute (filename or empty string to use the URL). |
59
+ | `name` | `string` | `''` | Native `name` for the button when submitted as part of a form. |
60
+ | `value` | `string` | `''` | Native `value` submitted with `name` for multi-button forms. |
61
+ | `ariaLabel` | `string` | `''` | Explicit accessible name. Required for icon-only buttons; overrides label. |
62
+ | `title` | `string` | `''` | Native tooltip / title attribute. |
63
+ | `autofocus` | `boolean` | `false` | Autofocus the control on render. |
64
+
65
+ ## Outputs
66
+
67
+ | Output | Type | Description |
68
+ | --- | --- | --- |
69
+ | `clicked` | `MouseEvent` | Emitted on click (suppressed while disabled or loading). |
70
+ | `focused` | `FocusEvent` | Emitted when the control receives focus. |
71
+ | `blurred` | `FocusEvent` | Emitted when the control loses focus. |
72
+
73
+ ## Documentation
74
+
75
+ Full API reference and live demos: https://styloviz.dev/docs
76
+
77
+ ## License
78
+
79
+ MIT
@@ -0,0 +1,342 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, output, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { NgTemplateOutlet } from '@angular/common';
4
+
5
+ // ─── Component ───────────────────────────────────────────────────────────────
6
+ /**
7
+ * SvButtonComponent — Premium, accessible button for StyloViz dashboards.
8
+ *
9
+ * Install: npm install @styloviz/button
10
+ * Import: import { SvButtonComponent } from '@styloviz/button';
11
+ *
12
+ * Features:
13
+ * - 9 variants × 6 styles × 5 sizes × 3 shapes
14
+ * - 3 loading animations: spinner · dots · pulse
15
+ * - Leading, trailing, and icon-only modes
16
+ * - Dual-icon layout via trailingIconPath
17
+ * - Bring-your-own icon via `iconTemplate` / `trailingIconTemplate` — render
18
+ * any third-party icon component, <img>, icon font, or custom SVG instead
19
+ * of the built-in path-based icon
20
+ * - Counter badge (top-right)
21
+ * - Renders as <a> when href is provided
22
+ * - Full dark-mode + OnPush
23
+ */
24
+ class SvButtonComponent {
25
+ // ── Appearance ────────────────────────────────────────────────────────────
26
+ /** Semantic color/intent: primary, secondary, success, danger, etc. @default 'primary' */
27
+ variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
28
+ /** Visual treatment: solid, soft, outline, ghost, link or gradient. @default 'solid' */
29
+ btnStyle = input('solid', ...(ngDevMode ? [{ debugName: "btnStyle" }] : /* istanbul ignore next */ []));
30
+ /** Button size from xs to xl. @default 'md' */
31
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
32
+ /** Corner style: rounded, pill or square. @default 'rounded' */
33
+ shape = input('rounded', ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
34
+ /** Stretch to 100% width. @default false */
35
+ block = input(false, ...(ngDevMode ? [{ debugName: "block" }] : /* istanbul ignore next */ []));
36
+ /** Add drop shadow. @default false */
37
+ elevated = input(false, ...(ngDevMode ? [{ debugName: "elevated" }] : /* istanbul ignore next */ []));
38
+ // ── Content ───────────────────────────────────────────────────────────────
39
+ /** Button text. Omit when projecting custom content. */
40
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
41
+ /**
42
+ * SVG path for the built-in leading/trailing icon (quick built-in icons,
43
+ * e.g. Heroicons path strings). Ignored when `iconTemplate` is set.
44
+ */
45
+ iconPath = input('', ...(ngDevMode ? [{ debugName: "iconPath" }] : /* istanbul ignore next */ []));
46
+ /** viewBox for the provided icon paths. @default '0 0 24 24' */
47
+ iconViewBox = input('0 0 24 24', ...(ngDevMode ? [{ debugName: "iconViewBox" }] : /* istanbul ignore next */ []));
48
+ /**
49
+ * SVG path for the built-in secondary/dual trailing icon. Ignored when
50
+ * `trailingIconTemplate` is set.
51
+ */
52
+ trailingIconPath = input('', ...(ngDevMode ? [{ debugName: "trailingIconPath" }] : /* istanbul ignore next */ []));
53
+ /**
54
+ * Custom template for the primary icon — use this to render a third-party
55
+ * icon component (e.g. lucide-angular, ngx-heroicons), an `<img>`, an icon
56
+ * font `<i>`, or arbitrary custom SVG instead of the built-in `iconPath`.
57
+ * Positioned per `iconPosition()`. Takes precedence over `iconPath` when set.
58
+ *
59
+ * @example
60
+ * ```html
61
+ * <ng-template #saveIcon>
62
+ * <img src="/assets/icons/save.svg" alt="" />
63
+ * </ng-template>
64
+ * <sv-button label="Save" [iconTemplate]="saveIcon" />
65
+ * ```
66
+ */
67
+ iconTemplate = input(null, ...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
68
+ /**
69
+ * Custom template for the secondary/dual trailing icon. Takes precedence
70
+ * over `trailingIconPath` when set. See `iconTemplate` for usage.
71
+ */
72
+ trailingIconTemplate = input(null, ...(ngDevMode ? [{ debugName: "trailingIconTemplate" }] : /* istanbul ignore next */ []));
73
+ /** Where the main icon sits relative to the label. @default 'leading' */
74
+ iconPosition = input('leading', ...(ngDevMode ? [{ debugName: "iconPosition" }] : /* istanbul ignore next */ []));
75
+ /** Numeric counter badge. null = hidden. @default null */
76
+ counter = input(null, ...(ngDevMode ? [{ debugName: "counter" }] : /* istanbul ignore next */ []));
77
+ /** Value above which the counter shows "{max}+". @default 99 */
78
+ counterMax = input(99, ...(ngDevMode ? [{ debugName: "counterMax" }] : /* istanbul ignore next */ []));
79
+ /** Noun describing the counter for screen readers, e.g. "unread". */
80
+ counterLabel = input('', ...(ngDevMode ? [{ debugName: "counterLabel" }] : /* istanbul ignore next */ []));
81
+ // ── State ─────────────────────────────────────────────────────────────────
82
+ /** Native button type when not in link mode. @default 'button' */
83
+ type = input('button', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
84
+ /** Disable interaction and dim the button. @default false */
85
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
86
+ /** Show a loading indicator and block activation. @default false */
87
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
88
+ /** Loading indicator style: spinner or dots. @default 'spinner' */
89
+ loadingStyle = input('spinner', ...(ngDevMode ? [{ debugName: "loadingStyle" }] : /* istanbul ignore next */ []));
90
+ /** Optional text shown beside the loading indicator. */
91
+ loadingLabel = input('', ...(ngDevMode ? [{ debugName: "loadingLabel" }] : /* istanbul ignore next */ []));
92
+ // ── Link mode ─────────────────────────────────────────────────────────────
93
+ /** When set, renders an <a> anchor instead of a <button>. */
94
+ href = input('', ...(ngDevMode ? [{ debugName: "href" }] : /* istanbul ignore next */ []));
95
+ /** Anchor target (e.g. _blank) when href is set. @default '_self' */
96
+ target = input('_self', ...(ngDevMode ? [{ debugName: "target" }] : /* istanbul ignore next */ []));
97
+ /** Anchor rel. `noopener noreferrer` is auto-added for target="_blank". */
98
+ rel = input('', ...(ngDevMode ? [{ debugName: "rel" }] : /* istanbul ignore next */ []));
99
+ /** Anchor download attribute (filename or empty string to use the URL). */
100
+ download = input(null, ...(ngDevMode ? [{ debugName: "download" }] : /* istanbul ignore next */ []));
101
+ // ── Form integration (button mode) ─────────────────────────────────────────
102
+ /** Native `name` for the button when submitted as part of a form. */
103
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
104
+ /** Native `value` submitted with `name` for multi-button forms. */
105
+ value = input('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
106
+ // ── Accessibility ───────────────────────────────────────────────────────────
107
+ /** Explicit accessible name. Required for icon-only buttons; overrides label. */
108
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
109
+ /** Native tooltip / title attribute. */
110
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
111
+ /** Autofocus the control on render. @default false */
112
+ autofocus = input(false, ...(ngDevMode ? [{ debugName: "autofocus" }] : /* istanbul ignore next */ []));
113
+ // ── Output ────────────────────────────────────────────────────────────────
114
+ /** Emitted on click (suppressed while disabled or loading). */
115
+ clicked = output();
116
+ /** Emitted when the control receives focus. */
117
+ focused = output();
118
+ /** Emitted when the control loses focus. */
119
+ blurred = output();
120
+ // ── Computed ──────────────────────────────────────────────────────────────
121
+ isDisabled = computed(() => this.disabled() || this.loading(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
122
+ displayLabel = computed(() => this.loading() && this.loadingLabel() ? this.loadingLabel() : this.label(), ...(ngDevMode ? [{ debugName: "displayLabel" }] : /* istanbul ignore next */ []));
123
+ /** True when a counter badge should be shown. */
124
+ hasCounter = computed(() => this.counter() !== null && this.counter() >= 0, ...(ngDevMode ? [{ debugName: "hasCounter" }] : /* istanbul ignore next */ []));
125
+ /** Text rendered inside the counter badge (e.g. "99+"). */
126
+ counterText = computed(() => {
127
+ const n = this.counter();
128
+ if (n === null)
129
+ return '';
130
+ const max = this.counterMax();
131
+ return n > max ? `${max}+` : `${n}`;
132
+ }, ...(ngDevMode ? [{ debugName: "counterText" }] : /* istanbul ignore next */ []));
133
+ /**
134
+ * Accessible name. Uses ariaLabel, then label. Appends the counter
135
+ * (e.g. "Inbox, 5 unread") so screen readers announce the badge.
136
+ */
137
+ accessibleLabel = computed(() => {
138
+ const base = this.ariaLabel() || this.label();
139
+ if (!this.hasCounter())
140
+ return base || null;
141
+ const noun = this.counterLabel() ? ` ${this.counterLabel()}` : '';
142
+ const count = `${this.counter()}${noun}`;
143
+ return base ? `${base}, ${count}` : count;
144
+ }, ...(ngDevMode ? [{ debugName: "accessibleLabel" }] : /* istanbul ignore next */ []));
145
+ /** Resolved rel for anchors; ensures safe defaults for new tabs. */
146
+ computedRel = computed(() => {
147
+ const tokens = new Set(this.rel().split(/\s+/).filter(Boolean));
148
+ if (this.target() === '_blank') {
149
+ tokens.add('noopener');
150
+ tokens.add('noreferrer');
151
+ }
152
+ return tokens.size ? [...tokens].join(' ') : null;
153
+ }, ...(ngDevMode ? [{ debugName: "computedRel" }] : /* istanbul ignore next */ []));
154
+ classes = computed(() => {
155
+ const displayClass = this.block() ? 'flex w-full' : 'inline-flex';
156
+ const baseClasses = this._base.replace('inline-flex', displayClass);
157
+ return [
158
+ baseClasses,
159
+ this._sizeClasses(this.size()),
160
+ this._shapeClasses(this.shape()),
161
+ this._variantStyleClasses(this.variant(), this.btnStyle()),
162
+ this._stateClasses(),
163
+ this.elevated() && !['link', 'ghost'].includes(this.btnStyle())
164
+ ? 'shadow-md hover:shadow-lg active:shadow-sm'
165
+ : '',
166
+ ].filter(Boolean).join(' ');
167
+ }, ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
168
+ iconSizeClass = computed(() => {
169
+ const map = {
170
+ xs: 'h-3.5 w-3.5', sm: 'h-4 w-4', md: 'h-[18px] w-[18px]',
171
+ lg: 'h-5 w-5', xl: 'h-6 w-6',
172
+ };
173
+ return map[this.size()];
174
+ }, ...(ngDevMode ? [{ debugName: "iconSizeClass" }] : /* istanbul ignore next */ []));
175
+ spinnerSizeClass = computed(() => {
176
+ const map = {
177
+ xs: 'h-3 w-3', sm: 'h-3.5 w-3.5', md: 'h-4 w-4',
178
+ lg: 'h-[18px] w-[18px]', xl: 'h-5 w-5',
179
+ };
180
+ return map[this.size()];
181
+ }, ...(ngDevMode ? [{ debugName: "spinnerSizeClass" }] : /* istanbul ignore next */ []));
182
+ /**
183
+ * Sizing wrapper for a projected `iconTemplate`. Constrains third-party
184
+ * icon components, `<img>`, and custom SVG to the same box the built-in
185
+ * icon would occupy, so custom icons line up regardless of their own
186
+ * intrinsic markup or default size.
187
+ */
188
+ customIconWrapperClass = computed(() => `${this.iconSizeClass()} inline-flex shrink-0 items-center justify-center ` +
189
+ '[&>svg]:h-full [&>svg]:w-full [&>img]:h-full [&>img]:w-full [&>img]:object-contain', ...(ngDevMode ? [{ debugName: "customIconWrapperClass" }] : /* istanbul ignore next */ []));
190
+ /** Same as `customIconWrapperClass`, dimmed to match `trailingIconPath`'s dual-icon treatment. */
191
+ trailingCustomIconWrapperClass = computed(() => `${this.customIconWrapperClass()} opacity-70`, ...(ngDevMode ? [{ debugName: "trailingCustomIconWrapperClass" }] : /* istanbul ignore next */ []));
192
+ // ── Event ─────────────────────────────────────────────────────────────────
193
+ handleClick(event) {
194
+ if (this.isDisabled()) {
195
+ event.preventDefault();
196
+ event.stopPropagation();
197
+ return;
198
+ }
199
+ this.clicked.emit(event);
200
+ }
201
+ // ── Private helpers ───────────────────────────────────────────────────────
202
+ _base = 'relative inline-flex items-center justify-center font-medium ' +
203
+ 'transition-all duration-150 focus-visible:outline-none ' +
204
+ 'focus-visible:ring-2 focus-visible:ring-offset-2 ' +
205
+ 'focus-visible:ring-offset-white dark:focus-visible:ring-offset-gray-950 ' +
206
+ 'select-none whitespace-nowrap leading-none';
207
+ _sizeClasses(sz) {
208
+ const iconOnly = this.iconPosition() === 'only';
209
+ const map = {
210
+ xs: { text: 'h-7 px-2.5 text-xs gap-1.5', icon: 'h-7 w-7 text-xs' },
211
+ sm: { text: 'h-8 px-3 text-sm gap-1.5', icon: 'h-8 w-8 text-sm' },
212
+ md: { text: 'h-9 px-4 text-sm gap-2', icon: 'h-9 w-9 text-sm' },
213
+ lg: { text: 'h-10 px-5 text-[15px] gap-2', icon: 'h-10 w-10 text-[15px]' },
214
+ xl: { text: 'h-12 px-6 text-base gap-2.5', icon: 'h-12 w-12 text-base' },
215
+ };
216
+ return iconOnly ? map[sz].icon : map[sz].text;
217
+ }
218
+ _shapeClasses(sh) {
219
+ const map = {
220
+ rounded: 'rounded-md', pill: 'rounded-full', square: 'rounded-none',
221
+ };
222
+ return map[sh];
223
+ }
224
+ _variantStyleClasses(v, s) {
225
+ switch (s) {
226
+ case 'solid': return this._solid(v);
227
+ case 'outline': return this._outline(v);
228
+ case 'soft': return this._soft(v);
229
+ case 'ghost': return this._ghost(v);
230
+ case 'link': return this._link(v);
231
+ case 'gradient': return this._gradient(v);
232
+ }
233
+ }
234
+ _solid(v) {
235
+ const map = {
236
+ primary: 'bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800 focus-visible:ring-blue-500',
237
+ secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200 active:bg-gray-300 focus-visible:ring-gray-400 dark:bg-gray-700 dark:text-gray-100 dark:hover:bg-gray-600',
238
+ success: 'bg-emerald-600 text-white hover:bg-emerald-700 active:bg-emerald-800 focus-visible:ring-emerald-500',
239
+ warning: 'bg-amber-500 text-white hover:bg-amber-600 active:bg-amber-700 focus-visible:ring-amber-400',
240
+ danger: 'bg-red-600 text-white hover:bg-red-700 active:bg-red-800 focus-visible:ring-red-500',
241
+ info: 'bg-sky-500 text-white hover:bg-sky-600 active:bg-sky-700 focus-visible:ring-sky-400',
242
+ neutral: 'bg-gray-800 text-white hover:bg-gray-900 focus-visible:ring-gray-600 dark:bg-gray-600 dark:hover:bg-gray-500',
243
+ ghost: 'bg-transparent text-gray-700 hover:bg-gray-100 focus-visible:ring-gray-400 dark:text-gray-300 dark:hover:bg-gray-800',
244
+ link: 'bg-transparent text-blue-600 hover:text-blue-700 hover:underline focus-visible:ring-blue-500 dark:text-blue-400',
245
+ };
246
+ return map[v];
247
+ }
248
+ _outline(v) {
249
+ const map = {
250
+ primary: 'border border-blue-600 text-blue-600 bg-transparent hover:bg-blue-50 focus-visible:ring-blue-500 dark:border-blue-500 dark:text-blue-400 dark:hover:bg-blue-900/20',
251
+ secondary: 'border border-gray-300 text-gray-700 bg-transparent hover:bg-gray-50 focus-visible:ring-gray-400 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800',
252
+ success: 'border border-emerald-600 text-emerald-600 bg-transparent hover:bg-emerald-50 focus-visible:ring-emerald-500 dark:border-emerald-500 dark:text-emerald-400 dark:hover:bg-emerald-900/20',
253
+ warning: 'border border-amber-500 text-amber-600 bg-transparent hover:bg-amber-50 focus-visible:ring-amber-400 dark:border-amber-400 dark:text-amber-400 dark:hover:bg-amber-900/20',
254
+ danger: 'border border-red-600 text-red-600 bg-transparent hover:bg-red-50 focus-visible:ring-red-500 dark:border-red-500 dark:text-red-400 dark:hover:bg-red-900/20',
255
+ info: 'border border-sky-500 text-sky-600 bg-transparent hover:bg-sky-50 focus-visible:ring-sky-400 dark:border-sky-400 dark:text-sky-400 dark:hover:bg-sky-900/20',
256
+ neutral: 'border border-gray-700 text-gray-800 bg-transparent hover:bg-gray-50 focus-visible:ring-gray-600 dark:border-gray-500 dark:text-gray-300 dark:hover:bg-gray-800',
257
+ ghost: 'border border-transparent text-gray-600 bg-transparent hover:border-gray-300 hover:bg-gray-50 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:border-gray-600 dark:hover:bg-gray-800',
258
+ link: 'border border-transparent text-blue-600 bg-transparent hover:border-blue-300 hover:bg-blue-50 focus-visible:ring-blue-500 dark:text-blue-400 dark:hover:bg-blue-900/20',
259
+ };
260
+ return map[v];
261
+ }
262
+ _soft(v) {
263
+ const map = {
264
+ primary: 'bg-blue-50 text-blue-700 hover:bg-blue-100 focus-visible:ring-blue-400 dark:bg-blue-900/30 dark:text-blue-300 dark:hover:bg-blue-900/50',
265
+ secondary: 'bg-gray-100 text-gray-700 hover:bg-gray-200 focus-visible:ring-gray-400 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700',
266
+ success: 'bg-emerald-50 text-emerald-700 hover:bg-emerald-100 focus-visible:ring-emerald-400 dark:bg-emerald-900/30 dark:text-emerald-300 dark:hover:bg-emerald-900/50',
267
+ warning: 'bg-amber-50 text-amber-700 hover:bg-amber-100 focus-visible:ring-amber-400 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50',
268
+ danger: 'bg-red-50 text-red-700 hover:bg-red-100 focus-visible:ring-red-400 dark:bg-red-900/30 dark:text-red-300 dark:hover:bg-red-900/50',
269
+ info: 'bg-sky-50 text-sky-700 hover:bg-sky-100 focus-visible:ring-sky-400 dark:bg-sky-900/30 dark:text-sky-300 dark:hover:bg-sky-900/50',
270
+ neutral: 'bg-gray-200 text-gray-700 hover:bg-gray-300 focus-visible:ring-gray-400 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600',
271
+ ghost: 'bg-transparent text-gray-600 hover:bg-gray-100 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:bg-gray-800',
272
+ link: 'bg-transparent text-blue-600 hover:bg-blue-50 hover:underline focus-visible:ring-blue-400 dark:text-blue-400 dark:hover:bg-blue-900/20',
273
+ };
274
+ return map[v];
275
+ }
276
+ _ghost(v) {
277
+ const map = {
278
+ primary: 'bg-transparent text-blue-600 hover:bg-blue-50 focus-visible:ring-blue-400 dark:text-blue-400 dark:hover:bg-blue-900/20',
279
+ secondary: 'bg-transparent text-gray-700 hover:bg-gray-100 focus-visible:ring-gray-400 dark:text-gray-300 dark:hover:bg-gray-800',
280
+ success: 'bg-transparent text-emerald-600 hover:bg-emerald-50 focus-visible:ring-emerald-400 dark:text-emerald-400 dark:hover:bg-emerald-900/20',
281
+ warning: 'bg-transparent text-amber-600 hover:bg-amber-50 focus-visible:ring-amber-400 dark:text-amber-400 dark:hover:bg-amber-900/20',
282
+ danger: 'bg-transparent text-red-600 hover:bg-red-50 focus-visible:ring-red-400 dark:text-red-400 dark:hover:bg-red-900/20',
283
+ info: 'bg-transparent text-sky-600 hover:bg-sky-50 focus-visible:ring-sky-400 dark:text-sky-400 dark:hover:bg-sky-900/20',
284
+ neutral: 'bg-transparent text-gray-600 hover:bg-gray-100 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:bg-gray-800',
285
+ ghost: 'bg-transparent text-gray-500 hover:bg-gray-100 focus-visible:ring-gray-300 dark:text-gray-500 dark:hover:bg-gray-800',
286
+ link: 'bg-transparent text-blue-600 hover:text-blue-700 focus-visible:ring-blue-400 dark:text-blue-400 dark:hover:text-blue-300',
287
+ };
288
+ return map[v];
289
+ }
290
+ _link(v) {
291
+ const map = {
292
+ primary: 'bg-transparent text-blue-600 underline-offset-4 hover:underline hover:text-blue-700 focus-visible:ring-blue-400 dark:text-blue-400',
293
+ secondary: 'bg-transparent text-gray-600 underline-offset-4 hover:underline hover:text-gray-900 focus-visible:ring-gray-400 dark:text-gray-400',
294
+ success: 'bg-transparent text-emerald-600 underline-offset-4 hover:underline hover:text-emerald-700 focus-visible:ring-emerald-400 dark:text-emerald-400',
295
+ warning: 'bg-transparent text-amber-600 underline-offset-4 hover:underline focus-visible:ring-amber-400 dark:text-amber-400',
296
+ danger: 'bg-transparent text-red-600 underline-offset-4 hover:underline hover:text-red-700 focus-visible:ring-red-400 dark:text-red-400',
297
+ info: 'bg-transparent text-sky-600 underline-offset-4 hover:underline hover:text-sky-700 focus-visible:ring-sky-400 dark:text-sky-400',
298
+ neutral: 'bg-transparent text-gray-600 underline-offset-4 hover:underline hover:text-gray-900 focus-visible:ring-gray-400 dark:text-gray-300',
299
+ ghost: 'bg-transparent text-gray-500 underline-offset-4 hover:underline hover:text-gray-700 focus-visible:ring-gray-300 dark:text-gray-400',
300
+ link: 'bg-transparent text-blue-600 underline underline-offset-4 hover:text-blue-800 focus-visible:ring-blue-400 dark:text-blue-400',
301
+ };
302
+ return map[v];
303
+ }
304
+ _gradient(v) {
305
+ const map = {
306
+ primary: 'bg-gradient-to-r from-blue-500 to-indigo-600 text-white hover:from-blue-600 hover:to-indigo-700 focus-visible:ring-indigo-500',
307
+ secondary: 'bg-gradient-to-r from-gray-100 to-gray-200 text-gray-900 hover:from-gray-200 hover:to-gray-300 focus-visible:ring-gray-400 dark:from-gray-700 dark:to-gray-800 dark:text-gray-100',
308
+ success: 'bg-gradient-to-r from-emerald-400 to-teal-600 text-white hover:from-emerald-500 hover:to-teal-700 focus-visible:ring-teal-500',
309
+ warning: 'bg-gradient-to-r from-amber-400 to-orange-500 text-white hover:from-amber-500 hover:to-orange-600 focus-visible:ring-orange-400',
310
+ danger: 'bg-gradient-to-r from-rose-500 to-red-600 text-white hover:from-rose-600 hover:to-red-700 focus-visible:ring-red-500',
311
+ info: 'bg-gradient-to-r from-sky-400 to-cyan-500 text-white hover:from-sky-500 hover:to-cyan-600 focus-visible:ring-cyan-400',
312
+ neutral: 'bg-gradient-to-r from-gray-700 to-gray-900 text-white hover:from-gray-800 hover:to-black focus-visible:ring-gray-600',
313
+ ghost: 'bg-gradient-to-r from-gray-50 to-gray-100 text-gray-700 hover:from-gray-100 hover:to-gray-200 focus-visible:ring-gray-400 dark:from-gray-800 dark:to-gray-900 dark:text-gray-200',
314
+ link: 'bg-gradient-to-r from-blue-500 to-violet-600 text-white hover:from-blue-600 hover:to-violet-700 focus-visible:ring-violet-500',
315
+ };
316
+ return map[v];
317
+ }
318
+ _stateClasses() {
319
+ if (this.loading())
320
+ return 'opacity-75 cursor-wait pointer-events-none';
321
+ if (this.disabled())
322
+ return 'opacity-50 cursor-not-allowed pointer-events-none';
323
+ return 'cursor-pointer';
324
+ }
325
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SvButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
326
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: SvButtonComponent, isStandalone: true, selector: "sv-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, btnStyle: { classPropertyName: "btnStyle", publicName: "btnStyle", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null }, elevated: { classPropertyName: "elevated", publicName: "elevated", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, iconPath: { classPropertyName: "iconPath", publicName: "iconPath", isSignal: true, isRequired: false, transformFunction: null }, iconViewBox: { classPropertyName: "iconViewBox", publicName: "iconViewBox", isSignal: true, isRequired: false, transformFunction: null }, trailingIconPath: { classPropertyName: "trailingIconPath", publicName: "trailingIconPath", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, trailingIconTemplate: { classPropertyName: "trailingIconTemplate", publicName: "trailingIconTemplate", isSignal: true, isRequired: false, transformFunction: null }, iconPosition: { classPropertyName: "iconPosition", publicName: "iconPosition", isSignal: true, isRequired: false, transformFunction: null }, counter: { classPropertyName: "counter", publicName: "counter", isSignal: true, isRequired: false, transformFunction: null }, counterMax: { classPropertyName: "counterMax", publicName: "counterMax", isSignal: true, isRequired: false, transformFunction: null }, counterLabel: { classPropertyName: "counterLabel", publicName: "counterLabel", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingStyle: { classPropertyName: "loadingStyle", publicName: "loadingStyle", isSignal: true, isRequired: false, transformFunction: null }, loadingLabel: { classPropertyName: "loadingLabel", publicName: "loadingLabel", isSignal: true, isRequired: false, transformFunction: null }, href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: false, transformFunction: null }, download: { classPropertyName: "download", publicName: "download", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked", focused: "focused", blurred: "blurred" }, ngImport: i0, template: "@if (href()) {\n <a\n [href]=\"isDisabled() ? null : href()\"\n [target]=\"target()\"\n [attr.rel]=\"computedRel()\"\n [attr.download]=\"download()\"\n [attr.role]=\"'link'\"\n [attr.tabindex]=\"isDisabled() ? -1 : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-label]=\"accessibleLabel()\"\n [attr.title]=\"title() || null\"\n [class]=\"classes()\"\n (click)=\"handleClick($event)\"\n (focus)=\"focused.emit($event)\"\n (blur)=\"blurred.emit($event)\"\n >\n <ng-container [ngTemplateOutlet]=\"btnInner\" />\n </a>\n} @else {\n <button\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.name]=\"name() || null\"\n [attr.value]=\"value() || null\"\n [attr.autofocus]=\"autofocus() ? '' : null\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-label]=\"accessibleLabel()\"\n [attr.title]=\"title() || null\"\n [class]=\"classes()\"\n (click)=\"handleClick($event)\"\n (focus)=\"focused.emit($event)\"\n (blur)=\"blurred.emit($event)\"\n >\n <ng-container [ngTemplateOutlet]=\"btnInner\" />\n </button>\n}\n\n<ng-template #btnInner>\n\n @if (loading()) {\n @if (loadingStyle() === 'spinner') {\n <svg [class]=\"spinnerSizeClass() + ' animate-spin shrink-0'\" fill=\"none\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n }\n @if (loadingStyle() === 'dots') {\n <span class=\"flex items-center gap-0.5\" aria-hidden=\"true\">\n @for (dot of [0, 1, 2]; track dot) {\n <span\n [class]=\"spinnerSizeClass() + ' rounded-full bg-current animate-bounce'\"\n [style.animation-delay]=\"(dot * 150) + 'ms'\"\n ></span>\n }\n </span>\n }\n @if (loadingStyle() === 'pulse') {\n <span [class]=\"spinnerSizeClass() + ' shrink-0 rounded-full bg-current/80 animate-pulse'\" aria-hidden=\"true\"></span>\n }\n <!-- Announce busy state when there is no visible label beside the indicator -->\n @if (iconPosition() === 'only' || !displayLabel()) {\n <span class=\"sr-only\">{{ loadingLabel() || 'Loading' }}</span>\n }\n }\n\n @if (!loading() && (iconPosition() === 'leading' || iconPosition() === 'only')) {\n @if (iconTemplate(); as tpl) {\n <span [class]=\"customIconWrapperClass()\" aria-hidden=\"true\">\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n </span>\n } @else if (iconPath()) {\n <svg [class]=\"iconSizeClass() + ' shrink-0'\" fill=\"none\" [attr.viewBox]=\"iconViewBox()\" stroke-width=\"1.8\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" [attr.d]=\"iconPath()\" />\n </svg>\n }\n }\n\n @if (iconPosition() !== 'only') {\n <span>{{ displayLabel() }}</span>\n }\n\n @if (!loading() && iconPosition() === 'trailing') {\n @if (iconTemplate(); as tpl) {\n <span [class]=\"customIconWrapperClass()\" aria-hidden=\"true\">\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n </span>\n } @else if (iconPath()) {\n <svg [class]=\"iconSizeClass() + ' shrink-0'\" fill=\"none\" [attr.viewBox]=\"iconViewBox()\" stroke-width=\"1.8\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" [attr.d]=\"iconPath()\" />\n </svg>\n }\n }\n\n @if (!loading()) {\n @if (trailingIconTemplate(); as tpl) {\n <span [class]=\"trailingCustomIconWrapperClass()\" aria-hidden=\"true\">\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n </span>\n } @else if (trailingIconPath()) {\n <svg [class]=\"iconSizeClass() + ' shrink-0 opacity-70'\" fill=\"none\" [attr.viewBox]=\"iconViewBox()\" stroke-width=\"1.8\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" [attr.d]=\"trailingIconPath()\" />\n </svg>\n }\n }\n\n @if (hasCounter()) {\n <span\n class=\"absolute -top-1.5 -right-1.5 flex h-4 min-w-[1rem] items-center justify-center\n rounded-full bg-red-500 px-1 text-[9px] font-bold leading-none text-white\n ring-2 ring-white dark:ring-gray-950\"\n aria-hidden=\"true\"\n >{{ counterText() }}</span>\n }\n\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
327
+ }
328
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SvButtonComponent, decorators: [{
329
+ type: Component,
330
+ args: [{ selector: 'sv-button', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (href()) {\n <a\n [href]=\"isDisabled() ? null : href()\"\n [target]=\"target()\"\n [attr.rel]=\"computedRel()\"\n [attr.download]=\"download()\"\n [attr.role]=\"'link'\"\n [attr.tabindex]=\"isDisabled() ? -1 : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-label]=\"accessibleLabel()\"\n [attr.title]=\"title() || null\"\n [class]=\"classes()\"\n (click)=\"handleClick($event)\"\n (focus)=\"focused.emit($event)\"\n (blur)=\"blurred.emit($event)\"\n >\n <ng-container [ngTemplateOutlet]=\"btnInner\" />\n </a>\n} @else {\n <button\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.name]=\"name() || null\"\n [attr.value]=\"value() || null\"\n [attr.autofocus]=\"autofocus() ? '' : null\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-label]=\"accessibleLabel()\"\n [attr.title]=\"title() || null\"\n [class]=\"classes()\"\n (click)=\"handleClick($event)\"\n (focus)=\"focused.emit($event)\"\n (blur)=\"blurred.emit($event)\"\n >\n <ng-container [ngTemplateOutlet]=\"btnInner\" />\n </button>\n}\n\n<ng-template #btnInner>\n\n @if (loading()) {\n @if (loadingStyle() === 'spinner') {\n <svg [class]=\"spinnerSizeClass() + ' animate-spin shrink-0'\" fill=\"none\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n }\n @if (loadingStyle() === 'dots') {\n <span class=\"flex items-center gap-0.5\" aria-hidden=\"true\">\n @for (dot of [0, 1, 2]; track dot) {\n <span\n [class]=\"spinnerSizeClass() + ' rounded-full bg-current animate-bounce'\"\n [style.animation-delay]=\"(dot * 150) + 'ms'\"\n ></span>\n }\n </span>\n }\n @if (loadingStyle() === 'pulse') {\n <span [class]=\"spinnerSizeClass() + ' shrink-0 rounded-full bg-current/80 animate-pulse'\" aria-hidden=\"true\"></span>\n }\n <!-- Announce busy state when there is no visible label beside the indicator -->\n @if (iconPosition() === 'only' || !displayLabel()) {\n <span class=\"sr-only\">{{ loadingLabel() || 'Loading' }}</span>\n }\n }\n\n @if (!loading() && (iconPosition() === 'leading' || iconPosition() === 'only')) {\n @if (iconTemplate(); as tpl) {\n <span [class]=\"customIconWrapperClass()\" aria-hidden=\"true\">\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n </span>\n } @else if (iconPath()) {\n <svg [class]=\"iconSizeClass() + ' shrink-0'\" fill=\"none\" [attr.viewBox]=\"iconViewBox()\" stroke-width=\"1.8\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" [attr.d]=\"iconPath()\" />\n </svg>\n }\n }\n\n @if (iconPosition() !== 'only') {\n <span>{{ displayLabel() }}</span>\n }\n\n @if (!loading() && iconPosition() === 'trailing') {\n @if (iconTemplate(); as tpl) {\n <span [class]=\"customIconWrapperClass()\" aria-hidden=\"true\">\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n </span>\n } @else if (iconPath()) {\n <svg [class]=\"iconSizeClass() + ' shrink-0'\" fill=\"none\" [attr.viewBox]=\"iconViewBox()\" stroke-width=\"1.8\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" [attr.d]=\"iconPath()\" />\n </svg>\n }\n }\n\n @if (!loading()) {\n @if (trailingIconTemplate(); as tpl) {\n <span [class]=\"trailingCustomIconWrapperClass()\" aria-hidden=\"true\">\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n </span>\n } @else if (trailingIconPath()) {\n <svg [class]=\"iconSizeClass() + ' shrink-0 opacity-70'\" fill=\"none\" [attr.viewBox]=\"iconViewBox()\" stroke-width=\"1.8\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" [attr.d]=\"trailingIconPath()\" />\n </svg>\n }\n }\n\n @if (hasCounter()) {\n <span\n class=\"absolute -top-1.5 -right-1.5 flex h-4 min-w-[1rem] items-center justify-center\n rounded-full bg-red-500 px-1 text-[9px] font-bold leading-none text-white\n ring-2 ring-white dark:ring-gray-950\"\n aria-hidden=\"true\"\n >{{ counterText() }}</span>\n }\n\n</ng-template>\n" }]
331
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], btnStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "btnStyle", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], block: [{ type: i0.Input, args: [{ isSignal: true, alias: "block", required: false }] }], elevated: [{ type: i0.Input, args: [{ isSignal: true, alias: "elevated", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], iconPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPath", required: false }] }], iconViewBox: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconViewBox", required: false }] }], trailingIconPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "trailingIconPath", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], trailingIconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "trailingIconTemplate", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], counter: [{ type: i0.Input, args: [{ isSignal: true, alias: "counter", required: false }] }], counterMax: [{ type: i0.Input, args: [{ isSignal: true, alias: "counterMax", required: false }] }], counterLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "counterLabel", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingStyle", required: false }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }], href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], rel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rel", required: false }] }], download: [{ type: i0.Input, args: [{ isSignal: true, alias: "download", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], autofocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autofocus", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }], focused: [{ type: i0.Output, args: ["focused"] }], blurred: [{ type: i0.Output, args: ["blurred"] }] } });
332
+
333
+ /**
334
+ * @styloviz/button — Public API
335
+ */
336
+
337
+ /**
338
+ * Generated bundle index. Do not edit.
339
+ */
340
+
341
+ export { SvButtonComponent };
342
+ //# sourceMappingURL=styloviz-button.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styloviz-button.mjs","sources":["../../../../projects/button/src/lib/button.component.ts","../../../../projects/button/src/lib/button.component.html","../../../../projects/button/src/public-api.ts","../../../../projects/button/src/styloviz-button.ts"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n computed,\n input,\n output,\n TemplateRef,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type ButtonVariant =\n | 'primary'\n | 'secondary'\n | 'success'\n | 'warning'\n | 'danger'\n | 'info'\n | 'neutral'\n | 'ghost'\n | 'link';\n\nexport type ButtonStyle =\n | 'solid'\n | 'outline'\n | 'soft'\n | 'ghost'\n | 'link'\n | 'gradient';\n\nexport type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\nexport type ButtonShape = 'rounded' | 'pill' | 'square';\nexport type ButtonIconPos = 'leading' | 'trailing' | 'only';\nexport type ButtonLoader = 'spinner' | 'dots' | 'pulse';\nexport type ButtonType = 'button' | 'submit' | 'reset';\n\n/** Template type for `iconTemplate` / `trailingIconTemplate` — any TemplateRef, or null when unset. */\nexport type ButtonIconTemplate = TemplateRef<unknown> | null;\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\n/**\n * SvButtonComponent — Premium, accessible button for StyloViz dashboards.\n *\n * Install: npm install @styloviz/button\n * Import: import { SvButtonComponent } from '@styloviz/button';\n *\n * Features:\n * - 9 variants × 6 styles × 5 sizes × 3 shapes\n * - 3 loading animations: spinner · dots · pulse\n * - Leading, trailing, and icon-only modes\n * - Dual-icon layout via trailingIconPath\n * - Bring-your-own icon via `iconTemplate` / `trailingIconTemplate` — render\n * any third-party icon component, <img>, icon font, or custom SVG instead\n * of the built-in path-based icon\n * - Counter badge (top-right)\n * - Renders as <a> when href is provided\n * - Full dark-mode + OnPush\n */\n@Component({\n selector: 'sv-button',\n standalone: true,\n imports: [NgTemplateOutlet],\n templateUrl: './button.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SvButtonComponent {\n // ── Appearance ────────────────────────────────────────────────────────────\n\n /** Semantic color/intent: primary, secondary, success, danger, etc. @default 'primary' */\n variant = input<ButtonVariant>('primary');\n /** Visual treatment: solid, soft, outline, ghost, link or gradient. @default 'solid' */\n btnStyle = input<ButtonStyle>('solid');\n /** Button size from xs to xl. @default 'md' */\n size = input<ButtonSize>('md');\n /** Corner style: rounded, pill or square. @default 'rounded' */\n shape = input<ButtonShape>('rounded');\n /** Stretch to 100% width. @default false */\n block = input<boolean>(false);\n /** Add drop shadow. @default false */\n elevated = input<boolean>(false);\n\n // ── Content ───────────────────────────────────────────────────────────────\n\n /** Button text. Omit when projecting custom content. */\n label = input<string>('');\n /**\n * SVG path for the built-in leading/trailing icon (quick built-in icons,\n * e.g. Heroicons path strings). Ignored when `iconTemplate` is set.\n */\n iconPath = input<string>('');\n /** viewBox for the provided icon paths. @default '0 0 24 24' */\n iconViewBox = input<string>('0 0 24 24');\n /**\n * SVG path for the built-in secondary/dual trailing icon. Ignored when\n * `trailingIconTemplate` is set.\n */\n trailingIconPath = input<string>('');\n /**\n * Custom template for the primary icon — use this to render a third-party\n * icon component (e.g. lucide-angular, ngx-heroicons), an `<img>`, an icon\n * font `<i>`, or arbitrary custom SVG instead of the built-in `iconPath`.\n * Positioned per `iconPosition()`. Takes precedence over `iconPath` when set.\n *\n * @example\n * ```html\n * <ng-template #saveIcon>\n * <img src=\"/assets/icons/save.svg\" alt=\"\" />\n * </ng-template>\n * <sv-button label=\"Save\" [iconTemplate]=\"saveIcon\" />\n * ```\n */\n iconTemplate = input<ButtonIconTemplate>(null);\n /**\n * Custom template for the secondary/dual trailing icon. Takes precedence\n * over `trailingIconPath` when set. See `iconTemplate` for usage.\n */\n trailingIconTemplate = input<ButtonIconTemplate>(null);\n /** Where the main icon sits relative to the label. @default 'leading' */\n iconPosition = input<ButtonIconPos>('leading');\n /** Numeric counter badge. null = hidden. @default null */\n counter = input<number | null>(null);\n /** Value above which the counter shows \"{max}+\". @default 99 */\n counterMax = input<number>(99);\n /** Noun describing the counter for screen readers, e.g. \"unread\". */\n counterLabel = input<string>('');\n\n // ── State ─────────────────────────────────────────────────────────────────\n\n /** Native button type when not in link mode. @default 'button' */\n type = input<ButtonType>('button');\n /** Disable interaction and dim the button. @default false */\n disabled = input<boolean>(false);\n /** Show a loading indicator and block activation. @default false */\n loading = input<boolean>(false);\n /** Loading indicator style: spinner or dots. @default 'spinner' */\n loadingStyle = input<ButtonLoader>('spinner');\n /** Optional text shown beside the loading indicator. */\n loadingLabel = input<string>('');\n\n // ── Link mode ─────────────────────────────────────────────────────────────\n\n /** When set, renders an <a> anchor instead of a <button>. */\n href = input<string>('');\n /** Anchor target (e.g. _blank) when href is set. @default '_self' */\n target = input<string>('_self');\n /** Anchor rel. `noopener noreferrer` is auto-added for target=\"_blank\". */\n rel = input<string>('');\n /** Anchor download attribute (filename or empty string to use the URL). */\n download = input<string | null>(null);\n\n // ── Form integration (button mode) ─────────────────────────────────────────\n\n /** Native `name` for the button when submitted as part of a form. */\n name = input<string>('');\n /** Native `value` submitted with `name` for multi-button forms. */\n value = input<string>('');\n\n // ── Accessibility ───────────────────────────────────────────────────────────\n\n /** Explicit accessible name. Required for icon-only buttons; overrides label. */\n ariaLabel = input<string>('');\n /** Native tooltip / title attribute. */\n title = input<string>('');\n /** Autofocus the control on render. @default false */\n autofocus = input<boolean>(false);\n\n // ── Output ────────────────────────────────────────────────────────────────\n\n /** Emitted on click (suppressed while disabled or loading). */\n clicked = output<MouseEvent>();\n /** Emitted when the control receives focus. */\n focused = output<FocusEvent>();\n /** Emitted when the control loses focus. */\n blurred = output<FocusEvent>();\n\n // ── Computed ──────────────────────────────────────────────────────────────\n\n readonly isDisabled = computed(() => this.disabled() || this.loading());\n readonly displayLabel = computed(() =>\n this.loading() && this.loadingLabel() ? this.loadingLabel() : this.label()\n );\n\n /** True when a counter badge should be shown. */\n readonly hasCounter = computed(\n () => this.counter() !== null && this.counter()! >= 0\n );\n\n /** Text rendered inside the counter badge (e.g. \"99+\"). */\n readonly counterText = computed(() => {\n const n = this.counter();\n if (n === null) return '';\n const max = this.counterMax();\n return n > max ? `${max}+` : `${n}`;\n });\n\n /**\n * Accessible name. Uses ariaLabel, then label. Appends the counter\n * (e.g. \"Inbox, 5 unread\") so screen readers announce the badge.\n */\n readonly accessibleLabel = computed(() => {\n const base = this.ariaLabel() || this.label();\n if (!this.hasCounter()) return base || null;\n const noun = this.counterLabel() ? ` ${this.counterLabel()}` : '';\n const count = `${this.counter()}${noun}`;\n return base ? `${base}, ${count}` : count;\n });\n\n /** Resolved rel for anchors; ensures safe defaults for new tabs. */\n readonly computedRel = computed(() => {\n const tokens = new Set(this.rel().split(/\\s+/).filter(Boolean));\n if (this.target() === '_blank') {\n tokens.add('noopener');\n tokens.add('noreferrer');\n }\n return tokens.size ? [...tokens].join(' ') : null;\n });\n\n readonly classes = computed(() => {\n const displayClass = this.block() ? 'flex w-full' : 'inline-flex';\n const baseClasses = this._base.replace('inline-flex', displayClass);\n return [\n baseClasses,\n this._sizeClasses(this.size()),\n this._shapeClasses(this.shape()),\n this._variantStyleClasses(this.variant(), this.btnStyle()),\n this._stateClasses(),\n this.elevated() && !['link', 'ghost'].includes(this.btnStyle())\n ? 'shadow-md hover:shadow-lg active:shadow-sm'\n : '',\n ].filter(Boolean).join(' ');\n });\n\n readonly iconSizeClass = computed(() => {\n const map: Record<ButtonSize, string> = {\n xs: 'h-3.5 w-3.5', sm: 'h-4 w-4', md: 'h-[18px] w-[18px]',\n lg: 'h-5 w-5', xl: 'h-6 w-6',\n };\n return map[this.size()];\n });\n\n readonly spinnerSizeClass = computed(() => {\n const map: Record<ButtonSize, string> = {\n xs: 'h-3 w-3', sm: 'h-3.5 w-3.5', md: 'h-4 w-4',\n lg: 'h-[18px] w-[18px]', xl: 'h-5 w-5',\n };\n return map[this.size()];\n });\n\n /**\n * Sizing wrapper for a projected `iconTemplate`. Constrains third-party\n * icon components, `<img>`, and custom SVG to the same box the built-in\n * icon would occupy, so custom icons line up regardless of their own\n * intrinsic markup or default size.\n */\n readonly customIconWrapperClass = computed(\n () =>\n `${this.iconSizeClass()} inline-flex shrink-0 items-center justify-center ` +\n '[&>svg]:h-full [&>svg]:w-full [&>img]:h-full [&>img]:w-full [&>img]:object-contain'\n );\n\n /** Same as `customIconWrapperClass`, dimmed to match `trailingIconPath`'s dual-icon treatment. */\n readonly trailingCustomIconWrapperClass = computed(\n () => `${this.customIconWrapperClass()} opacity-70`\n );\n\n // ── Event ─────────────────────────────────────────────────────────────────\n\n handleClick(event: MouseEvent): void {\n if (this.isDisabled()) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n this.clicked.emit(event);\n }\n\n // ── Private helpers ───────────────────────────────────────────────────────\n\n private readonly _base =\n 'relative inline-flex items-center justify-center font-medium ' +\n 'transition-all duration-150 focus-visible:outline-none ' +\n 'focus-visible:ring-2 focus-visible:ring-offset-2 ' +\n 'focus-visible:ring-offset-white dark:focus-visible:ring-offset-gray-950 ' +\n 'select-none whitespace-nowrap leading-none';\n\n private _sizeClasses(sz: ButtonSize): string {\n const iconOnly = this.iconPosition() === 'only';\n const map: Record<ButtonSize, { text: string; icon: string }> = {\n xs: { text: 'h-7 px-2.5 text-xs gap-1.5', icon: 'h-7 w-7 text-xs' },\n sm: { text: 'h-8 px-3 text-sm gap-1.5', icon: 'h-8 w-8 text-sm' },\n md: { text: 'h-9 px-4 text-sm gap-2', icon: 'h-9 w-9 text-sm' },\n lg: { text: 'h-10 px-5 text-[15px] gap-2', icon: 'h-10 w-10 text-[15px]' },\n xl: { text: 'h-12 px-6 text-base gap-2.5', icon: 'h-12 w-12 text-base' },\n };\n return iconOnly ? map[sz].icon : map[sz].text;\n }\n\n private _shapeClasses(sh: ButtonShape): string {\n const map: Record<ButtonShape, string> = {\n rounded: 'rounded-md', pill: 'rounded-full', square: 'rounded-none',\n };\n return map[sh];\n }\n\n private _variantStyleClasses(v: ButtonVariant, s: ButtonStyle): string {\n switch (s) {\n case 'solid': return this._solid(v);\n case 'outline': return this._outline(v);\n case 'soft': return this._soft(v);\n case 'ghost': return this._ghost(v);\n case 'link': return this._link(v);\n case 'gradient': return this._gradient(v);\n }\n }\n\n private _solid(v: ButtonVariant): string {\n const map: Record<ButtonVariant, string> = {\n primary: 'bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800 focus-visible:ring-blue-500',\n secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200 active:bg-gray-300 focus-visible:ring-gray-400 dark:bg-gray-700 dark:text-gray-100 dark:hover:bg-gray-600',\n success: 'bg-emerald-600 text-white hover:bg-emerald-700 active:bg-emerald-800 focus-visible:ring-emerald-500',\n warning: 'bg-amber-500 text-white hover:bg-amber-600 active:bg-amber-700 focus-visible:ring-amber-400',\n danger: 'bg-red-600 text-white hover:bg-red-700 active:bg-red-800 focus-visible:ring-red-500',\n info: 'bg-sky-500 text-white hover:bg-sky-600 active:bg-sky-700 focus-visible:ring-sky-400',\n neutral: 'bg-gray-800 text-white hover:bg-gray-900 focus-visible:ring-gray-600 dark:bg-gray-600 dark:hover:bg-gray-500',\n ghost: 'bg-transparent text-gray-700 hover:bg-gray-100 focus-visible:ring-gray-400 dark:text-gray-300 dark:hover:bg-gray-800',\n link: 'bg-transparent text-blue-600 hover:text-blue-700 hover:underline focus-visible:ring-blue-500 dark:text-blue-400',\n };\n return map[v];\n }\n\n private _outline(v: ButtonVariant): string {\n const map: Record<ButtonVariant, string> = {\n primary: 'border border-blue-600 text-blue-600 bg-transparent hover:bg-blue-50 focus-visible:ring-blue-500 dark:border-blue-500 dark:text-blue-400 dark:hover:bg-blue-900/20',\n secondary: 'border border-gray-300 text-gray-700 bg-transparent hover:bg-gray-50 focus-visible:ring-gray-400 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800',\n success: 'border border-emerald-600 text-emerald-600 bg-transparent hover:bg-emerald-50 focus-visible:ring-emerald-500 dark:border-emerald-500 dark:text-emerald-400 dark:hover:bg-emerald-900/20',\n warning: 'border border-amber-500 text-amber-600 bg-transparent hover:bg-amber-50 focus-visible:ring-amber-400 dark:border-amber-400 dark:text-amber-400 dark:hover:bg-amber-900/20',\n danger: 'border border-red-600 text-red-600 bg-transparent hover:bg-red-50 focus-visible:ring-red-500 dark:border-red-500 dark:text-red-400 dark:hover:bg-red-900/20',\n info: 'border border-sky-500 text-sky-600 bg-transparent hover:bg-sky-50 focus-visible:ring-sky-400 dark:border-sky-400 dark:text-sky-400 dark:hover:bg-sky-900/20',\n neutral: 'border border-gray-700 text-gray-800 bg-transparent hover:bg-gray-50 focus-visible:ring-gray-600 dark:border-gray-500 dark:text-gray-300 dark:hover:bg-gray-800',\n ghost: 'border border-transparent text-gray-600 bg-transparent hover:border-gray-300 hover:bg-gray-50 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:border-gray-600 dark:hover:bg-gray-800',\n link: 'border border-transparent text-blue-600 bg-transparent hover:border-blue-300 hover:bg-blue-50 focus-visible:ring-blue-500 dark:text-blue-400 dark:hover:bg-blue-900/20',\n };\n return map[v];\n }\n\n private _soft(v: ButtonVariant): string {\n const map: Record<ButtonVariant, string> = {\n primary: 'bg-blue-50 text-blue-700 hover:bg-blue-100 focus-visible:ring-blue-400 dark:bg-blue-900/30 dark:text-blue-300 dark:hover:bg-blue-900/50',\n secondary: 'bg-gray-100 text-gray-700 hover:bg-gray-200 focus-visible:ring-gray-400 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700',\n success: 'bg-emerald-50 text-emerald-700 hover:bg-emerald-100 focus-visible:ring-emerald-400 dark:bg-emerald-900/30 dark:text-emerald-300 dark:hover:bg-emerald-900/50',\n warning: 'bg-amber-50 text-amber-700 hover:bg-amber-100 focus-visible:ring-amber-400 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50',\n danger: 'bg-red-50 text-red-700 hover:bg-red-100 focus-visible:ring-red-400 dark:bg-red-900/30 dark:text-red-300 dark:hover:bg-red-900/50',\n info: 'bg-sky-50 text-sky-700 hover:bg-sky-100 focus-visible:ring-sky-400 dark:bg-sky-900/30 dark:text-sky-300 dark:hover:bg-sky-900/50',\n neutral: 'bg-gray-200 text-gray-700 hover:bg-gray-300 focus-visible:ring-gray-400 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600',\n ghost: 'bg-transparent text-gray-600 hover:bg-gray-100 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:bg-gray-800',\n link: 'bg-transparent text-blue-600 hover:bg-blue-50 hover:underline focus-visible:ring-blue-400 dark:text-blue-400 dark:hover:bg-blue-900/20',\n };\n return map[v];\n }\n\n private _ghost(v: ButtonVariant): string {\n const map: Record<ButtonVariant, string> = {\n primary: 'bg-transparent text-blue-600 hover:bg-blue-50 focus-visible:ring-blue-400 dark:text-blue-400 dark:hover:bg-blue-900/20',\n secondary: 'bg-transparent text-gray-700 hover:bg-gray-100 focus-visible:ring-gray-400 dark:text-gray-300 dark:hover:bg-gray-800',\n success: 'bg-transparent text-emerald-600 hover:bg-emerald-50 focus-visible:ring-emerald-400 dark:text-emerald-400 dark:hover:bg-emerald-900/20',\n warning: 'bg-transparent text-amber-600 hover:bg-amber-50 focus-visible:ring-amber-400 dark:text-amber-400 dark:hover:bg-amber-900/20',\n danger: 'bg-transparent text-red-600 hover:bg-red-50 focus-visible:ring-red-400 dark:text-red-400 dark:hover:bg-red-900/20',\n info: 'bg-transparent text-sky-600 hover:bg-sky-50 focus-visible:ring-sky-400 dark:text-sky-400 dark:hover:bg-sky-900/20',\n neutral: 'bg-transparent text-gray-600 hover:bg-gray-100 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:bg-gray-800',\n ghost: 'bg-transparent text-gray-500 hover:bg-gray-100 focus-visible:ring-gray-300 dark:text-gray-500 dark:hover:bg-gray-800',\n link: 'bg-transparent text-blue-600 hover:text-blue-700 focus-visible:ring-blue-400 dark:text-blue-400 dark:hover:text-blue-300',\n };\n return map[v];\n }\n\n private _link(v: ButtonVariant): string {\n const map: Record<ButtonVariant, string> = {\n primary: 'bg-transparent text-blue-600 underline-offset-4 hover:underline hover:text-blue-700 focus-visible:ring-blue-400 dark:text-blue-400',\n secondary: 'bg-transparent text-gray-600 underline-offset-4 hover:underline hover:text-gray-900 focus-visible:ring-gray-400 dark:text-gray-400',\n success: 'bg-transparent text-emerald-600 underline-offset-4 hover:underline hover:text-emerald-700 focus-visible:ring-emerald-400 dark:text-emerald-400',\n warning: 'bg-transparent text-amber-600 underline-offset-4 hover:underline focus-visible:ring-amber-400 dark:text-amber-400',\n danger: 'bg-transparent text-red-600 underline-offset-4 hover:underline hover:text-red-700 focus-visible:ring-red-400 dark:text-red-400',\n info: 'bg-transparent text-sky-600 underline-offset-4 hover:underline hover:text-sky-700 focus-visible:ring-sky-400 dark:text-sky-400',\n neutral: 'bg-transparent text-gray-600 underline-offset-4 hover:underline hover:text-gray-900 focus-visible:ring-gray-400 dark:text-gray-300',\n ghost: 'bg-transparent text-gray-500 underline-offset-4 hover:underline hover:text-gray-700 focus-visible:ring-gray-300 dark:text-gray-400',\n link: 'bg-transparent text-blue-600 underline underline-offset-4 hover:text-blue-800 focus-visible:ring-blue-400 dark:text-blue-400',\n };\n return map[v];\n }\n\n private _gradient(v: ButtonVariant): string {\n const map: Record<ButtonVariant, string> = {\n primary: 'bg-gradient-to-r from-blue-500 to-indigo-600 text-white hover:from-blue-600 hover:to-indigo-700 focus-visible:ring-indigo-500',\n secondary: 'bg-gradient-to-r from-gray-100 to-gray-200 text-gray-900 hover:from-gray-200 hover:to-gray-300 focus-visible:ring-gray-400 dark:from-gray-700 dark:to-gray-800 dark:text-gray-100',\n success: 'bg-gradient-to-r from-emerald-400 to-teal-600 text-white hover:from-emerald-500 hover:to-teal-700 focus-visible:ring-teal-500',\n warning: 'bg-gradient-to-r from-amber-400 to-orange-500 text-white hover:from-amber-500 hover:to-orange-600 focus-visible:ring-orange-400',\n danger: 'bg-gradient-to-r from-rose-500 to-red-600 text-white hover:from-rose-600 hover:to-red-700 focus-visible:ring-red-500',\n info: 'bg-gradient-to-r from-sky-400 to-cyan-500 text-white hover:from-sky-500 hover:to-cyan-600 focus-visible:ring-cyan-400',\n neutral: 'bg-gradient-to-r from-gray-700 to-gray-900 text-white hover:from-gray-800 hover:to-black focus-visible:ring-gray-600',\n ghost: 'bg-gradient-to-r from-gray-50 to-gray-100 text-gray-700 hover:from-gray-100 hover:to-gray-200 focus-visible:ring-gray-400 dark:from-gray-800 dark:to-gray-900 dark:text-gray-200',\n link: 'bg-gradient-to-r from-blue-500 to-violet-600 text-white hover:from-blue-600 hover:to-violet-700 focus-visible:ring-violet-500',\n };\n return map[v];\n }\n\n private _stateClasses(): string {\n if (this.loading()) return 'opacity-75 cursor-wait pointer-events-none';\n if (this.disabled()) return 'opacity-50 cursor-not-allowed pointer-events-none';\n return 'cursor-pointer';\n }\n}\n","@if (href()) {\n <a\n [href]=\"isDisabled() ? null : href()\"\n [target]=\"target()\"\n [attr.rel]=\"computedRel()\"\n [attr.download]=\"download()\"\n [attr.role]=\"'link'\"\n [attr.tabindex]=\"isDisabled() ? -1 : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-label]=\"accessibleLabel()\"\n [attr.title]=\"title() || null\"\n [class]=\"classes()\"\n (click)=\"handleClick($event)\"\n (focus)=\"focused.emit($event)\"\n (blur)=\"blurred.emit($event)\"\n >\n <ng-container [ngTemplateOutlet]=\"btnInner\" />\n </a>\n} @else {\n <button\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.name]=\"name() || null\"\n [attr.value]=\"value() || null\"\n [attr.autofocus]=\"autofocus() ? '' : null\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-label]=\"accessibleLabel()\"\n [attr.title]=\"title() || null\"\n [class]=\"classes()\"\n (click)=\"handleClick($event)\"\n (focus)=\"focused.emit($event)\"\n (blur)=\"blurred.emit($event)\"\n >\n <ng-container [ngTemplateOutlet]=\"btnInner\" />\n </button>\n}\n\n<ng-template #btnInner>\n\n @if (loading()) {\n @if (loadingStyle() === 'spinner') {\n <svg [class]=\"spinnerSizeClass() + ' animate-spin shrink-0'\" fill=\"none\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\" />\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n }\n @if (loadingStyle() === 'dots') {\n <span class=\"flex items-center gap-0.5\" aria-hidden=\"true\">\n @for (dot of [0, 1, 2]; track dot) {\n <span\n [class]=\"spinnerSizeClass() + ' rounded-full bg-current animate-bounce'\"\n [style.animation-delay]=\"(dot * 150) + 'ms'\"\n ></span>\n }\n </span>\n }\n @if (loadingStyle() === 'pulse') {\n <span [class]=\"spinnerSizeClass() + ' shrink-0 rounded-full bg-current/80 animate-pulse'\" aria-hidden=\"true\"></span>\n }\n <!-- Announce busy state when there is no visible label beside the indicator -->\n @if (iconPosition() === 'only' || !displayLabel()) {\n <span class=\"sr-only\">{{ loadingLabel() || 'Loading' }}</span>\n }\n }\n\n @if (!loading() && (iconPosition() === 'leading' || iconPosition() === 'only')) {\n @if (iconTemplate(); as tpl) {\n <span [class]=\"customIconWrapperClass()\" aria-hidden=\"true\">\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n </span>\n } @else if (iconPath()) {\n <svg [class]=\"iconSizeClass() + ' shrink-0'\" fill=\"none\" [attr.viewBox]=\"iconViewBox()\" stroke-width=\"1.8\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" [attr.d]=\"iconPath()\" />\n </svg>\n }\n }\n\n @if (iconPosition() !== 'only') {\n <span>{{ displayLabel() }}</span>\n }\n\n @if (!loading() && iconPosition() === 'trailing') {\n @if (iconTemplate(); as tpl) {\n <span [class]=\"customIconWrapperClass()\" aria-hidden=\"true\">\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n </span>\n } @else if (iconPath()) {\n <svg [class]=\"iconSizeClass() + ' shrink-0'\" fill=\"none\" [attr.viewBox]=\"iconViewBox()\" stroke-width=\"1.8\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" [attr.d]=\"iconPath()\" />\n </svg>\n }\n }\n\n @if (!loading()) {\n @if (trailingIconTemplate(); as tpl) {\n <span [class]=\"trailingCustomIconWrapperClass()\" aria-hidden=\"true\">\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n </span>\n } @else if (trailingIconPath()) {\n <svg [class]=\"iconSizeClass() + ' shrink-0 opacity-70'\" fill=\"none\" [attr.viewBox]=\"iconViewBox()\" stroke-width=\"1.8\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" [attr.d]=\"trailingIconPath()\" />\n </svg>\n }\n }\n\n @if (hasCounter()) {\n <span\n class=\"absolute -top-1.5 -right-1.5 flex h-4 min-w-[1rem] items-center justify-center\n rounded-full bg-red-500 px-1 text-[9px] font-bold leading-none text-white\n ring-2 ring-white dark:ring-gray-950\"\n aria-hidden=\"true\"\n >{{ counterText() }}</span>\n }\n\n</ng-template>\n","/**\n * @styloviz/button — Public API\n */\nexport { SvButtonComponent } from './lib/button.component';\nexport type {\n ButtonVariant,\n ButtonStyle,\n ButtonSize,\n ButtonShape,\n ButtonIconPos,\n ButtonLoader,\n ButtonType,\n ButtonIconTemplate,\n} from './lib/button.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/button",
3
+ "version": "0.1.1",
4
+ "description": "Versatile button with semantic variants, sizes, icon slots, loading and block states.",
5
+ "keywords": [
6
+ "angular",
7
+ "tailwind",
8
+ "ui-kit",
9
+ "button",
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/button"
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-button.mjs",
36
+ "typings": "types/styloviz-button.d.ts",
37
+ "exports": {
38
+ "./package.json": {
39
+ "default": "./package.json"
40
+ },
41
+ ".": {
42
+ "types": "./types/styloviz-button.d.ts",
43
+ "default": "./fesm2022/styloviz-button.mjs"
44
+ }
45
+ },
46
+ "type": "module",
47
+ "dependencies": {
48
+ "tslib": "^2.3.0"
49
+ }
50
+ }
@@ -0,0 +1,162 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
3
+
4
+ type ButtonVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'neutral' | 'ghost' | 'link';
5
+ type ButtonStyle = 'solid' | 'outline' | 'soft' | 'ghost' | 'link' | 'gradient';
6
+ type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
7
+ type ButtonShape = 'rounded' | 'pill' | 'square';
8
+ type ButtonIconPos = 'leading' | 'trailing' | 'only';
9
+ type ButtonLoader = 'spinner' | 'dots' | 'pulse';
10
+ type ButtonType = 'button' | 'submit' | 'reset';
11
+ /** Template type for `iconTemplate` / `trailingIconTemplate` — any TemplateRef, or null when unset. */
12
+ type ButtonIconTemplate = TemplateRef<unknown> | null;
13
+ /**
14
+ * SvButtonComponent — Premium, accessible button for StyloViz dashboards.
15
+ *
16
+ * Install: npm install @styloviz/button
17
+ * Import: import { SvButtonComponent } from '@styloviz/button';
18
+ *
19
+ * Features:
20
+ * - 9 variants × 6 styles × 5 sizes × 3 shapes
21
+ * - 3 loading animations: spinner · dots · pulse
22
+ * - Leading, trailing, and icon-only modes
23
+ * - Dual-icon layout via trailingIconPath
24
+ * - Bring-your-own icon via `iconTemplate` / `trailingIconTemplate` — render
25
+ * any third-party icon component, <img>, icon font, or custom SVG instead
26
+ * of the built-in path-based icon
27
+ * - Counter badge (top-right)
28
+ * - Renders as <a> when href is provided
29
+ * - Full dark-mode + OnPush
30
+ */
31
+ declare class SvButtonComponent {
32
+ /** Semantic color/intent: primary, secondary, success, danger, etc. @default 'primary' */
33
+ variant: _angular_core.InputSignal<ButtonVariant>;
34
+ /** Visual treatment: solid, soft, outline, ghost, link or gradient. @default 'solid' */
35
+ btnStyle: _angular_core.InputSignal<ButtonStyle>;
36
+ /** Button size from xs to xl. @default 'md' */
37
+ size: _angular_core.InputSignal<ButtonSize>;
38
+ /** Corner style: rounded, pill or square. @default 'rounded' */
39
+ shape: _angular_core.InputSignal<ButtonShape>;
40
+ /** Stretch to 100% width. @default false */
41
+ block: _angular_core.InputSignal<boolean>;
42
+ /** Add drop shadow. @default false */
43
+ elevated: _angular_core.InputSignal<boolean>;
44
+ /** Button text. Omit when projecting custom content. */
45
+ label: _angular_core.InputSignal<string>;
46
+ /**
47
+ * SVG path for the built-in leading/trailing icon (quick built-in icons,
48
+ * e.g. Heroicons path strings). Ignored when `iconTemplate` is set.
49
+ */
50
+ iconPath: _angular_core.InputSignal<string>;
51
+ /** viewBox for the provided icon paths. @default '0 0 24 24' */
52
+ iconViewBox: _angular_core.InputSignal<string>;
53
+ /**
54
+ * SVG path for the built-in secondary/dual trailing icon. Ignored when
55
+ * `trailingIconTemplate` is set.
56
+ */
57
+ trailingIconPath: _angular_core.InputSignal<string>;
58
+ /**
59
+ * Custom template for the primary icon — use this to render a third-party
60
+ * icon component (e.g. lucide-angular, ngx-heroicons), an `<img>`, an icon
61
+ * font `<i>`, or arbitrary custom SVG instead of the built-in `iconPath`.
62
+ * Positioned per `iconPosition()`. Takes precedence over `iconPath` when set.
63
+ *
64
+ * @example
65
+ * ```html
66
+ * <ng-template #saveIcon>
67
+ * <img src="/assets/icons/save.svg" alt="" />
68
+ * </ng-template>
69
+ * <sv-button label="Save" [iconTemplate]="saveIcon" />
70
+ * ```
71
+ */
72
+ iconTemplate: _angular_core.InputSignal<ButtonIconTemplate>;
73
+ /**
74
+ * Custom template for the secondary/dual trailing icon. Takes precedence
75
+ * over `trailingIconPath` when set. See `iconTemplate` for usage.
76
+ */
77
+ trailingIconTemplate: _angular_core.InputSignal<ButtonIconTemplate>;
78
+ /** Where the main icon sits relative to the label. @default 'leading' */
79
+ iconPosition: _angular_core.InputSignal<ButtonIconPos>;
80
+ /** Numeric counter badge. null = hidden. @default null */
81
+ counter: _angular_core.InputSignal<number | null>;
82
+ /** Value above which the counter shows "{max}+". @default 99 */
83
+ counterMax: _angular_core.InputSignal<number>;
84
+ /** Noun describing the counter for screen readers, e.g. "unread". */
85
+ counterLabel: _angular_core.InputSignal<string>;
86
+ /** Native button type when not in link mode. @default 'button' */
87
+ type: _angular_core.InputSignal<ButtonType>;
88
+ /** Disable interaction and dim the button. @default false */
89
+ disabled: _angular_core.InputSignal<boolean>;
90
+ /** Show a loading indicator and block activation. @default false */
91
+ loading: _angular_core.InputSignal<boolean>;
92
+ /** Loading indicator style: spinner or dots. @default 'spinner' */
93
+ loadingStyle: _angular_core.InputSignal<ButtonLoader>;
94
+ /** Optional text shown beside the loading indicator. */
95
+ loadingLabel: _angular_core.InputSignal<string>;
96
+ /** When set, renders an <a> anchor instead of a <button>. */
97
+ href: _angular_core.InputSignal<string>;
98
+ /** Anchor target (e.g. _blank) when href is set. @default '_self' */
99
+ target: _angular_core.InputSignal<string>;
100
+ /** Anchor rel. `noopener noreferrer` is auto-added for target="_blank". */
101
+ rel: _angular_core.InputSignal<string>;
102
+ /** Anchor download attribute (filename or empty string to use the URL). */
103
+ download: _angular_core.InputSignal<string | null>;
104
+ /** Native `name` for the button when submitted as part of a form. */
105
+ name: _angular_core.InputSignal<string>;
106
+ /** Native `value` submitted with `name` for multi-button forms. */
107
+ value: _angular_core.InputSignal<string>;
108
+ /** Explicit accessible name. Required for icon-only buttons; overrides label. */
109
+ ariaLabel: _angular_core.InputSignal<string>;
110
+ /** Native tooltip / title attribute. */
111
+ title: _angular_core.InputSignal<string>;
112
+ /** Autofocus the control on render. @default false */
113
+ autofocus: _angular_core.InputSignal<boolean>;
114
+ /** Emitted on click (suppressed while disabled or loading). */
115
+ clicked: _angular_core.OutputEmitterRef<MouseEvent>;
116
+ /** Emitted when the control receives focus. */
117
+ focused: _angular_core.OutputEmitterRef<FocusEvent>;
118
+ /** Emitted when the control loses focus. */
119
+ blurred: _angular_core.OutputEmitterRef<FocusEvent>;
120
+ readonly isDisabled: _angular_core.Signal<boolean>;
121
+ readonly displayLabel: _angular_core.Signal<string>;
122
+ /** True when a counter badge should be shown. */
123
+ readonly hasCounter: _angular_core.Signal<boolean>;
124
+ /** Text rendered inside the counter badge (e.g. "99+"). */
125
+ readonly counterText: _angular_core.Signal<string>;
126
+ /**
127
+ * Accessible name. Uses ariaLabel, then label. Appends the counter
128
+ * (e.g. "Inbox, 5 unread") so screen readers announce the badge.
129
+ */
130
+ readonly accessibleLabel: _angular_core.Signal<string | null>;
131
+ /** Resolved rel for anchors; ensures safe defaults for new tabs. */
132
+ readonly computedRel: _angular_core.Signal<string | null>;
133
+ readonly classes: _angular_core.Signal<string>;
134
+ readonly iconSizeClass: _angular_core.Signal<string>;
135
+ readonly spinnerSizeClass: _angular_core.Signal<string>;
136
+ /**
137
+ * Sizing wrapper for a projected `iconTemplate`. Constrains third-party
138
+ * icon components, `<img>`, and custom SVG to the same box the built-in
139
+ * icon would occupy, so custom icons line up regardless of their own
140
+ * intrinsic markup or default size.
141
+ */
142
+ readonly customIconWrapperClass: _angular_core.Signal<string>;
143
+ /** Same as `customIconWrapperClass`, dimmed to match `trailingIconPath`'s dual-icon treatment. */
144
+ readonly trailingCustomIconWrapperClass: _angular_core.Signal<string>;
145
+ handleClick(event: MouseEvent): void;
146
+ private readonly _base;
147
+ private _sizeClasses;
148
+ private _shapeClasses;
149
+ private _variantStyleClasses;
150
+ private _solid;
151
+ private _outline;
152
+ private _soft;
153
+ private _ghost;
154
+ private _link;
155
+ private _gradient;
156
+ private _stateClasses;
157
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SvButtonComponent, never>;
158
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SvButtonComponent, "sv-button", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "btnStyle": { "alias": "btnStyle"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "shape": { "alias": "shape"; "required": false; "isSignal": true; }; "block": { "alias": "block"; "required": false; "isSignal": true; }; "elevated": { "alias": "elevated"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "iconPath": { "alias": "iconPath"; "required": false; "isSignal": true; }; "iconViewBox": { "alias": "iconViewBox"; "required": false; "isSignal": true; }; "trailingIconPath": { "alias": "trailingIconPath"; "required": false; "isSignal": true; }; "iconTemplate": { "alias": "iconTemplate"; "required": false; "isSignal": true; }; "trailingIconTemplate": { "alias": "trailingIconTemplate"; "required": false; "isSignal": true; }; "iconPosition": { "alias": "iconPosition"; "required": false; "isSignal": true; }; "counter": { "alias": "counter"; "required": false; "isSignal": true; }; "counterMax": { "alias": "counterMax"; "required": false; "isSignal": true; }; "counterLabel": { "alias": "counterLabel"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "loadingStyle": { "alias": "loadingStyle"; "required": false; "isSignal": true; }; "loadingLabel": { "alias": "loadingLabel"; "required": false; "isSignal": true; }; "href": { "alias": "href"; "required": false; "isSignal": true; }; "target": { "alias": "target"; "required": false; "isSignal": true; }; "rel": { "alias": "rel"; "required": false; "isSignal": true; }; "download": { "alias": "download"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "required": false; "isSignal": true; }; }, { "clicked": "clicked"; "focused": "focused"; "blurred": "blurred"; }, never, never, true, never>;
159
+ }
160
+
161
+ export { SvButtonComponent };
162
+ export type { ButtonIconPos, ButtonIconTemplate, ButtonLoader, ButtonShape, ButtonSize, ButtonStyle, ButtonType, ButtonVariant };