@eduboxpro/studio 0.1.2 → 0.1.4

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.
@@ -1,8 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output } from '@angular/core';
2
+ import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output, viewChild, forwardRef, model } from '@angular/core';
3
3
  import { DOCUMENT } from '@angular/common';
4
4
  import * as i1 from 'lucide-angular';
5
- import { icons, LucideAngularModule, LucideIconProvider, LUCIDE_ICONS, ShoppingCart, Loader2, Loader, RotateCw, RefreshCw, Printer, Save, Image, Folder, FileText, File, HelpCircle, XCircle, CheckCircle, Info, AlertTriangle, AlertCircle, LogOut, LogIn, Unlock, Lock, EyeOff, Eye, Clock, Calendar, Bell, MoreHorizontal, MoreVertical, Menu, Home, Share2, Copy, Link, ExternalLink, Filter, Search, X, Check, Minus, Plus, Edit, Trash2, User, Settings, Star, Heart, Phone, Mail, Upload, Download, ChevronRight, ChevronLeft, ChevronUp, ChevronDown, ArrowLeft, ArrowRight } from 'lucide-angular';
5
+ import { icons, LucideAngularModule, LucideIconProvider, LUCIDE_ICONS, Moon, Sun, ShoppingCart, Loader2, Loader, RotateCw, RefreshCw, Printer, Save, Image, Folder, FileText, File, HelpCircle, XCircle, CheckCircle, Info, AlertTriangle, AlertCircle, LogOut, LogIn, Unlock, Lock, EyeOff, Eye, Clock, Calendar, Bell, MoreHorizontal, MoreVertical, Menu, Home, Share2, Copy, Link, ExternalLink, Filter, Search, X, Check, Minus, Plus, Edit, Trash2, User, Settings, Star, Heart, Phone, Mail, Upload, Download, ChevronRight, ChevronLeft, ChevronUp, ChevronDown, ArrowLeft, ArrowRight } from 'lucide-angular';
6
+ import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
7
 
7
8
  /**
8
9
  * Injection token for Studio configuration
@@ -19,7 +20,7 @@ class StudioConfigService {
19
20
  constructor() {
20
21
  effect(() => {
21
22
  this.applyTheme(this.config().theme);
22
- }, { allowSignalWrites: false });
23
+ });
23
24
  }
24
25
  configure(config) {
25
26
  this.config.set(config);
@@ -35,29 +36,23 @@ class StudioConfigService {
35
36
  const newMode = this.themeMode() === 'light' ? 'dark' : 'light';
36
37
  this.setThemeMode(newMode);
37
38
  }
38
- async loadFromBackend(organizationSlug) {
39
- try {
40
- const response = await fetch(`/api/organizations/${organizationSlug}/design-config`);
41
- if (!response.ok) {
42
- throw new Error(`HTTP error! status: ${response.status}`);
43
- }
44
- const config = await response.json();
45
- this.configure(config);
46
- }
47
- catch (error) {
48
- console.error('[Studio] Failed to load config from backend:', error);
49
- throw error;
50
- }
39
+ updateTheme(theme) {
40
+ this.config.update(cfg => ({
41
+ ...cfg,
42
+ theme: { ...cfg.theme, ...theme }
43
+ }));
44
+ }
45
+ reset() {
46
+ this.config.set({});
47
+ this.setThemeMode('light');
51
48
  }
52
49
  applyTheme(theme) {
53
50
  if (!theme)
54
51
  return;
55
52
  const root = this.document.documentElement;
56
- // Apply colors
57
53
  if (theme.colors) {
58
54
  this.applyColorTokens(root, theme.colors);
59
55
  }
60
- // Apply typography
61
56
  if (theme.typography) {
62
57
  if (theme.typography.fontFamily) {
63
58
  root.style.setProperty('--studio-font-family', theme.typography.fontFamily);
@@ -75,29 +70,23 @@ class StudioConfigService {
75
70
  this.applyTokens(root, 'studio-line-height', theme.typography.lineHeight);
76
71
  }
77
72
  }
78
- // Apply spacing
79
73
  if (theme.spacing) {
80
74
  this.applyTokens(root, 'studio-spacing', theme.spacing);
81
75
  }
82
- // Apply border radius
83
76
  if (theme.borderRadius) {
84
77
  this.applyTokens(root, 'studio-radius', theme.borderRadius);
85
78
  }
86
- // Apply shadows
87
79
  if (theme.shadows) {
88
80
  this.applyTokens(root, 'studio-shadow', theme.shadows);
89
81
  }
90
- // Apply transitions
91
82
  if (theme.transitions) {
92
83
  this.applyTokens(root, 'studio-transition', theme.transitions);
93
84
  }
94
- // Apply z-index
95
85
  if (theme.zIndex) {
96
86
  this.applyZIndexTokens(root, theme.zIndex);
97
87
  }
98
88
  }
99
89
  applyColorTokens(root, colors) {
100
- // Brand colors with hover/active states
101
90
  const brandColors = ['primary', 'secondary', 'success', 'error', 'warning', 'info'];
102
91
  brandColors.forEach(colorName => {
103
92
  const colorValue = colors[colorName];
@@ -122,15 +111,12 @@ class StudioConfigService {
122
111
  }
123
112
  }
124
113
  });
125
- // Background colors
126
114
  if (colors.bg) {
127
115
  this.applyTokens(root, 'studio-bg', colors.bg);
128
116
  }
129
- // Text colors
130
117
  if (colors.text) {
131
118
  this.applyTokens(root, 'studio-text', colors.text);
132
119
  }
133
- // Border colors
134
120
  if (colors.border) {
135
121
  this.applyTokens(root, 'studio-border', colors.border);
136
122
  }
@@ -212,17 +198,48 @@ function provideStudioConfig(config = {}) {
212
198
  * @module config
213
199
  */
214
200
 
201
+ /**
202
+ * Icon component with Lucide icons support
203
+ *
204
+ * @example
205
+ * <studio-icon name="check" size="24" color="primary" />
206
+ */
215
207
  class IconComponent {
216
208
  name = input.required(...(ngDevMode ? [{ debugName: "name" }] : []));
217
209
  size = input(24, ...(ngDevMode ? [{ debugName: "size" }] : []));
218
210
  color = input('inherit', ...(ngDevMode ? [{ debugName: "color" }] : []));
219
211
  strokeWidth = input(2, ...(ngDevMode ? [{ debugName: "strokeWidth" }] : []));
220
212
  absoluteStrokeWidth = input(false, ...(ngDevMode ? [{ debugName: "absoluteStrokeWidth" }] : []));
213
+ showFallback = input(true, ...(ngDevMode ? [{ debugName: "showFallback" }] : []));
214
+ fallbackIcon = input('help-circle', ...(ngDevMode ? [{ debugName: "fallbackIcon" }] : []));
221
215
  icons = icons;
222
216
  lucideIcon = computed(() => {
223
217
  const iconName = this.name();
224
- return iconName;
218
+ if (iconName && icons[iconName]) {
219
+ return iconName;
220
+ }
221
+ const pascalCaseName = this.kebabToPascalCase(iconName);
222
+ if (pascalCaseName && icons[pascalCaseName]) {
223
+ return pascalCaseName;
224
+ }
225
+ if (this.showFallback()) {
226
+ const fallback = this.fallbackIcon();
227
+ if (icons[fallback]) {
228
+ return fallback;
229
+ }
230
+ const pascalCaseFallback = this.kebabToPascalCase(fallback);
231
+ if (pascalCaseFallback && icons[pascalCaseFallback]) {
232
+ return pascalCaseFallback;
233
+ }
234
+ }
235
+ return null;
225
236
  }, ...(ngDevMode ? [{ debugName: "lucideIcon" }] : []));
237
+ kebabToPascalCase(str) {
238
+ return str
239
+ .split('-')
240
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
241
+ .join('');
242
+ }
226
243
  computedColor = computed(() => {
227
244
  const colorValue = this.color();
228
245
  const colorMap = {
@@ -239,7 +256,7 @@ class IconComponent {
239
256
  return ['studio-icon'];
240
257
  }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
241
258
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
242
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: IconComponent, isStandalone: true, selector: "studio-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, absoluteStrokeWidth: { classPropertyName: "absoluteStrokeWidth", publicName: "absoluteStrokeWidth", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "style.width.px": "size()", "style.height.px": "size()" } }, ngImport: i0, template: `
259
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: IconComponent, isStandalone: true, selector: "studio-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, absoluteStrokeWidth: { classPropertyName: "absoluteStrokeWidth", publicName: "absoluteStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, showFallback: { classPropertyName: "showFallback", publicName: "showFallback", isSignal: true, isRequired: false, transformFunction: null }, fallbackIcon: { classPropertyName: "fallbackIcon", publicName: "fallbackIcon", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "style.width.px": "size()", "style.height.px": "size()" } }, ngImport: i0, template: `
243
260
  @if (lucideIcon(); as iconName) {
244
261
  <lucide-icon
245
262
  [name]="iconName"
@@ -268,11 +285,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
268
285
  />
269
286
  }
270
287
  `, styles: [":host{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}\n"] }]
271
- }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], absoluteStrokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "absoluteStrokeWidth", required: false }] }] } });
288
+ }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], absoluteStrokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "absoluteStrokeWidth", required: false }] }], showFallback: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFallback", required: false }] }], fallbackIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "fallbackIcon", required: false }] }] } });
272
289
 
273
290
  /**
274
- * Провайдер иконок для Studio
275
- * Регистрирует базовый набор часто используемых иконок
291
+ * Studio icon provider
292
+ * Registers commonly used Lucide icons
276
293
  *
277
294
  * @example
278
295
  * ```typescript
@@ -286,7 +303,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
286
303
  * };
287
304
  * ```
288
305
  *
289
- * Для добавления дополнительных иконок:
306
+ * To add additional icons:
290
307
  * @example
291
308
  * ```typescript
292
309
  * import { LUCIDE_ICONS, LucideIconProvider } from 'lucide-angular';
@@ -363,17 +380,19 @@ function provideStudioIcons() {
363
380
  RotateCw,
364
381
  Loader,
365
382
  Loader2,
366
- ShoppingCart
383
+ ShoppingCart,
384
+ Sun,
385
+ Moon
367
386
  })
368
387
  }
369
388
  ]);
370
389
  }
371
390
 
372
391
  /**
373
- * Проверяет безопасность URL для навигации
392
+ * Checks if URL is safe for navigation
374
393
  *
375
- * @param url - URL для проверки
376
- * @returns true если URL безопасен (http/https или относительный)
394
+ * @param url - URL to check
395
+ * @returns true if URL is safe (http/https or relative)
377
396
  *
378
397
  * @example
379
398
  * ```typescript
@@ -388,24 +407,22 @@ function isSafeUrl(url) {
388
407
  }
389
408
  try {
390
409
  const parsed = new URL(url, window.location.origin);
391
- // Разрешаем только http(s) и относительные URL (пустой protocol)
392
410
  return ['http:', 'https:', ''].includes(parsed.protocol);
393
411
  }
394
412
  catch {
395
- // Невалидный URL
396
413
  return false;
397
414
  }
398
415
  }
399
416
  /**
400
- * Sanitize URL перед использованием в навигации
417
+ * Sanitize URL before using in navigation
401
418
  *
402
- * @param url - URL для sanitization
403
- * @returns Безопасный URL или '#' если URL небезопасен
419
+ * @param url - URL to sanitize
420
+ * @returns Safe URL or '#' if URL is unsafe
404
421
  *
405
422
  * @example
406
423
  * ```typescript
407
424
  * sanitizeUrl('https://example.com') // 'https://example.com'
408
- * sanitizeUrl('javascript:alert(1)') // '#' (с предупреждением в консоли)
425
+ * sanitizeUrl('javascript:alert(1)') // '#' (with console warning)
409
426
  * ```
410
427
  */
