@eduboxpro/studio 0.1.12 → 0.1.14

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,10 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output, ElementRef, forwardRef, DOCUMENT as DOCUMENT$1, DestroyRef, contentChild, viewChild, model, HostListener, PLATFORM_ID, Renderer2, Directive } from '@angular/core';
2
+ import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output, ElementRef, forwardRef, viewChild, DOCUMENT as DOCUMENT$1, DestroyRef, Injector, contentChild, model, afterNextRender, HostListener, PLATFORM_ID, Renderer2, Directive } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { DOCUMENT, CommonModule, NgTemplateOutlet, isPlatformBrowser } from '@angular/common';
5
5
  import * as LucideIcons from 'lucide-angular';
6
6
  import { icons, LucideAngularModule, LucideIconProvider, LUCIDE_ICONS } from 'lucide-angular';
7
- import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
7
+ import * as i1$1 from '@angular/forms';
8
+ import { NG_VALUE_ACCESSOR, FormsModule, NG_VALIDATORS } from '@angular/forms';
9
+ import { autoUpdate, offset, flip, shift, arrow, computePosition } from '@floating-ui/dom';
8
10
  import { Router, RouterLink, RouterLinkActive, NavigationEnd } from '@angular/router';
9
11
  import { trigger, state, transition, style, animate } from '@angular/animations';
10
12
  import { filter } from 'rxjs/operators';
@@ -1278,6 +1280,871 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
1278
1280
  }, template: "<label\n [for]=\"checkboxId()\"\n [ngClass]=\"hostClasses()\"\n (click)=\"handleLabelClick($event)\"\n>\n <!-- Checkbox input -->\n <input\n type=\"checkbox\"\n [id]=\"checkboxId()\"\n [name]=\"name()\"\n [checked]=\"internalChecked()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [tabIndex]=\"tabIndex()\"\n [attr.aria-checked]=\"ariaChecked()\"\n [attr.aria-label]=\"label() || undefined\"\n [attr.aria-describedby]=\"showHint() || showError() ? checkboxId() + '-description' : undefined\"\n [attr.aria-invalid]=\"error()\"\n [attr.aria-required]=\"required()\"\n class=\"studio-checkbox__input\"\n (change)=\"handleChange($event)\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n />\n\n <!-- Custom checkbox -->\n <span [ngClass]=\"checkboxClasses()\">\n <!-- Checkmark icon -->\n @if (internalChecked() && !indeterminate()) {\n <svg\n class=\"studio-checkbox__icon\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M13.3333 4L6 11.3333L2.66666 8\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n\n <!-- Indeterminate icon -->\n @if (indeterminate()) {\n <svg\n class=\"studio-checkbox__icon studio-checkbox__icon--indeterminate\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M4 8H12\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n </span>\n\n <!-- Label content -->\n @if (label() || description()) {\n <span class=\"studio-checkbox__label-wrapper\">\n @if (label()) {\n <span class=\"studio-checkbox__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-checkbox__required\" aria-hidden=\"true\">*</span>\n }\n </span>\n }\n\n @if (description()) {\n <span class=\"studio-checkbox__description\">\n {{ description() }}\n </span>\n }\n </span>\n }\n</label>\n\n<!-- Helper text / Error message -->\n@if (showHint() || showError()) {\n <div\n [id]=\"checkboxId() + '-description'\"\n class=\"studio-checkbox__info\"\n >\n @if (showError()) {\n <span class=\"studio-checkbox__error\">\n {{ errorMessage() }}\n </span>\n }\n\n @if (showHint()) {\n <span class=\"studio-checkbox__hint\">\n {{ hint() }}\n </span>\n }\n </div>\n}\n", styles: [":host{display:inline-flex;flex-direction:column;font-family:var(--studio-font-family)!important}.studio-checkbox-wrapper{display:inline-flex;align-items:flex-start;gap:var(--studio-spacing-sm);cursor:pointer;-webkit-user-select:none;user-select:none;position:relative}.studio-checkbox-wrapper--label-left{flex-direction:row-reverse}.studio-checkbox-wrapper--disabled{cursor:not-allowed;opacity:.5}.studio-checkbox-wrapper--sm{font-size:var(--studio-font-size-sm)}.studio-checkbox-wrapper--md{font-size:var(--studio-font-size-base)}.studio-checkbox-wrapper--lg{font-size:var(--studio-font-size-lg)}.studio-checkbox__input{position:absolute;opacity:0;pointer-events:none;width:0;height:0}.studio-checkbox{position:relative;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;border:2px solid var(--studio-border-primary);background-color:var(--studio-bg-primary);transition:all var(--studio-transition-base)}.studio-checkbox--sm{width:1rem;height:1rem}.studio-checkbox--md{width:1.25rem;height:1.25rem}.studio-checkbox--lg{width:1.5rem;height:1.5rem}.studio-checkbox--radius-none{border-radius:0}.studio-checkbox--radius-sm{border-radius:var(--studio-radius-sm)}.studio-checkbox--radius-md{border-radius:var(--studio-radius-md)}.studio-checkbox--radius-lg{border-radius:var(--studio-radius-lg)}.studio-checkbox--radius-full{border-radius:var(--studio-radius-full)}.studio-checkbox--default.studio-checkbox--checked,.studio-checkbox--default.studio-checkbox--indeterminate{border-color:transparent}.studio-checkbox--default.studio-checkbox--checked.studio-checkbox--primary,.studio-checkbox--default.studio-checkbox--indeterminate.studio-checkbox--primary{background-color:var(--studio-primary);color:var(--studio-text-inverse)}.studio-checkbox--default.studio-checkbox--checked.studio-checkbox--secondary,.studio-checkbox--default.studio-checkbox--indeterminate.studio-checkbox--secondary{background-color:var(--studio-secondary);color:var(--studio-text-inverse)}.studio-checkbox--default.studio-checkbox--checked.studio-checkbox--success,.studio-checkbox--default.studio-checkbox--indeterminate.studio-checkbox--success{background-color:var(--studio-success);color:var(--studio-text-inverse)}.studio-checkbox--default.studio-checkbox--checked.studio-checkbox--error,.studio-checkbox--default.studio-checkbox--indeterminate.studio-checkbox--error{background-color:var(--studio-error);color:var(--studio-text-inverse)}.studio-checkbox--outlined.studio-checkbox--checked,.studio-checkbox--outlined.studio-checkbox--indeterminate{background-color:transparent}.studio-checkbox--outlined.studio-checkbox--checked.studio-checkbox--primary,.studio-checkbox--outlined.studio-checkbox--indeterminate.studio-checkbox--primary{border-color:var(--studio-primary);color:var(--studio-primary)}.studio-checkbox--outlined.studio-checkbox--checked.studio-checkbox--secondary,.studio-checkbox--outlined.studio-checkbox--indeterminate.studio-checkbox--secondary{border-color:var(--studio-secondary);color:var(--studio-secondary)}.studio-checkbox--outlined.studio-checkbox--checked.studio-checkbox--success,.studio-checkbox--outlined.studio-checkbox--indeterminate.studio-checkbox--success{border-color:var(--studio-success);color:var(--studio-success)}.studio-checkbox--outlined.studio-checkbox--checked.studio-checkbox--error,.studio-checkbox--outlined.studio-checkbox--indeterminate.studio-checkbox--error{border-color:var(--studio-error);color:var(--studio-error)}.studio-checkbox--filled.studio-checkbox--primary{background-color:var(--studio-primary-bg);border-color:var(--studio-primary-bg)}.studio-checkbox--filled.studio-checkbox--secondary{background-color:var(--studio-secondary-bg);border-color:var(--studio-secondary-bg)}.studio-checkbox--filled.studio-checkbox--success{background-color:var(--studio-success-bg);border-color:var(--studio-success-bg)}.studio-checkbox--filled.studio-checkbox--error{background-color:var(--studio-error-bg);border-color:var(--studio-error-bg)}.studio-checkbox--filled.studio-checkbox--checked.studio-checkbox--primary,.studio-checkbox--filled.studio-checkbox--indeterminate.studio-checkbox--primary{background-color:var(--studio-primary);border-color:var(--studio-primary);color:var(--studio-text-inverse)}.studio-checkbox--filled.studio-checkbox--checked.studio-checkbox--secondary,.studio-checkbox--filled.studio-checkbox--indeterminate.studio-checkbox--secondary{background-color:var(--studio-secondary);border-color:var(--studio-secondary);color:var(--studio-text-inverse)}.studio-checkbox--filled.studio-checkbox--checked.studio-checkbox--success,.studio-checkbox--filled.studio-checkbox--indeterminate.studio-checkbox--success{background-color:var(--studio-success);border-color:var(--studio-success);color:var(--studio-text-inverse)}.studio-checkbox--filled.studio-checkbox--checked.studio-checkbox--error,.studio-checkbox--filled.studio-checkbox--indeterminate.studio-checkbox--error{background-color:var(--studio-error);border-color:var(--studio-error);color:var(--studio-text-inverse)}.studio-checkbox--error:not(.studio-checkbox--checked):not(.studio-checkbox--indeterminate){border-color:var(--studio-error)}.studio-checkbox:hover:not(.studio-checkbox--disabled){border-color:var(--studio-border-secondary)}.studio-checkbox__input:focus-visible+.studio-checkbox{outline:2px solid var(--studio-primary);outline-offset:2px}.studio-checkbox__icon{width:100%;height:100%;opacity:0;transform:scale(.8);transition:all var(--studio-transition-fast)}.studio-checkbox--checked .studio-checkbox__icon,.studio-checkbox--indeterminate .studio-checkbox__icon{opacity:1;transform:scale(1)}.studio-checkbox__label-wrapper{display:flex;flex-direction:column;gap:var(--studio-spacing-xs)}.studio-checkbox__label{font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);line-height:var(--studio-line-height-normal)}.studio-checkbox__description{font-size:var(--studio-font-size-sm);color:var(--studio-text-secondary);line-height:var(--studio-line-height-normal)}.studio-checkbox__required{color:var(--studio-error);margin-left:var(--studio-spacing-xs)}.studio-checkbox__info{display:flex;flex-direction:column;gap:var(--studio-spacing-xs);margin-top:var(--studio-spacing-xs);padding-left:calc(var(--studio-spacing-sm) + 1.25rem)}.studio-checkbox-wrapper--label-left+.studio-checkbox__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1.25rem)}.studio-checkbox-wrapper--sm .studio-checkbox__info{padding-left:calc(var(--studio-spacing-sm) + 1rem)}.studio-checkbox-wrapper--sm.studio-checkbox-wrapper--label-left .studio-checkbox__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1rem)}.studio-checkbox-wrapper--lg .studio-checkbox__info{padding-left:calc(var(--studio-spacing-sm) + 1.5rem)}.studio-checkbox-wrapper--lg.studio-checkbox-wrapper--label-left .studio-checkbox__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1.5rem)}.studio-checkbox__hint{font-size:var(--studio-font-size-xs);color:var(--studio-text-secondary);line-height:var(--studio-line-height-normal)}.studio-checkbox__error{font-size:var(--studio-font-size-xs);color:var(--studio-error);line-height:var(--studio-line-height-normal)}\n"] }]
1279
1281
  }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
1280
1282
 