411
428
  function sanitizeUrl(url) {
@@ -417,15 +434,15 @@ function sanitizeUrl(url) {
417
434
  }
418
435
 
419
436
  /**
420
- * Объединяет CSS классы, игнорируя falsy значения
437
+ * Combines CSS classes, ignoring falsy values
421
438
  *
422
- * @param classes - Массив классов (строки, undefined, null, false)
423
- * @returns Строка с объединенными классами
439
+ * @param classes - Array of classes (strings, undefined, null, false)
440
+ * @returns String with combined classes
424
441
  *
425
442
  * @example
426
443
  * ```typescript
427
444
  * classNames('btn', 'btn-primary') // 'btn btn-primary'
428
- * classNames('btn', isActive && 'active') // 'btn active' если isActive=true, иначе 'btn'
445
+ * classNames('btn', isActive && 'active') // 'btn active' if isActive=true, else 'btn'
429
446
  * classNames('btn', undefined, null, false, 'large') // 'btn large'
430
447
  * ```
431
448
  */
@@ -434,24 +451,20 @@ function classNames(...classes) {
434
451
  }
435
452
 
436
453
  /**
437
- * Создает computed signal с fallback chain: input → config → default
438
- *
439
- * Упрощает паттерн configurable inputs, убирая boilerplate код.
454
+ * Creates computed signal with fallback chain: input → config → default
440
455
  *
441
- * @param inputSignal - Input signal от пользователя
442
- * @param configSignal - Config значение (может быть undefined)
443
- * @param defaultValue - Fallback значение
444
- * @returns Computed signal с resolved значением
456
+ * @param inputSignal - User input signal
457
+ * @param configSignal - Config value (can be undefined)
458
+ * @param defaultValue - Fallback value
459
+ * @returns Computed signal with resolved value
445
460
  *
446
461
  * @example
447
462
  * ```typescript
448
463
  * export class ButtonComponent {
449
464
  * private defaults = computed(() => this.configService.config().components?.button);
450
465
  *
451
- * // Input
452
466
  * variantInput = input<Variant | undefined>(undefined, { alias: 'variant' });
453
467
  *
454
- * // Resolved value с config fallback
455
468
  * variant = withConfigDefault(
456
469
  * this.variantInput,
457
470
  * computed(() => this.defaults()?.variant),
@@ -481,40 +494,30 @@ function withConfigDefault(inputSignal, configSignal, defaultValue) {
481
494
  class BadgeComponent {
482
495
  configService = inject(StudioConfigService);
483
496
  badgeDefaults = computed(() => this.configService.config().components?.badge, ...(ngDevMode ? [{ debugName: "badgeDefaults" }] : []));
484
- // Appearance - inputs
485
497
  variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
486
498
  sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
487
499
  colorInput = input(undefined, ...(ngDevMode ? [{ debugName: "colorInput", alias: 'color' }] : [{ alias: 'color' }]));
488
500
  radiusInput = input(undefined, ...(ngDevMode ? [{ debugName: "radiusInput", alias: 'radius' }] : [{ alias: 'radius' }]));
489
- // Values with config defaults
490
501
  variant = withConfigDefault(this.variantInput, computed(() => this.badgeDefaults()?.variant), 'solid');
491
502
  size = withConfigDefault(this.sizeInput, computed(() => this.badgeDefaults()?.size), 'md');
492
503
  color = withConfigDefault(this.colorInput, computed(() => this.badgeDefaults()?.color), 'primary');
493
504
  radius = withConfigDefault(this.radiusInput, computed(() => this.badgeDefaults()?.radius), 'full');
494
- // Icon
495
505
  icon = input(...(ngDevMode ? [undefined, { debugName: "icon" }] : []));
496
506
  iconPosition = input('left', ...(ngDevMode ? [{ debugName: "iconPosition" }] : []));
497
- // Dot indicator
498
507
  dot = input(false, ...(ngDevMode ? [{ debugName: "dot" }] : []));
499
508
  dotColor = input(...(ngDevMode ? [undefined, { debugName: "dotColor" }] : []));
500
- // Removable
501
509
  removable = input(false, ...(ngDevMode ? [{ debugName: "removable" }] : []));
502
510
  removed = output();
503
- // Clickable & Navigation
504
511
  href = input(...(ngDevMode ? [undefined, { debugName: "href" }] : []));
505
512
  target = input('_self', ...(ngDevMode ? [{ debugName: "target" }] : []));
506
513
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
507
514
  clicked = output();
508
- // Number badge
509
515
  value = input(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
510
516
  max = input(...(ngDevMode ? [undefined, { debugName: "max" }] : []));
511
517
  showZero = input(true, ...(ngDevMode ? [{ debugName: "showZero" }] : []));
512
- // Typography
513
518
  uppercase = input(false, ...(ngDevMode ? [{ debugName: "uppercase" }] : []));
514
519
  bold = input(false, ...(ngDevMode ? [{ debugName: "bold" }] : []));
515
- // Animation
516
520
  pulse = input(false, ...(ngDevMode ? [{ debugName: "pulse" }] : []));
517
- // Auto color (будет реализовано позже если нужно)
518
521
  autoColor = input(false, ...(ngDevMode ? [{ debugName: "autoColor" }] : []));
519
522
  iconSize = computed(() => {
520
523
  const sizeMap = { sm: 12, md: 14, lg: 16 };
@@ -525,12 +528,9 @@ class BadgeComponent {
525
528
  if (val === undefined || val === null)
526
529
  return '';
527
530
  const numVal = typeof val === 'number' ? val : parseInt(val, 10);
528
- // Если это число
529
531
  if (!isNaN(numVal)) {
530
- // Не показывать 0 если showZero = false
531
532
  if (numVal === 0 && !this.showZero())
532
533
  return '';
533
- // Показать max+ если превышает максимум
534
534
  const maxVal = this.max();
535
535
  if (maxVal !== undefined && numVal > maxVal) {
536
536
  return `${maxVal}+`;
@@ -540,7 +540,6 @@ class BadgeComponent {
540
540
  return val.toString();
541
541
  }, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
542
542
  isVisible = computed(() => {
543
- // Скрыть если значение 0 и showZero = false
544
543
  const val = this.value();
545
544
  if (val !== undefined && val !== null) {
546
545
  const numVal = typeof val === 'number' ? val : parseInt(val, 10);
@@ -557,12 +556,10 @@ class BadgeComponent {
557
556
  event.stopPropagation();
558
557
  return;
559
558
  }
560
- // Handle link navigation
561
559
  const url = this.href();
562
560
  if (url) {
563
561
  const safeUrl = sanitizeUrl(url);
564
562
  if (safeUrl === '#') {
565
- // URL was blocked - don't navigate
566
563
  return;
567
564
  }
568
565
  const target = this.target();
@@ -615,7 +612,7 @@ class BadgeComponent {
615
612
  </button>
616
613
  }
617
614
  </span>
618
- `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;font-family:var(--studio-font-family);font-weight:var(--studio-badge-font-weight, 500);line-height:1;white-space:nowrap;transition:all .2s ease;cursor:default;-webkit-user-select:none;user-select:none}.studio-badge__content{display:inline-flex;align-items:center;gap:var(--studio-badge-gap);padding:var(--studio-badge-padding-y) var(--studio-badge-padding-x);border-radius:var(--studio-badge-radius);background:var(--studio-badge-bg);color:var(--studio-badge-color);border:var(--studio-badge-border-width, 1px) solid var(--studio-badge-border-color, transparent);font-size:var(--studio-badge-font-size)}.studio-badge__text{display:inline-block}.studio-badge__dot{width:var(--studio-badge-dot-size, 6px);height:var(--studio-badge-dot-size, 6px);border-radius:50%;background:var(--studio-badge-dot-bg);flex-shrink:0}.studio-badge__remove{all:unset;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;opacity:.7;transition:opacity .2s ease}.studio-badge__remove:hover{opacity:1}.studio-badge__remove:focus-visible{outline:2px solid currentColor;outline-offset:2px;border-radius:2px}:host(.studio-badge--solid){--studio-badge-bg: var(--studio-primary);--studio-badge-color: white}:host(.studio-badge--solid).studio-badge--primary{--studio-badge-bg: var(--studio-primary)}:host(.studio-badge--solid).studio-badge--secondary{--studio-badge-bg: var(--studio-secondary)}:host(.studio-badge--solid).studio-badge--success{--studio-badge-bg: var(--studio-success)}:host(.studio-badge--solid).studio-badge--error{--studio-badge-bg: var(--studio-error)}:host(.studio-badge--solid).studio-badge--warning{--studio-badge-bg: var(--studio-warning)}:host(.studio-badge--solid).studio-badge--info{--studio-badge-bg: var(--studio-info)}:host(.studio-badge--solid).studio-badge--neutral{--studio-badge-bg: var(--studio-border-secondary);--studio-badge-color: var(--studio-text-primary)}:host(.studio-badge--outline){--studio-badge-bg: transparent;--studio-badge-color: var(--studio-primary);--studio-badge-border-color: var(--studio-primary)}:host(.studio-badge--outline).studio-badge--primary{--studio-badge-color: var(--studio-primary);--studio-badge-border-color: var(--studio-primary)}:host(.studio-badge--outline).studio-badge--secondary{--studio-badge-color: var(--studio-secondary);--studio-badge-border-color: var(--studio-secondary)}:host(.studio-badge--outline).studio-badge--success{--studio-badge-color: var(--studio-success);--studio-badge-border-color: var(--studio-success)}:host(.studio-badge--outline).studio-badge--error{--studio-badge-color: var(--studio-error);--studio-badge-border-color: var(--studio-error)}:host(.studio-badge--outline).studio-badge--warning{--studio-badge-color: var(--studio-warning);--studio-badge-border-color: var(--studio-warning)}:host(.studio-badge--outline).studio-badge--info{--studio-badge-color: var(--studio-info);--studio-badge-border-color: var(--studio-info)}:host(.studio-badge--outline).studio-badge--neutral{--studio-badge-color: var(--studio-text-secondary);--studio-badge-border-color: var(--studio-border-secondary)}:host(.studio-badge--soft){--studio-badge-bg: rgba(124, 58, 237, .1);--studio-badge-color: var(--studio-primary)}:host(.studio-badge--soft).studio-badge--primary{--studio-badge-bg: rgba(124, 58, 237, .1);--studio-badge-color: var(--studio-primary)}:host(.studio-badge--soft).studio-badge--secondary{--studio-badge-bg: rgba(99, 102, 241, .1);--studio-badge-color: var(--studio-secondary)}:host(.studio-badge--soft).studio-badge--success{--studio-badge-bg: var(--studio-success-bg);--studio-badge-color: var(--studio-success)}:host(.studio-badge--soft).studio-badge--error{--studio-badge-bg: var(--studio-error-bg);--studio-badge-color: var(--studio-error)}:host(.studio-badge--soft).studio-badge--warning{--studio-badge-bg: var(--studio-warning-bg);--studio-badge-color: var(--studio-warning)}:host(.studio-badge--soft).studio-badge--info{--studio-badge-bg: var(--studio-info-bg);--studio-badge-color: var(--studio-info)}:host(.studio-badge--soft).studio-badge--neutral{--studio-badge-bg: var(--studio-bg-secondary);--studio-badge-color: var(--studio-text-secondary)}:host(.studio-badge--dot){--studio-badge-bg: transparent;--studio-badge-color: var(--studio-text-primary);--studio-badge-border-width: 0}:host(.studio-badge--sm){--studio-badge-padding-y: .125rem;--studio-badge-padding-x: .5rem;--studio-badge-font-size: .6875rem;--studio-badge-gap: .25rem}:host(.studio-badge--md){--studio-badge-padding-y: .25rem;--studio-badge-padding-x: .625rem;--studio-badge-font-size: .75rem;--studio-badge-gap: .375rem}:host(.studio-badge--lg){--studio-badge-padding-y: .375rem;--studio-badge-padding-x: .75rem;--studio-badge-font-size: .875rem;--studio-badge-gap: .5rem}:host(.studio-badge--radius-sm){--studio-badge-radius: 2px}:host(.studio-badge--radius-md){--studio-badge-radius: 4px}:host(.studio-badge--radius-lg){--studio-badge-radius: 8px}:host(.studio-badge--radius-full){--studio-badge-radius: 9999px}.studio-badge__dot--primary{--studio-badge-dot-bg: var(--studio-primary)}.studio-badge__dot--secondary{--studio-badge-dot-bg: var(--studio-secondary)}.studio-badge__dot--success{--studio-badge-dot-bg: var(--studio-success)}.studio-badge__dot--error{--studio-badge-dot-bg: var(--studio-error)}.studio-badge__dot--warning{--studio-badge-dot-bg: var(--studio-warning)}.studio-badge__dot--info{--studio-badge-dot-bg: var(--studio-info)}.studio-badge__dot--neutral{--studio-badge-dot-bg: var(--studio-text-secondary)}:host(.studio-badge--clickable){cursor:pointer}:host(.studio-badge--clickable):hover{opacity:.9;transform:translateY(-1px)}:host(.studio-badge--clickable):active{transform:translateY(0)}:host(.studio-badge--disabled){opacity:.5;cursor:not-allowed;pointer-events:none}:host(.studio-badge--uppercase){text-transform:uppercase;letter-spacing:.5px}:host(.studio-badge--bold){--studio-badge-font-weight: 600}@keyframes badge-pulse{0%,to{opacity:1}50%{opacity:.5}}:host(.studio-badge--pulse) .studio-badge__dot{animation:badge-pulse 2s cubic-bezier(.4,0,.6,1) infinite}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
615
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;font-family:var(--studio-font-family);font-weight:var(--studio-badge-font-weight, 500);line-height:1;white-space:nowrap;transition:all .2s ease;cursor:default;-webkit-user-select:none;user-select:none}.studio-badge__content{display:inline-flex;align-items:center;gap:var(--studio-badge-gap);padding:var(--studio-badge-padding-y) var(--studio-badge-padding-x);border-radius:var(--studio-badge-radius);background:var(--studio-badge-bg);color:var(--studio-badge-color);border:var(--studio-badge-border-width, 1px) solid var(--studio-badge-border-color, transparent);font-size:var(--studio-badge-font-size)}.studio-badge__text{display:inline-block}.studio-badge__dot{width:var(--studio-badge-dot-size, 6px);height:var(--studio-badge-dot-size, 6px);border-radius:50%;background:var(--studio-badge-dot-bg);flex-shrink:0}.studio-badge__remove{all:unset;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;opacity:.7;transition:opacity .2s ease}.studio-badge__remove:hover{opacity:1}.studio-badge__remove:focus-visible{outline:2px solid currentColor;outline-offset:2px;border-radius:2px}:host(.studio-badge--solid){--studio-badge-bg: var(--studio-primary);--studio-badge-color: white}:host(.studio-badge--solid).studio-badge--primary{--studio-badge-bg: var(--studio-primary)}:host(.studio-badge--solid).studio-badge--secondary{--studio-badge-bg: var(--studio-secondary)}:host(.studio-badge--solid).studio-badge--success{--studio-badge-bg: var(--studio-success)}:host(.studio-badge--solid).studio-badge--error{--studio-badge-bg: var(--studio-error)}:host(.studio-badge--solid).studio-badge--warning{--studio-badge-bg: var(--studio-warning)}:host(.studio-badge--solid).studio-badge--info{--studio-badge-bg: var(--studio-info)}:host(.studio-badge--solid).studio-badge--neutral{--studio-badge-bg: var(--studio-border-secondary);--studio-badge-color: var(--studio-text-primary)}:host(.studio-badge--outline){--studio-badge-bg: transparent;--studio-badge-color: var(--studio-primary);--studio-badge-border-color: var(--studio-primary)}:host(.studio-badge--outline).studio-badge--primary{--studio-badge-color: var(--studio-primary);--studio-badge-border-color: var(--studio-primary)}:host(.studio-badge--outline).studio-badge--secondary{--studio-badge-color: var(--studio-secondary);--studio-badge-border-color: var(--studio-secondary)}:host(.studio-badge--outline).studio-badge--success{--studio-badge-color: var(--studio-success);--studio-badge-border-color: var(--studio-success)}:host(.studio-badge--outline).studio-badge--error{--studio-badge-color: var(--studio-error);--studio-badge-border-color: var(--studio-error)}:host(.studio-badge--outline).studio-badge--warning{--studio-badge-color: var(--studio-warning);--studio-badge-border-color: var(--studio-warning)}:host(.studio-badge--outline).studio-badge--info{--studio-badge-color: var(--studio-info);--studio-badge-border-color: var(--studio-info)}:host(.studio-badge--outline).studio-badge--neutral{--studio-badge-color: var(--studio-text-secondary);--studio-badge-border-color: var(--studio-border-secondary)}:host(.studio-badge--soft){--studio-badge-bg: rgba(124, 58, 237, .1);--studio-badge-color: var(--studio-primary)}:host(.studio-badge--soft).studio-badge--primary{--studio-badge-bg: rgba(124, 58, 237, .1);--studio-badge-color: var(--studio-primary)}:host(.studio-badge--soft).studio-badge--secondary{--studio-badge-bg: rgba(99, 102, 241, .1);--studio-badge-color: var(--studio-secondary)}:host(.studio-badge--soft).studio-badge--success{--studio-badge-bg: var(--studio-success-bg);--studio-badge-color: var(--studio-success)}:host(.studio-badge--soft).studio-badge--error{--studio-badge-bg: var(--studio-error-bg);--studio-badge-color: var(--studio-error)}:host(.studio-badge--soft).studio-badge--warning{--studio-badge-bg: var(--studio-warning-bg);--studio-badge-color: var(--studio-warning)}:host(.studio-badge--soft).studio-badge--info{--studio-badge-bg: var(--studio-info-bg);--studio-badge-color: var(--studio-info)}:host(.studio-badge--soft).studio-badge--neutral{--studio-badge-bg: var(--studio-bg-secondary);--studio-badge-color: var(--studio-text-secondary)}:host(.studio-badge--dot){--studio-badge-bg: transparent;--studio-badge-color: var(--studio-text-primary);--studio-badge-border-width: 0}:host(.studio-badge--sm){--studio-badge-padding-y: .125rem;--studio-badge-padding-x: .5rem;--studio-badge-font-size: .6875rem;--studio-badge-gap: .25rem}:host(.studio-badge--md){--studio-badge-padding-y: .25rem;--studio-badge-padding-x: .625rem;--studio-badge-font-size: .75rem;--studio-badge-gap: .375rem}:host(.studio-badge--lg){--studio-badge-padding-y: .375rem;--studio-badge-padding-x: .75rem;--studio-badge-font-size: .875rem;--studio-badge-gap: .5rem}:host(.studio-badge--radius-sm){--studio-badge-radius: 2px}:host(.studio-badge--radius-md){--studio-badge-radius: 4px}:host(.studio-badge--radius-lg){--studio-badge-radius: 8px}:host(.studio-badge--radius-full){--studio-badge-radius: 9999px}.studio-badge__dot--primary{--studio-badge-dot-bg: var(--studio-primary)}.studio-badge__dot--secondary{--studio-badge-dot-bg: var(--studio-secondary)}.studio-badge__dot--success{--studio-badge-dot-bg: var(--studio-success)}.studio-badge__dot--error{--studio-badge-dot-bg: var(--studio-error)}.studio-badge__dot--warning{--studio-badge-dot-bg: var(--studio-warning)}.studio-badge__dot--info{--studio-badge-dot-bg: var(--studio-info)}.studio-badge__dot--neutral{--studio-badge-dot-bg: var(--studio-text-secondary)}:host(.studio-badge--clickable){cursor:pointer}:host(.studio-badge--clickable):hover{opacity:.9;transform:translateY(-1px)}:host(.studio-badge--clickable):active{transform:translateY(0)}:host(.studio-badge--disabled){opacity:.5;cursor:not-allowed;pointer-events:none}:host(.studio-badge--uppercase){text-transform:uppercase;letter-spacing:.5px}:host(.studio-badge--bold){--studio-badge-font-weight: 600}@keyframes badge-pulse{0%,to{opacity:1}50%{opacity:.5}}:host(.studio-badge--pulse) .studio-badge__dot{animation:badge-pulse 2s cubic-bezier(.4,0,.6,1) infinite}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
619
616
  }
620
617
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: BadgeComponent, decorators: [{
621
618
  type: Component,
@@ -666,41 +663,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
666
663
  * Badge component
667
664
  */
668
665
 
666
+ /**
667
+ * Button component with multiple variants, sizes, colors and states
668
+ *
669
+ * @example
670
+ * <studio-button variant="solid" color="primary" (clicked)="onClick()">
671
+ * Click me
672
+ * </studio-button>
673
+ */
669
674
  class ButtonComponent {
670
675
  configService = inject(StudioConfigService);
671
676
  buttonDefaults = computed(() => this.configService.config().components?.button, ...(ngDevMode ? [{ debugName: "buttonDefaults" }] : []));
672
- // Appearance - inputs
673
677
  variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
674
678
  sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
675
679
  colorInput = input(undefined, ...(ngDevMode ? [{ debugName: "colorInput", alias: 'color' }] : [{ alias: 'color' }]));
676
680
  radiusInput = input(undefined, ...(ngDevMode ? [{ debugName: "radiusInput", alias: 'radius' }] : [{ alias: 'radius' }]));
677
681
  shadowInput = input(undefined, ...(ngDevMode ? [{ debugName: "shadowInput", alias: 'shadow' }] : [{ alias: 'shadow' }]));
678
682
  compactInput = input(undefined, ...(ngDevMode ? [{ debugName: "compactInput", alias: 'compact' }] : [{ alias: 'compact' }]));
679
- // Values with config defaults
680
683
  variant = withConfigDefault(this.variantInput, computed(() => this.buttonDefaults()?.variant), 'solid');
681
684
  size = withConfigDefault(this.sizeInput, computed(() => this.buttonDefaults()?.size), 'md');
682
685
  color = withConfigDefault(this.colorInput, computed(() => this.buttonDefaults()?.color), 'primary');
683
686
  radius = withConfigDefault(this.radiusInput, computed(() => this.buttonDefaults()?.radius), 'sm');
684
687
  shadow = withConfigDefault(this.shadowInput, computed(() => this.buttonDefaults()?.shadow), 'none');
685
688
  compact = withConfigDefault(this.compactInput, computed(() => this.buttonDefaults()?.compact), false);
686
- // State
687
689
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
688
690
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
689
691
  loadingText = input('Loading...', ...(ngDevMode ? [{ debugName: "loadingText" }] : []));
690
- // Layout
691
692
  fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
692
- // Button props
693
693
  type = input('button', ...(ngDevMode ? [{ debugName: "type" }] : []));
694
- // Icon
695
694
  icon = input(...(ngDevMode ? [undefined, { debugName: "icon" }] : []));
696
695
  iconPosition = input('left', ...(ngDevMode ? [{ debugName: "iconPosition" }] : []));
697
- // Link mode
698
696
  href = input(...(ngDevMode ? [undefined, { debugName: "href" }] : []));
699
697
  target = input('_self', ...(ngDevMode ? [{ debugName: "target" }] : []));
700
- // Badge
701
698
  badge = input(...(ngDevMode ? [undefined, { debugName: "badge" }] : []));
702
699
  badgeColor = input('error', ...(ngDevMode ? [{ debugName: "badgeColor" }] : []));
703
- // Accessibility
704
700
  ariaLabel = input(...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : []));
705
701
  clicked = output();
706
702
  iconSize = computed(() => {
@@ -714,14 +710,11 @@ class ButtonComponent {
714
710
  event.stopPropagation();
715
711
  return;
716
712
  }
717
- // Handle link navigation
718
713
  const url = this.href();
719
714
  if (url) {
720
715
  const safeUrl = sanitizeUrl(url);
721
- if (safeUrl === '#') {
722
- // URL was blocked - don't navigate
716
+ if (safeUrl === '#')
723
717
  return;
724
- }
725
718
  const target = this.target();
726
719
  if (target === '_blank') {
727
720
  window.open(safeUrl, '_blank', 'noopener,noreferrer');
@@ -755,7 +748,6 @@ class ButtonComponent {
755
748
  <studio-icon [name]="icon()!" [size]="iconSize()" />
756
749
  }
757
750
  @if (loading() && iconPosition() === 'only') {
758
- <!-- Empty, spinner already shown -->
759
751
  } @else if (loading()) {
760
752
  <span>{{ loadingText() }}</span>
761
753
  }
@@ -765,7 +757,7 @@ class ButtonComponent {
765
757
  </span>
766
758
  }
767
759
  </span>
768
- `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;gap:var(--studio-spacing-sm);font-family:var(--studio-font-family);font-weight:var(--studio-font-weight-medium);border:none;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;white-space:nowrap;vertical-align:middle;transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast),border-color var(--studio-transition-fast),box-shadow var(--studio-transition-fast),transform var(--studio-transition-fast)}:host:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}:host(.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);font-size:var(--studio-font-size-sm);height:2rem;min-width:2rem}:host(.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);font-size:var(--studio-font-size-base);height:2.5rem;min-width:2.5rem}:host(.studio-button--lg){padding:var(--studio-spacing-md) var(--studio-spacing-lg);font-size:var(--studio-font-size-lg);height:3rem;min-width:3rem}:host(.studio-button--radius-none){border-radius:var(--studio-radius-none)}:host(.studio-button--radius-sm){border-radius:var(--studio-radius-sm)}:host(.studio-button--radius-md){border-radius:var(--studio-radius-md)}:host(.studio-button--radius-lg){border-radius:var(--studio-radius-lg)}:host(.studio-button--radius-xl){border-radius:var(--studio-radius-xl)}:host(.studio-button--radius-full){border-radius:var(--studio-radius-full)}:host(.studio-button--shadow-none){box-shadow:none}:host(.studio-button--shadow-sm){box-shadow:var(--studio-shadow-sm)}:host(.studio-button--shadow-md){box-shadow:var(--studio-shadow-md)}:host(.studio-button--shadow-lg){box-shadow:var(--studio-shadow-lg)}:host(.studio-button--compact.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);height:1.75rem;min-width:1.75rem;font-size:.813rem}:host(.studio-button--compact.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);height:2rem;min-width:2rem;font-size:.875rem}:host(.studio-button--compact.studio-button--lg){padding:var(--studio-spacing-sm) var(--studio-spacing-lg);height:2.5rem;min-width:2.5rem;font-size:1rem}:host(.studio-button--solid.studio-button--primary){background:var(--studio-primary);color:#fff}:host(.studio-button--solid.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary-hover)}:host(.studio-button--outline.studio-button--primary){background:transparent;border:1px solid var(--studio-primary);color:var(--studio-primary)}:host(.studio-button--outline.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary);color:#fff}:host(.studio-button--ghost.studio-button--primary){background:transparent;color:var(--studio-primary)}:host(.studio-button--ghost.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:#3b82f61a}:host(.studio-button--solid.studio-button--secondary){background:var(--studio-secondary);color:#fff}:host(.studio-button--solid.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary-hover)}:host(.studio-button--outline.studio-button--secondary){background:transparent;border:1px solid var(--studio-secondary);color:var(--studio-secondary)}:host(.studio-button--outline.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary);color:#fff}:host(.studio-button--ghost.studio-button--secondary){background:transparent;color:var(--studio-secondary)}:host(.studio-button--ghost.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:#8b5cf61a}:host(.studio-button--solid.studio-button--success){background:var(--studio-success);color:#fff}:host(.studio-button--solid.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-hover)}:host(.studio-button--outline.studio-button--success){background:transparent;border:1px solid var(--studio-success);color:var(--studio-success)}:host(.studio-button--outline.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success);color:#fff}:host(.studio-button--ghost.studio-button--success){background:transparent;color:var(--studio-success)}:host(.studio-button--ghost.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-bg)}:host(.studio-button--solid.studio-button--error){background:var(--studio-error);color:#fff}:host(.studio-button--solid.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-hover)}:host(.studio-button--outline.studio-button--error){background:transparent;border:1px solid var(--studio-error);color:var(--studio-error)}:host(.studio-button--outline.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error);color:#fff}:host(.studio-button--ghost.studio-button--error){background:transparent;color:var(--studio-error)}:host(.studio-button--ghost.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-bg)}:host(.studio-button--solid.studio-button--warning){background:var(--studio-warning);color:#fff}:host(.studio-button--solid.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-hover)}:host(.studio-button--outline.studio-button--warning){background:transparent;border:1px solid var(--studio-warning);color:var(--studio-warning)}:host(.studio-button--outline.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning);color:#fff}:host(.studio-button--ghost.studio-button--warning){background:transparent;color:var(--studio-warning)}:host(.studio-button--ghost.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-bg)}:host(.studio-button--full){width:100%}:host(.studio-button--icon-only){padding:0;aspect-ratio:1}:host(.studio-button--icon-only.studio-button--sm){width:2rem;padding:0}:host(.studio-button--icon-only.studio-button--md){width:2.5rem;padding:0}:host(.studio-button--icon-only.studio-button--lg){width:3rem;padding:0}:host(.studio-button--loading){cursor:wait;pointer-events:none}:host([disabled]){opacity:.6;cursor:not-allowed!important;background:var(--studio-bg-secondary)!important;color:var(--studio-text-tertiary)!important;border-color:var(--studio-border-primary)!important}:host([disabled]:hover){transform:none!important;background:var(--studio-bg-secondary)!important}:host(:active:not([disabled]):not(.studio-button--loading)){transform:scale(.98)}.studio-button__content{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}.studio-button__spinner{animation:studio-spin 1s linear infinite}@keyframes studio-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-button__badge{position:absolute;top:-.375rem;right:-.375rem;display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;font-size:.625rem;font-weight:var(--studio-font-weight-semibold);line-height:1;color:#fff;border-radius:var(--studio-radius-full);box-shadow:0 0 0 2px var(--studio-bg-primary)}.studio-button__badge--primary{background:var(--studio-primary)}.studio-button__badge--error{background:var(--studio-error)}.studio-button__badge--warning{background:var(--studio-warning)}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
760
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;gap:var(--studio-spacing-sm);font-family:var(--studio-font-family);font-weight:var(--studio-font-weight-medium);border:none;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;white-space:nowrap;vertical-align:middle;transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast),border-color var(--studio-transition-fast),box-shadow var(--studio-transition-fast),transform var(--studio-transition-fast)}:host:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}:host(.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);font-size:var(--studio-font-size-sm);height:2rem;min-width:2rem}:host(.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);font-size:var(--studio-font-size-base);height:2.5rem;min-width:2.5rem}:host(.studio-button--lg){padding:var(--studio-spacing-md) var(--studio-spacing-lg);font-size:var(--studio-font-size-lg);height:3rem;min-width:3rem}:host(.studio-button--radius-none){border-radius:var(--studio-radius-none)}:host(.studio-button--radius-sm){border-radius:var(--studio-radius-sm)}:host(.studio-button--radius-md){border-radius:var(--studio-radius-md)}:host(.studio-button--radius-lg){border-radius:var(--studio-radius-lg)}:host(.studio-button--radius-xl){border-radius:var(--studio-radius-xl)}:host(.studio-button--radius-full){border-radius:var(--studio-radius-full)}:host(.studio-button--shadow-none){box-shadow:none}:host(.studio-button--shadow-sm){box-shadow:var(--studio-shadow-sm)}:host(.studio-button--shadow-md){box-shadow:var(--studio-shadow-md)}:host(.studio-button--shadow-lg){box-shadow:var(--studio-shadow-lg)}:host(.studio-button--compact.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);height:1.75rem;min-width:1.75rem;font-size:.813rem}:host(.studio-button--compact.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);height:2rem;min-width:2rem;font-size:.875rem}:host(.studio-button--compact.studio-button--lg){padding:var(--studio-spacing-sm) var(--studio-spacing-lg);height:2.5rem;min-width:2.5rem;font-size:1rem}:host(.studio-button--solid.studio-button--primary){background:var(--studio-primary);color:#fff}:host(.studio-button--solid.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary-hover)}:host(.studio-button--outline.studio-button--primary){background:transparent;border:1px solid var(--studio-primary);color:var(--studio-primary)}:host(.studio-button--outline.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary);color:#fff}:host(.studio-button--ghost.studio-button--primary){background:transparent;color:var(--studio-primary)}:host(.studio-button--ghost.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary-bg)}:host(.studio-button--solid.studio-button--secondary){background:var(--studio-secondary);color:#fff}:host(.studio-button--solid.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary-hover)}:host(.studio-button--outline.studio-button--secondary){background:transparent;border:1px solid var(--studio-secondary);color:var(--studio-secondary)}:host(.studio-button--outline.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary);color:#fff}:host(.studio-button--ghost.studio-button--secondary){background:transparent;color:var(--studio-secondary)}:host(.studio-button--ghost.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary-bg)}:host(.studio-button--solid.studio-button--success){background:var(--studio-success);color:#fff}:host(.studio-button--solid.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-hover)}:host(.studio-button--outline.studio-button--success){background:transparent;border:1px solid var(--studio-success);color:var(--studio-success)}:host(.studio-button--outline.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success);color:#fff}:host(.studio-button--ghost.studio-button--success){background:transparent;color:var(--studio-success)}:host(.studio-button--ghost.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-bg)}:host(.studio-button--solid.studio-button--error){background:var(--studio-error);color:#fff}:host(.studio-button--solid.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-hover)}:host(.studio-button--outline.studio-button--error){background:transparent;border:1px solid var(--studio-error);color:var(--studio-error)}:host(.studio-button--outline.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error);color:#fff}:host(.studio-button--ghost.studio-button--error){background:transparent;color:var(--studio-error)}:host(.studio-button--ghost.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-bg)}:host(.studio-button--solid.studio-button--warning){background:var(--studio-warning);color:#fff}:host(.studio-button--solid.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-hover)}:host(.studio-button--outline.studio-button--warning){background:transparent;border:1px solid var(--studio-warning);color:var(--studio-warning)}:host(.studio-button--outline.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning);color:#fff}:host(.studio-button--ghost.studio-button--warning){background:transparent;color:var(--studio-warning)}:host(.studio-button--ghost.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-bg)}:host(.studio-button--full){width:100%}:host(.studio-button--icon-only){padding:0;aspect-ratio:1}:host(.studio-button--icon-only.studio-button--sm){width:2rem;padding:0}:host(.studio-button--icon-only.studio-button--md){width:2.5rem;padding:0}:host(.studio-button--icon-only.studio-button--lg){width:3rem;padding:0}:host(.studio-button--loading){cursor:wait;pointer-events:none}:host([disabled]){opacity:.6;cursor:not-allowed!important;background:var(--studio-bg-secondary)!important;color:var(--studio-text-tertiary)!important;border-color:var(--studio-border-primary)!important}:host([disabled]:hover){transform:none!important;background:var(--studio-bg-secondary)!important}:host(:active:not([disabled]):not(.studio-button--loading)){transform:scale(.98)}.studio-button__content{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}.studio-button__spinner{animation:studio-spin 1s linear infinite}@keyframes studio-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-button__badge{position:absolute;top:-.375rem;right:-.375rem;display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;font-size:.625rem;font-weight:var(--studio-font-weight-semibold);line-height:1;color:#fff;border-radius:var(--studio-radius-full);box-shadow:0 0 0 2px var(--studio-bg-primary)}.studio-button__badge--primary{background:var(--studio-primary)}.studio-button__badge--error{background:var(--studio-error)}.studio-button__badge--warning{background:var(--studio-warning)}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
769
761
  }
770
762
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ButtonComponent, decorators: [{
771
763
  type: Component,
@@ -800,7 +792,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
800
792
  <studio-icon [name]="icon()!" [size]="iconSize()" />
801
793
  }
802
794
  @if (loading() && iconPosition() === 'only') {
803
- <!-- Empty, spinner already shown -->
804
795
  } @else if (loading()) {
805
796
  <span>{{ loadingText() }}</span>
806
797
  }
@@ -810,18 +801,361 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
810
801
  </span>
811
802
  }
812
803
  </span>
813
- `, styles: [":host{display:inline-flex;align-items:center;justify-content:center;gap:var(--studio-spacing-sm);font-family:var(--studio-font-family);font-weight:var(--studio-font-weight-medium);border:none;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;white-space:nowrap;vertical-align:middle;transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast),border-color var(--studio-transition-fast),box-shadow var(--studio-transition-fast),transform var(--studio-transition-fast)}:host:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}:host(.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);font-size:var(--studio-font-size-sm);height:2rem;min-width:2rem}:host(.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);font-size:var(--studio-font-size-base);height:2.5rem;min-width:2.5rem}:host(.studio-button--lg){padding:var(--studio-spacing-md) var(--studio-spacing-lg);font-size:var(--studio-font-size-lg);height:3rem;min-width:3rem}:host(.studio-button--radius-none){border-radius:var(--studio-radius-none)}:host(.studio-button--radius-sm){border-radius:var(--studio-radius-sm)}:host(.studio-button--radius-md){border-radius:var(--studio-radius-md)}:host(.studio-button--radius-lg){border-radius:var(--studio-radius-lg)}:host(.studio-button--radius-xl){border-radius:var(--studio-radius-xl)}:host(.studio-button--radius-full){border-radius:var(--studio-radius-full)}:host(.studio-button--shadow-none){box-shadow:none}:host(.studio-button--shadow-sm){box-shadow:var(--studio-shadow-sm)}:host(.studio-button--shadow-md){box-shadow:var(--studio-shadow-md)}:host(.studio-button--shadow-lg){box-shadow:var(--studio-shadow-lg)}:host(.studio-button--compact.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);height:1.75rem;min-width:1.75rem;font-size:.813rem}:host(.studio-button--compact.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);height:2rem;min-width:2rem;font-size:.875rem}:host(.studio-button--compact.studio-button--lg){padding:var(--studio-spacing-sm) var(--studio-spacing-lg);height:2.5rem;min-width:2.5rem;font-size:1rem}:host(.studio-button--solid.studio-button--primary){background:var(--studio-primary);color:#fff}:host(.studio-button--solid.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary-hover)}:host(.studio-button--outline.studio-button--primary){background:transparent;border:1px solid var(--studio-primary);color:var(--studio-primary)}:host(.studio-button--outline.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary);color:#fff}:host(.studio-button--ghost.studio-button--primary){background:transparent;color:var(--studio-primary)}:host(.studio-button--ghost.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:#3b82f61a}:host(.studio-button--solid.studio-button--secondary){background:var(--studio-secondary);color:#fff}:host(.studio-button--solid.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary-hover)}:host(.studio-button--outline.studio-button--secondary){background:transparent;border:1px solid var(--studio-secondary);color:var(--studio-secondary)}:host(.studio-button--outline.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary);color:#fff}:host(.studio-button--ghost.studio-button--secondary){background:transparent;color:var(--studio-secondary)}:host(.studio-button--ghost.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:#8b5cf61a}:host(.studio-button--solid.studio-button--success){background:var(--studio-success);color:#fff}:host(.studio-button--solid.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-hover)}:host(.studio-button--outline.studio-button--success){background:transparent;border:1px solid var(--studio-success);color:var(--studio-success)}:host(.studio-button--outline.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success);color:#fff}:host(.studio-button--ghost.studio-button--success){background:transparent;color:var(--studio-success)}:host(.studio-button--ghost.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-bg)}:host(.studio-button--solid.studio-button--error){background:var(--studio-error);color:#fff}:host(.studio-button--solid.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-hover)}:host(.studio-button--outline.studio-button--error){background:transparent;border:1px solid var(--studio-error);color:var(--studio-error)}:host(.studio-button--outline.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error);color:#fff}:host(.studio-button--ghost.studio-button--error){background:transparent;color:var(--studio-error)}:host(.studio-button--ghost.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-bg)}:host(.studio-button--solid.studio-button--warning){background:var(--studio-warning);color:#fff}:host(.studio-button--solid.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-hover)}:host(.studio-button--outline.studio-button--warning){background:transparent;border:1px solid var(--studio-warning);color:var(--studio-warning)}:host(.studio-button--outline.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning);color:#fff}:host(.studio-button--ghost.studio-button--warning){background:transparent;color:var(--studio-warning)}:host(.studio-button--ghost.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-bg)}:host(.studio-button--full){width:100%}:host(.studio-button--icon-only){padding:0;aspect-ratio:1}:host(.studio-button--icon-only.studio-button--sm){width:2rem;padding:0}:host(.studio-button--icon-only.studio-button--md){width:2.5rem;padding:0}:host(.studio-button--icon-only.studio-button--lg){width:3rem;padding:0}:host(.studio-button--loading){cursor:wait;pointer-events:none}:host([disabled]){opacity:.6;cursor:not-allowed!important;background:var(--studio-bg-secondary)!important;color:var(--studio-text-tertiary)!important;border-color:var(--studio-border-primary)!important}:host([disabled]:hover){transform:none!important;background:var(--studio-bg-secondary)!important}:host(:active:not([disabled]):not(.studio-button--loading)){transform:scale(.98)}.studio-button__content{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}.studio-button__spinner{animation:studio-spin 1s linear infinite}@keyframes studio-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-button__badge{position:absolute;top:-.375rem;right:-.375rem;display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;font-size:.625rem;font-weight:var(--studio-font-weight-semibold);line-height:1;color:#fff;border-radius:var(--studio-radius-full);box-shadow:0 0 0 2px var(--studio-bg-primary)}.studio-button__badge--primary{background:var(--studio-primary)}.studio-button__badge--error{background:var(--studio-error)}.studio-button__badge--warning{background:var(--studio-warning)}\n"] }]
804
+ `, styles: [":host{display:inline-flex;align-items:center;justify-content:center;gap:var(--studio-spacing-sm);font-family:var(--studio-font-family);font-weight:var(--studio-font-weight-medium);border:none;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;white-space:nowrap;vertical-align:middle;transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast),border-color var(--studio-transition-fast),box-shadow var(--studio-transition-fast),transform var(--studio-transition-fast)}:host:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}:host(.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);font-size:var(--studio-font-size-sm);height:2rem;min-width:2rem}:host(.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);font-size:var(--studio-font-size-base);height:2.5rem;min-width:2.5rem}:host(.studio-button--lg){padding:var(--studio-spacing-md) var(--studio-spacing-lg);font-size:var(--studio-font-size-lg);height:3rem;min-width:3rem}:host(.studio-button--radius-none){border-radius:var(--studio-radius-none)}:host(.studio-button--radius-sm){border-radius:var(--studio-radius-sm)}:host(.studio-button--radius-md){border-radius:var(--studio-radius-md)}:host(.studio-button--radius-lg){border-radius:var(--studio-radius-lg)}:host(.studio-button--radius-xl){border-radius:var(--studio-radius-xl)}:host(.studio-button--radius-full){border-radius:var(--studio-radius-full)}:host(.studio-button--shadow-none){box-shadow:none}:host(.studio-button--shadow-sm){box-shadow:var(--studio-shadow-sm)}:host(.studio-button--shadow-md){box-shadow:var(--studio-shadow-md)}:host(.studio-button--shadow-lg){box-shadow:var(--studio-shadow-lg)}:host(.studio-button--compact.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);height:1.75rem;min-width:1.75rem;font-size:.813rem}:host(.studio-button--compact.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);height:2rem;min-width:2rem;font-size:.875rem}:host(.studio-button--compact.studio-button--lg){padding:var(--studio-spacing-sm) var(--studio-spacing-lg);height:2.5rem;min-width:2.5rem;font-size:1rem}:host(.studio-button--solid.studio-button--primary){background:var(--studio-primary);color:#fff}:host(.studio-button--solid.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary-hover)}:host(.studio-button--outline.studio-button--primary){background:transparent;border:1px solid var(--studio-primary);color:var(--studio-primary)}:host(.studio-button--outline.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary);color:#fff}:host(.studio-button--ghost.studio-button--primary){background:transparent;color:var(--studio-primary)}:host(.studio-button--ghost.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary-bg)}:host(.studio-button--solid.studio-button--secondary){background:var(--studio-secondary);color:#fff}:host(.studio-button--solid.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary-hover)}:host(.studio-button--outline.studio-button--secondary){background:transparent;border:1px solid var(--studio-secondary);color:var(--studio-secondary)}:host(.studio-button--outline.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary);color:#fff}:host(.studio-button--ghost.studio-button--secondary){background:transparent;color:var(--studio-secondary)}:host(.studio-button--ghost.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary-bg)}:host(.studio-button--solid.studio-button--success){background:var(--studio-success);color:#fff}:host(.studio-button--solid.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-hover)}:host(.studio-button--outline.studio-button--success){background:transparent;border:1px solid var(--studio-success);color:var(--studio-success)}:host(.studio-button--outline.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success);color:#fff}:host(.studio-button--ghost.studio-button--success){background:transparent;color:var(--studio-success)}:host(.studio-button--ghost.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-bg)}:host(.studio-button--solid.studio-button--error){background:var(--studio-error);color:#fff}:host(.studio-button--solid.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-hover)}:host(.studio-button--outline.studio-button--error){background:transparent;border:1px solid var(--studio-error);color:var(--studio-error)}:host(.studio-button--outline.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error);color:#fff}:host(.studio-button--ghost.studio-button--error){background:transparent;color:var(--studio-error)}:host(.studio-button--ghost.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-bg)}:host(.studio-button--solid.studio-button--warning){background:var(--studio-warning);color:#fff}:host(.studio-button--solid.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-hover)}:host(.studio-button--outline.studio-button--warning){background:transparent;border:1px solid var(--studio-warning);color:var(--studio-warning)}:host(.studio-button--outline.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning);color:#fff}:host(.studio-button--ghost.studio-button--warning){background:transparent;color:var(--studio-warning)}:host(.studio-button--ghost.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-bg)}:host(.studio-button--full){width:100%}:host(.studio-button--icon-only){padding:0;aspect-ratio:1}:host(.studio-button--icon-only.studio-button--sm){width:2rem;padding:0}:host(.studio-button--icon-only.studio-button--md){width:2.5rem;padding:0}:host(.studio-button--icon-only.studio-button--lg){width:3rem;padding:0}:host(.studio-button--loading){cursor:wait;pointer-events:none}:host([disabled]){opacity:.6;cursor:not-allowed!important;background:var(--studio-bg-secondary)!important;color:var(--studio-text-tertiary)!important;border-color:var(--studio-border-primary)!important}:host([disabled]:hover){transform:none!important;background:var(--studio-bg-secondary)!important}:host(:active:not([disabled]):not(.studio-button--loading)){transform:scale(.98)}.studio-button__content{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}.studio-button__spinner{animation:studio-spin 1s linear infinite}@keyframes studio-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-button__badge{position:absolute;top:-.375rem;right:-.375rem;display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;font-size:.625rem;font-weight:var(--studio-font-weight-semibold);line-height:1;color:#fff;border-radius:var(--studio-radius-full);box-shadow:0 0 0 2px var(--studio-bg-primary)}.studio-button__badge--primary{background:var(--studio-primary)}.studio-button__badge--error{background:var(--studio-error)}.studio-button__badge--warning{background:var(--studio-warning)}\n"] }]
814
805
  }], propDecorators: { variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], colorInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], radiusInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], shadowInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "shadow", required: false }] }], compactInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], badgeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeColor", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
815
806
 
816
807
  /**
817
808
  * Button component
818
809
  */
819
810
 
811
+ /**
812
+ * Input component with form control support, variants, and accessibility
813
+ *
814
+ * @example
815
+ * <studio-input [(ngModel)]="email" label="Email" type="email" />
816
+ * <studio-input [formControl]="passwordControl" type="password" [showPasswordToggle]="true" />
817
+ */
818
+ class InputComponent {
819
+ configService = inject(StudioConfigService);
820
+ inputDefaults = computed(() => this.configService.config().components?.input, ...(ngDevMode ? [{ debugName: "inputDefaults" }] : []));
821
+ inputEl = viewChild('inputElement', ...(ngDevMode ? [{ debugName: "inputEl" }] : []));
822
+ variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
823
+ sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
824
+ radiusInput = input(undefined, ...(ngDevMode ? [{ debugName: "radiusInput", alias: 'radius' }] : [{ alias: 'radius' }]));
825
+ variant = withConfigDefault(this.variantInput, computed(() => this.inputDefaults()?.variant), 'outline');
826
+ size = withConfigDefault(this.sizeInput, computed(() => this.inputDefaults()?.size), 'md');
827
+ radius = withConfigDefault(this.radiusInput, computed(() => this.inputDefaults()?.radius), 'md');
828
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
829
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
830
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
831
+ type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : []));
832
+ inputmode = input(undefined, ...(ngDevMode ? [{ debugName: "inputmode" }] : []));
833
+ autocomplete = input(undefined, ...(ngDevMode ? [{ debugName: "autocomplete" }] : []));
834
+ placeholder = input(undefined, ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
835
+ maxLength = input(undefined, ...(ngDevMode ? [{ debugName: "maxLength" }] : []));
836
+ minLength = input(undefined, ...(ngDevMode ? [{ debugName: "minLength" }] : []));
837
+ min = input(undefined, ...(ngDevMode ? [{ debugName: "min" }] : []));
838
+ max = input(undefined, ...(ngDevMode ? [{ debugName: "max" }] : []));
839
+ step = input(undefined, ...(ngDevMode ? [{ debugName: "step" }] : []));
840
+ pattern = input(undefined, ...(ngDevMode ? [{ debugName: "pattern" }] : []));
841
+ label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : []));
842
+ floatingLabel = input(false, ...(ngDevMode ? [{ debugName: "floatingLabel" }] : []));
843
+ hint = input(undefined, ...(ngDevMode ? [{ debugName: "hint" }] : []));
844
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
845
+ error = input(false, ...(ngDevMode ? [{ debugName: "error" }] : []));
846
+ errorMessage = input(undefined, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
847
+ prefixIcon = input(undefined, ...(ngDevMode ? [{ debugName: "prefixIcon" }] : []));
848
+ suffixIcon = input(undefined, ...(ngDevMode ? [{ debugName: "suffixIcon" }] : []));
849
+ clearable = input(false, ...(ngDevMode ? [{ debugName: "clearable" }] : []));
850
+ showPasswordToggle = input(false, ...(ngDevMode ? [{ debugName: "showPasswordToggle" }] : []));
851
+ fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
852
+ autoFocus = input(false, ...(ngDevMode ? [{ debugName: "autoFocus" }] : []));
853
+ name = input(undefined, ...(ngDevMode ? [{ debugName: "name" }] : []));
854
+ id = input(undefined, ...(ngDevMode ? [{ debugName: "id" }] : []));
855
+ ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
856
+ valueChange = output();
857
+ focused = output();
858
+ blurred = output();
859
+ cleared = output();
860
+ entered = output();
861
+ value = signal('', ...(ngDevMode ? [{ debugName: "value" }] : []));
862
+ isPasswordVisible = signal(false, ...(ngDevMode ? [{ debugName: "isPasswordVisible" }] : []));
863
+ isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : []));
864
+ isTouched = signal(false, ...(ngDevMode ? [{ debugName: "isTouched" }] : []));
865
+ generatedId = `studio-input-${Math.random().toString(36).substr(2, 9)}`;
866
+ onChange = () => { };
867
+ onTouched = () => { };
868
+ constructor() {
869
+ effect(() => {
870
+ if (this.autoFocus() && this.inputEl()) {
871
+ setTimeout(() => this.inputEl()?.nativeElement.focus(), 0);
872
+ }
873
+ });
874
+ }
875
+ writeValue(value) {
876
+ this.value.set(value ?? '');
877
+ }
878
+ registerOnChange(fn) {
879
+ this.onChange = fn;
880
+ }
881
+ registerOnTouched(fn) {
882
+ this.onTouched = fn;
883
+ }
884
+ setDisabledState(isDisabled) {
885
+ }
886
+ computedType = computed(() => {
887
+ if (this.type() === 'password' && this.isPasswordVisible()) {
888
+ return 'text';
889
+ }
890
+ return this.type();
891
+ }, ...(ngDevMode ? [{ debugName: "computedType" }] : []));
892
+ hasValue = computed(() => {
893
+ const val = this.value();
894
+ return val !== '' && val !== null && val !== undefined;
895
+ }, ...(ngDevMode ? [{ debugName: "hasValue" }] : []));
896
+ hostClasses = computed(() => classNames('studio-input', `studio-input--${this.variant()}`, `studio-input--${this.size()}`, `studio-input--radius-${this.radius()}`, this.error() && 'studio-input--error', this.disabled() && 'studio-input--disabled', this.readonly() && 'studio-input--readonly', this.loading() && 'studio-input--loading', this.fullWidth() && 'studio-input--full-width', this.isFocused() && 'studio-input--focused', this.isTouched() && 'studio-input--touched', this.hasValue() && 'studio-input--has-value'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
897
+ ariaDescribedByValue = computed(() => {
898
+ const ids = [];
899
+ if (this.hint())
900
+ ids.push(this.hintId);
901
+ if (this.error() && this.errorMessage())
902
+ ids.push(this.errorId);
903
+ return ids.length > 0 ? ids.join(' ') : null;
904
+ }, ...(ngDevMode ? [{ debugName: "ariaDescribedByValue" }] : []));
905
+ hintId = `${this.generatedId}-hint`;
906
+ errorId = `${this.generatedId}-error`;
907
+ handleInput(event) {
908
+ const target = event.target;
909
+ const newValue = this.type() === 'number' ? +target.value : target.value;
910
+ this.value.set(newValue);
911
+ this.onChange(newValue);
912
+ this.valueChange.emit(newValue);
913
+ }
914
+ handleFocus(event) {
915
+ this.isFocused.set(true);
916
+ this.focused.emit(event);
917
+ }
918
+ handleBlur(event) {
919
+ this.isFocused.set(false);
920
+ this.isTouched.set(true);
921
+ this.onTouched();
922
+ this.blurred.emit(event);
923
+ }
924
+ handleClear() {
925
+ this.value.set('');
926
+ this.onChange('');
927
+ this.valueChange.emit('');
928
+ this.cleared.emit();
929
+ this.inputEl()?.nativeElement.focus();
930
+ }
931
+ handleEnter(event) {
932
+ this.entered.emit(event);
933
+ }
934
+ togglePasswordVisibility() {
935
+ this.isPasswordVisible.update(v => !v);
936
+ }
937
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: InputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
938
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: InputComponent, isStandalone: true, selector: "studio-input", inputs: { variantInput: { classPropertyName: "variantInput", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, sizeInput: { classPropertyName: "sizeInput", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, radiusInput: { classPropertyName: "radiusInput", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, inputmode: { classPropertyName: "inputmode", publicName: "inputmode", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, pattern: { classPropertyName: "pattern", publicName: "pattern", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, floatingLabel: { classPropertyName: "floatingLabel", publicName: "floatingLabel", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, prefixIcon: { classPropertyName: "prefixIcon", publicName: "prefixIcon", isSignal: true, isRequired: false, transformFunction: null }, suffixIcon: { classPropertyName: "suffixIcon", publicName: "suffixIcon", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, showPasswordToggle: { classPropertyName: "showPasswordToggle", publicName: "showPasswordToggle", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", focused: "focused", blurred: "blurred", cleared: "cleared", entered: "entered" }, host: { properties: { "class": "hostClasses()" } }, providers: [
939
+ {
940
+ provide: NG_VALUE_ACCESSOR,
941
+ useExisting: forwardRef(() => InputComponent),
942
+ multi: true
943
+ }
944
+ ], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputElement"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (label() && !floatingLabel()) {\n <label [for]=\"id() || generatedId\" class=\"studio-input__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-input__required\">*</span>\n }\n </label>\n}\n\n<div class=\"studio-input__container\">\n @if (prefixIcon()) {\n <span class=\"studio-input__prefix\">\n <studio-icon [name]=\"prefixIcon()!\" [size]=\"16\" />\n </span>\n }\n\n @if (label() && floatingLabel()) {\n <label [for]=\"id() || generatedId\" class=\"studio-input__label--floating\">\n {{ label() }}\n @if (required()) {\n <span>*</span>\n }\n </label>\n }\n\n <input\n #inputElement\n class=\"studio-input__field\"\n [type]=\"computedType()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"placeholder()\"\n [required]=\"required()\"\n [attr.maxlength]=\"maxLength()\"\n [attr.minlength]=\"minLength()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [step]=\"step()\"\n [pattern]=\"pattern()\"\n [attr.inputmode]=\"inputmode()\"\n [attr.autocomplete]=\"autocomplete()\"\n [name]=\"name()\"\n [id]=\"id() || generatedId\"\n [attr.aria-label]=\"ariaLabel() || (!label() ? placeholder() : null)\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"ariaDescribedByValue()\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleFocus($event)\"\n (blur)=\"handleBlur($event)\"\n (keydown.enter)=\"handleEnter($event)\"\n />\n\n @if (loading()) {\n <span class=\"studio-input__loading\">\n <studio-icon name=\"loader-2\" [size]=\"16\" class=\"studio-icon--spin\" />\n </span>\n }\n\n @if (clearable() && value() && !disabled() && !loading()) {\n <button\n type=\"button\"\n class=\"studio-input__clear\"\n (click)=\"handleClear()\"\n [attr.aria-label]=\"'Clear input'\"\n tabindex=\"-1\"\n >\n <studio-icon name=\"x\" [size]=\"14\" />\n </button>\n }\n\n @if (type() === 'password' && showPasswordToggle() && !loading()) {\n <button\n type=\"button\"\n class=\"studio-input__toggle-password\"\n (click)=\"togglePasswordVisibility()\"\n [attr.aria-label]=\"isPasswordVisible() ? 'Hide password' : 'Show password'\"\n tabindex=\"-1\"\n >\n <studio-icon [name]=\"isPasswordVisible() ? 'eye-off' : 'eye'\" [size]=\"16\" />\n </button>\n }\n\n @if (suffixIcon() && !loading() && !clearable() && !(type() === 'password' && showPasswordToggle())) {\n <span class=\"studio-input__suffix\">\n <studio-icon [name]=\"suffixIcon()!\" [size]=\"16\" />\n </span>\n }\n </div>\n\n@if (hint() && !error()) {\n <span class=\"studio-input__hint\" [id]=\"hintId\">\n {{ hint() }}\n </span>\n}\n\n@if (error() && errorMessage()) {\n <span class=\"studio-input__error\" [id]=\"errorId\" role=\"alert\">\n <studio-icon name=\"alert-circle\" [size]=\"14\" />\n {{ errorMessage() }}\n </span>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:.375rem;font-family:var(--studio-font-family)}:host(.studio-input--full-width){width:100%}.studio-input__label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);margin-bottom:.25rem}.studio-input__label .studio-input__required{color:var(--studio-error);margin-left:.125rem}.studio-input__container{position:relative;display:flex;align-items:center;transition:all var(--studio-transition-fast)}.studio-input__field{flex:1;width:100%;font-family:inherit;font-size:1rem;color:var(--studio-text-primary);background:transparent;border:none;outline:none;transition:all var(--studio-transition-fast)}.studio-input__field::placeholder{color:var(--studio-text-tertiary)}.studio-input__field:disabled{cursor:not-allowed;opacity:.6}.studio-input__field:read-only{cursor:default}.studio-input__prefix,.studio-input__suffix{display:flex;align-items:center;justify-content:center;color:var(--studio-text-secondary);flex-shrink:0}.studio-input__clear,.studio-input__toggle-password{display:flex;align-items:center;justify-content:center;background:none;border:none;padding:.25rem;color:var(--studio-text-secondary);cursor:pointer;border-radius:var(--studio-radius-sm);transition:all var(--studio-transition-fast);flex-shrink:0}.studio-input__clear:hover,.studio-input__toggle-password:hover{color:var(--studio-text-primary);background:var(--studio-bg-secondary)}.studio-input__clear:active,.studio-input__toggle-password:active{transform:scale(.95)}.studio-input__loading{display:flex;align-items:center;color:var(--studio-primary);flex-shrink:0}.studio-input__loading .studio-icon--spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-input__hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-input__error{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:var(--studio-error);line-height:1.4}:host(.studio-input--outline) .studio-input__container{border:1px solid var(--studio-border-primary);background:var(--studio-bg-primary);border-radius:var(--studio-radius-md)}:host(.studio-input--outline) .studio-input__container:hover:not(:has(.studio-input__field:disabled)){border-color:var(--studio-primary)}:host(.studio-input--outline.studio-input--focused) .studio-input__container{border-color:var(--studio-primary);box-shadow:0 0 0 3px var(--studio-primary-bg)}:host(.studio-input--outline.studio-input--error) .studio-input__container{border-color:var(--studio-error)}:host(.studio-input--outline.studio-input--error) .studio-input__container:hover{border-color:var(--studio-error)}:host(.studio-input--outline.studio-input--error.studio-input--focused) .studio-input__container{box-shadow:0 0 0 3px #ef44441a}:host(.studio-input--outline.studio-input--disabled) .studio-input__container{background:var(--studio-bg-secondary);border-color:var(--studio-border-secondary)}:host(.studio-input--filled) .studio-input__container{background:var(--studio-bg-secondary);border:none;border-bottom:2px solid var(--studio-border-primary);border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0}:host(.studio-input--filled) .studio-input__container:hover:not(:has(.studio-input__field:disabled)){background:var(--studio-bg-tertiary)}:host(.studio-input--filled.studio-input--focused) .studio-input__container{border-bottom-color:var(--studio-primary);background:var(--studio-bg-tertiary)}:host(.studio-input--filled.studio-input--error) .studio-input__container{border-bottom-color:var(--studio-error)}:host(.studio-input--filled.studio-input--disabled) .studio-input__container{background:var(--studio-bg-secondary);opacity:.6}:host(.studio-input--underline) .studio-input__container{background:transparent;border:none;border-bottom:1px solid var(--studio-border-primary);border-radius:0}:host(.studio-input--underline) .studio-input__container:hover:not(:has(.studio-input__field:disabled)){border-bottom-color:var(--studio-primary)}:host(.studio-input--underline.studio-input--focused) .studio-input__container{border-bottom:2px solid var(--studio-primary)}:host(.studio-input--underline.studio-input--error) .studio-input__container{border-bottom-color:var(--studio-error)}:host(.studio-input--underline.studio-input--disabled) .studio-input__container{border-bottom-style:dashed;opacity:.6}:host(.studio-input--sm) .studio-input__field{height:2rem;font-size:.875rem;padding:0 .75rem}:host(.studio-input--sm) .studio-input__prefix{padding-left:.75rem}:host(.studio-input--sm) .studio-input__suffix,:host(.studio-input--sm) .studio-input__clear,:host(.studio-input--sm) .studio-input__toggle-password,:host(.studio-input--sm) .studio-input__loading{padding-right:.5rem}:host(.studio-input--md) .studio-input__field{height:2.5rem;font-size:1rem;padding:0 1rem}:host(.studio-input--md) .studio-input__prefix{padding-left:1rem}:host(.studio-input--md) .studio-input__suffix,:host(.studio-input--md) .studio-input__clear,:host(.studio-input--md) .studio-input__toggle-password,:host(.studio-input--md) .studio-input__loading{padding-right:.75rem}:host(.studio-input--lg) .studio-input__field{height:3rem;font-size:1.125rem;padding:0 1.25rem}:host(.studio-input--lg) .studio-input__prefix{padding-left:1.25rem}:host(.studio-input--lg) .studio-input__suffix,:host(.studio-input--lg) .studio-input__clear,:host(.studio-input--lg) .studio-input__toggle-password,:host(.studio-input--lg) .studio-input__loading{padding-right:1rem}.studio-input__label--floating{position:absolute;top:50%;left:1rem;transform:translateY(-50%);font-size:1rem;color:var(--studio-text-tertiary);pointer-events:none;transition:all var(--studio-transition-fast);background:var(--studio-bg-primary);padding:0 .25rem}:host(.studio-input--filled) .studio-input__label--floating{background:transparent}:host(.studio-input--focused) .studio-input__label--floating,:host(.studio-input--has-value) .studio-input__label--floating{top:0;font-size:.75rem;color:var(--studio-primary)}:host(.studio-input--error) .studio-input__label--floating{color:var(--studio-error)}:host(.studio-input--radius-none) .studio-input__container{border-radius:0}:host(.studio-input--radius-sm) .studio-input__container{border-radius:var(--studio-radius-sm)}:host(.studio-input--radius-md) .studio-input__container{border-radius:var(--studio-radius-md)}:host(.studio-input--radius-lg) .studio-input__container{border-radius:var(--studio-radius-lg)}:host(.studio-input--radius-full) .studio-input__container{border-radius:9999px}:host(.studio-input--filled.studio-input--radius-none) .studio-input__container{border-radius:0}:host(.studio-input--filled.studio-input--radius-sm) .studio-input__container{border-radius:var(--studio-radius-sm) var(--studio-radius-sm) 0 0}:host(.studio-input--filled.studio-input--radius-md) .studio-input__container{border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0}:host(.studio-input--filled.studio-input--radius-lg) .studio-input__container{border-radius:var(--studio-radius-lg) var(--studio-radius-lg) 0 0}:host(.studio-input--filled.studio-input--radius-full) .studio-input__container{border-radius:9999px 9999px 0 0}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
945
+ }
946
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: InputComponent, decorators: [{
947
+ type: Component,
948
+ args: [{ selector: 'studio-input', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
949
+ {
950
+ provide: NG_VALUE_ACCESSOR,
951
+ useExisting: forwardRef(() => InputComponent),
952
+ multi: true
953
+ }
954
+ ], host: {
955
+ '[class]': 'hostClasses()',
956
+ }, template: "@if (label() && !floatingLabel()) {\n <label [for]=\"id() || generatedId\" class=\"studio-input__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-input__required\">*</span>\n }\n </label>\n}\n\n<div class=\"studio-input__container\">\n @if (prefixIcon()) {\n <span class=\"studio-input__prefix\">\n <studio-icon [name]=\"prefixIcon()!\" [size]=\"16\" />\n </span>\n }\n\n @if (label() && floatingLabel()) {\n <label [for]=\"id() || generatedId\" class=\"studio-input__label--floating\">\n {{ label() }}\n @if (required()) {\n <span>*</span>\n }\n </label>\n }\n\n <input\n #inputElement\n class=\"studio-input__field\"\n [type]=\"computedType()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"placeholder()\"\n [required]=\"required()\"\n [attr.maxlength]=\"maxLength()\"\n [attr.minlength]=\"minLength()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [step]=\"step()\"\n [pattern]=\"pattern()\"\n [attr.inputmode]=\"inputmode()\"\n [attr.autocomplete]=\"autocomplete()\"\n [name]=\"name()\"\n [id]=\"id() || generatedId\"\n [attr.aria-label]=\"ariaLabel() || (!label() ? placeholder() : null)\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"ariaDescribedByValue()\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleFocus($event)\"\n (blur)=\"handleBlur($event)\"\n (keydown.enter)=\"handleEnter($event)\"\n />\n\n @if (loading()) {\n <span class=\"studio-input__loading\">\n <studio-icon name=\"loader-2\" [size]=\"16\" class=\"studio-icon--spin\" />\n </span>\n }\n\n @if (clearable() && value() && !disabled() && !loading()) {\n <button\n type=\"button\"\n class=\"studio-input__clear\"\n (click)=\"handleClear()\"\n [attr.aria-label]=\"'Clear input'\"\n tabindex=\"-1\"\n >\n <studio-icon name=\"x\" [size]=\"14\" />\n </button>\n }\n\n @if (type() === 'password' && showPasswordToggle() && !loading()) {\n <button\n type=\"button\"\n class=\"studio-input__toggle-password\"\n (click)=\"togglePasswordVisibility()\"\n [attr.aria-label]=\"isPasswordVisible() ? 'Hide password' : 'Show password'\"\n tabindex=\"-1\"\n >\n <studio-icon [name]=\"isPasswordVisible() ? 'eye-off' : 'eye'\" [size]=\"16\" />\n </button>\n }\n\n @if (suffixIcon() && !loading() && !clearable() && !(type() === 'password' && showPasswordToggle())) {\n <span class=\"studio-input__suffix\">\n <studio-icon [name]=\"suffixIcon()!\" [size]=\"16\" />\n </span>\n }\n </div>\n\n@if (hint() && !error()) {\n <span class=\"studio-input__hint\" [id]=\"hintId\">\n {{ hint() }}\n </span>\n}\n\n@if (error() && errorMessage()) {\n <span class=\"studio-input__error\" [id]=\"errorId\" role=\"alert\">\n <studio-icon name=\"alert-circle\" [size]=\"14\" />\n {{ errorMessage() }}\n </span>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:.375rem;font-family:var(--studio-font-family)}:host(.studio-input--full-width){width:100%}.studio-input__label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);margin-bottom:.25rem}.studio-input__label .studio-input__required{color:var(--studio-error);margin-left:.125rem}.studio-input__container{position:relative;display:flex;align-items:center;transition:all var(--studio-transition-fast)}.studio-input__field{flex:1;width:100%;font-family:inherit;font-size:1rem;color:var(--studio-text-primary);background:transparent;border:none;outline:none;transition:all var(--studio-transition-fast)}.studio-input__field::placeholder{color:var(--studio-text-tertiary)}.studio-input__field:disabled{cursor:not-allowed;opacity:.6}.studio-input__field:read-only{cursor:default}.studio-input__prefix,.studio-input__suffix{display:flex;align-items:center;justify-content:center;color:var(--studio-text-secondary);flex-shrink:0}.studio-input__clear,.studio-input__toggle-password{display:flex;align-items:center;justify-content:center;background:none;border:none;padding:.25rem;color:var(--studio-text-secondary);cursor:pointer;border-radius:var(--studio-radius-sm);transition:all var(--studio-transition-fast);flex-shrink:0}.studio-input__clear:hover,.studio-input__toggle-password:hover{color:var(--studio-text-primary);background:var(--studio-bg-secondary)}.studio-input__clear:active,.studio-input__toggle-password:active{transform:scale(.95)}.studio-input__loading{display:flex;align-items:center;color:var(--studio-primary);flex-shrink:0}.studio-input__loading .studio-icon--spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-input__hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-input__error{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:var(--studio-error);line-height:1.4}:host(.studio-input--outline) .studio-input__container{border:1px solid var(--studio-border-primary);background:var(--studio-bg-primary);border-radius:var(--studio-radius-md)}:host(.studio-input--outline) .studio-input__container:hover:not(:has(.studio-input__field:disabled)){border-color:var(--studio-primary)}:host(.studio-input--outline.studio-input--focused) .studio-input__container{border-color:var(--studio-primary);box-shadow:0 0 0 3px var(--studio-primary-bg)}:host(.studio-input--outline.studio-input--error) .studio-input__container{border-color:var(--studio-error)}:host(.studio-input--outline.studio-input--error) .studio-input__container:hover{border-color:var(--studio-error)}:host(.studio-input--outline.studio-input--error.studio-input--focused) .studio-input__container{box-shadow:0 0 0 3px #ef44441a}:host(.studio-input--outline.studio-input--disabled) .studio-input__container{background:var(--studio-bg-secondary);border-color:var(--studio-border-secondary)}:host(.studio-input--filled) .studio-input__container{background:var(--studio-bg-secondary);border:none;border-bottom:2px solid var(--studio-border-primary);border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0}:host(.studio-input--filled) .studio-input__container:hover:not(:has(.studio-input__field:disabled)){background:var(--studio-bg-tertiary)}:host(.studio-input--filled.studio-input--focused) .studio-input__container{border-bottom-color:var(--studio-primary);background:var(--studio-bg-tertiary)}:host(.studio-input--filled.studio-input--error) .studio-input__container{border-bottom-color:var(--studio-error)}:host(.studio-input--filled.studio-input--disabled) .studio-input__container{background:var(--studio-bg-secondary);opacity:.6}:host(.studio-input--underline) .studio-input__container{background:transparent;border:none;border-bottom:1px solid var(--studio-border-primary);border-radius:0}:host(.studio-input--underline) .studio-input__container:hover:not(:has(.studio-input__field:disabled)){border-bottom-color:var(--studio-primary)}:host(.studio-input--underline.studio-input--focused) .studio-input__container{border-bottom:2px solid var(--studio-primary)}:host(.studio-input--underline.studio-input--error) .studio-input__container{border-bottom-color:var(--studio-error)}:host(.studio-input--underline.studio-input--disabled) .studio-input__container{border-bottom-style:dashed;opacity:.6}:host(.studio-input--sm) .studio-input__field{height:2rem;font-size:.875rem;padding:0 .75rem}:host(.studio-input--sm) .studio-input__prefix{padding-left:.75rem}:host(.studio-input--sm) .studio-input__suffix,:host(.studio-input--sm) .studio-input__clear,:host(.studio-input--sm) .studio-input__toggle-password,:host(.studio-input--sm) .studio-input__loading{padding-right:.5rem}:host(.studio-input--md) .studio-input__field{height:2.5rem;font-size:1rem;padding:0 1rem}:host(.studio-input--md) .studio-input__prefix{padding-left:1rem}:host(.studio-input--md) .studio-input__suffix,:host(.studio-input--md) .studio-input__clear,:host(.studio-input--md) .studio-input__toggle-password,:host(.studio-input--md) .studio-input__loading{padding-right:.75rem}:host(.studio-input--lg) .studio-input__field{height:3rem;font-size:1.125rem;padding:0 1.25rem}:host(.studio-input--lg) .studio-input__prefix{padding-left:1.25rem}:host(.studio-input--lg) .studio-input__suffix,:host(.studio-input--lg) .studio-input__clear,:host(.studio-input--lg) .studio-input__toggle-password,:host(.studio-input--lg) .studio-input__loading{padding-right:1rem}.studio-input__label--floating{position:absolute;top:50%;left:1rem;transform:translateY(-50%);font-size:1rem;color:var(--studio-text-tertiary);pointer-events:none;transition:all var(--studio-transition-fast);background:var(--studio-bg-primary);padding:0 .25rem}:host(.studio-input--filled) .studio-input__label--floating{background:transparent}:host(.studio-input--focused) .studio-input__label--floating,:host(.studio-input--has-value) .studio-input__label--floating{top:0;font-size:.75rem;color:var(--studio-primary)}:host(.studio-input--error) .studio-input__label--floating{color:var(--studio-error)}:host(.studio-input--radius-none) .studio-input__container{border-radius:0}:host(.studio-input--radius-sm) .studio-input__container{border-radius:var(--studio-radius-sm)}:host(.studio-input--radius-md) .studio-input__container{border-radius:var(--studio-radius-md)}:host(.studio-input--radius-lg) .studio-input__container{border-radius:var(--studio-radius-lg)}:host(.studio-input--radius-full) .studio-input__container{border-radius:9999px}:host(.studio-input--filled.studio-input--radius-none) .studio-input__container{border-radius:0}:host(.studio-input--filled.studio-input--radius-sm) .studio-input__container{border-radius:var(--studio-radius-sm) var(--studio-radius-sm) 0 0}:host(.studio-input--filled.studio-input--radius-md) .studio-input__container{border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0}:host(.studio-input--filled.studio-input--radius-lg) .studio-input__container{border-radius:var(--studio-radius-lg) var(--studio-radius-lg) 0 0}:host(.studio-input--filled.studio-input--radius-full) .studio-input__container{border-radius:9999px 9999px 0 0}\n"] }]
957
+ }], ctorParameters: () => [], propDecorators: { inputEl: [{ type: i0.ViewChild, args: ['inputElement', { isSignal: true }] }], variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], radiusInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], inputmode: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputmode", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], pattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "pattern", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], prefixIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefixIcon", required: false }] }], suffixIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffixIcon", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], showPasswordToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPasswordToggle", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], focused: [{ type: i0.Output, args: ["focused"] }], blurred: [{ type: i0.Output, args: ["blurred"] }], cleared: [{ type: i0.Output, args: ["cleared"] }], entered: [{ type: i0.Output, args: ["entered"] }] } });
958
+
959
+ /**
960
+ * Toggle switch component with customizable size and color
961
+ *
962
+ * @example
963
+ * <studio-switch [(checked)]="isEnabled" label="Enable feature" />
964
+ */
965
+ class SwitchComponent {
966
+ configService = inject(StudioConfigService);
967
+ switchDefaults = computed(() => this.configService.config().components?.switch, ...(ngDevMode ? [{ debugName: "switchDefaults" }] : []));
968
+ checked = model(false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
969
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
970
+ label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
971
+ labelPosition = input('right', ...(ngDevMode ? [{ debugName: "labelPosition" }] : []));
972
+ showIcons = input(false, ...(ngDevMode ? [{ debugName: "showIcons" }] : []));
973
+ ariaLabel = input(...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : []));
974
+ sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
975
+ colorInput = input(undefined, ...(ngDevMode ? [{ debugName: "colorInput", alias: 'color' }] : [{ alias: 'color' }]));
976
+ size = withConfigDefault(this.sizeInput, computed(() => this.switchDefaults()?.size), 'md');
977
+ color = withConfigDefault(this.colorInput, computed(() => this.switchDefaults()?.color), 'primary');
978
+ checkedChange = output();
979
+ iconSize = computed(() => {
980
+ const sizeMap = { sm: 10, md: 12, lg: 14 };
981
+ return sizeMap[this.size()];
982
+ }, ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
983
+ hostClasses = computed(() => classNames('studio-switch', `studio-switch--${this.size()}`, `studio-switch--${this.color()}`, this.checked() && 'studio-switch--checked', this.disabled() && 'studio-switch--disabled'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
984
+ handleClick() {
985
+ if (this.disabled())
986
+ return;
987
+ this.toggle();
988
+ }
989
+ handleKeydown(event) {
990
+ if (this.disabled())
991
+ return;
992
+ event.preventDefault();
993
+ this.toggle();
994
+ }
995
+ toggle() {
996
+ const newValue = !this.checked();
997
+ this.checked.set(newValue);
998
+ this.checkedChange.emit(newValue);
999
+ }
1000
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SwitchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1001
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: SwitchComponent, isStandalone: true, selector: "studio-switch", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelPosition: { classPropertyName: "labelPosition", publicName: "labelPosition", isSignal: true, isRequired: false, transformFunction: null }, showIcons: { classPropertyName: "showIcons", publicName: "showIcons", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, sizeInput: { classPropertyName: "sizeInput", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, colorInput: { classPropertyName: "colorInput", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", checkedChange: "checkedChange" }, host: { listeners: { "click": "handleClick()", "keydown.space": "handleKeydown($event)", "keydown.enter": "handleKeydown($event)" }, properties: { "class": "hostClasses()", "attr.role": "\"switch\"", "attr.aria-checked": "checked()", "attr.aria-disabled": "disabled() ? \"true\" : null", "attr.aria-label": "ariaLabel() || label()", "tabindex": "disabled() ? -1 : 0" } }, ngImport: i0, template: `
1002
+ <span class="studio-switch__container">
1003
+ @if (label() && labelPosition() === 'left') {
1004
+ <span class="studio-switch__label studio-switch__label--left">
1005
+ {{ label() }}
1006
+ </span>
1007
+ }
1008
+
1009
+ <span class="studio-switch__track">
1010
+ <span class="studio-switch__thumb">
1011
+ @if (showIcons()) {
1012
+ @if (checked()) {
1013
+ <studio-icon name="check" [size]="iconSize()" color="inherit" />
1014
+ } @else {
1015
+ <studio-icon name="x" [size]="iconSize()" color="inherit" />
1016
+ }
1017
+ }
1018
+ </span>
1019
+ </span>
1020
+
1021
+ @if (label() && labelPosition() === 'right') {
1022
+ <span class="studio-switch__label studio-switch__label--right">
1023
+ {{ label() }}
1024
+ </span>
1025
+ }
1026
+ </span>
1027
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;transition:opacity var(--studio-transition-fast)}:host(:focus-visible) .studio-switch__track{outline:2px solid var(--studio-primary);outline-offset:2px}:host(.studio-switch--disabled){cursor:not-allowed;opacity:.5}.studio-switch__container{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}.studio-switch__label{font-size:var(--studio-font-size-sm);color:var(--studio-text-primary);font-weight:var(--studio-font-weight-medium)}.studio-switch__track{position:relative;display:inline-flex;align-items:center;border-radius:var(--studio-radius-full);background:var(--studio-bg-tertiary);transition:background-color var(--studio-transition-base);flex-shrink:0}.studio-switch__thumb{position:absolute;display:inline-flex;align-items:center;justify-content:center;background:#fff;border-radius:var(--studio-radius-full);box-shadow:var(--studio-shadow-sm);transition:transform var(--studio-transition-base),background-color var(--studio-transition-base);color:var(--studio-text-tertiary)}:host(.studio-switch--sm) .studio-switch__track{width:2rem;height:1.25rem;padding:.125rem}:host(.studio-switch--sm) .studio-switch__thumb{width:1rem;height:1rem;left:.125rem}:host(.studio-switch--md) .studio-switch__track{width:2.5rem;height:1.5rem;padding:.125rem}:host(.studio-switch--md) .studio-switch__thumb{width:1.25rem;height:1.25rem;left:.125rem}:host(.studio-switch--lg) .studio-switch__track{width:3rem;height:1.75rem;padding:.125rem}:host(.studio-switch--lg) .studio-switch__thumb{width:1.5rem;height:1.5rem;left:.125rem}:host(.studio-switch--checked.studio-switch--primary) .studio-switch__track{background:var(--studio-primary)}:host(.studio-switch--checked.studio-switch--primary) .studio-switch__thumb{color:var(--studio-primary)}:host(.studio-switch--checked.studio-switch--sm.studio-switch--primary) .studio-switch__thumb{transform:translate(.75rem)}:host(.studio-switch--checked.studio-switch--md.studio-switch--primary) .studio-switch__thumb{transform:translate(1rem)}:host(.studio-switch--checked.studio-switch--lg.studio-switch--primary) .studio-switch__thumb{transform:translate(1.25rem)}:host(.studio-switch--checked.studio-switch--secondary) .studio-switch__track{background:var(--studio-secondary)}:host(.studio-switch--checked.studio-switch--secondary) .studio-switch__thumb{color:var(--studio-secondary)}:host(.studio-switch--checked.studio-switch--sm.studio-switch--secondary) .studio-switch__thumb{transform:translate(.75rem)}:host(.studio-switch--checked.studio-switch--md.studio-switch--secondary) .studio-switch__thumb{transform:translate(1rem)}:host(.studio-switch--checked.studio-switch--lg.studio-switch--secondary) .studio-switch__thumb{transform:translate(1.25rem)}:host(.studio-switch--checked.studio-switch--success) .studio-switch__track{background:var(--studio-success)}:host(.studio-switch--checked.studio-switch--success) .studio-switch__thumb{color:var(--studio-success)}:host(.studio-switch--checked.studio-switch--sm.studio-switch--success) .studio-switch__thumb{transform:translate(.75rem)}:host(.studio-switch--checked.studio-switch--md.studio-switch--success) .studio-switch__thumb{transform:translate(1rem)}:host(.studio-switch--checked.studio-switch--lg.studio-switch--success) .studio-switch__thumb{transform:translate(1.25rem)}:host(:not(.studio-switch--disabled):hover) .studio-switch__track{opacity:.9}:host(.studio-switch--disabled) .studio-switch__track{background:var(--studio-bg-secondary)!important}:host(.studio-switch--disabled) .studio-switch__thumb{box-shadow:none}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1028
+ }
1029
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SwitchComponent, decorators: [{
1030
+ type: Component,
1031
+ args: [{ selector: 'studio-switch', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1032
+ '[class]': 'hostClasses()',
1033
+ '[attr.role]': '"switch"',
1034
+ '[attr.aria-checked]': 'checked()',
1035
+ '[attr.aria-disabled]': 'disabled() ? "true" : null',
1036
+ '[attr.aria-label]': 'ariaLabel() || label()',
1037
+ '(click)': 'handleClick()',
1038
+ '(keydown.space)': 'handleKeydown($event)',
1039
+ '(keydown.enter)': 'handleKeydown($event)',
1040
+ '[tabindex]': 'disabled() ? -1 : 0'
1041
+ }, template: `
1042
+ <span class="studio-switch__container">
1043
+ @if (label() && labelPosition() === 'left') {
1044
+ <span class="studio-switch__label studio-switch__label--left">
1045
+ {{ label() }}
1046
+ </span>
1047
+ }
1048
+
1049
+ <span class="studio-switch__track">
1050
+ <span class="studio-switch__thumb">
1051
+ @if (showIcons()) {
1052
+ @if (checked()) {
1053
+ <studio-icon name="check" [size]="iconSize()" color="inherit" />
1054
+ } @else {
1055
+ <studio-icon name="x" [size]="iconSize()" color="inherit" />
1056
+ }
1057
+ }
1058
+ </span>
1059
+ </span>
1060
+
1061
+ @if (label() && labelPosition() === 'right') {
1062
+ <span class="studio-switch__label studio-switch__label--right">
1063
+ {{ label() }}
1064
+ </span>
1065
+ }
1066
+ </span>
1067
+ `, styles: [":host{display:inline-flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;transition:opacity var(--studio-transition-fast)}:host(:focus-visible) .studio-switch__track{outline:2px solid var(--studio-primary);outline-offset:2px}:host(.studio-switch--disabled){cursor:not-allowed;opacity:.5}.studio-switch__container{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}.studio-switch__label{font-size:var(--studio-font-size-sm);color:var(--studio-text-primary);font-weight:var(--studio-font-weight-medium)}.studio-switch__track{position:relative;display:inline-flex;align-items:center;border-radius:var(--studio-radius-full);background:var(--studio-bg-tertiary);transition:background-color var(--studio-transition-base);flex-shrink:0}.studio-switch__thumb{position:absolute;display:inline-flex;align-items:center;justify-content:center;background:#fff;border-radius:var(--studio-radius-full);box-shadow:var(--studio-shadow-sm);transition:transform var(--studio-transition-base),background-color var(--studio-transition-base);color:var(--studio-text-tertiary)}:host(.studio-switch--sm) .studio-switch__track{width:2rem;height:1.25rem;padding:.125rem}:host(.studio-switch--sm) .studio-switch__thumb{width:1rem;height:1rem;left:.125rem}:host(.studio-switch--md) .studio-switch__track{width:2.5rem;height:1.5rem;padding:.125rem}:host(.studio-switch--md) .studio-switch__thumb{width:1.25rem;height:1.25rem;left:.125rem}:host(.studio-switch--lg) .studio-switch__track{width:3rem;height:1.75rem;padding:.125rem}:host(.studio-switch--lg) .studio-switch__thumb{width:1.5rem;height:1.5rem;left:.125rem}:host(.studio-switch--checked.studio-switch--primary) .studio-switch__track{background:var(--studio-primary)}:host(.studio-switch--checked.studio-switch--primary) .studio-switch__thumb{color:var(--studio-primary)}:host(.studio-switch--checked.studio-switch--sm.studio-switch--primary) .studio-switch__thumb{transform:translate(.75rem)}:host(.studio-switch--checked.studio-switch--md.studio-switch--primary) .studio-switch__thumb{transform:translate(1rem)}:host(.studio-switch--checked.studio-switch--lg.studio-switch--primary) .studio-switch__thumb{transform:translate(1.25rem)}:host(.studio-switch--checked.studio-switch--secondary) .studio-switch__track{background:var(--studio-secondary)}:host(.studio-switch--checked.studio-switch--secondary) .studio-switch__thumb{color:var(--studio-secondary)}:host(.studio-switch--checked.studio-switch--sm.studio-switch--secondary) .studio-switch__thumb{transform:translate(.75rem)}:host(.studio-switch--checked.studio-switch--md.studio-switch--secondary) .studio-switch__thumb{transform:translate(1rem)}:host(.studio-switch--checked.studio-switch--lg.studio-switch--secondary) .studio-switch__thumb{transform:translate(1.25rem)}:host(.studio-switch--checked.studio-switch--success) .studio-switch__track{background:var(--studio-success)}:host(.studio-switch--checked.studio-switch--success) .studio-switch__thumb{color:var(--studio-success)}:host(.studio-switch--checked.studio-switch--sm.studio-switch--success) .studio-switch__thumb{transform:translate(.75rem)}:host(.studio-switch--checked.studio-switch--md.studio-switch--success) .studio-switch__thumb{transform:translate(1rem)}:host(.studio-switch--checked.studio-switch--lg.studio-switch--success) .studio-switch__thumb{transform:translate(1.25rem)}:host(:not(.studio-switch--disabled):hover) .studio-switch__track{opacity:.9}:host(.studio-switch--disabled) .studio-switch__track{background:var(--studio-bg-secondary)!important}:host(.studio-switch--disabled) .studio-switch__thumb{box-shadow:none}\n"] }]
1068
+ }], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }], showIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcons", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], colorInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], checkedChange: [{ type: i0.Output, args: ["checkedChange"] }] } });
1069
+
1070
+ /**
1071
+ * Switch component
1072
+ */
1073
+
820
1074
  /**
821
1075
  * Primitives (Atoms)
822
1076
  * Basic building blocks
823
1077
  */
824
1078
 
1079
+ /**
1080
+ * Theme toggle switch with sun/moon icons
1081
+ *
1082
+ * @example
1083
+ * <studio-theme-switch />
1084
+ * <studio-theme-switch [showLabel]="true" />
1085
+ */
1086
+ class ThemeSwitchComponent {
1087
+ configService = inject(StudioConfigService);
1088
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
1089
+ showLabel = input(false, ...(ngDevMode ? [{ debugName: "showLabel" }] : []));
1090
+ iconOnly = input(true, ...(ngDevMode ? [{ debugName: "iconOnly" }] : []));
1091
+ isDark = computed(() => this.configService.themeMode() === 'dark', ...(ngDevMode ? [{ debugName: "isDark" }] : []));
1092
+ iconSize = computed(() => {
1093
+ const sizeMap = { sm: 16, md: 20, lg: 24 };
1094
+ return sizeMap[this.size()];
1095
+ }, ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
1096
+ toggleTheme() {
1097
+ this.configService.toggleTheme();
1098
+ }
1099
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ThemeSwitchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1100
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: ThemeSwitchComponent, isStandalone: true, selector: "studio-theme-switch", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showLabel: { classPropertyName: "showLabel", publicName: "showLabel", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "iconOnly", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1101
+ <div class="studio-theme-switch">
1102
+ @if (iconOnly()) {
1103
+ <button
1104
+ type="button"
1105
+ class="studio-theme-switch__button studio-theme-switch__button--{{ size() }}"
1106
+ [attr.aria-label]="isDark() ? 'Switch to light mode' : 'Switch to dark mode'"
1107
+ (click)="toggleTheme()">
1108
+ @if (isDark()) {
1109
+ <studio-icon name="moon" [size]="iconSize()" color="inherit" />
1110
+ } @else {
1111
+ <studio-icon name="sun" [size]="iconSize()" color="inherit" />
1112
+ }
1113
+ </button>
1114
+ } @else {
1115
+ <studio-switch
1116
+ [checked]="isDark()"
1117
+ (checkedChange)="toggleTheme()"
1118
+ [size]="size()"
1119
+ [label]="showLabel() ? (isDark() ? 'Dark' : 'Light') : undefined"
1120
+ labelPosition="left">
1121
+ </studio-switch>
1122
+ }
1123
+ </div>
1124
+ `, isInline: true, styles: [".studio-theme-switch{display:inline-flex;align-items:center}.studio-theme-switch__button{display:inline-flex;align-items:center;justify-content:center;border:none;background:transparent;color:var(--studio-text-secondary);cursor:pointer;border-radius:var(--studio-radius-md);transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast);padding:var(--studio-spacing-xs)}.studio-theme-switch__button:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-theme-switch__button:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}.studio-theme-switch__button--sm{width:2rem;height:2rem}.studio-theme-switch__button--md{width:2.5rem;height:2.5rem}.studio-theme-switch__button--lg{width:3rem;height:3rem}\n"], dependencies: [{ kind: "component", type: SwitchComponent, selector: "studio-switch", inputs: ["checked", "disabled", "label", "labelPosition", "showIcons", "ariaLabel", "size", "color"], outputs: ["checkedChange"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1125
+ }
1126
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ThemeSwitchComponent, decorators: [{
1127
+ type: Component,
1128
+ args: [{ selector: 'studio-theme-switch', standalone: true, imports: [SwitchComponent, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1129
+ <div class="studio-theme-switch">
1130
+ @if (iconOnly()) {
1131
+ <button
1132
+ type="button"
1133
+ class="studio-theme-switch__button studio-theme-switch__button--{{ size() }}"
1134
+ [attr.aria-label]="isDark() ? 'Switch to light mode' : 'Switch to dark mode'"
1135
+ (click)="toggleTheme()">
1136
+ @if (isDark()) {
1137
+ <studio-icon name="moon" [size]="iconSize()" color="inherit" />
1138
+ } @else {
1139
+ <studio-icon name="sun" [size]="iconSize()" color="inherit" />
1140
+ }
1141
+ </button>
1142
+ } @else {
1143
+ <studio-switch
1144
+ [checked]="isDark()"
1145
+ (checkedChange)="toggleTheme()"
1146
+ [size]="size()"
1147
+ [label]="showLabel() ? (isDark() ? 'Dark' : 'Light') : undefined"
1148
+ labelPosition="left">
1149
+ </studio-switch>
1150
+ }
1151
+ </div>
1152
+ `, styles: [".studio-theme-switch{display:inline-flex;align-items:center}.studio-theme-switch__button{display:inline-flex;align-items:center;justify-content:center;border:none;background:transparent;color:var(--studio-text-secondary);cursor:pointer;border-radius:var(--studio-radius-md);transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast);padding:var(--studio-spacing-xs)}.studio-theme-switch__button:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-theme-switch__button:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}.studio-theme-switch__button--sm{width:2rem;height:2rem}.studio-theme-switch__button--md{width:2.5rem;height:2.5rem}.studio-theme-switch__button--lg{width:3rem;height:3rem}\n"] }]
1153
+ }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLabel", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }] } });
1154
+
1155
+ /**
1156
+ * Theme switch component
1157
+ */
1158
+
825
1159
  /**
826
1160
  * Composites (Molecules + Organisms)
827
1161
  * Complex components built from primitives
@@ -843,5 +1177,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
843
1177
  * Generated bundle index. Do not edit.
844
1178
  */
845
1179
 
846
- export { BadgeComponent, ButtonComponent, IconComponent, STUDIO_CONFIG, StudioConfigService, classNames, isSafeUrl, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
1180
+ export { BadgeComponent, ButtonComponent, IconComponent, InputComponent, STUDIO_CONFIG, StudioConfigService, SwitchComponent, ThemeSwitchComponent, classNames, isSafeUrl, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
847
1181
  //# sourceMappingURL=eduboxpro-studio.mjs.map