1283
+ class ColorConverter {
1284
+ static hexToRgb(hex) {
1285
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
1286
+ return result ? {
1287
+ r: parseInt(result[1], 16),
1288
+ g: parseInt(result[2], 16),
1289
+ b: parseInt(result[3], 16)
1290
+ } : null;
1291
+ }
1292
+ static rgbToHex(r, g, b) {
1293
+ return "#" + [r, g, b]
1294
+ .map(x => {
1295
+ const hex = Math.round(x).toString(16);
1296
+ return hex.length === 1 ? "0" + hex : hex;
1297
+ })
1298
+ .join("");
1299
+ }
1300
+ static rgbToHsl(r, g, b) {
1301
+ r /= 255;
1302
+ g /= 255;
1303
+ b /= 255;
1304
+ const max = Math.max(r, g, b);
1305
+ const min = Math.min(r, g, b);
1306
+ let h = 0, s = 0;
1307
+ const l = (max + min) / 2;
1308
+ if (max !== min) {
1309
+ const d = max - min;
1310
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1311
+ switch (max) {
1312
+ case r:
1313
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
1314
+ break;
1315
+ case g:
1316
+ h = ((b - r) / d + 2) / 6;
1317
+ break;
1318
+ case b:
1319
+ h = ((r - g) / d + 4) / 6;
1320
+ break;
1321
+ }
1322
+ }
1323
+ return {
1324
+ h: Math.round(h * 360),
1325
+ s: Math.round(s * 100),
1326
+ l: Math.round(l * 100)
1327
+ };
1328
+ }
1329
+ static hslToRgb(h, s, l) {
1330
+ h = h / 360;
1331
+ s = s / 100;
1332
+ l = l / 100;
1333
+ let r, g, b;
1334
+ if (s === 0) {
1335
+ r = g = b = l;
1336
+ }
1337
+ else {
1338
+ const hue2rgb = (p, q, t) => {
1339
+ if (t < 0)
1340
+ t += 1;
1341
+ if (t > 1)
1342
+ t -= 1;
1343
+ if (t < 1 / 6)
1344
+ return p + (q - p) * 6 * t;
1345
+ if (t < 1 / 2)
1346
+ return q;
1347
+ if (t < 2 / 3)
1348
+ return p + (q - p) * (2 / 3 - t) * 6;
1349
+ return p;
1350
+ };
1351
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1352
+ const p = 2 * l - q;
1353
+ r = hue2rgb(p, q, h + 1 / 3);
1354
+ g = hue2rgb(p, q, h);
1355
+ b = hue2rgb(p, q, h - 1 / 3);
1356
+ }
1357
+ return {
1358
+ r: Math.round(r * 255),
1359
+ g: Math.round(g * 255),
1360
+ b: Math.round(b * 255)
1361
+ };
1362
+ }
1363
+ static format(color, format) {
1364
+ switch (format) {
1365
+ case 'hex':
1366
+ return color.hex;
1367
+ case 'rgb':
1368
+ if (color.alpha < 1) {
1369
+ return `rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${color.alpha})`;
1370
+ }
1371
+ return `rgb(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b})`;
1372
+ case 'hsl':
1373
+ if (color.alpha < 1) {
1374
+ return `hsla(${color.hsl.h}, ${color.hsl.s}%, ${color.hsl.l}%, ${color.alpha})`;
1375
+ }
1376
+ return `hsl(${color.hsl.h}, ${color.hsl.s}%, ${color.hsl.l}%)`;
1377
+ default:
1378
+ return color.hex;
1379
+ }
1380
+ }
1381
+ static parse(colorString) {
1382
+ const trimmed = colorString.trim();
1383
+ const hexMatch = /^#?([a-f\d]{6})$/i.exec(trimmed);
1384
+ if (hexMatch) {
1385
+ const hex = '#' + hexMatch[1];
1386
+ const rgb = this.hexToRgb(hex);
1387
+ if (!rgb)
1388
+ return null;
1389
+ return {
1390
+ hex,
1391
+ rgb,
1392
+ hsl: this.rgbToHsl(rgb.r, rgb.g, rgb.b),
1393
+ alpha: 1
1394
+ };
1395
+ }
1396
+ const rgbMatch = /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)$/i.exec(trimmed);
1397
+ if (rgbMatch) {
1398
+ const r = parseInt(rgbMatch[1]);
1399
+ const g = parseInt(rgbMatch[2]);
1400
+ const b = parseInt(rgbMatch[3]);
1401
+ const alpha = rgbMatch[4] ? parseFloat(rgbMatch[4]) : 1;
1402
+ return {
1403
+ hex: this.rgbToHex(r, g, b),
1404
+ rgb: { r, g, b },
1405
+ hsl: this.rgbToHsl(r, g, b),
1406
+ alpha
1407
+ };
1408
+ }
1409
+ const hslMatch = /^hsla?\((\d+),\s*(\d+)%?,\s*(\d+)%?(?:,\s*([\d.]+))?\)$/i.exec(trimmed);
1410
+ if (hslMatch) {
1411
+ const h = parseInt(hslMatch[1]);
1412
+ const s = parseInt(hslMatch[2]);
1413
+ const l = parseInt(hslMatch[3]);
1414
+ const alpha = hslMatch[4] ? parseFloat(hslMatch[4]) : 1;
1415
+ const rgb = this.hslToRgb(h, s, l);
1416
+ return {
1417
+ hex: this.rgbToHex(rgb.r, rgb.g, rgb.b),
1418
+ rgb,
1419
+ hsl: { h, s, l },
1420
+ alpha
1421
+ };
1422
+ }
1423
+ return null;
1424
+ }
1425
+ static isValid(colorString) {
1426
+ return this.parse(colorString) !== null;
1427
+ }
1428
+ }
1429
+
1430
+ const DEFAULT_COLOR_PRESETS = [
1431
+ {
1432
+ label: 'Brand Colors',
1433
+ colors: [
1434
+ { label: 'Primary', value: '#7c3aed' },
1435
+ { label: 'Secondary', value: '#6366f1' },
1436
+ { label: 'Success', value: '#10b981' },
1437
+ { label: 'Error', value: '#ef4444' },
1438
+ { label: 'Warning', value: '#f59e0b' },
1439
+ { label: 'Info', value: '#3b82f6' }
1440
+ ]
1441
+ },
1442
+ {
1443
+ label: 'Grays',
1444
+ colors: [
1445
+ { value: '#ffffff' },
1446
+ { value: '#f3f4f6' },
1447
+ { value: '#d1d5db' },
1448
+ { value: '#9ca3af' },
1449
+ { value: '#6b7280' },
1450
+ { value: '#374151' },
1451
+ { value: '#1f2937' },
1452
+ { value: '#000000' }
1453
+ ]
1454
+ },
1455
+ {
1456
+ label: 'Common',
1457
+ colors: [
1458
+ { value: '#ff0000' },
1459
+ { value: '#ff7f00' },
1460
+ { value: '#ffff00' },
1461
+ { value: '#00ff00' },
1462
+ { value: '#0000ff' },
1463
+ { value: '#4b0082' },
1464
+ { value: '#9400d3' },
1465
+ { value: '#ff1493' }
1466
+ ]
1467
+ }
1468
+ ];
1469
+
1470
+ class ColorPickerComponent {
1471
+ configService = inject(StudioConfigService);
1472
+ pickerDefaults = computed(() => this.configService.config().components?.colorPicker, ...(ngDevMode ? [{ debugName: "pickerDefaults" }] : []));
1473
+ colorAreaCanvas = viewChild('colorArea', ...(ngDevMode ? [{ debugName: "colorAreaCanvas" }] : []));
1474
+ variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
1475
+ sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
1476
+ variant = withConfigDefault(this.variantInput, computed(() => this.pickerDefaults()?.variant), 'inline');
1477
+ size = withConfigDefault(this.sizeInput, computed(() => this.pickerDefaults()?.size), 'md');
1478
+ format = input('hex', ...(ngDevMode ? [{ debugName: "format" }] : []));
1479
+ showAlpha = input(false, ...(ngDevMode ? [{ debugName: "showAlpha" }] : []));
1480
+ showPresets = input(true, ...(ngDevMode ? [{ debugName: "showPresets" }] : []));
1481
+ showFormatToggle = input(true, ...(ngDevMode ? [{ debugName: "showFormatToggle" }] : []));
1482
+ showCopyButton = input(true, ...(ngDevMode ? [{ debugName: "showCopyButton" }] : []));
1483
+ presets = input(...(ngDevMode ? [undefined, { debugName: "presets" }] : []));
1484
+ label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : []));
1485
+ hint = input(undefined, ...(ngDevMode ? [{ debugName: "hint" }] : []));
1486
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
1487
+ error = input(false, ...(ngDevMode ? [{ debugName: "error" }] : []));
1488
+ errorMessage = input(undefined, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
1489
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1490
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
1491
+ colorChange = output();
1492
+ colorValueChange = output();
1493
+ copied = output();
1494
+ currentColor = signal(this.createColorValue('#000000'), ...(ngDevMode ? [{ debugName: "currentColor" }] : []));
1495
+ hue = signal(0, ...(ngDevMode ? [{ debugName: "hue" }] : []));
1496
+ saturation = signal(100, ...(ngDevMode ? [{ debugName: "saturation" }] : []));
1497
+ lightness = signal(50, ...(ngDevMode ? [{ debugName: "lightness" }] : []));
1498
+ alpha = signal(1, ...(ngDevMode ? [{ debugName: "alpha" }] : []));
1499
+ currentFormat = signal('hex', ...(ngDevMode ? [{ debugName: "currentFormat" }] : []));
1500
+ generatedId = `studio-color-picker-${Math.random().toString(36).substr(2, 9)}`;
1501
+ onChange = () => { };
1502
+ onTouched = () => { };
1503
+ isDragging = false;
1504
+ constructor() {
1505
+ effect(() => {
1506
+ this.currentFormat.set(this.format());
1507
+ });
1508
+ effect(() => {
1509
+ this.renderColorArea();
1510
+ });
1511
+ }
1512
+ ngAfterViewInit() {
1513
+ this.renderColorArea();
1514
+ }
1515
+ displayColor = computed(() => {
1516
+ const color = this.currentColor();
1517
+ return ColorConverter.format(color, this.currentFormat());
1518
+ }, ...(ngDevMode ? [{ debugName: "displayColor" }] : []));
1519
+ effectivePresets = computed(() => {
1520
+ const custom = this.presets();
1521
+ return custom && custom.length > 0 ? custom : DEFAULT_COLOR_PRESETS;
1522
+ }, ...(ngDevMode ? [{ debugName: "effectivePresets" }] : []));
1523
+ hostClasses = computed(() => classNames('studio-color-picker', `studio-color-picker--${this.variant()}`, `studio-color-picker--${this.size()}`, this.error() && 'studio-color-picker--error', this.disabled() && 'studio-color-picker--disabled'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1524
+ writeValue(value) {
1525
+ if (!value)
1526
+ return;
1527
+ const colorValue = ColorConverter.parse(value);
1528
+ if (colorValue) {
1529
+ this.currentColor.set(colorValue);
1530
+ this.hue.set(colorValue.hsl.h);
1531
+ this.saturation.set(colorValue.hsl.s);
1532
+ this.lightness.set(colorValue.hsl.l);
1533
+ this.alpha.set(colorValue.alpha);
1534
+ }
1535
+ }
1536
+ registerOnChange(fn) {
1537
+ this.onChange = fn;
1538
+ }
1539
+ registerOnTouched(fn) {
1540
+ this.onTouched = fn;
1541
+ }
1542
+ setDisabledState(isDisabled) { }
1543
+ onHueChange(event) {
1544
+ const value = +event.target.value;
1545
+ this.hue.set(value);
1546
+ this.updateColor();
1547
+ }
1548
+ onAlphaChange(event) {
1549
+ const value = +event.target.value;
1550
+ this.alpha.set(value / 100);
1551
+ this.updateColor();
1552
+ }
1553
+ onColorAreaMouseDown(event) {
1554
+ if (this.disabled() || this.readonly())
1555
+ return;
1556
+ this.isDragging = true;
1557
+ this.updateColorArea(event);
1558
+ const onMouseMove = (e) => {
1559
+ if (this.isDragging) {
1560
+ this.updateColorArea(e);
1561
+ }
1562
+ };
1563
+ const onMouseUp = () => {
1564
+ this.isDragging = false;
1565
+ document.removeEventListener('mousemove', onMouseMove);
1566
+ document.removeEventListener('mouseup', onMouseUp);
1567
+ };
1568
+ document.addEventListener('mousemove', onMouseMove);
1569
+ document.addEventListener('mouseup', onMouseUp);
1570
+ }
1571
+ updateColorArea(event) {
1572
+ const canvas = this.colorAreaCanvas()?.nativeElement;
1573
+ if (!canvas)
1574
+ return;
1575
+ const rect = canvas.getBoundingClientRect();
1576
+ const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
1577
+ const y = Math.max(0, Math.min(event.clientY - rect.top, rect.height));
1578
+ this.saturation.set((x / rect.width) * 100);
1579
+ this.lightness.set(100 - (y / rect.height) * 100);
1580
+ this.updateColor();
1581
+ }
1582
+ updateColor() {
1583
+ const h = this.hue();
1584
+ const s = this.saturation();
1585
+ const l = this.lightness();
1586
+ const rgb = ColorConverter.hslToRgb(h, s, l);
1587
+ const hex = ColorConverter.rgbToHex(rgb.r, rgb.g, rgb.b);
1588
+ const colorValue = {
1589
+ hex,
1590
+ rgb,
1591
+ hsl: { h, s, l },
1592
+ alpha: this.alpha()
1593
+ };
1594
+ this.currentColor.set(colorValue);
1595
+ const formatted = ColorConverter.format(colorValue, this.currentFormat());
1596
+ this.onChange(formatted);
1597
+ this.colorChange.emit(formatted);
1598
+ this.colorValueChange.emit(colorValue);
1599
+ }
1600
+ renderColorArea() {
1601
+ const canvas = this.colorAreaCanvas()?.nativeElement;
1602
+ if (!canvas)
1603
+ return;
1604
+ const ctx = canvas.getContext('2d');
1605
+ if (!ctx)
1606
+ return;
1607
+ const width = canvas.width;
1608
+ const height = canvas.height;
1609
+ const hue = this.hue();
1610
+ const horizGradient = ctx.createLinearGradient(0, 0, width, 0);
1611
+ horizGradient.addColorStop(0, 'white');
1612
+ horizGradient.addColorStop(1, `hsl(${hue}, 100%, 50%)`);
1613
+ ctx.fillStyle = horizGradient;
1614
+ ctx.fillRect(0, 0, width, height);
1615
+ const vertGradient = ctx.createLinearGradient(0, 0, 0, height);
1616
+ vertGradient.addColorStop(0, 'transparent');
1617
+ vertGradient.addColorStop(1, 'black');
1618
+ ctx.fillStyle = vertGradient;
1619
+ ctx.fillRect(0, 0, width, height);
1620
+ }
1621
+ toggleFormat() {
1622
+ const formats = ['hex', 'rgb', 'hsl'];
1623
+ const current = this.currentFormat();
1624
+ const index = formats.indexOf(current);
1625
+ const next = formats[(index + 1) % formats.length];
1626
+ this.currentFormat.set(next);
1627
+ }
1628
+ async copyColor() {
1629
+ const color = this.displayColor();
1630
+ try {
1631
+ await navigator.clipboard.writeText(color);
1632
+ this.copied.emit(color);
1633
+ }
1634
+ catch (error) {
1635
+ console.error('Copy failed:', error);
1636
+ }
1637
+ }
1638
+ selectPreset(preset) {
1639
+ this.writeValue(preset.value);
1640
+ this.updateColor();
1641
+ }
1642
+ isPresetGroup(item) {
1643
+ return item && 'colors' in item && Array.isArray(item.colors);
1644
+ }
1645
+ createColorValue(hex) {
1646
+ const rgb = ColorConverter.hexToRgb(hex) || { r: 0, g: 0, b: 0 };
1647
+ const hsl = ColorConverter.rgbToHsl(rgb.r, rgb.g, rgb.b);
1648
+ return {
1649
+ hex,
1650
+ rgb,
1651
+ hsl,
1652
+ alpha: 1
1653
+ };
1654
+ }
1655
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ColorPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1656
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: ColorPickerComponent, isStandalone: true, selector: "studio-color-picker", inputs: { variantInput: { classPropertyName: "variantInput", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, sizeInput: { classPropertyName: "sizeInput", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, showAlpha: { classPropertyName: "showAlpha", publicName: "showAlpha", isSignal: true, isRequired: false, transformFunction: null }, showPresets: { classPropertyName: "showPresets", publicName: "showPresets", isSignal: true, isRequired: false, transformFunction: null }, showFormatToggle: { classPropertyName: "showFormatToggle", publicName: "showFormatToggle", isSignal: true, isRequired: false, transformFunction: null }, showCopyButton: { classPropertyName: "showCopyButton", publicName: "showCopyButton", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { colorChange: "colorChange", colorValueChange: "colorValueChange", copied: "copied" }, host: { properties: { "class": "hostClasses()" } }, providers: [
1657
+ {
1658
+ provide: NG_VALUE_ACCESSOR,
1659
+ useExisting: forwardRef(() => ColorPickerComponent),
1660
+ multi: true
1661
+ }
1662
+ ], viewQueries: [{ propertyName: "colorAreaCanvas", first: true, predicate: ["colorArea"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (label()) {\n <label [for]=\"generatedId\" class=\"studio-color-picker__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-color-picker__required\">*</span>\n }\n </label>\n}\n\n<div class=\"studio-color-picker__picker\">\n <div class=\"studio-color-picker__preview\">\n <div\n class=\"studio-color-picker__preview-color\"\n [style.background-color]=\"displayColor()\"\n ></div>\n <div class=\"studio-color-picker__preview-info\">\n <span class=\"studio-color-picker__preview-value\">{{ displayColor() }}</span>\n @if (showFormatToggle()) {\n <button\n type=\"button\"\n class=\"studio-color-picker__format-btn\"\n (click)=\"toggleFormat()\"\n [disabled]=\"disabled() || readonly()\"\n >\n {{ currentFormat().toUpperCase() }}\n </button>\n }\n </div>\n @if (showCopyButton()) {\n <button\n type=\"button\"\n class=\"studio-color-picker__copy-btn\"\n (click)=\"copyColor()\"\n [disabled]=\"disabled() || readonly()\"\n aria-label=\"Copy color\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect>\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path>\n </svg>\n </button>\n }\n </div>\n\n <div class=\"studio-color-picker__area\">\n <canvas\n #colorArea\n class=\"studio-color-picker__canvas\"\n width=\"280\"\n height=\"180\"\n (mousedown)=\"onColorAreaMouseDown($event)\"\n ></canvas>\n <div\n class=\"studio-color-picker__cursor\"\n [style.left.%]=\"saturation()\"\n [style.top.%]=\"100 - lightness()\"\n ></div>\n </div>\n\n <div class=\"studio-color-picker__sliders\">\n <div class=\"studio-color-picker__slider\">\n <div class=\"studio-color-picker__slider-label\">Hue</div>\n <input\n type=\"range\"\n class=\"studio-color-picker__hue-slider\"\n min=\"0\"\n max=\"360\"\n [value]=\"hue()\"\n (input)=\"onHueChange($event)\"\n [disabled]=\"disabled() || readonly()\"\n aria-label=\"Hue\"\n />\n </div>\n\n @if (showAlpha()) {\n <div class=\"studio-color-picker__slider\">\n <div class=\"studio-color-picker__slider-label\">Opacity</div>\n <input\n type=\"range\"\n class=\"studio-color-picker__alpha-slider\"\n min=\"0\"\n max=\"100\"\n [value]=\"alpha() * 100\"\n (input)=\"onAlphaChange($event)\"\n [disabled]=\"disabled() || readonly()\"\n aria-label=\"Opacity\"\n />\n <span class=\"studio-color-picker__alpha-value\">{{ (alpha() * 100).toFixed(0) }}%</span>\n </div>\n }\n </div>\n\n @if (showPresets() && effectivePresets().length > 0) {\n <div class=\"studio-color-picker__presets\">\n @for (preset of effectivePresets(); track $index) {\n @if (isPresetGroup(preset)) {\n <div class=\"studio-color-picker__preset-group\">\n <div class=\"studio-color-picker__preset-group-label\">{{ preset.label }}</div>\n <div class=\"studio-color-picker__preset-swatches\">\n @for (color of preset.colors; track color.value) {\n <button\n type=\"button\"\n class=\"studio-color-picker__preset-swatch\"\n [style.background-color]=\"color.value\"\n [title]=\"color.label || color.value\"\n (click)=\"selectPreset(color)\"\n [disabled]=\"disabled() || readonly()\"\n ></button>\n }\n </div>\n </div>\n } @else {\n <button\n type=\"button\"\n class=\"studio-color-picker__preset-swatch\"\n [style.background-color]=\"preset.value\"\n [title]=\"preset.label || preset.value\"\n (click)=\"selectPreset(preset)\"\n [disabled]=\"disabled() || readonly()\"\n ></button>\n }\n }\n </div>\n }\n</div>\n\n@if (hint() && !error()) {\n <span class=\"studio-color-picker__hint\">\n {{ hint() }}\n </span>\n}\n\n@if (error() && errorMessage()) {\n <span class=\"studio-color-picker__error\" role=\"alert\">\n {{ errorMessage() }}\n </span>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:.5rem;font-family:var(--studio-font-family)}.studio-color-picker__label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary)}.studio-color-picker__label .studio-color-picker__required{color:var(--studio-error);margin-left:.125rem}.studio-color-picker__picker{display:flex;flex-direction:column;gap:1rem;padding:1rem;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md)}.studio-color-picker__preview{display:flex;align-items:center;gap:.75rem}.studio-color-picker__preview-color{width:3rem;height:3rem;border-radius:var(--studio-radius-sm);border:1px solid var(--studio-border-primary);flex-shrink:0}.studio-color-picker__preview-info{flex:1;display:flex;align-items:center;gap:.5rem}.studio-color-picker__preview-value{font-family:var(--studio-font-mono, monospace);font-size:.875rem;color:var(--studio-text-primary)}.studio-color-picker__format-btn{padding:.25rem .5rem;background:var(--studio-bg-secondary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-sm);font-size:.75rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast)}.studio-color-picker__format-btn:hover:not(:disabled){background:var(--studio-bg-tertiary);color:var(--studio-text-primary)}.studio-color-picker__format-btn:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__copy-btn{padding:.5rem;background:none;border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--studio-transition-fast)}.studio-color-picker__copy-btn:hover:not(:disabled){background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-color-picker__copy-btn:active:not(:disabled){transform:scale(.95)}.studio-color-picker__copy-btn:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__area{position:relative;width:100%;aspect-ratio:28/18;border-radius:var(--studio-radius-sm);overflow:hidden;border:1px solid var(--studio-border-primary)}.studio-color-picker__canvas{display:block;width:100%;height:100%;cursor:crosshair}.studio-color-picker__cursor{position:absolute;width:16px;height:16px;border:2px solid white;border-radius:50%;transform:translate(-50%,-50%);pointer-events:none;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003}.studio-color-picker__sliders{display:flex;flex-direction:column;gap:.75rem}.studio-color-picker__slider{display:flex;flex-direction:column;gap:.5rem}.studio-color-picker__slider-label{font-size:.75rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-secondary)}.studio-color-picker__hue-slider{-webkit-appearance:none;appearance:none;width:100%;height:12px;border-radius:6px;background:linear-gradient(to right,red,#ff0 17%,#0f0 33%,#0ff,#00f 67%,#f0f 83%,red);outline:none;cursor:pointer}.studio-color-picker__hue-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__hue-slider::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__hue-slider:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__alpha-slider{-webkit-appearance:none;appearance:none;width:100%;height:12px;border-radius:6px;background:linear-gradient(to right,transparent 0%,var(--studio-text-primary) 100%);outline:none;cursor:pointer;position:relative}.studio-color-picker__alpha-slider:before{content:\"\";position:absolute;inset:0;border-radius:6px;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:10px 10px;background-position:0 0,0 5px,5px -5px,-5px 0px;z-index:-1}.studio-color-picker__alpha-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__alpha-slider::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__alpha-slider:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__alpha-value{font-size:.75rem;color:var(--studio-text-secondary);margin-left:auto}.studio-color-picker__presets{display:flex;flex-direction:column;gap:.75rem}.studio-color-picker__preset-group{display:flex;flex-direction:column;gap:.5rem}.studio-color-picker__preset-group-label{font-size:.75rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-secondary)}.studio-color-picker__preset-swatches{display:flex;flex-wrap:wrap;gap:.375rem}.studio-color-picker__preset-swatch{width:2rem;height:2rem;border-radius:var(--studio-radius-sm);border:1px solid var(--studio-border-primary);cursor:pointer;transition:all var(--studio-transition-fast);padding:0}.studio-color-picker__preset-swatch:hover:not(:disabled){transform:scale(1.1);box-shadow:0 2px 8px #00000026}.studio-color-picker__preset-swatch:active:not(:disabled){transform:scale(1.05)}.studio-color-picker__preset-swatch:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-color-picker__error{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:var(--studio-error);line-height:1.4}:host(.studio-color-picker--disabled) .studio-color-picker__picker{opacity:.6;pointer-events:none}:host(.studio-color-picker--error) .studio-color-picker__picker{border-color:var(--studio-error)}:host(.studio-color-picker--sm) .studio-color-picker__preview-color{width:2.5rem;height:2.5rem}:host(.studio-color-picker--sm) .studio-color-picker__picker{padding:.75rem}:host(.studio-color-picker--lg) .studio-color-picker__preview-color{width:3.5rem;height:3.5rem}:host(.studio-color-picker--lg) .studio-color-picker__picker{padding:1.25rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1663
+ }
1664
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ColorPickerComponent, decorators: [{
1665
+ type: Component,
1666
+ args: [{ selector: 'studio-color-picker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
1667
+ {
1668
+ provide: NG_VALUE_ACCESSOR,
1669
+ useExisting: forwardRef(() => ColorPickerComponent),
1670
+ multi: true
1671
+ }
1672
+ ], host: {
1673
+ '[class]': 'hostClasses()',
1674
+ }, template: "@if (label()) {\n <label [for]=\"generatedId\" class=\"studio-color-picker__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-color-picker__required\">*</span>\n }\n </label>\n}\n\n<div class=\"studio-color-picker__picker\">\n <div class=\"studio-color-picker__preview\">\n <div\n class=\"studio-color-picker__preview-color\"\n [style.background-color]=\"displayColor()\"\n ></div>\n <div class=\"studio-color-picker__preview-info\">\n <span class=\"studio-color-picker__preview-value\">{{ displayColor() }}</span>\n @if (showFormatToggle()) {\n <button\n type=\"button\"\n class=\"studio-color-picker__format-btn\"\n (click)=\"toggleFormat()\"\n [disabled]=\"disabled() || readonly()\"\n >\n {{ currentFormat().toUpperCase() }}\n </button>\n }\n </div>\n @if (showCopyButton()) {\n <button\n type=\"button\"\n class=\"studio-color-picker__copy-btn\"\n (click)=\"copyColor()\"\n [disabled]=\"disabled() || readonly()\"\n aria-label=\"Copy color\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect>\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path>\n </svg>\n </button>\n }\n </div>\n\n <div class=\"studio-color-picker__area\">\n <canvas\n #colorArea\n class=\"studio-color-picker__canvas\"\n width=\"280\"\n height=\"180\"\n (mousedown)=\"onColorAreaMouseDown($event)\"\n ></canvas>\n <div\n class=\"studio-color-picker__cursor\"\n [style.left.%]=\"saturation()\"\n [style.top.%]=\"100 - lightness()\"\n ></div>\n </div>\n\n <div class=\"studio-color-picker__sliders\">\n <div class=\"studio-color-picker__slider\">\n <div class=\"studio-color-picker__slider-label\">Hue</div>\n <input\n type=\"range\"\n class=\"studio-color-picker__hue-slider\"\n min=\"0\"\n max=\"360\"\n [value]=\"hue()\"\n (input)=\"onHueChange($event)\"\n [disabled]=\"disabled() || readonly()\"\n aria-label=\"Hue\"\n />\n </div>\n\n @if (showAlpha()) {\n <div class=\"studio-color-picker__slider\">\n <div class=\"studio-color-picker__slider-label\">Opacity</div>\n <input\n type=\"range\"\n class=\"studio-color-picker__alpha-slider\"\n min=\"0\"\n max=\"100\"\n [value]=\"alpha() * 100\"\n (input)=\"onAlphaChange($event)\"\n [disabled]=\"disabled() || readonly()\"\n aria-label=\"Opacity\"\n />\n <span class=\"studio-color-picker__alpha-value\">{{ (alpha() * 100).toFixed(0) }}%</span>\n </div>\n }\n </div>\n\n @if (showPresets() && effectivePresets().length > 0) {\n <div class=\"studio-color-picker__presets\">\n @for (preset of effectivePresets(); track $index) {\n @if (isPresetGroup(preset)) {\n <div class=\"studio-color-picker__preset-group\">\n <div class=\"studio-color-picker__preset-group-label\">{{ preset.label }}</div>\n <div class=\"studio-color-picker__preset-swatches\">\n @for (color of preset.colors; track color.value) {\n <button\n type=\"button\"\n class=\"studio-color-picker__preset-swatch\"\n [style.background-color]=\"color.value\"\n [title]=\"color.label || color.value\"\n (click)=\"selectPreset(color)\"\n [disabled]=\"disabled() || readonly()\"\n ></button>\n }\n </div>\n </div>\n } @else {\n <button\n type=\"button\"\n class=\"studio-color-picker__preset-swatch\"\n [style.background-color]=\"preset.value\"\n [title]=\"preset.label || preset.value\"\n (click)=\"selectPreset(preset)\"\n [disabled]=\"disabled() || readonly()\"\n ></button>\n }\n }\n </div>\n }\n</div>\n\n@if (hint() && !error()) {\n <span class=\"studio-color-picker__hint\">\n {{ hint() }}\n </span>\n}\n\n@if (error() && errorMessage()) {\n <span class=\"studio-color-picker__error\" role=\"alert\">\n {{ errorMessage() }}\n </span>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:.5rem;font-family:var(--studio-font-family)}.studio-color-picker__label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary)}.studio-color-picker__label .studio-color-picker__required{color:var(--studio-error);margin-left:.125rem}.studio-color-picker__picker{display:flex;flex-direction:column;gap:1rem;padding:1rem;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md)}.studio-color-picker__preview{display:flex;align-items:center;gap:.75rem}.studio-color-picker__preview-color{width:3rem;height:3rem;border-radius:var(--studio-radius-sm);border:1px solid var(--studio-border-primary);flex-shrink:0}.studio-color-picker__preview-info{flex:1;display:flex;align-items:center;gap:.5rem}.studio-color-picker__preview-value{font-family:var(--studio-font-mono, monospace);font-size:.875rem;color:var(--studio-text-primary)}.studio-color-picker__format-btn{padding:.25rem .5rem;background:var(--studio-bg-secondary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-sm);font-size:.75rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast)}.studio-color-picker__format-btn:hover:not(:disabled){background:var(--studio-bg-tertiary);color:var(--studio-text-primary)}.studio-color-picker__format-btn:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__copy-btn{padding:.5rem;background:none;border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--studio-transition-fast)}.studio-color-picker__copy-btn:hover:not(:disabled){background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-color-picker__copy-btn:active:not(:disabled){transform:scale(.95)}.studio-color-picker__copy-btn:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__area{position:relative;width:100%;aspect-ratio:28/18;border-radius:var(--studio-radius-sm);overflow:hidden;border:1px solid var(--studio-border-primary)}.studio-color-picker__canvas{display:block;width:100%;height:100%;cursor:crosshair}.studio-color-picker__cursor{position:absolute;width:16px;height:16px;border:2px solid white;border-radius:50%;transform:translate(-50%,-50%);pointer-events:none;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003}.studio-color-picker__sliders{display:flex;flex-direction:column;gap:.75rem}.studio-color-picker__slider{display:flex;flex-direction:column;gap:.5rem}.studio-color-picker__slider-label{font-size:.75rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-secondary)}.studio-color-picker__hue-slider{-webkit-appearance:none;appearance:none;width:100%;height:12px;border-radius:6px;background:linear-gradient(to right,red,#ff0 17%,#0f0 33%,#0ff,#00f 67%,#f0f 83%,red);outline:none;cursor:pointer}.studio-color-picker__hue-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__hue-slider::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__hue-slider:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__alpha-slider{-webkit-appearance:none;appearance:none;width:100%;height:12px;border-radius:6px;background:linear-gradient(to right,transparent 0%,var(--studio-text-primary) 100%);outline:none;cursor:pointer;position:relative}.studio-color-picker__alpha-slider:before{content:\"\";position:absolute;inset:0;border-radius:6px;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:10px 10px;background-position:0 0,0 5px,5px -5px,-5px 0px;z-index:-1}.studio-color-picker__alpha-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__alpha-slider::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__alpha-slider:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__alpha-value{font-size:.75rem;color:var(--studio-text-secondary);margin-left:auto}.studio-color-picker__presets{display:flex;flex-direction:column;gap:.75rem}.studio-color-picker__preset-group{display:flex;flex-direction:column;gap:.5rem}.studio-color-picker__preset-group-label{font-size:.75rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-secondary)}.studio-color-picker__preset-swatches{display:flex;flex-wrap:wrap;gap:.375rem}.studio-color-picker__preset-swatch{width:2rem;height:2rem;border-radius:var(--studio-radius-sm);border:1px solid var(--studio-border-primary);cursor:pointer;transition:all var(--studio-transition-fast);padding:0}.studio-color-picker__preset-swatch:hover:not(:disabled){transform:scale(1.1);box-shadow:0 2px 8px #00000026}.studio-color-picker__preset-swatch:active:not(:disabled){transform:scale(1.05)}.studio-color-picker__preset-swatch:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-color-picker__error{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:var(--studio-error);line-height:1.4}:host(.studio-color-picker--disabled) .studio-color-picker__picker{opacity:.6;pointer-events:none}:host(.studio-color-picker--error) .studio-color-picker__picker{border-color:var(--studio-error)}:host(.studio-color-picker--sm) .studio-color-picker__preview-color{width:2.5rem;height:2.5rem}:host(.studio-color-picker--sm) .studio-color-picker__picker{padding:.75rem}:host(.studio-color-picker--lg) .studio-color-picker__preview-color{width:3.5rem;height:3.5rem}:host(.studio-color-picker--lg) .studio-color-picker__picker{padding:1.25rem}\n"] }]
1675
+ }], ctorParameters: () => [], propDecorators: { colorAreaCanvas: [{ type: i0.ViewChild, args: ['colorArea', { isSignal: true }] }], variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], showAlpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlpha", required: false }] }], showPresets: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPresets", required: false }] }], showFormatToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFormatToggle", required: false }] }], showCopyButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCopyButton", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], colorChange: [{ type: i0.Output, args: ["colorChange"] }], colorValueChange: [{ type: i0.Output, args: ["colorValueChange"] }], copied: [{ type: i0.Output, args: ["copied"] }] } });
1676
+
1677
+ class PopoverComponent {
1678
+ document = inject(DOCUMENT$1);
1679
+ destroyRef = inject(DestroyRef);
1680
+ injector = inject(Injector);
1681
+ configService = inject(StudioConfigService);
1682
+ popoverDefaults = computed(() => this.configService.config().components?.popover, ...(ngDevMode ? [{ debugName: "popoverDefaults" }] : []));
1683
+ headerTemplate = contentChild('popoverHeader', ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
1684
+ footerTemplate = contentChild('popoverFooter', ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
1685
+ contentTemplate = contentChild('popoverContent', ...(ngDevMode ? [{ debugName: "contentTemplate" }] : []));
1686
+ triggerEl = viewChild('popoverTrigger', ...(ngDevMode ? [{ debugName: "triggerEl" }] : []));
1687
+ panelEl = viewChild('popoverPanel', ...(ngDevMode ? [{ debugName: "panelEl" }] : []));
1688
+ arrowEl = viewChild('popoverArrow', ...(ngDevMode ? [{ debugName: "arrowEl" }] : []));
1689
+ id = input('studio-popover-' + Math.random().toString(36).substring(2, 11), ...(ngDevMode ? [{ debugName: "id" }] : []));
1690
+ visible = model(false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
1691
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1692
+ triggerInput = input(undefined, ...(ngDevMode ? [{ debugName: "triggerInput", alias: 'trigger' }] : [{ alias: 'trigger' }]));
1693
+ openDelay = input(0, ...(ngDevMode ? [{ debugName: "openDelay" }] : []));
1694
+ closeDelay = input(200, ...(ngDevMode ? [{ debugName: "closeDelay" }] : []));
1695
+ trigger = withConfigDefault(this.triggerInput, computed(() => this.popoverDefaults()?.trigger), 'click');
1696
+ positionInput = input(undefined, ...(ngDevMode ? [{ debugName: "positionInput", alias: 'position' }] : [{ alias: 'position' }]));
1697
+ offset = input(8, ...(ngDevMode ? [{ debugName: "offset" }] : []));
1698
+ preventOverflow = input(true, ...(ngDevMode ? [{ debugName: "preventOverflow" }] : []));
1699
+ flipValue = input(true, ...(ngDevMode ? [{ debugName: "flipValue" }] : []));
1700
+ position = withConfigDefault(this.positionInput, computed(() => this.popoverDefaults()?.position), 'bottom');
1701
+ variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
1702
+ sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
1703
+ width = input('auto', ...(ngDevMode ? [{ debugName: "width" }] : []));
1704
+ minWidth = input(undefined, ...(ngDevMode ? [{ debugName: "minWidth" }] : []));
1705
+ maxWidth = input(undefined, ...(ngDevMode ? [{ debugName: "maxWidth" }] : []));
1706
+ maxHeight = input(undefined, ...(ngDevMode ? [{ debugName: "maxHeight" }] : []));
1707
+ padding = input(undefined, ...(ngDevMode ? [{ debugName: "padding" }] : []));
1708
+ variant = withConfigDefault(this.variantInput, computed(() => this.popoverDefaults()?.variant), 'default');
1709
+ size = withConfigDefault(this.sizeInput, computed(() => this.popoverDefaults()?.size), 'md');
1710
+ arrow = input(true, ...(ngDevMode ? [{ debugName: "arrow" }] : []));
1711
+ arrowSize = input(8, ...(ngDevMode ? [{ debugName: "arrowSize" }] : []));
1712
+ closeOnClickOutside = input(true, ...(ngDevMode ? [{ debugName: "closeOnClickOutside" }] : []));
1713
+ closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : []));
1714
+ closeOnScroll = input(false, ...(ngDevMode ? [{ debugName: "closeOnScroll" }] : []));
1715
+ showOverlay = input(false, ...(ngDevMode ? [{ debugName: "showOverlay" }] : []));
1716
+ overlayOpacity = input(0.5, ...(ngDevMode ? [{ debugName: "overlayOpacity" }] : []));
1717
+ animationInput = input(undefined, ...(ngDevMode ? [{ debugName: "animationInput", alias: 'animation' }] : [{ alias: 'animation' }]));
1718
+ animationDuration = input(200, ...(ngDevMode ? [{ debugName: "animationDuration" }] : []));
1719
+ animation = withConfigDefault(this.animationInput, computed(() => this.popoverDefaults()?.animation), 'fade');
1720
+ showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
1721
+ showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
1722
+ showCloseButton = input(false, ...(ngDevMode ? [{ debugName: "showCloseButton" }] : []));
1723
+ content = input(undefined, ...(ngDevMode ? [{ debugName: "content" }] : []));
1724
+ zIndex = input(1000, ...(ngDevMode ? [{ debugName: "zIndex" }] : []));
1725
+ ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
1726
+ role = input('dialog', ...(ngDevMode ? [{ debugName: "role" }] : []));
1727
+ visibleChange = output();
1728
+ opened = output();
1729
+ closed = output();
1730
+ positionChanged = output();
1731
+ cleanup;
1732
+ openTimeout;
1733
+ closeTimeout;
1734
+ isHovered = signal(false, ...(ngDevMode ? [{ debugName: "isHovered" }] : []));
1735
+ isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : []));
1736
+ hostClasses = computed(() => classNames('studio-popover', 'studio-popover--' + this.variant(), 'studio-popover--' + this.size(), 'studio-popover--' + this.animation(), this.visible() && 'studio-popover--visible', this.showOverlay() && 'studio-popover--with-overlay'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1737
+ constructor() {
1738
+ effect(() => {
1739
+ if (this.visible()) {
1740
+ this.handleOpen();
1741
+ }
1742
+ else {
1743
+ this.handleClose();
1744
+ }
1745
+ });
1746
+ afterNextRender(() => {
1747
+ this.setupPositioning();
1748
+ }, { injector: this.injector });
1749
+ this.destroyRef.onDestroy(() => {
1750
+ this.cleanup?.();
1751
+ this.clearTimeouts();
1752
+ });
1753
+ }
1754
+ setupPositioning() {
1755
+ const triggerElement = this.triggerEl()?.nativeElement;
1756
+ const panelElement = this.panelEl()?.nativeElement;
1757
+ if (!triggerElement || !panelElement)
1758
+ return;
1759
+ this.cleanup?.();
1760
+ this.cleanup = autoUpdate(triggerElement, panelElement, () => {
1761
+ this.updatePosition();
1762
+ });
1763
+ }
1764
+ async updatePosition() {
1765
+ const triggerElement = this.triggerEl()?.nativeElement;
1766
+ const panelElement = this.panelEl()?.nativeElement;
1767
+ const arrowElement = this.arrowEl()?.nativeElement;
1768
+ if (!triggerElement || !panelElement || !this.visible())
1769
+ return;
1770
+ const middleware = [
1771
+ offset(this.offset()),
1772
+ this.flipValue() && flip(),
1773
+ this.preventOverflow() && shift({ padding: 8 }),
1774
+ arrowElement && this.arrow() && arrow({ element: arrowElement })
1775
+ ].filter(Boolean);
1776
+ const { x, y, placement, middlewareData } = await computePosition(triggerElement, panelElement, {
1777
+ placement: this.position(),
1778
+ middleware
1779
+ });
1780
+ Object.assign(panelElement.style, {
1781
+ left: x + 'px',
1782
+ top: y + 'px',
1783
+ });
1784
+ if (arrowElement && middlewareData.arrow && this.arrow()) {
1785
+ const { x: arrowX, y: arrowY } = middlewareData.arrow;
1786
+ const staticSide = {
1787
+ top: 'bottom',
1788
+ right: 'left',
1789
+ bottom: 'top',
1790
+ left: 'right',
1791
+ }[placement.split('-')[0]];
1792
+ Object.assign(arrowElement.style, {
1793
+ left: arrowX != null ? arrowX + 'px' : '',
1794
+ top: arrowY != null ? arrowY + 'px' : '',
1795
+ right: '',
1796
+ bottom: '',
1797
+ [staticSide]: '-' + (this.arrowSize() / 2) + 'px',
1798
+ });
1799
+ }
1800
+ this.positionChanged.emit(placement);
1801
+ }
1802
+ handleOpen() {
1803
+ if (this.closeOnScroll()) {
1804
+ this.document.addEventListener('scroll', this.handleScrollBind, true);
1805
+ }
1806
+ this.opened.emit();
1807
+ setTimeout(() => this.updatePosition(), 0);
1808
+ }
1809
+ handleClose() {
1810
+ if (this.closeOnScroll()) {
1811
+ this.document.removeEventListener('scroll', this.handleScrollBind, true);
1812
+ }
1813
+ this.closed.emit();
1814
+ }
1815
+ handleScrollBind = this.handleScroll.bind(this);
1816
+ handleScroll() {
1817
+ if (this.visible()) {
1818
+ this.close();
1819
+ }
1820
+ }
1821
+ open() {
1822
+ if (this.disabled())
1823
+ return;
1824
+ this.visible.set(true);
1825
+ this.visibleChange.emit(true);
1826
+ }
1827
+ close() {
1828
+ this.visible.set(false);
1829
+ this.visibleChange.emit(false);
1830
+ }
1831
+ toggle() {
1832
+ if (this.visible()) {
1833
+ this.close();
1834
+ }
1835
+ else {
1836
+ this.open();
1837
+ }
1838
+ }
1839
+ handleTriggerClick() {
1840
+ if (this.trigger() === 'click' || this.trigger() === 'manual') {
1841
+ this.toggle();
1842
+ }
1843
+ }
1844
+ handleTriggerMouseEnter() {
1845
+ if (this.trigger() === 'hover') {
1846
+ this.clearTimeouts();
1847
+ this.isHovered.set(true);
1848
+ this.openTimeout = window.setTimeout(() => {
1849
+ this.open();
1850
+ }, this.openDelay());
1851
+ }
1852
+ }
1853
+ handleTriggerMouseLeave() {
1854
+ if (this.trigger() === 'hover') {
1855
+ this.clearTimeouts();
1856
+ this.isHovered.set(false);
1857
+ this.closeTimeout = window.setTimeout(() => {
1858
+ if (!this.isHovered()) {
1859
+ this.close();
1860
+ }
1861
+ }, this.closeDelay());
1862
+ }
1863
+ }
1864
+ handlePanelMouseEnter() {
1865
+ if (this.trigger() === 'hover') {
1866
+ this.clearTimeouts();
1867
+ this.isHovered.set(true);
1868
+ }
1869
+ }
1870
+ handlePanelMouseLeave() {
1871
+ if (this.trigger() === 'hover') {
1872
+ this.isHovered.set(false);
1873
+ this.closeTimeout = window.setTimeout(() => {
1874
+ if (!this.isHovered()) {
1875
+ this.close();
1876
+ }
1877
+ }, this.closeDelay());
1878
+ }
1879
+ }
1880
+ handleTriggerFocus() {
1881
+ if (this.trigger() === 'focus') {
1882
+ this.isFocused.set(true);
1883
+ this.open();
1884
+ }
1885
+ }
1886
+ handleTriggerBlur() {
1887
+ if (this.trigger() === 'focus') {
1888
+ this.isFocused.set(false);
1889
+ setTimeout(() => {
1890
+ if (!this.isFocused()) {
1891
+ this.close();
1892
+ }
1893
+ }, 100);
1894
+ }
1895
+ }
1896
+ handleBackdropClick() {
1897
+ if (this.closeOnClickOutside()) {
1898
+ this.close();
1899
+ }
1900
+ }
1901
+ handleDocumentClick(event) {
1902
+ if (!this.visible() || !this.closeOnClickOutside())
1903
+ return;
1904
+ const target = event.target;
1905
+ const panel = this.panelEl()?.nativeElement;
1906
+ const trigger = this.triggerEl()?.nativeElement;
1907
+ if (panel && !panel.contains(target) && trigger && !trigger.contains(target)) {
1908
+ this.close();
1909
+ }
1910
+ }
1911
+ handleEscapeKey(event) {
1912
+ if (this.visible() && this.closeOnEscape()) {
1913
+ event.preventDefault();
1914
+ this.close();
1915
+ }
1916
+ }
1917
+ clearTimeouts() {
1918
+ if (this.openTimeout) {
1919
+ window.clearTimeout(this.openTimeout);
1920
+ this.openTimeout = undefined;
1921
+ }
1922
+ if (this.closeTimeout) {
1923
+ window.clearTimeout(this.closeTimeout);
1924
+ this.closeTimeout = undefined;
1925
+ }
1926
+ }
1927
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1928
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: PopoverComponent, isStandalone: true, selector: "studio-popover", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, triggerInput: { classPropertyName: "triggerInput", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, positionInput: { classPropertyName: "positionInput", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, preventOverflow: { classPropertyName: "preventOverflow", publicName: "preventOverflow", isSignal: true, isRequired: false, transformFunction: null }, flipValue: { classPropertyName: "flipValue", publicName: "flipValue", isSignal: true, isRequired: false, transformFunction: null }, variantInput: { classPropertyName: "variantInput", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, sizeInput: { classPropertyName: "sizeInput", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, arrow: { classPropertyName: "arrow", publicName: "arrow", isSignal: true, isRequired: false, transformFunction: null }, arrowSize: { classPropertyName: "arrowSize", publicName: "arrowSize", isSignal: true, isRequired: false, transformFunction: null }, closeOnClickOutside: { classPropertyName: "closeOnClickOutside", publicName: "closeOnClickOutside", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeOnScroll: { classPropertyName: "closeOnScroll", publicName: "closeOnScroll", isSignal: true, isRequired: false, transformFunction: null }, showOverlay: { classPropertyName: "showOverlay", publicName: "showOverlay", isSignal: true, isRequired: false, transformFunction: null }, overlayOpacity: { classPropertyName: "overlayOpacity", publicName: "overlayOpacity", isSignal: true, isRequired: false, transformFunction: null }, animationInput: { classPropertyName: "animationInput", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange", visibleChange: "visibleChange", opened: "opened", closed: "closed", positionChanged: "positionChanged" }, host: { listeners: { "document:click": "handleDocumentClick($event)", "document:keydown.escape": "handleEscapeKey($event)" }, properties: { "class": "hostClasses()", "attr.data-visible": "visible()" } }, queries: [{ propertyName: "headerTemplate", first: true, predicate: ["popoverHeader"], descendants: true, isSignal: true }, { propertyName: "footerTemplate", first: true, predicate: ["popoverFooter"], descendants: true, isSignal: true }, { propertyName: "contentTemplate", first: true, predicate: ["popoverContent"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["popoverTrigger"], descendants: true, isSignal: true }, { propertyName: "panelEl", first: true, predicate: ["popoverPanel"], descendants: true, isSignal: true }, { propertyName: "arrowEl", first: true, predicate: ["popoverArrow"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (showOverlay() && visible()) {\n <div\n class=\"studio-popover__overlay\"\n [style.opacity]=\"overlayOpacity()\"\n [style.z-index]=\"zIndex()\"\n (click)=\"handleBackdropClick()\"\n ></div>\n}\n\n<div\n #popoverTrigger\n class=\"studio-popover__trigger\"\n (click)=\"handleTriggerClick()\"\n (mouseenter)=\"handleTriggerMouseEnter()\"\n (mouseleave)=\"handleTriggerMouseLeave()\"\n (focus)=\"handleTriggerFocus()\"\n (blur)=\"handleTriggerBlur()\"\n>\n <ng-content />\n</div>\n\n@if (visible()) {\n <div\n #popoverPanel\n class=\"studio-popover__panel\"\n [style.z-index]=\"zIndex() + 1\"\n [style.width]=\"width() === 'auto' ? 'auto' : width() === 'trigger' && triggerEl()?.nativeElement ? triggerEl()!.nativeElement.offsetWidth + 'px' : width()\"\n [style.min-width]=\"minWidth() ? (typeof minWidth() === 'number' ? minWidth() + 'px' : minWidth()) : undefined\"\n [style.max-width]=\"maxWidth() ? (typeof maxWidth() === 'number' ? maxWidth() + 'px' : maxWidth()) : undefined\"\n [style.max-height]=\"maxHeight() ? (typeof maxHeight() === 'number' ? maxHeight() + 'px' : maxHeight()) : undefined\"\n [style.padding]=\"padding()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"ariaLabel()\"\n (mouseenter)=\"handlePanelMouseEnter()\"\n (mouseleave)=\"handlePanelMouseLeave()\"\n >\n @if (arrow()) {\n <div #popoverArrow class=\"studio-popover__arrow\" [style.width.px]=\"arrowSize()\" [style.height.px]=\"arrowSize()\"></div>\n }\n\n @if (showHeader() && (headerTemplate() || showCloseButton())) {\n <div class=\"studio-popover__header\">\n @if (headerTemplate()) {\n <ng-container *ngTemplateOutlet=\"headerTemplate()!\" />\n }\n \n @if (showCloseButton()) {\n <button\n type=\"button\"\n class=\"studio-popover__close\"\n (click)=\"close()\"\n aria-label=\"Close\"\n >\n <studio-icon name=\"x\" [size]=\"18\" />\n </button>\n }\n </div>\n }\n\n <div class=\"studio-popover__content\">\n @if (contentTemplate()) {\n <ng-container *ngTemplateOutlet=\"contentTemplate()!\" />\n } @else if (content()) {\n {{ content() }}\n } @else {\n <ng-content select=\"[popoverContent]\" />\n }\n </div>\n\n @if (showFooter() && footerTemplate()) {\n <div class=\"studio-popover__footer\">\n <ng-container *ngTemplateOutlet=\"footerTemplate()!\" />\n </div>\n }\n </div>\n}\n", styles: [":host{display:inline-block;font-family:var(--studio-font-family)}.studio-popover__trigger{display:inline-flex;cursor:pointer}.studio-popover__overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);opacity:0;transition:opacity var(--studio-transition-base)}:host(.studio-popover--visible) .studio-popover__overlay{opacity:var(--popover-overlay-opacity, .5)}.studio-popover__panel{position:absolute;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);box-shadow:var(--studio-shadow-lg);opacity:0;visibility:hidden;transition:opacity var(--popover-animation-duration, .2s) ease-out,transform var(--popover-animation-duration, .2s) ease-out,visibility 0ms var(--popover-animation-duration, .2s);will-change:transform,opacity}:host(.studio-popover--visible) .studio-popover__panel{opacity:1;visibility:visible;transition:opacity var(--popover-animation-duration, .2s) ease-out,transform var(--popover-animation-duration, .2s) ease-out,visibility 0ms}:host(.studio-popover--fade) .studio-popover__panel{transform:scale(.95)}:host(.studio-popover--fade.studio-popover--visible) .studio-popover__panel{transform:scale(1)}:host(.studio-popover--scale) .studio-popover__panel{transform:scale(.8)}:host(.studio-popover--scale.studio-popover--visible) .studio-popover__panel{transform:scale(1)}:host(.studio-popover--slide) .studio-popover__panel{transform:translateY(-8px)}:host(.studio-popover--slide.studio-popover--visible) .studio-popover__panel{transform:translateY(0)}:host(.studio-popover--none) .studio-popover__panel{transition:none}:host(.studio-popover--bordered) .studio-popover__panel{border:2px solid var(--studio-border-secondary);box-shadow:none}:host(.studio-popover--shadow) .studio-popover__panel{border:none;box-shadow:var(--studio-shadow-xl)}:host(.studio-popover--minimal) .studio-popover__panel{border:none;box-shadow:var(--studio-shadow-sm)}:host(.studio-popover--sm) .studio-popover__panel{font-size:var(--studio-font-size-sm)}:host(.studio-popover--md) .studio-popover__panel{font-size:var(--studio-font-size-base)}:host(.studio-popover--lg) .studio-popover__panel{font-size:var(--studio-font-size-lg)}.studio-popover__arrow{position:absolute;background:var(--studio-bg-primary);transform:rotate(45deg);border:1px solid var(--studio-border-primary);border-right:none;border-bottom:none;z-index:-1}:host(.studio-popover--bordered) .studio-popover__arrow{border-color:var(--studio-border-secondary);border-width:2px}:host(.studio-popover--shadow) .studio-popover__arrow,:host(.studio-popover--minimal) .studio-popover__arrow{border:none}.studio-popover__header{display:flex;align-items:center;justify-content:space-between;gap:var(--studio-spacing-md);padding:var(--studio-spacing-md) var(--studio-spacing-md) var(--studio-spacing-sm);border-bottom:1px solid var(--studio-border-primary)}.studio-popover__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast);flex-shrink:0}.studio-popover__close:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-popover__close:active{transform:scale(.95)}.studio-popover__content{padding:var(--studio-spacing-md);color:var(--studio-text-primary)}.studio-popover__header+.studio-popover__content{padding-top:var(--studio-spacing-md)}.studio-popover__footer{padding:var(--studio-spacing-sm) var(--studio-spacing-md) var(--studio-spacing-md);border-top:1px solid var(--studio-border-primary);display:flex;align-items:center;gap:var(--studio-spacing-sm)}:host(.studio-popover--sm) .studio-popover__content{padding:var(--studio-spacing-sm)}:host(.studio-popover--lg) .studio-popover__content{padding:var(--studio-spacing-lg)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1929
+ }
1930
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: PopoverComponent, decorators: [{
1931
+ type: Component,
1932
+ args: [{ selector: 'studio-popover', standalone: true, imports: [NgTemplateOutlet, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1933
+ '[class]': 'hostClasses()',
1934
+ '[attr.data-visible]': 'visible()',
1935
+ }, template: "@if (showOverlay() && visible()) {\n <div\n class=\"studio-popover__overlay\"\n [style.opacity]=\"overlayOpacity()\"\n [style.z-index]=\"zIndex()\"\n (click)=\"handleBackdropClick()\"\n ></div>\n}\n\n<div\n #popoverTrigger\n class=\"studio-popover__trigger\"\n (click)=\"handleTriggerClick()\"\n (mouseenter)=\"handleTriggerMouseEnter()\"\n (mouseleave)=\"handleTriggerMouseLeave()\"\n (focus)=\"handleTriggerFocus()\"\n (blur)=\"handleTriggerBlur()\"\n>\n <ng-content />\n</div>\n\n@if (visible()) {\n <div\n #popoverPanel\n class=\"studio-popover__panel\"\n [style.z-index]=\"zIndex() + 1\"\n [style.width]=\"width() === 'auto' ? 'auto' : width() === 'trigger' && triggerEl()?.nativeElement ? triggerEl()!.nativeElement.offsetWidth + 'px' : width()\"\n [style.min-width]=\"minWidth() ? (typeof minWidth() === 'number' ? minWidth() + 'px' : minWidth()) : undefined\"\n [style.max-width]=\"maxWidth() ? (typeof maxWidth() === 'number' ? maxWidth() + 'px' : maxWidth()) : undefined\"\n [style.max-height]=\"maxHeight() ? (typeof maxHeight() === 'number' ? maxHeight() + 'px' : maxHeight()) : undefined\"\n [style.padding]=\"padding()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"ariaLabel()\"\n (mouseenter)=\"handlePanelMouseEnter()\"\n (mouseleave)=\"handlePanelMouseLeave()\"\n >\n @if (arrow()) {\n <div #popoverArrow class=\"studio-popover__arrow\" [style.width.px]=\"arrowSize()\" [style.height.px]=\"arrowSize()\"></div>\n }\n\n @if (showHeader() && (headerTemplate() || showCloseButton())) {\n <div class=\"studio-popover__header\">\n @if (headerTemplate()) {\n <ng-container *ngTemplateOutlet=\"headerTemplate()!\" />\n }\n \n @if (showCloseButton()) {\n <button\n type=\"button\"\n class=\"studio-popover__close\"\n (click)=\"close()\"\n aria-label=\"Close\"\n >\n <studio-icon name=\"x\" [size]=\"18\" />\n </button>\n }\n </div>\n }\n\n <div class=\"studio-popover__content\">\n @if (contentTemplate()) {\n <ng-container *ngTemplateOutlet=\"contentTemplate()!\" />\n } @else if (content()) {\n {{ content() }}\n } @else {\n <ng-content select=\"[popoverContent]\" />\n }\n </div>\n\n @if (showFooter() && footerTemplate()) {\n <div class=\"studio-popover__footer\">\n <ng-container *ngTemplateOutlet=\"footerTemplate()!\" />\n </div>\n }\n </div>\n}\n", styles: [":host{display:inline-block;font-family:var(--studio-font-family)}.studio-popover__trigger{display:inline-flex;cursor:pointer}.studio-popover__overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);opacity:0;transition:opacity var(--studio-transition-base)}:host(.studio-popover--visible) .studio-popover__overlay{opacity:var(--popover-overlay-opacity, .5)}.studio-popover__panel{position:absolute;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);box-shadow:var(--studio-shadow-lg);opacity:0;visibility:hidden;transition:opacity var(--popover-animation-duration, .2s) ease-out,transform var(--popover-animation-duration, .2s) ease-out,visibility 0ms var(--popover-animation-duration, .2s);will-change:transform,opacity}:host(.studio-popover--visible) .studio-popover__panel{opacity:1;visibility:visible;transition:opacity var(--popover-animation-duration, .2s) ease-out,transform var(--popover-animation-duration, .2s) ease-out,visibility 0ms}:host(.studio-popover--fade) .studio-popover__panel{transform:scale(.95)}:host(.studio-popover--fade.studio-popover--visible) .studio-popover__panel{transform:scale(1)}:host(.studio-popover--scale) .studio-popover__panel{transform:scale(.8)}:host(.studio-popover--scale.studio-popover--visible) .studio-popover__panel{transform:scale(1)}:host(.studio-popover--slide) .studio-popover__panel{transform:translateY(-8px)}:host(.studio-popover--slide.studio-popover--visible) .studio-popover__panel{transform:translateY(0)}:host(.studio-popover--none) .studio-popover__panel{transition:none}:host(.studio-popover--bordered) .studio-popover__panel{border:2px solid var(--studio-border-secondary);box-shadow:none}:host(.studio-popover--shadow) .studio-popover__panel{border:none;box-shadow:var(--studio-shadow-xl)}:host(.studio-popover--minimal) .studio-popover__panel{border:none;box-shadow:var(--studio-shadow-sm)}:host(.studio-popover--sm) .studio-popover__panel{font-size:var(--studio-font-size-sm)}:host(.studio-popover--md) .studio-popover__panel{font-size:var(--studio-font-size-base)}:host(.studio-popover--lg) .studio-popover__panel{font-size:var(--studio-font-size-lg)}.studio-popover__arrow{position:absolute;background:var(--studio-bg-primary);transform:rotate(45deg);border:1px solid var(--studio-border-primary);border-right:none;border-bottom:none;z-index:-1}:host(.studio-popover--bordered) .studio-popover__arrow{border-color:var(--studio-border-secondary);border-width:2px}:host(.studio-popover--shadow) .studio-popover__arrow,:host(.studio-popover--minimal) .studio-popover__arrow{border:none}.studio-popover__header{display:flex;align-items:center;justify-content:space-between;gap:var(--studio-spacing-md);padding:var(--studio-spacing-md) var(--studio-spacing-md) var(--studio-spacing-sm);border-bottom:1px solid var(--studio-border-primary)}.studio-popover__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast);flex-shrink:0}.studio-popover__close:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-popover__close:active{transform:scale(.95)}.studio-popover__content{padding:var(--studio-spacing-md);color:var(--studio-text-primary)}.studio-popover__header+.studio-popover__content{padding-top:var(--studio-spacing-md)}.studio-popover__footer{padding:var(--studio-spacing-sm) var(--studio-spacing-md) var(--studio-spacing-md);border-top:1px solid var(--studio-border-primary);display:flex;align-items:center;gap:var(--studio-spacing-sm)}:host(.studio-popover--sm) .studio-popover__content{padding:var(--studio-spacing-sm)}:host(.studio-popover--lg) .studio-popover__content{padding:var(--studio-spacing-lg)}\n"] }]
1936
+ }], ctorParameters: () => [], propDecorators: { headerTemplate: [{ type: i0.ContentChild, args: ['popoverHeader', { isSignal: true }] }], footerTemplate: [{ type: i0.ContentChild, args: ['popoverFooter', { isSignal: true }] }], contentTemplate: [{ type: i0.ContentChild, args: ['popoverContent', { isSignal: true }] }], triggerEl: [{ type: i0.ViewChild, args: ['popoverTrigger', { isSignal: true }] }], panelEl: [{ type: i0.ViewChild, args: ['popoverPanel', { isSignal: true }] }], arrowEl: [{ type: i0.ViewChild, args: ['popoverArrow', { isSignal: true }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], triggerInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], positionInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], preventOverflow: [{ type: i0.Input, args: [{ isSignal: true, alias: "preventOverflow", required: false }] }], flipValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "flipValue", required: false }] }], variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], arrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrow", required: false }] }], arrowSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowSize", required: false }] }], closeOnClickOutside: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClickOutside", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], closeOnScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnScroll", required: false }] }], showOverlay: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOverlay", required: false }] }], overlayOpacity: [{ type: i0.Input, args: [{ isSignal: true, alias: "overlayOpacity", required: false }] }], animationInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "animation", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], visibleChange: [{ type: i0.Output, args: ["visibleChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], positionChanged: [{ type: i0.Output, args: ["positionChanged"] }], handleDocumentClick: [{
1937
+ type: HostListener,
1938
+ args: ['document:click', ['$event']]
1939
+ }], handleEscapeKey: [{
1940
+ type: HostListener,
1941
+ args: ['document:keydown.escape', ['$event']]
1942
+ }] } });
1943
+
1944
+ class ColorPickerCompactComponent {
1945
+ configService = inject(StudioConfigService);
1946
+ trigger = input('click', ...(ngDevMode ? [{ debugName: "trigger" }] : []));
1947
+ position = input('bottom-start', ...(ngDevMode ? [{ debugName: "position" }] : []));
1948
+ popoverWidth = input('280px', ...(ngDevMode ? [{ debugName: "popoverWidth" }] : []));
1949
+ showArrow = input(false, ...(ngDevMode ? [{ debugName: "showArrow" }] : []));
1950
+ closeOnClickOutside = input(true, ...(ngDevMode ? [{ debugName: "closeOnClickOutside" }] : []));
1951
+ triggerSize = input('32px', ...(ngDevMode ? [{ debugName: "triggerSize" }] : []));
1952
+ triggerRadius = input('var(--studio-radius-sm)', ...(ngDevMode ? [{ debugName: "triggerRadius" }] : []));
1953
+ showCurrentColor = input(false, ...(ngDevMode ? [{ debugName: "showCurrentColor" }] : []));
1954
+ format = input('hex', ...(ngDevMode ? [{ debugName: "format" }] : []));
1955
+ showAlpha = input(false, ...(ngDevMode ? [{ debugName: "showAlpha" }] : []));
1956
+ showPresets = input(true, ...(ngDevMode ? [{ debugName: "showPresets" }] : []));
1957
+ showFormatToggle = input(false, ...(ngDevMode ? [{ debugName: "showFormatToggle" }] : []));
1958
+ showCopyButton = input(false, ...(ngDevMode ? [{ debugName: "showCopyButton" }] : []));
1959
+ presets = input(undefined, ...(ngDevMode ? [{ debugName: "presets" }] : []));
1960
+ showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
1961
+ applyLabel = input('OK', ...(ngDevMode ? [{ debugName: "applyLabel" }] : []));
1962
+ cancelLabel = input('Отмена', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : []));
1963
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1964
+ ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
1965
+ colorChange = output();
1966
+ currentValue = signal('#000000', ...(ngDevMode ? [{ debugName: "currentValue" }] : []));
1967
+ tempValue = signal('#000000', ...(ngDevMode ? [{ debugName: "tempValue" }] : []));
1968
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
1969
+ hostClasses = computed(() => classNames('color-picker-compact', this.disabled() && 'color-picker-compact--disabled'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1970
+ onChange = () => { };
1971
+ onTouched = () => { };
1972
+ constructor() {
1973
+ effect(() => {
1974
+ // Sync temp value when popover opens
1975
+ if (this.isOpen()) {
1976
+ this.tempValue.set(this.currentValue());
1977
+ }
1978
+ });
1979
+ }
1980
+ handleApply() {
1981
+ this.currentValue.set(this.tempValue());
1982
+ this.onChange(this.tempValue());
1983
+ this.colorChange.emit(this.tempValue());
1984
+ this.onTouched();
1985
+ this.isOpen.set(false);
1986
+ }
1987
+ handleCancel() {
1988
+ this.tempValue.set(this.currentValue());
1989
+ this.isOpen.set(false);
1990
+ }
1991
+ writeValue(value) {
1992
+ if (value) {
1993
+ this.currentValue.set(value);
1994
+ this.tempValue.set(value);
1995
+ }
1996
+ }
1997
+ registerOnChange(fn) {
1998
+ this.onChange = fn;
1999
+ }
2000
+ registerOnTouched(fn) {
2001
+ this.onTouched = fn;
2002
+ }
2003
+ setDisabledState(isDisabled) { }
2004
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ColorPickerCompactComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2005
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: ColorPickerCompactComponent, isStandalone: true, selector: "studio-color-picker-compact", inputs: { trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, popoverWidth: { classPropertyName: "popoverWidth", publicName: "popoverWidth", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, closeOnClickOutside: { classPropertyName: "closeOnClickOutside", publicName: "closeOnClickOutside", isSignal: true, isRequired: false, transformFunction: null }, triggerSize: { classPropertyName: "triggerSize", publicName: "triggerSize", isSignal: true, isRequired: false, transformFunction: null }, triggerRadius: { classPropertyName: "triggerRadius", publicName: "triggerRadius", isSignal: true, isRequired: false, transformFunction: null }, showCurrentColor: { classPropertyName: "showCurrentColor", publicName: "showCurrentColor", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, showAlpha: { classPropertyName: "showAlpha", publicName: "showAlpha", isSignal: true, isRequired: false, transformFunction: null }, showPresets: { classPropertyName: "showPresets", publicName: "showPresets", isSignal: true, isRequired: false, transformFunction: null }, showFormatToggle: { classPropertyName: "showFormatToggle", publicName: "showFormatToggle", isSignal: true, isRequired: false, transformFunction: null }, showCopyButton: { classPropertyName: "showCopyButton", publicName: "showCopyButton", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, applyLabel: { classPropertyName: "applyLabel", publicName: "applyLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { colorChange: "colorChange" }, host: { properties: { "class": "hostClasses()" } }, providers: [
2006
+ {
2007
+ provide: NG_VALUE_ACCESSOR,
2008
+ useExisting: forwardRef(() => ColorPickerCompactComponent),
2009
+ multi: true
2010
+ }
2011
+ ], ngImport: i0, template: `
2012
+ <studio-popover
2013
+ [trigger]="trigger()"
2014
+ [position]="position()"
2015
+ [width]="popoverWidth()"
2016
+ [arrow]="showArrow()"
2017
+ [closeOnClickOutside]="false"
2018
+ [(visible)]="isOpen"
2019
+ [showFooter]="showFooter()"
2020
+ >
2021
+ <div
2022
+ class="color-picker-compact__trigger"
2023
+ [class.color-picker-compact__trigger--disabled]="disabled()"
2024
+ [style.width]="triggerSize()"
2025
+ [style.height]="triggerSize()"
2026
+ [style.border-radius]="triggerRadius()"
2027
+ [style.background]="currentValue()"
2028
+ [attr.aria-label]="ariaLabel() || 'Select color'"
2029
+ [attr.role]="'button'"
2030
+ [attr.tabindex]="disabled() ? -1 : 0"
2031
+ >
2032
+ @if (showCurrentColor()) {
2033
+ <span class="color-picker-compact__color-text">{{ currentValue() }}</span>
2034
+ }
2035
+ </div>
2036
+
2037
+ <div popoverContent>
2038
+ <studio-color-picker
2039
+ [(ngModel)]="tempValue"
2040
+ [format]="format()"
2041
+ [showAlpha]="showAlpha()"
2042
+ [showPresets]="showPresets()"
2043
+ [showFormatToggle]="showFormatToggle()"
2044
+ [showCopyButton]="showCopyButton()"
2045
+ [presets]="presets()"
2046
+ [disabled]="disabled()"
2047
+ />
2048
+ </div>
2049
+
2050
+ @if (showFooter()) {
2051
+ <ng-template #popoverFooter>
2052
+ <div class="color-picker-compact__footer">
2053
+ <studio-button
2054
+ variant="outline"
2055
+ size="sm"
2056
+ (click)="handleCancel()"
2057
+ [fullWidth]="true"
2058
+ >
2059
+ {{ cancelLabel() }}
2060
+ </studio-button>
2061
+ <studio-button
2062
+ size="sm"
2063
+ (click)="handleApply()"
2064
+ [fullWidth]="true"
2065
+ >
2066
+ {{ applyLabel() }}
2067
+ </studio-button>
2068
+ </div>
2069
+ </ng-template>
2070
+ }
2071
+ </studio-popover>
2072
+ `, isInline: true, styles: [":host{display:inline-block}.color-picker-compact__trigger{position:relative;cursor:pointer;border:2px solid var(--studio-border-primary);transition:all var(--studio-transition-fast);overflow:hidden;&--disabled{cursor:not-allowed;opacity:.5}}.color-picker-compact__trigger:hover:not(.color-picker-compact__trigger--disabled){border-color:var(--studio-border-secondary);transform:scale(1.05)}.color-picker-compact__trigger:active:not(.color-picker-compact__trigger--disabled){transform:scale(.95)}.color-picker-compact__trigger:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}.color-picker-compact__color-text{position:absolute;bottom:0;left:0;right:0;padding:.125rem .25rem;background:#0009;color:#fff;font-size:.625rem;text-align:center;font-family:var(--studio-font-family-mono, monospace)}.color-picker-compact__footer{display:flex;gap:.75rem;padding:1rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: PopoverComponent, selector: "studio-popover", inputs: ["id", "visible", "disabled", "trigger", "openDelay", "closeDelay", "position", "offset", "preventOverflow", "flipValue", "variant", "size", "width", "minWidth", "maxWidth", "maxHeight", "padding", "arrow", "arrowSize", "closeOnClickOutside", "closeOnEscape", "closeOnScroll", "showOverlay", "overlayOpacity", "animation", "animationDuration", "showHeader", "showFooter", "showCloseButton", "content", "zIndex", "ariaLabel", "role"], outputs: ["visibleChange", "opened", "closed", "positionChanged"] }, { kind: "component", type: ColorPickerComponent, selector: "studio-color-picker", inputs: ["variant", "size", "format", "showAlpha", "showPresets", "showFormatToggle", "showCopyButton", "presets", "label", "hint", "required", "error", "errorMessage", "disabled", "readonly"], outputs: ["colorChange", "colorValueChange", "copied"] }, { kind: "component", type: ButtonComponent, selector: "studio-button", inputs: ["variant", "size", "color", "radius", "shadow", "compact", "disabled", "loading", "loadingText", "fullWidth", "type", "icon", "iconPosition", "href", "target", "badge", "badgeColor", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2073
+ }
2074
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ColorPickerCompactComponent, decorators: [{
2075
+ type: Component,
2076
+ args: [{ selector: 'studio-color-picker-compact', standalone: true, imports: [FormsModule, PopoverComponent, ColorPickerComponent, ButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2077
+ {
2078
+ provide: NG_VALUE_ACCESSOR,
2079
+ useExisting: forwardRef(() => ColorPickerCompactComponent),
2080
+ multi: true
2081
+ }
2082
+ ], host: {
2083
+ '[class]': 'hostClasses()',
2084
+ }, template: `
2085
+ <studio-popover
2086
+ [trigger]="trigger()"
2087
+ [position]="position()"
2088
+ [width]="popoverWidth()"
2089
+ [arrow]="showArrow()"
2090
+ [closeOnClickOutside]="false"
2091
+ [(visible)]="isOpen"
2092
+ [showFooter]="showFooter()"
2093
+ >
2094
+ <div
2095
+ class="color-picker-compact__trigger"
2096
+ [class.color-picker-compact__trigger--disabled]="disabled()"
2097
+ [style.width]="triggerSize()"
2098
+ [style.height]="triggerSize()"
2099
+ [style.border-radius]="triggerRadius()"
2100
+ [style.background]="currentValue()"
2101
+ [attr.aria-label]="ariaLabel() || 'Select color'"
2102
+ [attr.role]="'button'"
2103
+ [attr.tabindex]="disabled() ? -1 : 0"
2104
+ >
2105
+ @if (showCurrentColor()) {
2106
+ <span class="color-picker-compact__color-text">{{ currentValue() }}</span>
2107
+ }
2108
+ </div>
2109
+
2110
+ <div popoverContent>
2111
+ <studio-color-picker
2112
+ [(ngModel)]="tempValue"
2113
+ [format]="format()"
2114
+ [showAlpha]="showAlpha()"
2115
+ [showPresets]="showPresets()"
2116
+ [showFormatToggle]="showFormatToggle()"
2117
+ [showCopyButton]="showCopyButton()"
2118
+ [presets]="presets()"
2119
+ [disabled]="disabled()"
2120
+ />
2121
+ </div>
2122
+
2123
+ @if (showFooter()) {
2124
+ <ng-template #popoverFooter>
2125
+ <div class="color-picker-compact__footer">
2126
+ <studio-button
2127
+ variant="outline"
2128
+ size="sm"
2129
+ (click)="handleCancel()"
2130
+ [fullWidth]="true"
2131
+ >
2132
+ {{ cancelLabel() }}
2133
+ </studio-button>
2134
+ <studio-button
2135
+ size="sm"
2136
+ (click)="handleApply()"
2137
+ [fullWidth]="true"
2138
+ >
2139
+ {{ applyLabel() }}
2140
+ </studio-button>
2141
+ </div>
2142
+ </ng-template>
2143
+ }
2144
+ </studio-popover>
2145
+ `, styles: [":host{display:inline-block}.color-picker-compact__trigger{position:relative;cursor:pointer;border:2px solid var(--studio-border-primary);transition:all var(--studio-transition-fast);overflow:hidden;&--disabled{cursor:not-allowed;opacity:.5}}.color-picker-compact__trigger:hover:not(.color-picker-compact__trigger--disabled){border-color:var(--studio-border-secondary);transform:scale(1.05)}.color-picker-compact__trigger:active:not(.color-picker-compact__trigger--disabled){transform:scale(.95)}.color-picker-compact__trigger:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}.color-picker-compact__color-text{position:absolute;bottom:0;left:0;right:0;padding:.125rem .25rem;background:#0009;color:#fff;font-size:.625rem;text-align:center;font-family:var(--studio-font-family-mono, monospace)}.color-picker-compact__footer{display:flex;gap:.75rem;padding:1rem}\n"] }]
2146
+ }], ctorParameters: () => [], propDecorators: { trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], popoverWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "popoverWidth", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], closeOnClickOutside: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClickOutside", required: false }] }], triggerSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerSize", required: false }] }], triggerRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerRadius", required: false }] }], showCurrentColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCurrentColor", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], showAlpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlpha", required: false }] }], showPresets: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPresets", required: false }] }], showFormatToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFormatToggle", required: false }] }], showCopyButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCopyButton", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], applyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "applyLabel", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], colorChange: [{ type: i0.Output, args: ["colorChange"] }] } });
2147
+
1281
2148
  /**
1282
2149
  * Service for programmatic control of Drawer components
1283
2150
  *
@@ -1708,6 +2575,106 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
1708
2575
  args: ['keydown', ['$event']]
1709
2576
  }] } });
1710
2577
 
2578
+ class DropdownComponent {
2579
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
2580
+ trigger = input('click', ...(ngDevMode ? [{ debugName: "trigger" }] : []));
2581
+ position = input('bottom-start', ...(ngDevMode ? [{ debugName: "position" }] : []));
2582
+ width = input('auto', ...(ngDevMode ? [{ debugName: "width" }] : []));
2583
+ minWidth = input('200px', ...(ngDevMode ? [{ debugName: "minWidth" }] : []));
2584
+ itemClick = output();
2585
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
2586
+ hostClasses = computed(() => classNames('studio-dropdown'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
2587
+ handleItemClick(item) {
2588
+ if (item.disabled)
2589
+ return;
2590
+ item.onClick?.();
2591
+ this.itemClick.emit(item);
2592
+ this.isOpen.set(false);
2593
+ }
2594
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: DropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2595
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: DropdownComponent, isStandalone: true, selector: "studio-dropdown", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
2596
+ <studio-popover
2597
+ [trigger]="trigger()"
2598
+ [position]="position()"
2599
+ [width]="width()"
2600
+ [minWidth]="minWidth()"
2601
+ [arrow]="false"
2602
+ [closeOnClickOutside]="true"
2603
+ [(visible)]="isOpen"
2604
+ >
2605
+ <ng-content />
2606
+
2607
+ <div popoverContent style="padding: 0.25rem;">
2608
+ @for (item of items(); track item.id) {
2609
+ @if (item.divider) {
2610
+ <div class="dropdown__divider"></div>
2611
+ } @else {
2612
+ <button
2613
+ type="button"
2614
+ class="dropdown__item"
2615
+ [class.dropdown__item--disabled]="item.disabled"
2616
+ [class.dropdown__item--danger]="item.danger"
2617
+ [disabled]="item.disabled"
2618
+ (click)="handleItemClick(item)"
2619
+ >
2620
+ @if (item.icon) {
2621
+ <studio-icon [name]="item.icon" [size]="16" class="dropdown__icon" />
2622
+ }
2623
+ <span class="dropdown__label">{{ item.label }}</span>
2624
+ @if (item.shortcut) {
2625
+ <span class="dropdown__shortcut">{{ item.shortcut }}</span>
2626
+ }
2627
+ </button>
2628
+ }
2629
+ }
2630
+ </div>
2631
+ </studio-popover>
2632
+ `, isInline: true, styles: [":host{display:inline-block}.dropdown__item{width:100%;display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-primary);font-size:.875rem;cursor:pointer;transition:all var(--studio-transition-fast);text-align:left;&--disabled{opacity:.5;cursor:not-allowed}&--danger{color:var(--studio-error)}}.dropdown__item:hover:not(:disabled){background:var(--studio-bg-secondary)}.dropdown__item:active:not(:disabled){transform:scale(.98)}.dropdown__icon{flex-shrink:0;color:var(--studio-text-secondary)}.dropdown__label{flex:1}.dropdown__shortcut{font-size:.75rem;color:var(--studio-text-tertiary);font-family:var(--studio-font-family-mono, monospace)}.dropdown__divider{height:1px;background:var(--studio-border-primary);margin:.25rem 0}\n"], dependencies: [{ kind: "component", type: PopoverComponent, selector: "studio-popover", inputs: ["id", "visible", "disabled", "trigger", "openDelay", "closeDelay", "position", "offset", "preventOverflow", "flipValue", "variant", "size", "width", "minWidth", "maxWidth", "maxHeight", "padding", "arrow", "arrowSize", "closeOnClickOutside", "closeOnEscape", "closeOnScroll", "showOverlay", "overlayOpacity", "animation", "animationDuration", "showHeader", "showFooter", "showCloseButton", "content", "zIndex", "ariaLabel", "role"], outputs: ["visibleChange", "opened", "closed", "positionChanged"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2633
+ }
2634
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: DropdownComponent, decorators: [{
2635
+ type: Component,
2636
+ args: [{ selector: 'studio-dropdown', standalone: true, imports: [PopoverComponent, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
2637
+ '[class]': 'hostClasses()',
2638
+ }, template: `
2639
+ <studio-popover
2640
+ [trigger]="trigger()"
2641
+ [position]="position()"
2642
+ [width]="width()"
2643
+ [minWidth]="minWidth()"
2644
+ [arrow]="false"
2645
+ [closeOnClickOutside]="true"
2646
+ [(visible)]="isOpen"
2647
+ >
2648
+ <ng-content />
2649
+
2650
+ <div popoverContent style="padding: 0.25rem;">
2651
+ @for (item of items(); track item.id) {
2652
+ @if (item.divider) {
2653
+ <div class="dropdown__divider"></div>
2654
+ } @else {
2655
+ <button
2656
+ type="button"
2657
+ class="dropdown__item"
2658
+ [class.dropdown__item--disabled]="item.disabled"
2659
+ [class.dropdown__item--danger]="item.danger"
2660
+ [disabled]="item.disabled"
2661
+ (click)="handleItemClick(item)"
2662
+ >
2663
+ @if (item.icon) {
2664
+ <studio-icon [name]="item.icon" [size]="16" class="dropdown__icon" />
2665
+ }
2666
+ <span class="dropdown__label">{{ item.label }}</span>
2667
+ @if (item.shortcut) {
2668
+ <span class="dropdown__shortcut">{{ item.shortcut }}</span>
2669
+ }
2670
+ </button>
2671
+ }
2672
+ }
2673
+ </div>
2674
+ </studio-popover>
2675
+ `, styles: [":host{display:inline-block}.dropdown__item{width:100%;display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-primary);font-size:.875rem;cursor:pointer;transition:all var(--studio-transition-fast);text-align:left;&--disabled{opacity:.5;cursor:not-allowed}&--danger{color:var(--studio-error)}}.dropdown__item:hover:not(:disabled){background:var(--studio-bg-secondary)}.dropdown__item:active:not(:disabled){transform:scale(.98)}.dropdown__icon{flex-shrink:0;color:var(--studio-text-secondary)}.dropdown__label{flex:1}.dropdown__shortcut{font-size:.75rem;color:var(--studio-text-tertiary);font-family:var(--studio-font-family-mono, monospace)}.dropdown__divider{height:1px;background:var(--studio-border-primary);margin:.25rem 0}\n"] }]
2676
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }] } });
2677
+
1711
2678
  /**
1712
2679
  * Input component with form control support, variants, and accessibility
1713
2680
  *
@@ -2227,39 +3194,256 @@ class MenuComponent {
2227
3194
  ])
2228
3195
  ], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2229
3196
  }
2230
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: MenuComponent, decorators: [{
3197
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: MenuComponent, decorators: [{
3198
+ type: Component,
3199
+ args: [{ selector: 'studio-menu', standalone: true, imports: [
3200
+ CommonModule,
3201
+ RouterLink,
3202
+ RouterLinkActive,
3203
+ IconComponent,
3204
+ BadgeComponent
3205
+ ], changeDetection: ChangeDetectionStrategy.OnPush, host: {
3206
+ '[class]': 'hostClasses()',
3207
+ '[attr.role]': 'role()',
3208
+ '[attr.aria-label]': 'ariaLabel()',
3209
+ '[attr.aria-orientation]': 'orientation()'
3210
+ }, animations: [
3211
+ trigger('expandCollapse', [
3212
+ state('collapsed', style({
3213
+ height: '0',
3214
+ opacity: '0',
3215
+ overflow: 'hidden'
3216
+ })),
3217
+ state('expanded', style({
3218
+ height: '*',
3219
+ opacity: '1',
3220
+ overflow: 'visible'
3221
+ })),
3222
+ transition('collapsed <=> expanded', [
3223
+ animate('200ms ease-in-out')
3224
+ ])
3225
+ ])
3226
+ ], template: "<div class=\"studio-menu__list\">\n @for (item of items(); track getItemId(item, $index)) {\n @if (isVisible(item)) {\n @if (item.separator) {\n <!-- Separator -->\n <div class=\"studio-menu__separator\"></div>\n } @else {\n <!-- Menu Item -->\n <div\n class=\"studio-menu-item\"\n [class.studio-menu-item--disabled]=\"isDisabled(item)\"\n [class.studio-menu-item--active]=\"isActive(item)\"\n [class.studio-menu-item--has-children]=\"hasChildren(item)\"\n [class.studio-menu-item--expanded]=\"isExpanded(item)\"\n [class]=\"itemClass() + ' ' + (item.class || '')\"\n [style]=\"getIndentStyle()\"\n [attr.role]=\"role() === 'menu' ? 'menuitem' : undefined\"\n [attr.aria-disabled]=\"isDisabled(item)\"\n [attr.aria-expanded]=\"hasChildren(item) ? isExpanded(item) : undefined\"\n [attr.title]=\"item.tooltip\"\n (click)=\"handleItemClick($event, item)\"\n (mouseenter)=\"handleItemMouseEnter(item)\"\n (mouseleave)=\"handleItemMouseLeave(item)\"\n >\n <!-- Router Link -->\n @if (item.routerLink && !isDisabled(item)) {\n <a\n class=\"studio-menu-item__link\"\n [routerLink]=\"item.routerLink\"\n [queryParams]=\"item.queryParams\"\n [fragment]=\"item.fragment\"\n [target]=\"item.target\"\n routerLinkActive=\"studio-menu-item__link--active\"\n [attr.aria-current]=\"isActive(item) ? 'page' : undefined\"\n >\n <ng-container *ngTemplateOutlet=\"itemContent; context: { $implicit: item }\" />\n </a>\n }\n <!-- External Link -->\n @else if (item.href && !isDisabled(item)) {\n <a\n class=\"studio-menu-item__link\"\n [href]=\"item.href\"\n [target]=\"item.target\"\n >\n <ng-container *ngTemplateOutlet=\"itemContent; context: { $implicit: item }\" />\n </a>\n }\n <!-- Button (no navigation) -->\n @else {\n <div class=\"studio-menu-item__content\">\n <ng-container *ngTemplateOutlet=\"itemContent; context: { $implicit: item }\" />\n </div>\n }\n </div>\n\n <!-- Submenu (recursive) -->\n @if (hasChildren(item) && isExpanded(item)) {\n <div\n class=\"studio-menu__submenu\"\n [@expandCollapse]=\"animated() ? 'expanded' : undefined\"\n >\n <studio-menu\n [items]=\"item.items!\"\n [orientation]=\"orientation()\"\n [mode]=\"mode()\"\n [collapsible]=\"collapsible()\"\n [expandOnHover]=\"expandOnHover()\"\n [selectOnNavigate]=\"selectOnNavigate()\"\n [keyboardNavigation]=\"keyboardNavigation()\"\n [arrowNavigation]=\"arrowNavigation()\"\n [homeEndNavigation]=\"homeEndNavigation()\"\n [animated]=\"animated()\"\n [animationDuration]=\"animationDuration()\"\n [size]=\"size()\"\n [compact]=\"compact()\"\n [fullWidth]=\"fullWidth()\"\n [variant]=\"variant()\"\n [color]=\"color()\"\n [radius]=\"radius()\"\n [spacing]=\"spacing()\"\n [showDividers]=\"showDividers()\"\n [iconSize]=\"iconSize()\"\n [iconOnly]=\"iconOnly()\"\n [indentLevel]=\"indentLevel()\"\n [showExpandIcon]=\"showExpandIcon()\"\n [expandIconPosition]=\"expandIconPosition()\"\n [expandIcon]=\"expandIcon()\"\n [itemClass]=\"itemClass()\"\n [level]=\"level() + 1\"\n [parentExpanded]=\"isExpanded(item)\"\n (itemClick)=\"itemClick.emit($event)\"\n (itemSelect)=\"itemSelect.emit($event)\"\n (expandChange)=\"expandChange.emit($event)\"\n (activeChange)=\"activeChange.emit($event)\"\n />\n </div>\n }\n\n <!-- Divider (if enabled) -->\n @if (showDividers() && $index < items().length - 1) {\n <div class=\"studio-menu__divider\"></div>\n }\n }\n }\n }\n</div>\n\n<!-- Item Content Template -->\n<ng-template #itemContent let-item>\n <div class=\"studio-menu-item__inner\">\n <!-- Left Icon -->\n @if (item.icon && (!item.iconPosition || item.iconPosition === 'left')) {\n <studio-icon\n class=\"studio-menu-item__icon studio-menu-item__icon--left\"\n [name]=\"item.icon\"\n [size]=\"iconSize()\"\n />\n }\n\n <!-- Label -->\n @if (!iconOnly()) {\n <span class=\"studio-menu-item__label\">{{ item.label }}</span>\n }\n\n <!-- Badge -->\n @if (item.badge && !iconOnly()) {\n <studio-badge\n class=\"studio-menu-item__badge\"\n [value]=\"item.badge\"\n [color]=\"item.badgeColor || 'primary'\"\n size=\"sm\"\n />\n }\n\n <!-- Right Icon -->\n @if (item.icon && item.iconPosition === 'right') {\n <studio-icon\n class=\"studio-menu-item__icon studio-menu-item__icon--right\"\n [name]=\"item.icon\"\n [size]=\"iconSize()\"\n />\n }\n\n <!-- Expand Icon -->\n @if (hasChildren(item) && showExpandIcon() && !iconOnly()) {\n <studio-icon\n class=\"studio-menu-item__expand-icon\"\n [class.studio-menu-item__expand-icon--expanded]=\"isExpanded(item)\"\n [name]=\"expandIcon()\"\n [size]=\"16\"\n />\n }\n </div>\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column;width:100%;--menu-padding-y: .5rem;--menu-padding-x: .75rem;--menu-font-size: .875rem;--menu-line-height: 1.25rem;--menu-gap: .25rem;--menu-indent: 1rem;--menu-transition: all .2s cubic-bezier(.4, 0, .2, 1);--menu-item-height: auto;--menu-item-min-height: 2.5rem;--menu-border-radius: .375rem;--menu-icon-size: 1rem}:host(.studio-menu--horizontal){flex-direction:row;overflow-x:auto}:host(.studio-menu--horizontal) .studio-menu__list{flex-direction:row;flex-wrap:nowrap}:host(.studio-menu--sm){--menu-padding-y: .375rem;--menu-padding-x: .625rem;--menu-font-size: .8125rem;--menu-line-height: 1.125rem;--menu-gap: .125rem;--menu-item-min-height: 2rem;--menu-border-radius: .25rem;--menu-icon-size: .875rem}:host(.studio-menu--md){--menu-padding-y: .5rem;--menu-padding-x: .75rem;--menu-font-size: .875rem;--menu-line-height: 1.25rem;--menu-gap: .25rem;--menu-item-min-height: 2.5rem;--menu-border-radius: .375rem;--menu-icon-size: 1rem}:host(.studio-menu--lg){--menu-padding-y: .625rem;--menu-padding-x: 1rem;--menu-font-size: .9375rem;--menu-line-height: 1.375rem;--menu-gap: .375rem;--menu-item-min-height: 3rem;--menu-border-radius: .5rem;--menu-icon-size: 1.125rem}:host(.studio-menu--compact){--menu-padding-y: .25rem;--menu-gap: .0625rem}:host(.studio-menu--full-width){width:100%}:host(.studio-menu--full-width) .studio-menu-item{width:100%}:host(.studio-menu--icon-only) .studio-menu-item__label,:host(.studio-menu--icon-only) .studio-menu-item__badge,:host(.studio-menu--icon-only) .studio-menu-item__expand-icon{display:none}:host(.studio-menu--icon-only) .studio-menu-item{justify-content:center;padding:var(--menu-padding-y)}:host(.studio-menu--filled){padding:.5rem;background:var(--studio-bg-secondary);border-radius:calc(var(--menu-border-radius) + .25rem);box-shadow:0 1px 2px #0000000d}:host(.studio-menu--outlined){padding:.5rem;border:1px solid var(--studio-border-primary);border-radius:calc(var(--menu-border-radius) + .25rem);background:var(--studio-bg-primary)}:host(.studio-menu--ghost){padding:0}:host(.studio-menu--primary) .studio-menu-item--active{background:hsl(var(--studio-primary-hsl)/.1);color:var(--studio-primary);font-weight:500}:host(.studio-menu--secondary) .studio-menu-item--active{background:hsl(var(--studio-secondary-hsl)/.1);color:var(--studio-secondary);font-weight:500}:host(.studio-menu--radius-none){--menu-border-radius: 0}:host(.studio-menu--radius-none.studio-menu--filled),:host(.studio-menu--radius-none.studio-menu--outlined){border-radius:0}:host(.studio-menu--radius-sm){--menu-border-radius: .25rem}:host(.studio-menu--radius-sm.studio-menu--filled),:host(.studio-menu--radius-sm.studio-menu--outlined){border-radius:.5rem}:host(.studio-menu--radius-md){--menu-border-radius: .375rem}:host(.studio-menu--radius-md.studio-menu--filled),:host(.studio-menu--radius-md.studio-menu--outlined){border-radius:.625rem}:host(.studio-menu--radius-lg){--menu-border-radius: .5rem}:host(.studio-menu--radius-lg.studio-menu--filled),:host(.studio-menu--radius-lg.studio-menu--outlined){border-radius:.75rem}:host(.studio-menu--spacing-none){--menu-gap: 0}:host(.studio-menu--spacing-sm){--menu-gap: .125rem}:host(.studio-menu--spacing-md){--menu-gap: .25rem}:host(.studio-menu--spacing-lg){--menu-gap: .5rem}.studio-menu__list{display:flex;flex-direction:column;gap:var(--menu-gap);list-style:none;margin:0;padding:0}.studio-menu-item{position:relative;display:flex;align-items:center;width:100%;min-height:var(--menu-item-min-height);padding:0;border:none;background:transparent;color:var(--studio-text-primary);font-size:var(--menu-font-size);line-height:var(--menu-line-height);font-family:inherit;font-weight:400;text-align:left;cursor:pointer;transition:var(--menu-transition);border-radius:var(--menu-border-radius);outline:none;-webkit-user-select:none;user-select:none}.studio-menu-item:hover:not(.studio-menu-item--disabled):not(.studio-menu-item--active){background:hsl(var(--studio-primary-hsl)/.04);color:var(--studio-text-primary)}.studio-menu-item--active{background:hsl(var(--studio-primary-hsl)/.1);color:var(--studio-text-primary);font-weight:500}.studio-menu-item--active .studio-menu-item__icon{color:var(--studio-text-primary)}.studio-menu-item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.studio-menu-item--has-children .studio-menu-item__expand-icon{transition:transform .2s cubic-bezier(.4,0,.2,1)}.studio-menu-item--expanded .studio-menu-item__expand-icon{transform:rotate(180deg)}.studio-menu-item:focus-visible{outline:2px solid var(--studio-primary);outline-offset:-1px;z-index:1}:host(.studio-menu--filled) .studio-menu-item:hover:not(.studio-menu-item--disabled):not(.studio-menu-item--active){background:var(--studio-bg-hover)}:host(.studio-menu--filled) .studio-menu-item.studio-menu-item--active{background:var(--studio-bg-primary);box-shadow:0 1px 2px #0000000d}:host(.studio-menu--outlined) .studio-menu-item{border:1px solid transparent}:host(.studio-menu--outlined) .studio-menu-item:hover:not(.studio-menu-item--disabled):not(.studio-menu-item--active){border-color:var(--studio-border-secondary);background:var(--studio-bg-secondary)}:host(.studio-menu--outlined) .studio-menu-item.studio-menu-item--active{border-color:var(--studio-primary);background:hsl(var(--studio-primary-hsl)/.05)}:host(.studio-menu--ghost) .studio-menu-item:hover:not(.studio-menu-item--disabled):not(.studio-menu-item--active){background:transparent;color:var(--studio-primary)}:host(.studio-menu--ghost) .studio-menu-item.studio-menu-item--active{background:transparent;color:var(--studio-primary);text-decoration:underline;text-underline-offset:4px}.studio-menu-item__link,.studio-menu-item__content{display:flex;align-items:center;width:100%;padding:var(--menu-padding-y) var(--menu-padding-x);color:inherit;text-decoration:none;gap:.5rem}.studio-menu-item__link:visited{color:inherit}.studio-menu-item__link:hover{text-decoration:none}.studio-menu-item__inner{display:flex;align-items:center;gap:.5rem;width:100%}.studio-menu-item__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:var(--menu-icon-size);height:var(--menu-icon-size);color:var(--studio-text-secondary);transition:var(--menu-transition)}.studio-menu-item__icon--left{order:-1}.studio-menu-item__icon--right{order:1;margin-left:auto}.studio-menu-item:hover .studio-menu-item__icon,.studio-menu-item--active .studio-menu-item__icon{color:var(--studio-text-primary)}.studio-menu-item__label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--menu-font-size);line-height:var(--menu-line-height)}.studio-menu-item__badge{flex-shrink:0;margin-left:auto}.studio-menu-item__expand-icon{flex-shrink:0;margin-left:auto;width:1rem;height:1rem;color:var(--studio-text-secondary);opacity:.7;transition:transform .2s cubic-bezier(.4,0,.2,1),opacity var(--menu-transition)}.studio-menu-item:hover .studio-menu-item__expand-icon{opacity:1}.studio-menu__submenu{overflow:hidden;margin-top:var(--menu-gap);margin-left:calc(var(--menu-indent) - .25rem)}.studio-menu__submenu studio-menu{padding-left:0}.studio-menu__submenu .studio-menu__list{padding-left:.75rem;border-left:1px solid var(--studio-border-secondary);margin-left:.75rem}.studio-menu__separator{height:1px;margin:.375rem 0;background:var(--studio-border-secondary);opacity:.6}.studio-menu__divider{height:1px;margin:.125rem 0;background:var(--studio-border-secondary);opacity:.4}@keyframes expandCollapse{0%{opacity:0;max-height:0;transform:translateY(-4px)}to{opacity:1;max-height:1000px;transform:translateY(0)}}@media (max-width: 768px){:host(.studio-menu--horizontal){flex-direction:column}:host(.studio-menu--horizontal) .studio-menu__list{flex-direction:column}}\n"] }]
3227
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], defaultExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultExpanded", required: false }] }], expandOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandOnHover", required: false }] }], activeItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeItem", required: false }] }], routerLinkActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLinkActive", required: false }] }], selectOnNavigate: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectOnNavigate", required: false }] }], routerLinkActiveOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLinkActiveOptions", required: false }] }], keyboardNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyboardNavigation", required: false }] }], arrowNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowNavigation", required: false }] }], homeEndNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "homeEndNavigation", required: false }] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], spacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "spacing", required: false }] }], showDividers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDividers", required: false }] }], iconSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconSize", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], indentLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentLevel", required: false }] }], showExpandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExpandIcon", required: false }] }], expandIconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandIconPosition", required: false }] }], expandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandIcon", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], level: [{ type: i0.Input, args: [{ isSignal: true, alias: "level", required: false }] }], parentExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentExpanded", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], itemSelect: [{ type: i0.Output, args: ["itemSelect"] }], expandChange: [{ type: i0.Output, args: ["expandChange"] }], activeChange: [{ type: i0.Output, args: ["activeChange"] }], handleKeyDown: [{
3228
+ type: HostListener,
3229
+ args: ['keydown', ['$event']]
3230
+ }] } });
3231
+
3232
+ class ModalComponent {
3233
+ destroyRef = inject(DestroyRef);
3234
+ // Inputs
3235
+ visible = model(false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
3236
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
3237
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
3238
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
3239
+ animation = input('scale', ...(ngDevMode ? [{ debugName: "animation" }] : []));
3240
+ position = input('center', ...(ngDevMode ? [{ debugName: "position" }] : []));
3241
+ showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
3242
+ showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
3243
+ showCloseButton = input(true, ...(ngDevMode ? [{ debugName: "showCloseButton" }] : []));
3244
+ closeOnOverlayClick = input(true, ...(ngDevMode ? [{ debugName: "closeOnOverlayClick" }] : []));
3245
+ closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : []));
3246
+ // Outputs
3247
+ visibleChange = output();
3248
+ opened = output();
3249
+ closed = output();
3250
+ // Template refs
3251
+ headerTemplate = contentChild('modalHeader', ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
3252
+ footerTemplate = contentChild('modalFooter', ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
3253
+ modalPanel = viewChild('modalPanel', ...(ngDevMode ? [{ debugName: "modalPanel" }] : []));
3254
+ // Computed
3255
+ hostClasses = computed(() => classNames('studio-modal', 'modal--' + this.size(), 'modal--' + this.variant(), 'modal--' + this.animation(), 'modal--' + this.position()), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
3256
+ constructor() {
3257
+ afterNextRender(() => {
3258
+ this.setupFocusTrap();
3259
+ });
3260
+ effect(() => {
3261
+ if (this.visible()) {
3262
+ this.handleOpen();
3263
+ }
3264
+ else {
3265
+ this.handleClose();
3266
+ }
3267
+ });
3268
+ }
3269
+ handleEscape(event) {
3270
+ if (this.closeOnEscape() && this.visible()) {
3271
+ event.preventDefault();
3272
+ this.close();
3273
+ }
3274
+ }
3275
+ handleOverlayClick() {
3276
+ if (this.closeOnOverlayClick()) {
3277
+ this.close();
3278
+ }
3279
+ }
3280
+ close() {
3281
+ this.visible.set(false);
3282
+ }
3283
+ open() {
3284
+ this.visible.set(true);
3285
+ }
3286
+ handleOpen() {
3287
+ // Prevent body scroll
3288
+ document.body.style.overflow = 'hidden';
3289
+ this.opened.emit();
3290
+ // Focus first focusable element
3291
+ setTimeout(() => {
3292
+ const panel = this.modalPanel()?.nativeElement;
3293
+ if (panel) {
3294
+ const focusable = panel.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
3295
+ focusable?.focus();
3296
+ }
3297
+ }, 100);
3298
+ }
3299
+ handleClose() {
3300
+ // Restore body scroll
3301
+ document.body.style.overflow = '';
3302
+ this.closed.emit();
3303
+ }
3304
+ setupFocusTrap() {
3305
+ // Simple focus trap: keep focus within modal when it's open
3306
+ const handleTab = (e) => {
3307
+ if (!this.visible() || e.key !== 'Tab')
3308
+ return;
3309
+ const panel = this.modalPanel()?.nativeElement;
3310
+ if (!panel)
3311
+ return;
3312
+ const focusableElements = panel.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
3313
+ const firstElement = focusableElements[0];
3314
+ const lastElement = focusableElements[focusableElements.length - 1];
3315
+ if (e.shiftKey && document.activeElement === firstElement) {
3316
+ lastElement?.focus();
3317
+ e.preventDefault();
3318
+ }
3319
+ else if (!e.shiftKey && document.activeElement === lastElement) {
3320
+ firstElement?.focus();
3321
+ e.preventDefault();
3322
+ }
3323
+ };
3324
+ document.addEventListener('keydown', handleTab);
3325
+ this.destroyRef.onDestroy(() => {
3326
+ document.removeEventListener('keydown', handleTab);
3327
+ document.body.style.overflow = ''; // Cleanup on destroy
3328
+ });
3329
+ }
3330
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3331
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: ModalComponent, isStandalone: true, selector: "studio-modal", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, animation: { classPropertyName: "animation", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeOnOverlayClick: { classPropertyName: "closeOnOverlayClick", publicName: "closeOnOverlayClick", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange", visibleChange: "visibleChange", opened: "opened", closed: "closed" }, host: { listeners: { "document:keydown.escape": "handleEscape($event)" }, properties: { "class": "hostClasses()" } }, queries: [{ propertyName: "headerTemplate", first: true, predicate: ["modalHeader"], descendants: true, isSignal: true }, { propertyName: "footerTemplate", first: true, predicate: ["modalFooter"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "modalPanel", first: true, predicate: ["modalPanel"], descendants: true, isSignal: true }], ngImport: i0, template: `
3332
+ @if (visible()) {
3333
+ <!-- Overlay -->
3334
+ <div
3335
+ class="studio-modal__overlay"
3336
+ [class.studio-modal__overlay--visible]="visible()"
3337
+ (click)="handleOverlayClick()"
3338
+ ></div>
3339
+
3340
+ <!-- Modal -->
3341
+ <div
3342
+ #modalPanel
3343
+ class="studio-modal__panel"
3344
+ [class.studio-modal__panel--visible]="visible()"
3345
+ role="dialog"
3346
+ [attr.aria-modal]="true"
3347
+ [attr.aria-labelledby]="showHeader() ? 'modal-title' : null"
3348
+ >
3349
+ <!-- Header -->
3350
+ @if (showHeader()) {
3351
+ <div class="studio-modal__header">
3352
+ @if (headerTemplate()) {
3353
+ <ng-container *ngTemplateOutlet="headerTemplate()!" />
3354
+ } @else {
3355
+ <h3 id="modal-title" class="studio-modal__title">{{ title() }}</h3>
3356
+ }
3357
+
3358
+ @if (showCloseButton()) {
3359
+ <button
3360
+ type="button"
3361
+ class="studio-modal__close"
3362
+ (click)="close()"
3363
+ aria-label="Close"
3364
+ >
3365
+ <studio-icon name="x" [size]="20" />
3366
+ </button>
3367
+ }
3368
+ </div>
3369
+ }
3370
+
3371
+ <!-- Content -->
3372
+ <div class="studio-modal__content">
3373
+ <ng-content />
3374
+ </div>
3375
+
3376
+ <!-- Footer -->
3377
+ @if (showFooter() && footerTemplate()) {
3378
+ <div class="studio-modal__footer">
3379
+ <ng-container *ngTemplateOutlet="footerTemplate()!" />
3380
+ </div>
3381
+ }
3382
+ </div>
3383
+ }
3384
+ `, isInline: true, styles: [":host{display:contents;font-family:var(--studio-font-family)}.studio-modal__overlay{position:fixed;inset:0;background:#00000080;z-index:1000;opacity:0;transition:opacity var(--studio-transition-normal);&--visible{opacity:1}}.studio-modal__panel{position:fixed;z-index:1001;background:var(--studio-bg-primary);border-radius:var(--studio-radius-lg);box-shadow:var(--studio-shadow-xl);display:flex;flex-direction:column;max-height:90vh;opacity:0;transform:scale(.95);transition:opacity var(--studio-transition-normal),transform var(--studio-transition-normal);&--visible{opacity:1;transform:scale(1)}}:host(.modal--center) .studio-modal__panel{top:50%;left:50%;transform:translate(-50%,-50%) scale(.95);&--visible{transform:translate(-50%,-50%) scale(1)}}:host(.modal--top) .studio-modal__panel{top:5vh;left:50%;transform:translate(-50%,-20px) scale(.95);&--visible{transform:translate(-50%) scale(1)}}:host(.modal--bottom) .studio-modal__panel{bottom:5vh;left:50%;transform:translate(-50%,20px) scale(.95);&--visible{transform:translate(-50%) scale(1)}}:host(.modal--sm) .studio-modal__panel{width:90%;max-width:400px}:host(.modal--md) .studio-modal__panel{width:90%;max-width:600px}:host(.modal--lg) .studio-modal__panel{width:90%;max-width:800px}:host(.modal--xl) .studio-modal__panel{width:90%;max-width:1200px}:host(.modal--full) .studio-modal__panel{width:95vw;height:95vh;max-width:none;max-height:none}:host(.modal--bordered) .studio-modal__panel{border:1px solid var(--studio-border-primary)}:host(.modal--minimal) .studio-modal__panel{box-shadow:var(--studio-shadow-md)}:host(.modal--fade) .studio-modal__panel{transform:translate(-50%,-50%);&--visible{transform:translate(-50%,-50%)}}:host(.modal--slide-down) .studio-modal__panel{transform:translate(-50%,-60%);&--visible{transform:translate(-50%,-50%)}}:host(.modal--none) .studio-modal__panel{transition:none}:host(.modal--none) .studio-modal__overlay{transition:none}.studio-modal__header{display:flex;align-items:center;justify-content:space-between;padding:1.5rem;border-bottom:1px solid var(--studio-border-primary);flex-shrink:0}.studio-modal__title{margin:0;font-size:1.25rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast)}.studio-modal__close:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-modal__close:active{transform:scale(.95)}.studio-modal__content{padding:1.5rem;overflow-y:auto;flex:1}.studio-modal__footer{padding:1.5rem;border-top:1px solid var(--studio-border-primary);display:flex;gap:.75rem;justify-content:flex-end;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3385
+ }
3386
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ModalComponent, decorators: [{
2231
3387
  type: Component,
2232
- args: [{ selector: 'studio-menu', standalone: true, imports: [
2233
- CommonModule,
2234
- RouterLink,
2235
- RouterLinkActive,
2236
- IconComponent,
2237
- BadgeComponent
2238
- ], changeDetection: ChangeDetectionStrategy.OnPush, host: {
3388
+ args: [{ selector: 'studio-modal', standalone: true, imports: [CommonModule, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
2239
3389
  '[class]': 'hostClasses()',
2240
- '[attr.role]': 'role()',
2241
- '[attr.aria-label]': 'ariaLabel()',
2242
- '[attr.aria-orientation]': 'orientation()'
2243
- }, animations: [
2244
- trigger('expandCollapse', [
2245
- state('collapsed', style({
2246
- height: '0',
2247
- opacity: '0',
2248
- overflow: 'hidden'
2249
- })),
2250
- state('expanded', style({
2251
- height: '*',
2252
- opacity: '1',
2253
- overflow: 'visible'
2254
- })),
2255
- transition('collapsed <=> expanded', [
2256
- animate('200ms ease-in-out')
2257
- ])
2258
- ])
2259
- ], template: "<div class=\"studio-menu__list\">\n @for (item of items(); track getItemId(item, $index)) {\n @if (isVisible(item)) {\n @if (item.separator) {\n <!-- Separator -->\n <div class=\"studio-menu__separator\"></div>\n } @else {\n <!-- Menu Item -->\n <div\n class=\"studio-menu-item\"\n [class.studio-menu-item--disabled]=\"isDisabled(item)\"\n [class.studio-menu-item--active]=\"isActive(item)\"\n [class.studio-menu-item--has-children]=\"hasChildren(item)\"\n [class.studio-menu-item--expanded]=\"isExpanded(item)\"\n [class]=\"itemClass() + ' ' + (item.class || '')\"\n [style]=\"getIndentStyle()\"\n [attr.role]=\"role() === 'menu' ? 'menuitem' : undefined\"\n [attr.aria-disabled]=\"isDisabled(item)\"\n [attr.aria-expanded]=\"hasChildren(item) ? isExpanded(item) : undefined\"\n [attr.title]=\"item.tooltip\"\n (click)=\"handleItemClick($event, item)\"\n (mouseenter)=\"handleItemMouseEnter(item)\"\n (mouseleave)=\"handleItemMouseLeave(item)\"\n >\n <!-- Router Link -->\n @if (item.routerLink && !isDisabled(item)) {\n <a\n class=\"studio-menu-item__link\"\n [routerLink]=\"item.routerLink\"\n [queryParams]=\"item.queryParams\"\n [fragment]=\"item.fragment\"\n [target]=\"item.target\"\n routerLinkActive=\"studio-menu-item__link--active\"\n [attr.aria-current]=\"isActive(item) ? 'page' : undefined\"\n >\n <ng-container *ngTemplateOutlet=\"itemContent; context: { $implicit: item }\" />\n </a>\n }\n <!-- External Link -->\n @else if (item.href && !isDisabled(item)) {\n <a\n class=\"studio-menu-item__link\"\n [href]=\"item.href\"\n [target]=\"item.target\"\n >\n <ng-container *ngTemplateOutlet=\"itemContent; context: { $implicit: item }\" />\n </a>\n }\n <!-- Button (no navigation) -->\n @else {\n <div class=\"studio-menu-item__content\">\n <ng-container *ngTemplateOutlet=\"itemContent; context: { $implicit: item }\" />\n </div>\n }\n </div>\n\n <!-- Submenu (recursive) -->\n @if (hasChildren(item) && isExpanded(item)) {\n <div\n class=\"studio-menu__submenu\"\n [@expandCollapse]=\"animated() ? 'expanded' : undefined\"\n >\n <studio-menu\n [items]=\"item.items!\"\n [orientation]=\"orientation()\"\n [mode]=\"mode()\"\n [collapsible]=\"collapsible()\"\n [expandOnHover]=\"expandOnHover()\"\n [selectOnNavigate]=\"selectOnNavigate()\"\n [keyboardNavigation]=\"keyboardNavigation()\"\n [arrowNavigation]=\"arrowNavigation()\"\n [homeEndNavigation]=\"homeEndNavigation()\"\n [animated]=\"animated()\"\n [animationDuration]=\"animationDuration()\"\n [size]=\"size()\"\n [compact]=\"compact()\"\n [fullWidth]=\"fullWidth()\"\n [variant]=\"variant()\"\n [color]=\"color()\"\n [radius]=\"radius()\"\n [spacing]=\"spacing()\"\n [showDividers]=\"showDividers()\"\n [iconSize]=\"iconSize()\"\n [iconOnly]=\"iconOnly()\"\n [indentLevel]=\"indentLevel()\"\n [showExpandIcon]=\"showExpandIcon()\"\n [expandIconPosition]=\"expandIconPosition()\"\n [expandIcon]=\"expandIcon()\"\n [itemClass]=\"itemClass()\"\n [level]=\"level() + 1\"\n [parentExpanded]=\"isExpanded(item)\"\n (itemClick)=\"itemClick.emit($event)\"\n (itemSelect)=\"itemSelect.emit($event)\"\n (expandChange)=\"expandChange.emit($event)\"\n (activeChange)=\"activeChange.emit($event)\"\n />\n </div>\n }\n\n <!-- Divider (if enabled) -->\n @if (showDividers() && $index < items().length - 1) {\n <div class=\"studio-menu__divider\"></div>\n }\n }\n }\n }\n</div>\n\n<!-- Item Content Template -->\n<ng-template #itemContent let-item>\n <div class=\"studio-menu-item__inner\">\n <!-- Left Icon -->\n @if (item.icon && (!item.iconPosition || item.iconPosition === 'left')) {\n <studio-icon\n class=\"studio-menu-item__icon studio-menu-item__icon--left\"\n [name]=\"item.icon\"\n [size]=\"iconSize()\"\n />\n }\n\n <!-- Label -->\n @if (!iconOnly()) {\n <span class=\"studio-menu-item__label\">{{ item.label }}</span>\n }\n\n <!-- Badge -->\n @if (item.badge && !iconOnly()) {\n <studio-badge\n class=\"studio-menu-item__badge\"\n [value]=\"item.badge\"\n [color]=\"item.badgeColor || 'primary'\"\n size=\"sm\"\n />\n }\n\n <!-- Right Icon -->\n @if (item.icon && item.iconPosition === 'right') {\n <studio-icon\n class=\"studio-menu-item__icon studio-menu-item__icon--right\"\n [name]=\"item.icon\"\n [size]=\"iconSize()\"\n />\n }\n\n <!-- Expand Icon -->\n @if (hasChildren(item) && showExpandIcon() && !iconOnly()) {\n <studio-icon\n class=\"studio-menu-item__expand-icon\"\n [class.studio-menu-item__expand-icon--expanded]=\"isExpanded(item)\"\n [name]=\"expandIcon()\"\n [size]=\"16\"\n />\n }\n </div>\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column;width:100%;--menu-padding-y: .5rem;--menu-padding-x: .75rem;--menu-font-size: .875rem;--menu-line-height: 1.25rem;--menu-gap: .25rem;--menu-indent: 1rem;--menu-transition: all .2s cubic-bezier(.4, 0, .2, 1);--menu-item-height: auto;--menu-item-min-height: 2.5rem;--menu-border-radius: .375rem;--menu-icon-size: 1rem}:host(.studio-menu--horizontal){flex-direction:row;overflow-x:auto}:host(.studio-menu--horizontal) .studio-menu__list{flex-direction:row;flex-wrap:nowrap}:host(.studio-menu--sm){--menu-padding-y: .375rem;--menu-padding-x: .625rem;--menu-font-size: .8125rem;--menu-line-height: 1.125rem;--menu-gap: .125rem;--menu-item-min-height: 2rem;--menu-border-radius: .25rem;--menu-icon-size: .875rem}:host(.studio-menu--md){--menu-padding-y: .5rem;--menu-padding-x: .75rem;--menu-font-size: .875rem;--menu-line-height: 1.25rem;--menu-gap: .25rem;--menu-item-min-height: 2.5rem;--menu-border-radius: .375rem;--menu-icon-size: 1rem}:host(.studio-menu--lg){--menu-padding-y: .625rem;--menu-padding-x: 1rem;--menu-font-size: .9375rem;--menu-line-height: 1.375rem;--menu-gap: .375rem;--menu-item-min-height: 3rem;--menu-border-radius: .5rem;--menu-icon-size: 1.125rem}:host(.studio-menu--compact){--menu-padding-y: .25rem;--menu-gap: .0625rem}:host(.studio-menu--full-width){width:100%}:host(.studio-menu--full-width) .studio-menu-item{width:100%}:host(.studio-menu--icon-only) .studio-menu-item__label,:host(.studio-menu--icon-only) .studio-menu-item__badge,:host(.studio-menu--icon-only) .studio-menu-item__expand-icon{display:none}:host(.studio-menu--icon-only) .studio-menu-item{justify-content:center;padding:var(--menu-padding-y)}:host(.studio-menu--filled){padding:.5rem;background:var(--studio-bg-secondary);border-radius:calc(var(--menu-border-radius) + .25rem);box-shadow:0 1px 2px #0000000d}:host(.studio-menu--outlined){padding:.5rem;border:1px solid var(--studio-border-primary);border-radius:calc(var(--menu-border-radius) + .25rem);background:var(--studio-bg-primary)}:host(.studio-menu--ghost){padding:0}:host(.studio-menu--primary) .studio-menu-item--active{background:hsl(var(--studio-primary-hsl)/.1);color:var(--studio-primary);font-weight:500}:host(.studio-menu--secondary) .studio-menu-item--active{background:hsl(var(--studio-secondary-hsl)/.1);color:var(--studio-secondary);font-weight:500}:host(.studio-menu--radius-none){--menu-border-radius: 0}:host(.studio-menu--radius-none.studio-menu--filled),:host(.studio-menu--radius-none.studio-menu--outlined){border-radius:0}:host(.studio-menu--radius-sm){--menu-border-radius: .25rem}:host(.studio-menu--radius-sm.studio-menu--filled),:host(.studio-menu--radius-sm.studio-menu--outlined){border-radius:.5rem}:host(.studio-menu--radius-md){--menu-border-radius: .375rem}:host(.studio-menu--radius-md.studio-menu--filled),:host(.studio-menu--radius-md.studio-menu--outlined){border-radius:.625rem}:host(.studio-menu--radius-lg){--menu-border-radius: .5rem}:host(.studio-menu--radius-lg.studio-menu--filled),:host(.studio-menu--radius-lg.studio-menu--outlined){border-radius:.75rem}:host(.studio-menu--spacing-none){--menu-gap: 0}:host(.studio-menu--spacing-sm){--menu-gap: .125rem}:host(.studio-menu--spacing-md){--menu-gap: .25rem}:host(.studio-menu--spacing-lg){--menu-gap: .5rem}.studio-menu__list{display:flex;flex-direction:column;gap:var(--menu-gap);list-style:none;margin:0;padding:0}.studio-menu-item{position:relative;display:flex;align-items:center;width:100%;min-height:var(--menu-item-min-height);padding:0;border:none;background:transparent;color:var(--studio-text-primary);font-size:var(--menu-font-size);line-height:var(--menu-line-height);font-family:inherit;font-weight:400;text-align:left;cursor:pointer;transition:var(--menu-transition);border-radius:var(--menu-border-radius);outline:none;-webkit-user-select:none;user-select:none}.studio-menu-item:hover:not(.studio-menu-item--disabled):not(.studio-menu-item--active){background:hsl(var(--studio-primary-hsl)/.04);color:var(--studio-text-primary)}.studio-menu-item--active{background:hsl(var(--studio-primary-hsl)/.1);color:var(--studio-text-primary);font-weight:500}.studio-menu-item--active .studio-menu-item__icon{color:var(--studio-text-primary)}.studio-menu-item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.studio-menu-item--has-children .studio-menu-item__expand-icon{transition:transform .2s cubic-bezier(.4,0,.2,1)}.studio-menu-item--expanded .studio-menu-item__expand-icon{transform:rotate(180deg)}.studio-menu-item:focus-visible{outline:2px solid var(--studio-primary);outline-offset:-1px;z-index:1}:host(.studio-menu--filled) .studio-menu-item:hover:not(.studio-menu-item--disabled):not(.studio-menu-item--active){background:var(--studio-bg-hover)}:host(.studio-menu--filled) .studio-menu-item.studio-menu-item--active{background:var(--studio-bg-primary);box-shadow:0 1px 2px #0000000d}:host(.studio-menu--outlined) .studio-menu-item{border:1px solid transparent}:host(.studio-menu--outlined) .studio-menu-item:hover:not(.studio-menu-item--disabled):not(.studio-menu-item--active){border-color:var(--studio-border-secondary);background:var(--studio-bg-secondary)}:host(.studio-menu--outlined) .studio-menu-item.studio-menu-item--active{border-color:var(--studio-primary);background:hsl(var(--studio-primary-hsl)/.05)}:host(.studio-menu--ghost) .studio-menu-item:hover:not(.studio-menu-item--disabled):not(.studio-menu-item--active){background:transparent;color:var(--studio-primary)}:host(.studio-menu--ghost) .studio-menu-item.studio-menu-item--active{background:transparent;color:var(--studio-primary);text-decoration:underline;text-underline-offset:4px}.studio-menu-item__link,.studio-menu-item__content{display:flex;align-items:center;width:100%;padding:var(--menu-padding-y) var(--menu-padding-x);color:inherit;text-decoration:none;gap:.5rem}.studio-menu-item__link:visited{color:inherit}.studio-menu-item__link:hover{text-decoration:none}.studio-menu-item__inner{display:flex;align-items:center;gap:.5rem;width:100%}.studio-menu-item__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:var(--menu-icon-size);height:var(--menu-icon-size);color:var(--studio-text-secondary);transition:var(--menu-transition)}.studio-menu-item__icon--left{order:-1}.studio-menu-item__icon--right{order:1;margin-left:auto}.studio-menu-item:hover .studio-menu-item__icon,.studio-menu-item--active .studio-menu-item__icon{color:var(--studio-text-primary)}.studio-menu-item__label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--menu-font-size);line-height:var(--menu-line-height)}.studio-menu-item__badge{flex-shrink:0;margin-left:auto}.studio-menu-item__expand-icon{flex-shrink:0;margin-left:auto;width:1rem;height:1rem;color:var(--studio-text-secondary);opacity:.7;transition:transform .2s cubic-bezier(.4,0,.2,1),opacity var(--menu-transition)}.studio-menu-item:hover .studio-menu-item__expand-icon{opacity:1}.studio-menu__submenu{overflow:hidden;margin-top:var(--menu-gap);margin-left:calc(var(--menu-indent) - .25rem)}.studio-menu__submenu studio-menu{padding-left:0}.studio-menu__submenu .studio-menu__list{padding-left:.75rem;border-left:1px solid var(--studio-border-secondary);margin-left:.75rem}.studio-menu__separator{height:1px;margin:.375rem 0;background:var(--studio-border-secondary);opacity:.6}.studio-menu__divider{height:1px;margin:.125rem 0;background:var(--studio-border-secondary);opacity:.4}@keyframes expandCollapse{0%{opacity:0;max-height:0;transform:translateY(-4px)}to{opacity:1;max-height:1000px;transform:translateY(0)}}@media (max-width: 768px){:host(.studio-menu--horizontal){flex-direction:column}:host(.studio-menu--horizontal) .studio-menu__list{flex-direction:column}}\n"] }]
2260
- }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], defaultExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultExpanded", required: false }] }], expandOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandOnHover", required: false }] }], activeItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeItem", required: false }] }], routerLinkActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLinkActive", required: false }] }], selectOnNavigate: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectOnNavigate", required: false }] }], routerLinkActiveOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLinkActiveOptions", required: false }] }], keyboardNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyboardNavigation", required: false }] }], arrowNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowNavigation", required: false }] }], homeEndNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "homeEndNavigation", required: false }] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], spacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "spacing", required: false }] }], showDividers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDividers", required: false }] }], iconSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconSize", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], indentLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentLevel", required: false }] }], showExpandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExpandIcon", required: false }] }], expandIconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandIconPosition", required: false }] }], expandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandIcon", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], level: [{ type: i0.Input, args: [{ isSignal: true, alias: "level", required: false }] }], parentExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentExpanded", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], itemSelect: [{ type: i0.Output, args: ["itemSelect"] }], expandChange: [{ type: i0.Output, args: ["expandChange"] }], activeChange: [{ type: i0.Output, args: ["activeChange"] }], handleKeyDown: [{
3390
+ }, template: `
3391
+ @if (visible()) {
3392
+ <!-- Overlay -->
3393
+ <div
3394
+ class="studio-modal__overlay"
3395
+ [class.studio-modal__overlay--visible]="visible()"
3396
+ (click)="handleOverlayClick()"
3397
+ ></div>
3398
+
3399
+ <!-- Modal -->
3400
+ <div
3401
+ #modalPanel
3402
+ class="studio-modal__panel"
3403
+ [class.studio-modal__panel--visible]="visible()"
3404
+ role="dialog"
3405
+ [attr.aria-modal]="true"
3406
+ [attr.aria-labelledby]="showHeader() ? 'modal-title' : null"
3407
+ >
3408
+ <!-- Header -->
3409
+ @if (showHeader()) {
3410
+ <div class="studio-modal__header">
3411
+ @if (headerTemplate()) {
3412
+ <ng-container *ngTemplateOutlet="headerTemplate()!" />
3413
+ } @else {
3414
+ <h3 id="modal-title" class="studio-modal__title">{{ title() }}</h3>
3415
+ }
3416
+
3417
+ @if (showCloseButton()) {
3418
+ <button
3419
+ type="button"
3420
+ class="studio-modal__close"
3421
+ (click)="close()"
3422
+ aria-label="Close"
3423
+ >
3424
+ <studio-icon name="x" [size]="20" />
3425
+ </button>
3426
+ }
3427
+ </div>
3428
+ }
3429
+
3430
+ <!-- Content -->
3431
+ <div class="studio-modal__content">
3432
+ <ng-content />
3433
+ </div>
3434
+
3435
+ <!-- Footer -->
3436
+ @if (showFooter() && footerTemplate()) {
3437
+ <div class="studio-modal__footer">
3438
+ <ng-container *ngTemplateOutlet="footerTemplate()!" />
3439
+ </div>
3440
+ }
3441
+ </div>
3442
+ }
3443
+ `, styles: [":host{display:contents;font-family:var(--studio-font-family)}.studio-modal__overlay{position:fixed;inset:0;background:#00000080;z-index:1000;opacity:0;transition:opacity var(--studio-transition-normal);&--visible{opacity:1}}.studio-modal__panel{position:fixed;z-index:1001;background:var(--studio-bg-primary);border-radius:var(--studio-radius-lg);box-shadow:var(--studio-shadow-xl);display:flex;flex-direction:column;max-height:90vh;opacity:0;transform:scale(.95);transition:opacity var(--studio-transition-normal),transform var(--studio-transition-normal);&--visible{opacity:1;transform:scale(1)}}:host(.modal--center) .studio-modal__panel{top:50%;left:50%;transform:translate(-50%,-50%) scale(.95);&--visible{transform:translate(-50%,-50%) scale(1)}}:host(.modal--top) .studio-modal__panel{top:5vh;left:50%;transform:translate(-50%,-20px) scale(.95);&--visible{transform:translate(-50%) scale(1)}}:host(.modal--bottom) .studio-modal__panel{bottom:5vh;left:50%;transform:translate(-50%,20px) scale(.95);&--visible{transform:translate(-50%) scale(1)}}:host(.modal--sm) .studio-modal__panel{width:90%;max-width:400px}:host(.modal--md) .studio-modal__panel{width:90%;max-width:600px}:host(.modal--lg) .studio-modal__panel{width:90%;max-width:800px}:host(.modal--xl) .studio-modal__panel{width:90%;max-width:1200px}:host(.modal--full) .studio-modal__panel{width:95vw;height:95vh;max-width:none;max-height:none}:host(.modal--bordered) .studio-modal__panel{border:1px solid var(--studio-border-primary)}:host(.modal--minimal) .studio-modal__panel{box-shadow:var(--studio-shadow-md)}:host(.modal--fade) .studio-modal__panel{transform:translate(-50%,-50%);&--visible{transform:translate(-50%,-50%)}}:host(.modal--slide-down) .studio-modal__panel{transform:translate(-50%,-60%);&--visible{transform:translate(-50%,-50%)}}:host(.modal--none) .studio-modal__panel{transition:none}:host(.modal--none) .studio-modal__overlay{transition:none}.studio-modal__header{display:flex;align-items:center;justify-content:space-between;padding:1.5rem;border-bottom:1px solid var(--studio-border-primary);flex-shrink:0}.studio-modal__title{margin:0;font-size:1.25rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast)}.studio-modal__close:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-modal__close:active{transform:scale(.95)}.studio-modal__content{padding:1.5rem;overflow-y:auto;flex:1}.studio-modal__footer{padding:1.5rem;border-top:1px solid var(--studio-border-primary);display:flex;gap:.75rem;justify-content:flex-end;flex-shrink:0}\n"] }]
3444
+ }], ctorParameters: () => [], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], animation: [{ type: i0.Input, args: [{ isSignal: true, alias: "animation", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], closeOnOverlayClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnOverlayClick", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], visibleChange: [{ type: i0.Output, args: ["visibleChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], headerTemplate: [{ type: i0.ContentChild, args: ['modalHeader', { isSignal: true }] }], footerTemplate: [{ type: i0.ContentChild, args: ['modalFooter', { isSignal: true }] }], modalPanel: [{ type: i0.ViewChild, args: ['modalPanel', { isSignal: true }] }], handleEscape: [{
2261
3445
  type: HostListener,
2262
- args: ['keydown', ['$event']]
3446
+ args: ['document:keydown.escape', ['$event']]
2263
3447
  }] } });
2264
3448
 
2265
3449
  /**
@@ -2322,6 +3506,117 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2322
3506
  }, template: "<div class=\"studio-navbar__left\">\n <ng-content select=\"[navbarLeft]\" />\n</div>\n\n<div class=\"studio-navbar__center\">\n <ng-content select=\"[navbarCenter]\" />\n</div>\n\n<div class=\"studio-navbar__right\">\n <ng-content select=\"[navbarRight]\" />\n</div>\n\n<ng-content />\n", styles: [":host{display:flex;align-items:center;width:100%;min-height:var(--navbar-height, 4rem);padding:0 var(--navbar-padding-x, 1.5rem);gap:var(--navbar-gap, 1.5rem);background:var(--studio-bg-primary);transition:all .2s cubic-bezier(.4,0,.2,1);--navbar-height: 4rem;--navbar-padding-x: 1.5rem;--navbar-gap: 1.5rem;--navbar-z-index: 1000}:host(.studio-navbar--sm){--navbar-height: 3.5rem;--navbar-padding-x: 1rem;--navbar-gap: 1rem}:host(.studio-navbar--md){--navbar-height: 4rem;--navbar-padding-x: 1.5rem;--navbar-gap: 1.5rem}:host(.studio-navbar--lg){--navbar-height: 5rem;--navbar-padding-x: 2rem;--navbar-gap: 2rem}:host(.studio-navbar--sticky){position:sticky;top:0;z-index:var(--navbar-z-index)}:host(.studio-navbar--blur){-webkit-backdrop-filter:blur(12px) saturate(180%);backdrop-filter:blur(12px) saturate(180%);background:hsl(var(--studio-bg-primary-hsl)/.8)}:host(.studio-navbar--default){background:var(--studio-bg-primary);border-bottom:1px solid hsl(var(--studio-border-primary-hsl)/.1)}:host(.studio-navbar--filled){background:var(--studio-bg-secondary);border-bottom:1px solid var(--studio-border-secondary)}:host(.studio-navbar--outlined){background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-left:none;border-right:none}:host(.studio-navbar--ghost){background:transparent}:host(.studio-navbar--transparent){background:transparent}:host(.studio-navbar--primary){background:var(--studio-primary);color:var(--studio-primary-contrast);border-bottom:1px solid hsl(var(--studio-primary-hsl)/.2)}:host(.studio-navbar--secondary){background:var(--studio-secondary);color:var(--studio-secondary-contrast);border-bottom:1px solid hsl(var(--studio-secondary-hsl)/.2)}:host(.studio-navbar--bordered){border-bottom:1px solid var(--studio-border-secondary)}:host(.studio-navbar--shadow-none){box-shadow:none}:host(.studio-navbar--shadow-sm){box-shadow:0 1px 3px #0000001a,0 1px 2px -1px #0000001a}:host(.studio-navbar--shadow-md){box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}:host(.studio-navbar--shadow-lg){box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.studio-navbar__left{display:flex;align-items:center;gap:var(--navbar-gap);flex-shrink:0}.studio-navbar__center{display:flex;align-items:center;justify-content:center;gap:calc(var(--navbar-gap) * .75);flex:1}.studio-navbar__right{display:flex;align-items:center;gap:calc(var(--navbar-gap) * .5);flex-shrink:0;margin-left:auto}@media (max-width: 768px){:host{--navbar-padding-x: 1rem;--navbar-gap: 1rem}.studio-navbar__center{display:none}}\n"] }]
2323
3507
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], shadow: [{ type: i0.Input, args: [{ isSignal: true, alias: "shadow", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], customHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "customHeight", required: false }] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], blurBg: [{ type: i0.Input, args: [{ isSignal: true, alias: "blurBg", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], navbarClick: [{ type: i0.Output, args: ["navbarClick"] }] } });
2324
3508
 
3509
+ /**
3510
+ * RadioButton component for selecting a single option from a group
3511
+ *
3512
+ * @example
3513
+ * <studio-radio-button
3514
+ * [(ngModel)]="selectedValue"
3515
+ * [value]="'option1'"
3516
+ * label="Option 1"
3517
+ * name="options"
3518
+ * />
3519
+ */
3520
+ class RadioButtonComponent {
3521
+ configService = inject(StudioConfigService);
3522
+ radioDefaults = computed(() => this.configService.config().components?.radioButton, ...(ngDevMode ? [{ debugName: "radioDefaults" }] : []));
3523
+ size = input(this.radioDefaults()?.size ?? 'md', ...(ngDevMode ? [{ debugName: "size" }] : []));
3524
+ color = input(this.radioDefaults()?.color ?? 'primary', ...(ngDevMode ? [{ debugName: "color" }] : []));
3525
+ variant = input(this.radioDefaults()?.variant ?? 'default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
3526
+ radius = input(this.radioDefaults()?.radius ?? 'full', ...(ngDevMode ? [{ debugName: "radius" }] : []));
3527
+ label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
3528
+ labelPosition = input(this.radioDefaults()?.labelPosition ?? 'right', ...(ngDevMode ? [{ debugName: "labelPosition" }] : []));
3529
+ description = input(...(ngDevMode ? [undefined, { debugName: "description" }] : []));
3530
+ hint = input(...(ngDevMode ? [undefined, { debugName: "hint" }] : []));
3531
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
3532
+ error = input(false, ...(ngDevMode ? [{ debugName: "error" }] : []));
3533
+ errorMessage = input(...(ngDevMode ? [undefined, { debugName: "errorMessage" }] : []));
3534
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
3535
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
3536
+ name = input(...(ngDevMode ? [undefined, { debugName: "name" }] : []));
3537
+ tabIndex = input(0, ...(ngDevMode ? [{ debugName: "tabIndex" }] : []));
3538
+ value = input(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
3539
+ changed = output();
3540
+ internalValue = signal(null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
3541
+ isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : []));
3542
+ radioId = signal(`studio-radio-${Math.random().toString(36).substr(2, 9)}`, ...(ngDevMode ? [{ debugName: "radioId" }] : []));
3543
+ hostClasses = computed(() => ({
3544
+ 'studio-radio-wrapper': true,
3545
+ [`studio-radio-wrapper--${this.size()}`]: true,
3546
+ 'studio-radio-wrapper--disabled': this.disabled(),
3547
+ 'studio-radio-wrapper--error': this.error(),
3548
+ 'studio-radio-wrapper--focused': this.isFocused(),
3549
+ 'studio-radio-wrapper--label-left': this.labelPosition() === 'left'
3550
+ }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
3551
+ radioClasses = computed(() => ({
3552
+ 'studio-radio': true,
3553
+ [`studio-radio--${this.size()}`]: true,
3554
+ [`studio-radio--${this.color()}`]: true,
3555
+ [`studio-radio--${this.variant()}`]: true,
3556
+ [`studio-radio--radius-${this.radius()}`]: true,
3557
+ 'studio-radio--checked': this.isChecked(),
3558
+ 'studio-radio--disabled': this.disabled(),
3559
+ 'studio-radio--error': this.error()
3560
+ }), ...(ngDevMode ? [{ debugName: "radioClasses" }] : []));
3561
+ showError = computed(() => this.error() && this.errorMessage(), ...(ngDevMode ? [{ debugName: "showError" }] : []));
3562
+ showHint = computed(() => !this.error() && this.hint(), ...(ngDevMode ? [{ debugName: "showHint" }] : []));
3563
+ isChecked = computed(() => this.internalValue() === this.value(), ...(ngDevMode ? [{ debugName: "isChecked" }] : []));
3564
+ onChange = () => { };
3565
+ onTouched = () => { };
3566
+ writeValue(value) {
3567
+ this.internalValue.set(value);
3568
+ }
3569
+ registerOnChange(fn) {
3570
+ this.onChange = fn;
3571
+ }
3572
+ registerOnTouched(fn) {
3573
+ this.onTouched = fn;
3574
+ }
3575
+ setDisabledState(isDisabled) { }
3576
+ handleChange(event) {
3577
+ if (this.disabled() || this.readonly()) {
3578
+ event.preventDefault();
3579
+ return;
3580
+ }
3581
+ const inputValue = this.value();
3582
+ this.internalValue.set(inputValue);
3583
+ this.onChange(inputValue);
3584
+ this.changed.emit(inputValue);
3585
+ }
3586
+ handleFocus() {
3587
+ this.isFocused.set(true);
3588
+ }
3589
+ handleBlur() {
3590
+ this.isFocused.set(false);
3591
+ this.onTouched();
3592
+ }
3593
+ handleLabelClick(event) {
3594
+ if (this.disabled() || this.readonly()) {
3595
+ event.preventDefault();
3596
+ }
3597
+ }
3598
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: RadioButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3599
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: RadioButtonComponent, isStandalone: true, selector: "studio-radio-button", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", 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 }, description: { classPropertyName: "description", publicName: "description", 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { properties: { "class": "hostClasses()", "attr.data-size": "size()", "attr.data-color": "color()", "attr.data-disabled": "disabled()", "attr.data-error": "error()" } }, providers: [{
3600
+ provide: NG_VALUE_ACCESSOR,
3601
+ useExisting: forwardRef(() => RadioButtonComponent),
3602
+ multi: true
3603
+ }], ngImport: i0, template: "<label\n [for]=\"radioId()\"\n [ngClass]=\"hostClasses()\"\n (click)=\"handleLabelClick($event)\"\n>\n <input\n type=\"radio\"\n [id]=\"radioId()\"\n [name]=\"name()\"\n [value]=\"value()\"\n [checked]=\"isChecked()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [tabIndex]=\"tabIndex()\"\n [attr.aria-checked]=\"isChecked() ? 'true' : 'false'\"\n [attr.aria-label]=\"label() || undefined\"\n [attr.aria-describedby]=\"showHint() || showError() ? radioId() + '-description' : undefined\"\n [attr.aria-invalid]=\"error()\"\n [attr.aria-required]=\"required()\"\n class=\"studio-radio__input\"\n (change)=\"handleChange($event)\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n />\n\n <span [ngClass]=\"radioClasses()\">\n @if (isChecked()) {\n <span class=\"studio-radio__dot\"></span>\n }\n </span>\n\n @if (label() || description()) {\n <span class=\"studio-radio__label-wrapper\">\n @if (label()) {\n <span class=\"studio-radio__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-radio__required\" aria-hidden=\"true\">*</span>\n }\n </span>\n }\n\n @if (description()) {\n <span class=\"studio-radio__description\">\n {{ description() }}\n </span>\n }\n </span>\n }\n</label>\n\n@if (showHint() || showError()) {\n <div\n [id]=\"radioId() + '-description'\"\n class=\"studio-radio__info\"\n >\n @if (showError()) {\n <span class=\"studio-radio__error\">\n {{ errorMessage() }}\n </span>\n }\n\n @if (showHint()) {\n <span class=\"studio-radio__hint\">\n {{ hint() }}\n </span>\n }\n </div>\n}\n", styles: [":host{display:inline-flex;flex-direction:column;font-family:var(--studio-font-family)!important}.studio-radio-wrapper{display:inline-flex;align-items:flex-start;gap:var(--studio-spacing-sm);cursor:pointer;-webkit-user-select:none;user-select:none;position:relative}.studio-radio-wrapper--label-left{flex-direction:row-reverse}.studio-radio-wrapper--disabled{cursor:not-allowed;opacity:.5}.studio-radio-wrapper--sm{font-size:var(--studio-font-size-sm)}.studio-radio-wrapper--md{font-size:var(--studio-font-size-base)}.studio-radio-wrapper--lg{font-size:var(--studio-font-size-lg)}.studio-radio__input{position:absolute;opacity:0;pointer-events:none;width:0;height:0}.studio-radio{position:relative;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;border:2px solid var(--studio-border-primary);background-color:var(--studio-bg-primary);transition:all var(--studio-transition-base);border-radius:var(--studio-radius-full)}.studio-radio--sm{width:1rem;height:1rem}.studio-radio--md{width:1.25rem;height:1.25rem}.studio-radio--lg{width:1.5rem;height:1.5rem}.studio-radio--radius-none{border-radius:0}.studio-radio--radius-sm{border-radius:var(--studio-radius-sm)}.studio-radio--radius-md{border-radius:var(--studio-radius-md)}.studio-radio--radius-lg{border-radius:var(--studio-radius-lg)}.studio-radio--radius-full{border-radius:var(--studio-radius-full)}.studio-radio--default.studio-radio--checked{border-color:transparent}.studio-radio--default.studio-radio--checked.studio-radio--primary{background-color:var(--studio-primary)}.studio-radio--default.studio-radio--checked.studio-radio--secondary{background-color:var(--studio-secondary)}.studio-radio--default.studio-radio--checked.studio-radio--success{background-color:var(--studio-success)}.studio-radio--default.studio-radio--checked.studio-radio--error{background-color:var(--studio-error)}.studio-radio--outlined.studio-radio--checked{background-color:transparent}.studio-radio--outlined.studio-radio--checked.studio-radio--primary{border-color:var(--studio-primary)}.studio-radio--outlined.studio-radio--checked.studio-radio--primary .studio-radio__dot{background-color:var(--studio-primary)}.studio-radio--outlined.studio-radio--checked.studio-radio--secondary{border-color:var(--studio-secondary)}.studio-radio--outlined.studio-radio--checked.studio-radio--secondary .studio-radio__dot{background-color:var(--studio-secondary)}.studio-radio--outlined.studio-radio--checked.studio-radio--success{border-color:var(--studio-success)}.studio-radio--outlined.studio-radio--checked.studio-radio--success .studio-radio__dot{background-color:var(--studio-success)}.studio-radio--outlined.studio-radio--checked.studio-radio--error{border-color:var(--studio-error)}.studio-radio--outlined.studio-radio--checked.studio-radio--error .studio-radio__dot{background-color:var(--studio-error)}.studio-radio--filled.studio-radio--primary{background-color:var(--studio-primary-bg);border-color:var(--studio-primary-bg)}.studio-radio--filled.studio-radio--secondary{background-color:var(--studio-secondary-bg);border-color:var(--studio-secondary-bg)}.studio-radio--filled.studio-radio--success{background-color:var(--studio-success-bg);border-color:var(--studio-success-bg)}.studio-radio--filled.studio-radio--error{background-color:var(--studio-error-bg);border-color:var(--studio-error-bg)}.studio-radio--filled.studio-radio--checked.studio-radio--primary{background-color:var(--studio-primary);border-color:var(--studio-primary)}.studio-radio--filled.studio-radio--checked.studio-radio--secondary{background-color:var(--studio-secondary);border-color:var(--studio-secondary)}.studio-radio--filled.studio-radio--checked.studio-radio--success{background-color:var(--studio-success);border-color:var(--studio-success)}.studio-radio--filled.studio-radio--checked.studio-radio--error{background-color:var(--studio-error);border-color:var(--studio-error)}.studio-radio--error:not(.studio-radio--checked){border-color:var(--studio-error)}.studio-radio:hover:not(.studio-radio--disabled){border-color:var(--studio-border-secondary)}.studio-radio__input:focus-visible+.studio-radio{outline:2px solid var(--studio-primary);outline-offset:2px}.studio-radio__dot{border-radius:var(--studio-radius-full);background-color:var(--studio-text-inverse);opacity:0;transform:scale(.5);transition:all var(--studio-transition-fast)}.studio-radio--sm .studio-radio__dot{width:.375rem;height:.375rem}.studio-radio--md .studio-radio__dot{width:.5rem;height:.5rem}.studio-radio--lg .studio-radio__dot{width:.625rem;height:.625rem}.studio-radio--checked .studio-radio__dot{opacity:1;transform:scale(1)}.studio-radio__label-wrapper{display:flex;flex-direction:column;gap:var(--studio-spacing-xs)}.studio-radio__label{font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);line-height:var(--studio-line-height-normal)}.studio-radio__description{font-size:var(--studio-font-size-sm);color:var(--studio-text-secondary);line-height:var(--studio-line-height-normal)}.studio-radio__required{color:var(--studio-error);margin-left:var(--studio-spacing-xs)}.studio-radio__info{display:flex;flex-direction:column;gap:var(--studio-spacing-xs);margin-top:var(--studio-spacing-xs);padding-left:calc(var(--studio-spacing-sm) + 1.25rem)}.studio-radio-wrapper--label-left+.studio-radio__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1.25rem)}.studio-radio-wrapper--sm .studio-radio__info{padding-left:calc(var(--studio-spacing-sm) + 1rem)}.studio-radio-wrapper--sm.studio-radio-wrapper--label-left .studio-radio__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1rem)}.studio-radio-wrapper--lg .studio-radio__info{padding-left:calc(var(--studio-spacing-sm) + 1.5rem)}.studio-radio-wrapper--lg.studio-radio-wrapper--label-left .studio-radio__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1.5rem)}.studio-radio__hint{font-size:var(--studio-font-size-xs);color:var(--studio-text-secondary);line-height:var(--studio-line-height-normal)}.studio-radio__error{font-size:var(--studio-font-size-xs);color:var(--studio-error);line-height:var(--studio-line-height-normal)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
3604
+ }
3605
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: RadioButtonComponent, decorators: [{
3606
+ type: Component,
3607
+ args: [{ selector: 'studio-radio-button', standalone: true, imports: [CommonModule], providers: [{
3608
+ provide: NG_VALUE_ACCESSOR,
3609
+ useExisting: forwardRef(() => RadioButtonComponent),
3610
+ multi: true
3611
+ }], host: {
3612
+ '[class]': 'hostClasses()',
3613
+ '[attr.data-size]': 'size()',
3614
+ '[attr.data-color]': 'color()',
3615
+ '[attr.data-disabled]': 'disabled()',
3616
+ '[attr.data-error]': 'error()'
3617
+ }, template: "<label\n [for]=\"radioId()\"\n [ngClass]=\"hostClasses()\"\n (click)=\"handleLabelClick($event)\"\n>\n <input\n type=\"radio\"\n [id]=\"radioId()\"\n [name]=\"name()\"\n [value]=\"value()\"\n [checked]=\"isChecked()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [tabIndex]=\"tabIndex()\"\n [attr.aria-checked]=\"isChecked() ? 'true' : 'false'\"\n [attr.aria-label]=\"label() || undefined\"\n [attr.aria-describedby]=\"showHint() || showError() ? radioId() + '-description' : undefined\"\n [attr.aria-invalid]=\"error()\"\n [attr.aria-required]=\"required()\"\n class=\"studio-radio__input\"\n (change)=\"handleChange($event)\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n />\n\n <span [ngClass]=\"radioClasses()\">\n @if (isChecked()) {\n <span class=\"studio-radio__dot\"></span>\n }\n </span>\n\n @if (label() || description()) {\n <span class=\"studio-radio__label-wrapper\">\n @if (label()) {\n <span class=\"studio-radio__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-radio__required\" aria-hidden=\"true\">*</span>\n }\n </span>\n }\n\n @if (description()) {\n <span class=\"studio-radio__description\">\n {{ description() }}\n </span>\n }\n </span>\n }\n</label>\n\n@if (showHint() || showError()) {\n <div\n [id]=\"radioId() + '-description'\"\n class=\"studio-radio__info\"\n >\n @if (showError()) {\n <span class=\"studio-radio__error\">\n {{ errorMessage() }}\n </span>\n }\n\n @if (showHint()) {\n <span class=\"studio-radio__hint\">\n {{ hint() }}\n </span>\n }\n </div>\n}\n", styles: [":host{display:inline-flex;flex-direction:column;font-family:var(--studio-font-family)!important}.studio-radio-wrapper{display:inline-flex;align-items:flex-start;gap:var(--studio-spacing-sm);cursor:pointer;-webkit-user-select:none;user-select:none;position:relative}.studio-radio-wrapper--label-left{flex-direction:row-reverse}.studio-radio-wrapper--disabled{cursor:not-allowed;opacity:.5}.studio-radio-wrapper--sm{font-size:var(--studio-font-size-sm)}.studio-radio-wrapper--md{font-size:var(--studio-font-size-base)}.studio-radio-wrapper--lg{font-size:var(--studio-font-size-lg)}.studio-radio__input{position:absolute;opacity:0;pointer-events:none;width:0;height:0}.studio-radio{position:relative;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;border:2px solid var(--studio-border-primary);background-color:var(--studio-bg-primary);transition:all var(--studio-transition-base);border-radius:var(--studio-radius-full)}.studio-radio--sm{width:1rem;height:1rem}.studio-radio--md{width:1.25rem;height:1.25rem}.studio-radio--lg{width:1.5rem;height:1.5rem}.studio-radio--radius-none{border-radius:0}.studio-radio--radius-sm{border-radius:var(--studio-radius-sm)}.studio-radio--radius-md{border-radius:var(--studio-radius-md)}.studio-radio--radius-lg{border-radius:var(--studio-radius-lg)}.studio-radio--radius-full{border-radius:var(--studio-radius-full)}.studio-radio--default.studio-radio--checked{border-color:transparent}.studio-radio--default.studio-radio--checked.studio-radio--primary{background-color:var(--studio-primary)}.studio-radio--default.studio-radio--checked.studio-radio--secondary{background-color:var(--studio-secondary)}.studio-radio--default.studio-radio--checked.studio-radio--success{background-color:var(--studio-success)}.studio-radio--default.studio-radio--checked.studio-radio--error{background-color:var(--studio-error)}.studio-radio--outlined.studio-radio--checked{background-color:transparent}.studio-radio--outlined.studio-radio--checked.studio-radio--primary{border-color:var(--studio-primary)}.studio-radio--outlined.studio-radio--checked.studio-radio--primary .studio-radio__dot{background-color:var(--studio-primary)}.studio-radio--outlined.studio-radio--checked.studio-radio--secondary{border-color:var(--studio-secondary)}.studio-radio--outlined.studio-radio--checked.studio-radio--secondary .studio-radio__dot{background-color:var(--studio-secondary)}.studio-radio--outlined.studio-radio--checked.studio-radio--success{border-color:var(--studio-success)}.studio-radio--outlined.studio-radio--checked.studio-radio--success .studio-radio__dot{background-color:var(--studio-success)}.studio-radio--outlined.studio-radio--checked.studio-radio--error{border-color:var(--studio-error)}.studio-radio--outlined.studio-radio--checked.studio-radio--error .studio-radio__dot{background-color:var(--studio-error)}.studio-radio--filled.studio-radio--primary{background-color:var(--studio-primary-bg);border-color:var(--studio-primary-bg)}.studio-radio--filled.studio-radio--secondary{background-color:var(--studio-secondary-bg);border-color:var(--studio-secondary-bg)}.studio-radio--filled.studio-radio--success{background-color:var(--studio-success-bg);border-color:var(--studio-success-bg)}.studio-radio--filled.studio-radio--error{background-color:var(--studio-error-bg);border-color:var(--studio-error-bg)}.studio-radio--filled.studio-radio--checked.studio-radio--primary{background-color:var(--studio-primary);border-color:var(--studio-primary)}.studio-radio--filled.studio-radio--checked.studio-radio--secondary{background-color:var(--studio-secondary);border-color:var(--studio-secondary)}.studio-radio--filled.studio-radio--checked.studio-radio--success{background-color:var(--studio-success);border-color:var(--studio-success)}.studio-radio--filled.studio-radio--checked.studio-radio--error{background-color:var(--studio-error);border-color:var(--studio-error)}.studio-radio--error:not(.studio-radio--checked){border-color:var(--studio-error)}.studio-radio:hover:not(.studio-radio--disabled){border-color:var(--studio-border-secondary)}.studio-radio__input:focus-visible+.studio-radio{outline:2px solid var(--studio-primary);outline-offset:2px}.studio-radio__dot{border-radius:var(--studio-radius-full);background-color:var(--studio-text-inverse);opacity:0;transform:scale(.5);transition:all var(--studio-transition-fast)}.studio-radio--sm .studio-radio__dot{width:.375rem;height:.375rem}.studio-radio--md .studio-radio__dot{width:.5rem;height:.5rem}.studio-radio--lg .studio-radio__dot{width:.625rem;height:.625rem}.studio-radio--checked .studio-radio__dot{opacity:1;transform:scale(1)}.studio-radio__label-wrapper{display:flex;flex-direction:column;gap:var(--studio-spacing-xs)}.studio-radio__label{font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);line-height:var(--studio-line-height-normal)}.studio-radio__description{font-size:var(--studio-font-size-sm);color:var(--studio-text-secondary);line-height:var(--studio-line-height-normal)}.studio-radio__required{color:var(--studio-error);margin-left:var(--studio-spacing-xs)}.studio-radio__info{display:flex;flex-direction:column;gap:var(--studio-spacing-xs);margin-top:var(--studio-spacing-xs);padding-left:calc(var(--studio-spacing-sm) + 1.25rem)}.studio-radio-wrapper--label-left+.studio-radio__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1.25rem)}.studio-radio-wrapper--sm .studio-radio__info{padding-left:calc(var(--studio-spacing-sm) + 1rem)}.studio-radio-wrapper--sm.studio-radio-wrapper--label-left .studio-radio__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1rem)}.studio-radio-wrapper--lg .studio-radio__info{padding-left:calc(var(--studio-spacing-sm) + 1.5rem)}.studio-radio-wrapper--lg.studio-radio-wrapper--label-left .studio-radio__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1.5rem)}.studio-radio__hint{font-size:var(--studio-font-size-xs);color:var(--studio-text-secondary);line-height:var(--studio-line-height-normal)}.studio-radio__error{font-size:var(--studio-font-size-xs);color:var(--studio-error);line-height:var(--studio-line-height-normal)}\n"] }]
3618
+ }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
3619
+
2325
3620
  class SelectComponent {
2326
3621
  configService = inject(StudioConfigService);
2327
3622
  selectDefaults = computed(() => this.configService.config().components?.select, ...(ngDevMode ? [{ debugName: "selectDefaults" }] : []));
@@ -2722,6 +4017,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2722
4017
  *
2723
4018
  * @example
2724
4019
  * <studio-switch [(checked)]="isEnabled" label="Enable feature" />
4020
+ * <studio-switch [(ngModel)]="isEnabled" label="Enable feature" />
2725
4021
  */
2726
4022
  class SwitchComponent {
2727
4023
  configService = inject(StudioConfigService);
@@ -2737,11 +4033,25 @@ class SwitchComponent {
2737
4033
  size = withConfigDefault(this.sizeInput, computed(() => this.switchDefaults()?.size), 'md');
2738
4034
  color = withConfigDefault(this.colorInput, computed(() => this.switchDefaults()?.color), 'primary');
2739
4035
  checkedChange = output();
4036
+ internalChecked = signal(false, ...(ngDevMode ? [{ debugName: "internalChecked" }] : []));
4037
+ onChange = () => { };
4038
+ onTouched = () => { };
2740
4039
  iconSize = computed(() => {
2741
4040
  const sizeMap = { sm: 10, md: 12, lg: 14 };
2742
4041
  return sizeMap[this.size()];
2743
4042
  }, ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
2744
- 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" }] : []));
4043
+ hostClasses = computed(() => classNames('studio-switch', `studio-switch--${this.size()}`, `studio-switch--${this.color()}`, this.internalChecked() && 'studio-switch--checked', this.disabled() && 'studio-switch--disabled'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
4044
+ writeValue(value) {
4045
+ this.internalChecked.set(value ?? false);
4046
+ this.checked.set(value ?? false);
4047
+ }
4048
+ registerOnChange(fn) {
4049
+ this.onChange = fn;
4050
+ }
4051
+ registerOnTouched(fn) {
4052
+ this.onTouched = fn;
4053
+ }
4054
+ setDisabledState(isDisabled) { }
2745
4055
  handleClick() {
2746
4056
  if (this.disabled())
2747
4057
  return;
@@ -2754,12 +4064,21 @@ class SwitchComponent {
2754
4064
  this.toggle();
2755
4065
  }
2756
4066
  toggle() {
2757
- const newValue = !this.checked();
4067
+ const newValue = !this.internalChecked();
4068
+ this.internalChecked.set(newValue);
2758
4069
  this.checked.set(newValue);
4070
+ this.onChange(newValue);
4071
+ this.onTouched();
2759
4072
  this.checkedChange.emit(newValue);
2760
4073
  }
2761
4074
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SwitchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2762
- 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: `
4075
+ 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": "internalChecked()", "attr.aria-disabled": "disabled() ? \"true\" : null", "attr.aria-label": "ariaLabel() || label()", "tabindex": "disabled() ? -1 : 0" } }, providers: [
4076
+ {
4077
+ provide: NG_VALUE_ACCESSOR,
4078
+ useExisting: forwardRef(() => SwitchComponent),
4079
+ multi: true
4080
+ }
4081
+ ], ngImport: i0, template: `
2763
4082
  <span class="studio-switch__container">
2764
4083
  @if (label() && labelPosition() === 'left') {
2765
4084
  <span class="studio-switch__label studio-switch__label--left">
@@ -2770,7 +4089,7 @@ class SwitchComponent {
2770
4089
  <span class="studio-switch__track">
2771
4090
  <span class="studio-switch__thumb">
2772
4091
  @if (showIcons()) {
2773
- @if (checked()) {
4092
+ @if (internalChecked()) {
2774
4093
  <studio-icon name="check" [size]="iconSize()" color="inherit" />
2775
4094
  } @else {
2776
4095
  <studio-icon name="x" [size]="iconSize()" color="inherit" />
@@ -2789,10 +4108,16 @@ class SwitchComponent {
2789
4108
  }
2790
4109
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SwitchComponent, decorators: [{
2791
4110
  type: Component,
2792
- args: [{ selector: 'studio-switch', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
4111
+ args: [{ selector: 'studio-switch', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
4112
+ {
4113
+ provide: NG_VALUE_ACCESSOR,
4114
+ useExisting: forwardRef(() => SwitchComponent),
4115
+ multi: true
4116
+ }
4117
+ ], host: {
2793
4118
  '[class]': 'hostClasses()',
2794
4119
  '[attr.role]': '"switch"',
2795
- '[attr.aria-checked]': 'checked()',
4120
+ '[attr.aria-checked]': 'internalChecked()',
2796
4121
  '[attr.aria-disabled]': 'disabled() ? "true" : null',
2797
4122
  '[attr.aria-label]': 'ariaLabel() || label()',
2798
4123
  '(click)': 'handleClick()',
@@ -2810,7 +4135,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2810
4135
  <span class="studio-switch__track">
2811
4136
  <span class="studio-switch__thumb">
2812
4137
  @if (showIcons()) {
2813
- @if (checked()) {
4138
+ @if (internalChecked()) {
2814
4139
  <studio-icon name="check" [size]="iconSize()" color="inherit" />
2815
4140
  } @else {
2816
4141
  <studio-icon name="x" [size]="iconSize()" color="inherit" />
@@ -2832,6 +4157,86 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2832
4157
  * Switch component
2833
4158
  */
2834
4159
 
4160
+ class TabsComponent {
4161
+ tabs = input.required(...(ngDevMode ? [{ debugName: "tabs" }] : []));
4162
+ activeTab = signal('', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
4163
+ variant = input('line', ...(ngDevMode ? [{ debugName: "variant" }] : []));
4164
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
4165
+ orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
4166
+ tabChange = output();
4167
+ hostClasses = computed(() => classNames('tabs', 'tabs--' + this.variant(), 'tabs--' + this.size(), this.orientation() === 'vertical' && 'tabs--vertical'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
4168
+ iconSize = computed(() => {
4169
+ const sizeMap = { sm: 14, md: 16, lg: 18 };
4170
+ return sizeMap[this.size()];
4171
+ }, ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
4172
+ constructor() {
4173
+ effect(() => {
4174
+ // Set first tab as active by default when tabs change
4175
+ const tabsList = this.tabs();
4176
+ const firstTab = tabsList[0];
4177
+ if (firstTab && !this.activeTab()) {
4178
+ this.activeTab.set(firstTab.id);
4179
+ }
4180
+ });
4181
+ }
4182
+ selectTab(tabId) {
4183
+ this.activeTab.set(tabId);
4184
+ this.tabChange.emit(tabId);
4185
+ }
4186
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4187
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: TabsComponent, isStandalone: true, selector: "studio-tabs", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { tabChange: "tabChange" }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
4188
+ <div class="tabs__header" [class.tabs__header--vertical]="orientation() === 'vertical'">
4189
+ @for (tab of tabs(); track tab.id) {
4190
+ <button
4191
+ type="button"
4192
+ class="tabs__tab"
4193
+ [class.tabs__tab--active]="activeTab() === tab.id"
4194
+ [class.tabs__tab--disabled]="tab.disabled"
4195
+ [disabled]="tab.disabled"
4196
+ (click)="selectTab(tab.id)"
4197
+ >
4198
+ @if (tab.icon) {
4199
+ <studio-icon [name]="tab.icon" [size]="iconSize()" />
4200
+ }
4201
+ <span>{{ tab.label }}</span>
4202
+ </button>
4203
+ }
4204
+ </div>
4205
+
4206
+ <div class="tabs__content">
4207
+ <ng-content />
4208
+ </div>
4209
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;font-family:var(--studio-font-family)}:host(.tabs--vertical){flex-direction:row}.tabs__header{display:flex;gap:.25rem;border-bottom:2px solid var(--studio-border-primary);&--vertical{flex-direction:column;border-bottom:none;border-right:2px solid var(--studio-border-primary);padding-right:1rem}}.tabs__tab{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;background:none;border:none;border-bottom:2px solid transparent;color:var(--studio-text-secondary);font-size:.875rem;font-weight:var(--studio-font-weight-medium);cursor:pointer;transition:all var(--studio-transition-fast);position:relative;margin-bottom:-2px;&--active{color:var(--studio-primary);border-bottom-color:var(--studio-primary)}&--disabled{opacity:.5;cursor:not-allowed}}.tabs__tab:hover:not(:disabled){color:var(--studio-text-primary);background:var(--studio-bg-secondary)}:host(.tabs--pills) .tabs__header{border-bottom:none}:host(.tabs--pills) .tabs__tab{border-radius:var(--studio-radius-md);border-bottom:none;margin-bottom:0;&--active{background:var(--studio-primary);color:#fff}}:host(.tabs--enclosed) .tabs__tab{border:1px solid transparent;border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0;margin-bottom:-1px;&--active{border-color:var(--studio-border-primary);border-bottom-color:var(--studio-bg-primary);background:var(--studio-bg-primary)}}:host(.tabs--sm) .tabs__tab{padding:.5rem .75rem;font-size:.8125rem}:host(.tabs--lg) .tabs__tab{padding:1rem 1.25rem;font-size:1rem}.tabs__content{padding:1.5rem 0}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4210
+ }
4211
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TabsComponent, decorators: [{
4212
+ type: Component,
4213
+ args: [{ selector: 'studio-tabs', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
4214
+ '[class]': 'hostClasses()',
4215
+ }, template: `
4216
+ <div class="tabs__header" [class.tabs__header--vertical]="orientation() === 'vertical'">
4217
+ @for (tab of tabs(); track tab.id) {
4218
+ <button
4219
+ type="button"
4220
+ class="tabs__tab"
4221
+ [class.tabs__tab--active]="activeTab() === tab.id"
4222
+ [class.tabs__tab--disabled]="tab.disabled"
4223
+ [disabled]="tab.disabled"
4224
+ (click)="selectTab(tab.id)"
4225
+ >
4226
+ @if (tab.icon) {
4227
+ <studio-icon [name]="tab.icon" [size]="iconSize()" />
4228
+ }
4229
+ <span>{{ tab.label }}</span>
4230
+ </button>
4231
+ }
4232
+ </div>
4233
+
4234
+ <div class="tabs__content">
4235
+ <ng-content />
4236
+ </div>
4237
+ `, styles: [":host{display:flex;flex-direction:column;font-family:var(--studio-font-family)}:host(.tabs--vertical){flex-direction:row}.tabs__header{display:flex;gap:.25rem;border-bottom:2px solid var(--studio-border-primary);&--vertical{flex-direction:column;border-bottom:none;border-right:2px solid var(--studio-border-primary);padding-right:1rem}}.tabs__tab{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;background:none;border:none;border-bottom:2px solid transparent;color:var(--studio-text-secondary);font-size:.875rem;font-weight:var(--studio-font-weight-medium);cursor:pointer;transition:all var(--studio-transition-fast);position:relative;margin-bottom:-2px;&--active{color:var(--studio-primary);border-bottom-color:var(--studio-primary)}&--disabled{opacity:.5;cursor:not-allowed}}.tabs__tab:hover:not(:disabled){color:var(--studio-text-primary);background:var(--studio-bg-secondary)}:host(.tabs--pills) .tabs__header{border-bottom:none}:host(.tabs--pills) .tabs__tab{border-radius:var(--studio-radius-md);border-bottom:none;margin-bottom:0;&--active{background:var(--studio-primary);color:#fff}}:host(.tabs--enclosed) .tabs__tab{border:1px solid transparent;border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0;margin-bottom:-1px;&--active{border-color:var(--studio-border-primary);border-bottom-color:var(--studio-bg-primary);background:var(--studio-bg-primary)}}:host(.tabs--sm) .tabs__tab{padding:.5rem .75rem;font-size:.8125rem}:host(.tabs--lg) .tabs__tab{padding:1rem 1.25rem;font-size:1rem}.tabs__content{padding:1.5rem 0}\n"] }]
4238
+ }], ctorParameters: () => [], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], tabChange: [{ type: i0.Output, args: ["tabChange"] }] } });
4239
+
2835
4240
  /**
2836
4241
  * Textarea component for multi-line text input
2837
4242
  *
@@ -3181,6 +4586,73 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
3181
4586
  }, template: "<div class=\"studio-textarea-container\">\n <!-- Label (static or floating) -->\n @if (label() && !floatingLabel()) {\n <label\n [for]=\"textareaId()\"\n class=\"studio-textarea-label\"\n [class.studio-textarea-label--required]=\"required()\"\n >\n {{ label() }}\n @if (required()) {\n <span class=\"studio-textarea-label__required\">*</span>\n }\n </label>\n }\n\n <!-- Textarea wrapper -->\n <div class=\"studio-textarea-input-wrapper\">\n <!-- Floating label -->\n @if (floatingLabel() && label()) {\n <label\n [for]=\"textareaId()\"\n class=\"studio-textarea-label studio-textarea-label--floating\"\n [class.studio-textarea-label--floating-up]=\"showFloatingLabelUp()\"\n [class.studio-textarea-label--required]=\"required()\"\n >\n {{ label() }}\n @if (required()) {\n <span class=\"studio-textarea-label__required\">*</span>\n }\n </label>\n }\n\n <!-- Textarea element -->\n <textarea\n #textarea\n [id]=\"textareaId()\"\n [class]=\"textareaClasses()\"\n [value]=\"internalValue()\"\n [placeholder]=\"computedPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [rows]=\"rows()\"\n [attr.maxlength]=\"maxLength()\"\n [attr.minlength]=\"minLength()\"\n [required]=\"required()\"\n [name]=\"name()\"\n [autocomplete]=\"autocomplete()\"\n [spellcheck]=\"spellcheck()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-required]=\"required()\"\n [attr.aria-invalid]=\"error()\"\n [attr.aria-describedby]=\"showHint() || showError() ? textareaId() + '-description' : undefined\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleFocus($event)\"\n (blur)=\"handleBlur($event)\"\n (keypress)=\"handleKeyPress($event)\"\n ></textarea>\n\n <!-- Clear button -->\n @if (clearable() && internalValue().length > 0 && !disabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"studio-textarea-clear\"\n [attr.aria-label]=\"'Clear textarea'\"\n (click)=\"handleClear()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n }\n\n <!-- Loading indicator -->\n @if (loading()) {\n <div class=\"studio-textarea-loading\">\n <svg\n class=\"studio-textarea-spinner\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n </div>\n }\n\n <!-- Character counter -->\n @if (showCharCount()) {\n <div\n class=\"studio-textarea-char-count\"\n [class.studio-textarea-char-count--exceeded]=\"isCharLimitExceeded()\"\n [attr.data-position]=\"charCountPosition()\"\n >\n {{ charCountText() }}\n </div>\n }\n </div>\n\n <!-- Helper text / Error message -->\n @if (showError()) {\n <div\n class=\"studio-textarea-message studio-textarea-message--error\"\n [id]=\"textareaId() + '-description'\"\n role=\"alert\"\n >\n {{ errorMessage() }}\n </div>\n } @else if (showHint()) {\n <div\n class=\"studio-textarea-message studio-textarea-message--hint\"\n [id]=\"textareaId() + '-description'\"\n >\n {{ hint() }}\n </div>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;gap:.375rem;font-family:var(--studio-font-family)}:host(.studio-textarea-wrapper--full-width){width:100%}.studio-textarea-label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);margin-bottom:.25rem}.studio-textarea-label__required{color:var(--studio-error);margin-left:.125rem}.studio-textarea-label--floating{position:absolute;top:.75rem;left:.75rem;pointer-events:none;background:transparent;padding:0 .25rem;z-index:1;transition:all .2s ease}.studio-textarea-label--floating-up{top:-.5rem;font-size:.75rem;background:var(--studio-background);color:var(--studio-primary)}.studio-textarea-input-wrapper{position:relative;display:flex;flex-direction:column;transition:all var(--studio-transition-fast)}.studio-textarea{width:100%;padding:.75rem;font-size:1rem;font-family:inherit;color:var(--studio-text-primary);background:transparent;border:none;outline:none;resize:vertical;transition:all var(--studio-transition-fast)}.studio-textarea::placeholder{color:var(--studio-text-tertiary)}.studio-textarea:disabled{cursor:not-allowed;opacity:.6}.studio-textarea:read-only{cursor:default}.studio-textarea-clear,.studio-textarea-loading{position:absolute;top:.5rem;right:.5rem;display:flex;align-items:center;justify-content:center}.studio-textarea-clear{padding:.25rem;background:none;border:none;color:var(--studio-text-secondary);cursor:pointer;border-radius:var(--studio-radius-sm);transition:all var(--studio-transition-fast)}.studio-textarea-clear:hover{background:var(--studio-background-hover);color:var(--studio-text-primary)}.studio-textarea-clear svg{width:1rem;height:1rem}.studio-textarea-spinner{width:1rem;height:1rem;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-textarea-char-count{position:absolute;bottom:.5rem;font-size:.75rem;color:var(--studio-text-muted);pointer-events:none}.studio-textarea-char-count[data-position=bottom-right]{right:.75rem}.studio-textarea-char-count[data-position=bottom-left]{left:.75rem}.studio-textarea-char-count--exceeded{color:var(--studio-error);font-weight:500}.studio-textarea-message{font-size:.75rem;line-height:1.4}.studio-textarea-message--hint{color:var(--studio-text-secondary)}.studio-textarea-message--error{color:var(--studio-error)}:host(.studio-textarea-wrapper--outline) .studio-textarea-input-wrapper{border:1px solid var(--studio-border-primary);background:var(--studio-bg-primary);border-radius:var(--studio-radius-md)}:host(.studio-textarea-wrapper--outline) .studio-textarea-input-wrapper:hover:not(:has(.studio-textarea:disabled)){border-color:var(--studio-primary)}:host(.studio-textarea-wrapper--outline.studio-textarea-wrapper--focused) .studio-textarea-input-wrapper{border-color:var(--studio-primary);box-shadow:0 0 0 3px var(--studio-primary-bg)}:host(.studio-textarea-wrapper--outline.studio-textarea-wrapper--error) .studio-textarea-input-wrapper{border-color:var(--studio-error)}:host(.studio-textarea-wrapper--outline.studio-textarea-wrapper--error) .studio-textarea-input-wrapper:hover{border-color:var(--studio-error)}:host(.studio-textarea-wrapper--outline.studio-textarea-wrapper--disabled) .studio-textarea-input-wrapper{background:var(--studio-bg-secondary);border-color:var(--studio-border-secondary)}:host(.studio-textarea-wrapper--filled) .studio-textarea-input-wrapper{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-textarea-wrapper--filled) .studio-textarea-input-wrapper:hover:not(:has(.studio-textarea:disabled)){background:var(--studio-bg-tertiary)}:host(.studio-textarea-wrapper--filled.studio-textarea-wrapper--focused) .studio-textarea-input-wrapper{border-bottom-color:var(--studio-primary);background:var(--studio-bg-tertiary)}:host(.studio-textarea-wrapper--filled.studio-textarea-wrapper--error) .studio-textarea-input-wrapper{border-bottom-color:var(--studio-error)}:host(.studio-textarea-wrapper--filled.studio-textarea-wrapper--disabled) .studio-textarea-input-wrapper{background:var(--studio-bg-secondary);opacity:.6}:host(.studio-textarea-wrapper--underline) .studio-textarea-input-wrapper{background:transparent;border:none;border-bottom:2px solid var(--studio-border-primary);border-radius:0}:host(.studio-textarea-wrapper--underline) .studio-textarea-input-wrapper .studio-textarea{padding-left:0;padding-right:0}:host(.studio-textarea-wrapper--underline) .studio-textarea-input-wrapper:hover:not(:has(.studio-textarea:disabled)){border-bottom-color:var(--studio-primary)}:host(.studio-textarea-wrapper--underline.studio-textarea-wrapper--focused) .studio-textarea-input-wrapper{border-bottom-color:var(--studio-primary)}:host(.studio-textarea-wrapper--underline.studio-textarea-wrapper--error) .studio-textarea-input-wrapper{border-bottom-color:var(--studio-error)}:host(.studio-textarea-wrapper--sm) .studio-textarea{padding:.5rem .75rem;font-size:.875rem}:host(.studio-textarea-wrapper--md) .studio-textarea{padding:.75rem;font-size:1rem}:host(.studio-textarea-wrapper--lg) .studio-textarea{padding:1rem;font-size:1.125rem}\n"] }]
3182
4587
  }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], minRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "minRows", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }], autoResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoResize", required: false }] }], resize: [{ type: i0.Input, args: [{ isSignal: true, alias: "resize", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], showCharCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCharCount", required: false }] }], charCountPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "charCountPosition", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], spellcheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "spellcheck", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }], focused: [{ type: i0.Output, args: ["focused"] }], blurred: [{ type: i0.Output, args: ["blurred"] }], keyPressed: [{ type: i0.Output, args: ["keyPressed"] }], textareaEl: [{ type: i0.ViewChild, args: ['textarea', { isSignal: true }] }] } });
3183
4588
 
4589
+ class TooltipComponent {
4590
+ content = input.required(...(ngDevMode ? [{ debugName: "content" }] : []));
4591
+ trigger = input('hover', ...(ngDevMode ? [{ debugName: "trigger" }] : []));
4592
+ position = input('top', ...(ngDevMode ? [{ debugName: "position" }] : []));
4593
+ openDelay = input(200, ...(ngDevMode ? [{ debugName: "openDelay" }] : []));
4594
+ closeDelay = input(100, ...(ngDevMode ? [{ debugName: "closeDelay" }] : []));
4595
+ arrow = input(true, ...(ngDevMode ? [{ debugName: "arrow" }] : []));
4596
+ arrowSize = input(6, ...(ngDevMode ? [{ debugName: "arrowSize" }] : []));
4597
+ maxWidth = input('300px', ...(ngDevMode ? [{ debugName: "maxWidth" }] : []));
4598
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
4599
+ hostClasses = computed(() => classNames('studio-tooltip'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
4600
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4601
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.12", type: TooltipComponent, isStandalone: true, selector: "studio-tooltip", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: true, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, arrow: { classPropertyName: "arrow", publicName: "arrow", isSignal: true, isRequired: false, transformFunction: null }, arrowSize: { classPropertyName: "arrowSize", publicName: "arrowSize", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
4602
+ <studio-popover
4603
+ [trigger]="trigger()"
4604
+ [position]="position()"
4605
+ [openDelay]="openDelay()"
4606
+ [closeDelay]="closeDelay()"
4607
+ [arrow]="arrow()"
4608
+ [arrowSize]="arrowSize()"
4609
+ [variant]="'minimal'"
4610
+ [size]="'sm'"
4611
+ [animation]="'fade'"
4612
+ [animationDuration]="150"
4613
+ [showHeader]="false"
4614
+ [showFooter]="false"
4615
+ [closeOnClickOutside]="false"
4616
+ [closeOnEscape]="false"
4617
+ [disabled]="disabled()"
4618
+ [maxWidth]="maxWidth()"
4619
+ [padding]="'0.5rem 0.75rem'"
4620
+ >
4621
+ <ng-content />
4622
+ <div popoverContent [innerHTML]="content() || ''"></div>
4623
+ </studio-popover>
4624
+ `, isInline: true, styles: [":host{display:inline-block}\n"], dependencies: [{ kind: "component", type: PopoverComponent, selector: "studio-popover", inputs: ["id", "visible", "disabled", "trigger", "openDelay", "closeDelay", "position", "offset", "preventOverflow", "flipValue", "variant", "size", "width", "minWidth", "maxWidth", "maxHeight", "padding", "arrow", "arrowSize", "closeOnClickOutside", "closeOnEscape", "closeOnScroll", "showOverlay", "overlayOpacity", "animation", "animationDuration", "showHeader", "showFooter", "showCloseButton", "content", "zIndex", "ariaLabel", "role"], outputs: ["visibleChange", "opened", "closed", "positionChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4625
+ }
4626
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TooltipComponent, decorators: [{
4627
+ type: Component,
4628
+ args: [{ selector: 'studio-tooltip', standalone: true, imports: [PopoverComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
4629
+ '[class]': 'hostClasses()',
4630
+ }, template: `
4631
+ <studio-popover
4632
+ [trigger]="trigger()"
4633
+ [position]="position()"
4634
+ [openDelay]="openDelay()"
4635
+ [closeDelay]="closeDelay()"
4636
+ [arrow]="arrow()"
4637
+ [arrowSize]="arrowSize()"
4638
+ [variant]="'minimal'"
4639
+ [size]="'sm'"
4640
+ [animation]="'fade'"
4641
+ [animationDuration]="150"
4642
+ [showHeader]="false"
4643
+ [showFooter]="false"
4644
+ [closeOnClickOutside]="false"
4645
+ [closeOnEscape]="false"
4646
+ [disabled]="disabled()"
4647
+ [maxWidth]="maxWidth()"
4648
+ [padding]="'0.5rem 0.75rem'"
4649
+ >
4650
+ <ng-content />
4651
+ <div popoverContent [innerHTML]="content() || ''"></div>
4652
+ </studio-popover>
4653
+ `, styles: [":host{display:inline-block}\n"] }]
4654
+ }], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: true }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], arrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrow", required: false }] }], arrowSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowSize", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
4655
+
3184
4656
  /**
3185
4657
  * Primitives (Atoms)
3186
4658
  * Basic building blocks
@@ -3344,6 +4816,215 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
3344
4816
  `, styles: [":host{display:inline-block}:host(.studio-button-toggle-group--disabled){opacity:.6;pointer-events:none}\n"] }]
3345
4817
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], allowEmpty: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowEmpty", required: false }] }], orientationInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", 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 }] }], attached: [{ type: i0.Input, args: [{ isSignal: true, alias: "attached", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], spacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "spacing", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], showIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcons", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
3346
4818
 
4819
+ class InspectorComponent {
4820
+ configService = inject(StudioConfigService);
4821
+ componentSize = input('sm', ...(ngDevMode ? [{ debugName: "componentSize" }] : []));
4822
+ componentVariant = input('outline', ...(ngDevMode ? [{ debugName: "componentVariant" }] : []));
4823
+ compact = input(false, ...(ngDevMode ? [{ debugName: "compact" }] : []));
4824
+ showIcons = input(true, ...(ngDevMode ? [{ debugName: "showIcons" }] : []));
4825
+ showDefaultIndicator = input(true, ...(ngDevMode ? [{ debugName: "showDefaultIndicator" }] : []));
4826
+ collapsible = input(true, ...(ngDevMode ? [{ debugName: "collapsible" }] : []));
4827
+ expandedByDefault = input(true, ...(ngDevMode ? [{ debugName: "expandedByDefault" }] : []));
4828
+ expandedSectionsInput = input([], ...(ngDevMode ? [{ debugName: "expandedSectionsInput", alias: 'expandedSections' }] : [{ alias: 'expandedSections' }]));
4829
+ showGroupLabels = input(true, ...(ngDevMode ? [{ debugName: "showGroupLabels" }] : []));
4830
+ groupDivider = input('line', ...(ngDevMode ? [{ debugName: "groupDivider" }] : []));
4831
+ groupDividerSpacing = input('md', ...(ngDevMode ? [{ debugName: "groupDividerSpacing" }] : []));
4832
+ labelWidth = input('auto', ...(ngDevMode ? [{ debugName: "labelWidth" }] : []));
4833
+ fullWidth = input(true, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
4834
+ spacing = input('md', ...(ngDevMode ? [{ debugName: "spacing" }] : []));
4835
+ sectionTemplate = input(undefined, ...(ngDevMode ? [{ debugName: "sectionTemplate" }] : []));
4836
+ parameterTemplates = input(undefined, ...(ngDevMode ? [{ debugName: "parameterTemplates" }] : []));
4837
+ ariaLabel = input('Inspector panel', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
4838
+ ariaDescribedBy = input(undefined, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
4839
+ sectionToggled = output();
4840
+ parameterFocused = output();
4841
+ parameterBlurred = output();
4842
+ values = signal(null, ...(ngDevMode ? [{ debugName: "values" }] : []));
4843
+ expandedSections = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedSections" }] : []));
4844
+ onChange = () => { };
4845
+ onTouched = () => { };
4846
+ constructor() {
4847
+ effect(() => {
4848
+ const inputSections = this.expandedSectionsInput();
4849
+ if (inputSections.length > 0) {
4850
+ this.expandedSections.set(new Set(inputSections));
4851
+ }
4852
+ });
4853
+ }
4854
+ hostClasses = computed(() => classNames('studio-inspector', this.compact() && 'studio-inspector--compact', `studio-inspector--spacing-${this.spacing()}`), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
4855
+ isSectionExpanded(componentId) {
4856
+ return this.expandedSections().has(componentId);
4857
+ }
4858
+ toggleSection(componentId) {
4859
+ if (!this.collapsible())
4860
+ return;
4861
+ const expanded = new Set(this.expandedSections());
4862
+ if (expanded.has(componentId)) {
4863
+ expanded.delete(componentId);
4864
+ }
4865
+ else {
4866
+ expanded.add(componentId);
4867
+ }
4868
+ this.expandedSections.set(expanded);
4869
+ this.sectionToggled.emit({
4870
+ id: componentId,
4871
+ expanded: expanded.has(componentId)
4872
+ });
4873
+ }
4874
+ onParameterChange(componentId, groupId, parameterId, newValue) {
4875
+ const updated = structuredClone(this.values());
4876
+ if (!updated)
4877
+ return;
4878
+ const section = updated.sections.find(c => c.id === componentId);
4879
+ if (!section)
4880
+ return;
4881
+ let parameter;
4882
+ if (groupId) {
4883
+ const group = section.groups?.find(g => g.id === groupId);
4884
+ parameter = group?.parameters.find(p => p.id === parameterId);
4885
+ }
4886
+ else {
4887
+ parameter = section.parameters?.find(p => p.id === parameterId);
4888
+ }
4889
+ if (parameter) {
4890
+ parameter.value = newValue;
4891
+ }
4892
+ this.values.set(updated);
4893
+ this.onChange(updated);
4894
+ this.onTouched();
4895
+ }
4896
+ onCheckboxChange(componentId, groupId, parameterId, optionValue, checked) {
4897
+ const updated = structuredClone(this.values());
4898
+ if (!updated)
4899
+ return;
4900
+ const section = updated.sections.find(c => c.id === componentId);
4901
+ if (!section)
4902
+ return;
4903
+ let parameter;
4904
+ if (groupId) {
4905
+ const group = section.groups?.find(g => g.id === groupId);
4906
+ parameter = group?.parameters.find(p => p.id === parameterId);
4907
+ }
4908
+ else {
4909
+ parameter = section.parameters?.find(p => p.id === parameterId);
4910
+ }
4911
+ if (parameter && parameter.type === 'checkbox') {
4912
+ const currentValues = Array.isArray(parameter.value) ? parameter.value : [];
4913
+ if (checked) {
4914
+ if (!currentValues.includes(optionValue)) {
4915
+ parameter.value = [...currentValues, optionValue];
4916
+ }
4917
+ }
4918
+ else {
4919
+ parameter.value = currentValues.filter(v => v !== optionValue);
4920
+ }
4921
+ }
4922
+ this.values.set(updated);
4923
+ this.onChange(updated);
4924
+ this.onTouched();
4925
+ }
4926
+ onRadioChange(componentId, groupId, parameterId, newValue) {
4927
+ this.onParameterChange(componentId, groupId, parameterId, newValue);
4928
+ }
4929
+ getRadioName(componentId, groupId, parameterId) {
4930
+ return `${componentId}-${groupId || 'root'}-${parameterId}`;
4931
+ }
4932
+ isChecked(parameter, optionValue) {
4933
+ if (parameter.type === 'checkbox') {
4934
+ return Array.isArray(parameter.value) && parameter.value.includes(optionValue);
4935
+ }
4936
+ else if (parameter.type === 'radio') {
4937
+ return parameter.value === optionValue;
4938
+ }
4939
+ return false;
4940
+ }
4941
+ isRadioChecked(parameter, optionValue) {
4942
+ return parameter.value === optionValue;
4943
+ }
4944
+ isDefault(parameter, optionValue) {
4945
+ return parameter.default !== undefined && parameter.default === optionValue;
4946
+ }
4947
+ trackBySectionId(_, section) {
4948
+ return section.id;
4949
+ }
4950
+ trackByGroupId(_, group) {
4951
+ return group.id;
4952
+ }
4953
+ trackByParameterId(_, param) {
4954
+ return param.id;
4955
+ }
4956
+ trackByOptionValue(_, option) {
4957
+ return option.value;
4958
+ }
4959
+ writeValue(value) {
4960
+ this.values.set(value);
4961
+ this.initializeExpandedSections();
4962
+ }
4963
+ registerOnChange(fn) {
4964
+ this.onChange = fn;
4965
+ }
4966
+ registerOnTouched(fn) {
4967
+ this.onTouched = fn;
4968
+ }
4969
+ setDisabledState(_) { }
4970
+ initializeExpandedSections() {
4971
+ const expanded = new Set();
4972
+ const inputSections = this.expandedSectionsInput();
4973
+ if (inputSections.length > 0) {
4974
+ inputSections.forEach(id => expanded.add(id));
4975
+ }
4976
+ else if (this.expandedByDefault()) {
4977
+ this.values()?.sections.forEach(c => {
4978
+ if (c.expanded !== false) {
4979
+ expanded.add(c.id);
4980
+ }
4981
+ });
4982
+ }
4983
+ else {
4984
+ this.values()?.sections.forEach(c => {
4985
+ if (c.expanded === true) {
4986
+ expanded.add(c.id);
4987
+ }
4988
+ });
4989
+ }
4990
+ this.expandedSections.set(expanded);
4991
+ }
4992
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: InspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4993
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: InspectorComponent, isStandalone: true, selector: "studio-inspector", inputs: { componentSize: { classPropertyName: "componentSize", publicName: "componentSize", isSignal: true, isRequired: false, transformFunction: null }, componentVariant: { classPropertyName: "componentVariant", publicName: "componentVariant", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, showIcons: { classPropertyName: "showIcons", publicName: "showIcons", isSignal: true, isRequired: false, transformFunction: null }, showDefaultIndicator: { classPropertyName: "showDefaultIndicator", publicName: "showDefaultIndicator", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, expandedByDefault: { classPropertyName: "expandedByDefault", publicName: "expandedByDefault", isSignal: true, isRequired: false, transformFunction: null }, expandedSectionsInput: { classPropertyName: "expandedSectionsInput", publicName: "expandedSections", isSignal: true, isRequired: false, transformFunction: null }, showGroupLabels: { classPropertyName: "showGroupLabels", publicName: "showGroupLabels", isSignal: true, isRequired: false, transformFunction: null }, groupDivider: { classPropertyName: "groupDivider", publicName: "groupDivider", isSignal: true, isRequired: false, transformFunction: null }, groupDividerSpacing: { classPropertyName: "groupDividerSpacing", publicName: "groupDividerSpacing", isSignal: true, isRequired: false, transformFunction: null }, labelWidth: { classPropertyName: "labelWidth", publicName: "labelWidth", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, spacing: { classPropertyName: "spacing", publicName: "spacing", isSignal: true, isRequired: false, transformFunction: null }, sectionTemplate: { classPropertyName: "sectionTemplate", publicName: "sectionTemplate", isSignal: true, isRequired: false, transformFunction: null }, parameterTemplates: { classPropertyName: "parameterTemplates", publicName: "parameterTemplates", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sectionToggled: "sectionToggled", parameterFocused: "parameterFocused", parameterBlurred: "parameterBlurred" }, host: { properties: { "class": "hostClasses()", "attr.role": "\"region\"", "attr.aria-label": "ariaLabel()" } }, providers: [
4994
+ {
4995
+ provide: NG_VALUE_ACCESSOR,
4996
+ useExisting: forwardRef(() => InspectorComponent),
4997
+ multi: true
4998
+ }
4999
+ ], ngImport: i0, template: "@if (values()) {\n <div class=\"studio-inspector__container\">\n @for (section of values()!.sections; track trackBySectionId($index, section)) {\n <div class=\"studio-inspector__section\"\n [class.studio-inspector__section--expanded]=\"isSectionExpanded(section.id)\"\n [class.studio-inspector__section--collapsed]=\"!isSectionExpanded(section.id)\">\n\n <studio-button\n variant=\"ghost\"\n [fullWidth]=\"true\"\n class=\"studio-inspector__section-header\"\n [class.studio-inspector__section-header--collapsible]=\"collapsible()\"\n [disabled]=\"!collapsible()\"\n [attr.aria-expanded]=\"isSectionExpanded(section.id)\"\n [attr.aria-controls]=\"'section-content-' + section.id\"\n (click)=\"toggleSection(section.id)\">\n\n @if (showIcons() && section.icon) {\n <studio-icon\n [name]=\"section.icon\"\n [size]=\"16\"\n class=\"studio-inspector__section-icon\"\n />\n }\n\n <span class=\"studio-inspector__section-title\">{{ section.title }}</span>\n\n @if (collapsible()) {\n <studio-icon\n [name]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"studio-inspector__section-toggle\"\n />\n }\n </studio-button>\n\n @if (isSectionExpanded(section.id)) {\n <div\n class=\"studio-inspector__section-content\"\n [id]=\"'section-content-' + section.id\">\n\n @if (section.groups) {\n @for (group of section.groups; track trackByGroupId($index, group); let isLast = $last) {\n <div class=\"studio-inspector__group\">\n\n @if (showGroupLabels() && group.label) {\n <div class=\"studio-inspector__group-label\">{{ group.label }}</div>\n }\n\n @for (param of group.parameters; track trackByParameterId($index, param)) {\n <div class=\"studio-inspector__parameter\">\n @if (param.type !== 'boolean' && param.type !== 'checkbox' && param.type !== 'radio') {\n <div class=\"studio-inspector__parameter-label\">{{ param.label }}</div>\n }\n\n @if (param.type === 'text') {\n <studio-input\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'number') {\n <div class=\"studio-inspector__number-input\">\n <studio-input\n type=\"number\"\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [min]=\"param.min\"\n [max]=\"param.max\"\n [step]=\"param.step\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [fullWidth]=\"fullWidth()\"\n />\n @if (param.suffix) {\n <span class=\"studio-inspector__suffix\">{{ param.suffix }}</span>\n }\n </div>\n }\n\n @if (param.type === 'textarea') {\n <studio-textarea\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'color') {\n <studio-color-picker-compact\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'select') {\n <studio-select\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [options]=\"param.options || []\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'boolean') {\n <studio-switch\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [label]=\"param.label\"\n [size]=\"componentSize()\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'checkbox') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <studio-checkbox\n [ngModel]=\"isChecked(param, option.value)\"\n [name]=\"section.id + '-' + group.id + '-' + param.id + '-' + option.value\"\n (ngModelChange)=\"onCheckboxChange(section.id, group.id, param.id, option.value, $event)\"\n [label]=\"option.label\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n }\n </div>\n }\n\n @if (param.type === 'radio') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <div class=\"studio-inspector__option\">\n <studio-radio-button\n [ngModel]=\"param.value\"\n (ngModelChange)=\"onRadioChange(section.id, group.id, param.id, $event)\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n [name]=\"getRadioName(section.id, group.id, param.id)\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n @if (showDefaultIndicator() && isDefault(param, option.value)) {\n <span class=\"studio-inspector__default-indicator\">(default)</span>\n }\n </div>\n }\n </div>\n }\n\n @if (param.hint) {\n <div class=\"studio-inspector__parameter-hint\">{{ param.hint }}</div>\n }\n </div>\n }\n\n @if (!isLast && groupDivider() !== 'none') {\n <div class=\"studio-inspector__group-divider\"\n [class.studio-inspector__group-divider--line]=\"groupDivider() === 'line'\"\n [class.studio-inspector__group-divider--space]=\"groupDivider() === 'space'\">\n </div>\n }\n </div>\n }\n }\n\n @if (section.parameters) {\n @for (param of section.parameters; track trackByParameterId($index, param)) {\n <div class=\"studio-inspector__parameter\">\n @if (param.type !== 'boolean' && param.type !== 'checkbox' && param.type !== 'radio') {\n <div class=\"studio-inspector__parameter-label\">{{ param.label }}</div>\n }\n\n @if (param.type === 'text') {\n <studio-input\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'number') {\n <div class=\"studio-inspector__number-input\">\n <studio-input\n type=\"number\"\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [min]=\"param.min\"\n [max]=\"param.max\"\n [step]=\"param.step\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [fullWidth]=\"fullWidth()\"\n />\n @if (param.suffix) {\n <span class=\"studio-inspector__suffix\">{{ param.suffix }}</span>\n }\n </div>\n }\n\n @if (param.type === 'textarea') {\n <studio-textarea\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'color') {\n <studio-color-picker-compact\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'select') {\n <studio-select\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [options]=\"param.options || []\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'boolean') {\n <studio-switch\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [label]=\"param.label\"\n [size]=\"componentSize()\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'checkbox') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <studio-checkbox\n [ngModel]=\"isChecked(param, option.value)\"\n [name]=\"section.id + '-' + param.id + '-' + option.value\"\n (ngModelChange)=\"onCheckboxChange(section.id, null, param.id, option.value, $event)\"\n [label]=\"option.label\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n }\n </div>\n }\n\n @if (param.type === 'radio') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <div class=\"studio-inspector__option\">\n <studio-radio-button\n [ngModel]=\"param.value\"\n (ngModelChange)=\"onRadioChange(section.id, null, param.id, $event)\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n [name]=\"getRadioName(section.id, null, param.id)\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n @if (showDefaultIndicator() && isDefault(param, option.value)) {\n <span class=\"studio-inspector__default-indicator\">(default)</span>\n }\n </div>\n }\n </div>\n }\n\n @if (param.hint) {\n <div class=\"studio-inspector__parameter-hint\">{{ param.hint }}</div>\n }\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;font-family:var(--studio-font-family)}.studio-inspector__container{display:flex;flex-direction:column;gap:.75rem}.studio-inspector__section{background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);overflow:hidden}.studio-inspector__section-header{width:100%;display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:var(--studio-bg-secondary);border:none;border-bottom:1px solid var(--studio-border-primary);cursor:pointer;transition:background var(--studio-transition-fast);text-align:left}.studio-inspector__section-header--collapsible:hover{background:var(--studio-bg-tertiary)}.studio-inspector__section-header:disabled{cursor:default}.studio-inspector__section-icon{color:var(--studio-text-secondary);flex-shrink:0}.studio-inspector__section-title{flex:1;font-size:.875rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-inspector__section-toggle{color:var(--studio-text-secondary);flex-shrink:0;transition:transform var(--studio-transition-fast)}.studio-inspector__section--collapsed .studio-inspector__section-toggle{transform:rotate(-90deg)}.studio-inspector__section--collapsed .studio-inspector__section-content{display:none}.studio-inspector__section--expanded .studio-inspector__section-toggle{transform:rotate(0)}.studio-inspector__section-content{padding:1rem;display:flex;flex-direction:column;gap:.75rem}.studio-inspector__group{display:flex;flex-direction:column;gap:.75rem}.studio-inspector__group-label{font-size:.75rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-secondary);text-transform:uppercase;letter-spacing:.05em}.studio-inspector__group-divider--line{height:1px;background:var(--studio-border-primary);margin:.5rem 0}.studio-inspector__group-divider--space{height:.5rem}.studio-inspector__parameter{display:flex;flex-direction:column;gap:.5rem}.studio-inspector__parameter-label{font-size:.8125rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary)}.studio-inspector__parameter-hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-inspector__number-input{display:flex;align-items:center;gap:.5rem}.studio-inspector__suffix{font-size:.875rem;color:var(--studio-text-secondary);flex-shrink:0}.studio-inspector__options{display:flex;flex-direction:column;gap:.5rem}.studio-inspector__option{display:flex;align-items:center;gap:.5rem}.studio-inspector__default-indicator{font-size:.75rem;color:var(--studio-text-tertiary);font-style:italic}:host(.studio-inspector--compact) .studio-inspector__container{gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__section-header{padding:.625rem .75rem}:host(.studio-inspector--compact) .studio-inspector__section-content{padding:.75rem;gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__group{gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__parameter{gap:.375rem}:host(.studio-inspector--spacing-sm) .studio-inspector__section-content{gap:.5rem}:host(.studio-inspector--spacing-sm) .studio-inspector__group{gap:.5rem}:host(.studio-inspector--spacing-sm) .studio-inspector__parameter{gap:.375rem}:host(.studio-inspector--spacing-lg) .studio-inspector__section-content{gap:1rem}:host(.studio-inspector--spacing-lg) .studio-inspector__group{gap:1rem}:host(.studio-inspector--spacing-lg) .studio-inspector__parameter{gap:.625rem}:host(.studio-inspector--spacing-lg) .studio-inspector__group-divider--space{height:1rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ButtonComponent, selector: "studio-button", inputs: ["variant", "size", "color", "radius", "shadow", "compact", "disabled", "loading", "loadingText", "fullWidth", "type", "icon", "iconPosition", "href", "target", "badge", "badgeColor", "ariaLabel"], outputs: ["clicked"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }, { kind: "component", type: InputComponent, selector: "studio-input", inputs: ["variant", "size", "radius", "disabled", "readonly", "loading", "type", "inputmode", "autocomplete", "placeholder", "maxLength", "minLength", "min", "max", "step", "pattern", "label", "floatingLabel", "hint", "required", "error", "errorMessage", "prefixIcon", "suffixIcon", "clearable", "showPasswordToggle", "fullWidth", "autoFocus", "name", "id", "ariaLabel"], outputs: ["valueChange", "focused", "blurred", "cleared", "entered"] }, { kind: "component", type: CheckboxComponent, selector: "studio-checkbox", inputs: ["size", "color", "variant", "radius", "label", "labelPosition", "description", "hint", "required", "error", "errorMessage", "disabled", "readonly", "indeterminate", "name", "tabIndex", "value"], outputs: ["changed"] }, { kind: "component", type: RadioButtonComponent, selector: "studio-radio-button", inputs: ["size", "color", "variant", "radius", "label", "labelPosition", "description", "hint", "required", "error", "errorMessage", "disabled", "readonly", "name", "tabIndex", "value"], outputs: ["changed"] }, { kind: "component", type: ColorPickerCompactComponent, selector: "studio-color-picker-compact", inputs: ["trigger", "position", "popoverWidth", "showArrow", "closeOnClickOutside", "triggerSize", "triggerRadius", "showCurrentColor", "format", "showAlpha", "showPresets", "showFormatToggle", "showCopyButton", "presets", "showFooter", "applyLabel", "cancelLabel", "disabled", "ariaLabel"], outputs: ["colorChange"] }, { kind: "component", type: SelectComponent, selector: "studio-select", inputs: ["variant", "size", "radius", "options", "placeholder", "multiple", "searchable", "clearable", "disabled", "loading", "label", "floatingLabel", "hint", "error", "errorMessage", "required", "prefixIcon", "suffixIcon", "fullWidth", "maxHeight", "position", "searchPlaceholder"], outputs: ["valueChange", "searchChange", "opened", "closed", "optionSelected"] }, { kind: "component", type: TextareaComponent, selector: "studio-textarea", inputs: ["variant", "size", "color", "radius", "label", "floatingLabel", "placeholder", "hint", "rows", "minRows", "maxRows", "autoResize", "resize", "maxLength", "showCharCount", "charCountPosition", "required", "minLength", "error", "errorMessage", "disabled", "readonly", "fullWidth", "name", "autocomplete", "spellcheck", "clearable", "loading"], outputs: ["changed", "focused", "blurred", "keyPressed"] }, { kind: "component", type: SwitchComponent, selector: "studio-switch", inputs: ["checked", "disabled", "label", "labelPosition", "showIcons", "ariaLabel", "size", "color"], outputs: ["checkedChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5000
+ }
5001
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: InspectorComponent, decorators: [{
5002
+ type: Component,
5003
+ args: [{ selector: 'studio-inspector', standalone: true, imports: [
5004
+ CommonModule,
5005
+ FormsModule,
5006
+ ButtonComponent,
5007
+ IconComponent,
5008
+ InputComponent,
5009
+ CheckboxComponent,
5010
+ RadioButtonComponent,
5011
+ ColorPickerCompactComponent,
5012
+ SelectComponent,
5013
+ TextareaComponent,
5014
+ SwitchComponent
5015
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
5016
+ {
5017
+ provide: NG_VALUE_ACCESSOR,
5018
+ useExisting: forwardRef(() => InspectorComponent),
5019
+ multi: true
5020
+ }
5021
+ ], host: {
5022
+ '[class]': 'hostClasses()',
5023
+ '[attr.role]': '"region"',
5024
+ '[attr.aria-label]': 'ariaLabel()'
5025
+ }, template: "@if (values()) {\n <div class=\"studio-inspector__container\">\n @for (section of values()!.sections; track trackBySectionId($index, section)) {\n <div class=\"studio-inspector__section\"\n [class.studio-inspector__section--expanded]=\"isSectionExpanded(section.id)\"\n [class.studio-inspector__section--collapsed]=\"!isSectionExpanded(section.id)\">\n\n <studio-button\n variant=\"ghost\"\n [fullWidth]=\"true\"\n class=\"studio-inspector__section-header\"\n [class.studio-inspector__section-header--collapsible]=\"collapsible()\"\n [disabled]=\"!collapsible()\"\n [attr.aria-expanded]=\"isSectionExpanded(section.id)\"\n [attr.aria-controls]=\"'section-content-' + section.id\"\n (click)=\"toggleSection(section.id)\">\n\n @if (showIcons() && section.icon) {\n <studio-icon\n [name]=\"section.icon\"\n [size]=\"16\"\n class=\"studio-inspector__section-icon\"\n />\n }\n\n <span class=\"studio-inspector__section-title\">{{ section.title }}</span>\n\n @if (collapsible()) {\n <studio-icon\n [name]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"studio-inspector__section-toggle\"\n />\n }\n </studio-button>\n\n @if (isSectionExpanded(section.id)) {\n <div\n class=\"studio-inspector__section-content\"\n [id]=\"'section-content-' + section.id\">\n\n @if (section.groups) {\n @for (group of section.groups; track trackByGroupId($index, group); let isLast = $last) {\n <div class=\"studio-inspector__group\">\n\n @if (showGroupLabels() && group.label) {\n <div class=\"studio-inspector__group-label\">{{ group.label }}</div>\n }\n\n @for (param of group.parameters; track trackByParameterId($index, param)) {\n <div class=\"studio-inspector__parameter\">\n @if (param.type !== 'boolean' && param.type !== 'checkbox' && param.type !== 'radio') {\n <div class=\"studio-inspector__parameter-label\">{{ param.label }}</div>\n }\n\n @if (param.type === 'text') {\n <studio-input\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'number') {\n <div class=\"studio-inspector__number-input\">\n <studio-input\n type=\"number\"\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [min]=\"param.min\"\n [max]=\"param.max\"\n [step]=\"param.step\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [fullWidth]=\"fullWidth()\"\n />\n @if (param.suffix) {\n <span class=\"studio-inspector__suffix\">{{ param.suffix }}</span>\n }\n </div>\n }\n\n @if (param.type === 'textarea') {\n <studio-textarea\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'color') {\n <studio-color-picker-compact\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'select') {\n <studio-select\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [options]=\"param.options || []\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'boolean') {\n <studio-switch\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [label]=\"param.label\"\n [size]=\"componentSize()\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'checkbox') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <studio-checkbox\n [ngModel]=\"isChecked(param, option.value)\"\n [name]=\"section.id + '-' + group.id + '-' + param.id + '-' + option.value\"\n (ngModelChange)=\"onCheckboxChange(section.id, group.id, param.id, option.value, $event)\"\n [label]=\"option.label\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n }\n </div>\n }\n\n @if (param.type === 'radio') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <div class=\"studio-inspector__option\">\n <studio-radio-button\n [ngModel]=\"param.value\"\n (ngModelChange)=\"onRadioChange(section.id, group.id, param.id, $event)\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n [name]=\"getRadioName(section.id, group.id, param.id)\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n @if (showDefaultIndicator() && isDefault(param, option.value)) {\n <span class=\"studio-inspector__default-indicator\">(default)</span>\n }\n </div>\n }\n </div>\n }\n\n @if (param.hint) {\n <div class=\"studio-inspector__parameter-hint\">{{ param.hint }}</div>\n }\n </div>\n }\n\n @if (!isLast && groupDivider() !== 'none') {\n <div class=\"studio-inspector__group-divider\"\n [class.studio-inspector__group-divider--line]=\"groupDivider() === 'line'\"\n [class.studio-inspector__group-divider--space]=\"groupDivider() === 'space'\">\n </div>\n }\n </div>\n }\n }\n\n @if (section.parameters) {\n @for (param of section.parameters; track trackByParameterId($index, param)) {\n <div class=\"studio-inspector__parameter\">\n @if (param.type !== 'boolean' && param.type !== 'checkbox' && param.type !== 'radio') {\n <div class=\"studio-inspector__parameter-label\">{{ param.label }}</div>\n }\n\n @if (param.type === 'text') {\n <studio-input\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'number') {\n <div class=\"studio-inspector__number-input\">\n <studio-input\n type=\"number\"\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [min]=\"param.min\"\n [max]=\"param.max\"\n [step]=\"param.step\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [fullWidth]=\"fullWidth()\"\n />\n @if (param.suffix) {\n <span class=\"studio-inspector__suffix\">{{ param.suffix }}</span>\n }\n </div>\n }\n\n @if (param.type === 'textarea') {\n <studio-textarea\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'color') {\n <studio-color-picker-compact\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'select') {\n <studio-select\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [options]=\"param.options || []\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'boolean') {\n <studio-switch\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [label]=\"param.label\"\n [size]=\"componentSize()\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'checkbox') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <studio-checkbox\n [ngModel]=\"isChecked(param, option.value)\"\n [name]=\"section.id + '-' + param.id + '-' + option.value\"\n (ngModelChange)=\"onCheckboxChange(section.id, null, param.id, option.value, $event)\"\n [label]=\"option.label\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n }\n </div>\n }\n\n @if (param.type === 'radio') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <div class=\"studio-inspector__option\">\n <studio-radio-button\n [ngModel]=\"param.value\"\n (ngModelChange)=\"onRadioChange(section.id, null, param.id, $event)\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n [name]=\"getRadioName(section.id, null, param.id)\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n @if (showDefaultIndicator() && isDefault(param, option.value)) {\n <span class=\"studio-inspector__default-indicator\">(default)</span>\n }\n </div>\n }\n </div>\n }\n\n @if (param.hint) {\n <div class=\"studio-inspector__parameter-hint\">{{ param.hint }}</div>\n }\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;font-family:var(--studio-font-family)}.studio-inspector__container{display:flex;flex-direction:column;gap:.75rem}.studio-inspector__section{background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);overflow:hidden}.studio-inspector__section-header{width:100%;display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:var(--studio-bg-secondary);border:none;border-bottom:1px solid var(--studio-border-primary);cursor:pointer;transition:background var(--studio-transition-fast);text-align:left}.studio-inspector__section-header--collapsible:hover{background:var(--studio-bg-tertiary)}.studio-inspector__section-header:disabled{cursor:default}.studio-inspector__section-icon{color:var(--studio-text-secondary);flex-shrink:0}.studio-inspector__section-title{flex:1;font-size:.875rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-inspector__section-toggle{color:var(--studio-text-secondary);flex-shrink:0;transition:transform var(--studio-transition-fast)}.studio-inspector__section--collapsed .studio-inspector__section-toggle{transform:rotate(-90deg)}.studio-inspector__section--collapsed .studio-inspector__section-content{display:none}.studio-inspector__section--expanded .studio-inspector__section-toggle{transform:rotate(0)}.studio-inspector__section-content{padding:1rem;display:flex;flex-direction:column;gap:.75rem}.studio-inspector__group{display:flex;flex-direction:column;gap:.75rem}.studio-inspector__group-label{font-size:.75rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-secondary);text-transform:uppercase;letter-spacing:.05em}.studio-inspector__group-divider--line{height:1px;background:var(--studio-border-primary);margin:.5rem 0}.studio-inspector__group-divider--space{height:.5rem}.studio-inspector__parameter{display:flex;flex-direction:column;gap:.5rem}.studio-inspector__parameter-label{font-size:.8125rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary)}.studio-inspector__parameter-hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-inspector__number-input{display:flex;align-items:center;gap:.5rem}.studio-inspector__suffix{font-size:.875rem;color:var(--studio-text-secondary);flex-shrink:0}.studio-inspector__options{display:flex;flex-direction:column;gap:.5rem}.studio-inspector__option{display:flex;align-items:center;gap:.5rem}.studio-inspector__default-indicator{font-size:.75rem;color:var(--studio-text-tertiary);font-style:italic}:host(.studio-inspector--compact) .studio-inspector__container{gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__section-header{padding:.625rem .75rem}:host(.studio-inspector--compact) .studio-inspector__section-content{padding:.75rem;gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__group{gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__parameter{gap:.375rem}:host(.studio-inspector--spacing-sm) .studio-inspector__section-content{gap:.5rem}:host(.studio-inspector--spacing-sm) .studio-inspector__group{gap:.5rem}:host(.studio-inspector--spacing-sm) .studio-inspector__parameter{gap:.375rem}:host(.studio-inspector--spacing-lg) .studio-inspector__section-content{gap:1rem}:host(.studio-inspector--spacing-lg) .studio-inspector__group{gap:1rem}:host(.studio-inspector--spacing-lg) .studio-inspector__parameter{gap:.625rem}:host(.studio-inspector--spacing-lg) .studio-inspector__group-divider--space{height:1rem}\n"] }]
5026
+ }], ctorParameters: () => [], propDecorators: { componentSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentSize", required: false }] }], componentVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentVariant", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], showIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcons", required: false }] }], showDefaultIndicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDefaultIndicator", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], expandedByDefault: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedByDefault", required: false }] }], expandedSectionsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedSections", required: false }] }], showGroupLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGroupLabels", required: false }] }], groupDivider: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupDivider", required: false }] }], groupDividerSpacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupDividerSpacing", required: false }] }], labelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelWidth", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], spacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "spacing", required: false }] }], sectionTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionTemplate", required: false }] }], parameterTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterTemplates", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], sectionToggled: [{ type: i0.Output, args: ["sectionToggled"] }], parameterFocused: [{ type: i0.Output, args: ["parameterFocused"] }], parameterBlurred: [{ type: i0.Output, args: ["parameterBlurred"] }] } });
5027
+
3347
5028
  /**
3348
5029
  * Theme toggle switch with sun/moon icons
3349
5030
  *
@@ -3872,5 +5553,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
3872
5553
  * Generated bundle index. Do not edit.
3873
5554
  */
3874
5555
 
3875
- export { BadgeComponent, BadgeWrapperComponent, ButtonComponent, ButtonGroupComponent, ButtonToggleGroupComponent, CheckboxComponent, DrawerComponent, DrawerService, IconComponent, InputComponent, MASK_PRESETS, MaskDirective, MaskEngine, MenuComponent, NavbarComponent, STUDIO_CONFIG, SelectComponent, SidebarComponent, StudioConfigService, SwitchComponent, TextareaComponent, ThemeSwitchComponent, classNames, isSafeUrl, loadGoogleFont, loadGoogleFonts, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
5556
+ export { BadgeComponent, BadgeWrapperComponent, ButtonComponent, ButtonGroupComponent, ButtonToggleGroupComponent, CheckboxComponent, ColorPickerCompactComponent, ColorPickerComponent, DEFAULT_COLOR_PRESETS, DrawerComponent, DrawerService, DropdownComponent, IconComponent, InputComponent, InspectorComponent, MASK_PRESETS, MaskDirective, MaskEngine, MenuComponent, ModalComponent, NavbarComponent, PopoverComponent, RadioButtonComponent, STUDIO_CONFIG, SelectComponent, SidebarComponent, StudioConfigService, SwitchComponent, TabsComponent, TextareaComponent, ThemeSwitchComponent, TooltipComponent, classNames, isSafeUrl, loadGoogleFont, loadGoogleFonts, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
3876
5557
  //# sourceMappingURL=eduboxpro-studio.mjs.map