@eduboxpro/studio 0.1.12 → 0.1.13

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,11 @@
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, contentChild, model, 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';
8
9
  import { Router, RouterLink, RouterLinkActive, NavigationEnd } from '@angular/router';
9
10
  import { trigger, state, transition, style, animate } from '@angular/animations';
10
11
  import { filter } from 'rxjs/operators';
@@ -1278,6 +1279,400 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
1278
1279
  }, 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
1280
  }], 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
1281
 
1282
+ class ColorConverter {
1283
+ static hexToRgb(hex) {
1284
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
1285
+ return result ? {
1286
+ r: parseInt(result[1], 16),
1287
+ g: parseInt(result[2], 16),
1288
+ b: parseInt(result[3], 16)
1289
+ } : null;
1290
+ }
1291
+ static rgbToHex(r, g, b) {
1292
+ return "#" + [r, g, b]
1293
+ .map(x => {
1294
+ const hex = Math.round(x).toString(16);
1295
+ return hex.length === 1 ? "0" + hex : hex;
1296
+ })
1297
+ .join("");
1298
+ }
1299
+ static rgbToHsl(r, g, b) {
1300
+ r /= 255;
1301
+ g /= 255;
1302
+ b /= 255;
1303
+ const max = Math.max(r, g, b);
1304
+ const min = Math.min(r, g, b);
1305
+ let h = 0, s = 0;
1306
+ const l = (max + min) / 2;
1307
+ if (max !== min) {
1308
+ const d = max - min;
1309
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1310
+ switch (max) {
1311
+ case r:
1312
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
1313
+ break;
1314
+ case g:
1315
+ h = ((b - r) / d + 2) / 6;
1316
+ break;
1317
+ case b:
1318
+ h = ((r - g) / d + 4) / 6;
1319
+ break;
1320
+ }
1321
+ }
1322
+ return {
1323
+ h: Math.round(h * 360),
1324
+ s: Math.round(s * 100),
1325
+ l: Math.round(l * 100)
1326
+ };
1327
+ }
1328
+ static hslToRgb(h, s, l) {
1329
+ h = h / 360;
1330
+ s = s / 100;
1331
+ l = l / 100;
1332
+ let r, g, b;
1333
+ if (s === 0) {
1334
+ r = g = b = l;
1335
+ }
1336
+ else {
1337
+ const hue2rgb = (p, q, t) => {
1338
+ if (t < 0)
1339
+ t += 1;
1340
+ if (t > 1)
1341
+ t -= 1;
1342
+ if (t < 1 / 6)
1343
+ return p + (q - p) * 6 * t;
1344
+ if (t < 1 / 2)
1345
+ return q;
1346
+ if (t < 2 / 3)
1347
+ return p + (q - p) * (2 / 3 - t) * 6;
1348
+ return p;
1349
+ };
1350
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1351
+ const p = 2 * l - q;
1352
+ r = hue2rgb(p, q, h + 1 / 3);
1353
+ g = hue2rgb(p, q, h);
1354
+ b = hue2rgb(p, q, h - 1 / 3);
1355
+ }
1356
+ return {
1357
+ r: Math.round(r * 255),
1358
+ g: Math.round(g * 255),
1359
+ b: Math.round(b * 255)
1360
+ };
1361
+ }
1362
+ static format(color, format) {
1363
+ switch (format) {
1364
+ case 'hex':
1365
+ return color.hex;
1366
+ case 'rgb':
1367
+ if (color.alpha < 1) {
1368
+ return `rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${color.alpha})`;
1369
+ }
1370
+ return `rgb(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b})`;
1371
+ case 'hsl':
1372
+ if (color.alpha < 1) {
1373
+ return `hsla(${color.hsl.h}, ${color.hsl.s}%, ${color.hsl.l}%, ${color.alpha})`;
1374
+ }
1375
+ return `hsl(${color.hsl.h}, ${color.hsl.s}%, ${color.hsl.l}%)`;
1376
+ default:
1377
+ return color.hex;
1378
+ }
1379
+ }
1380
+ static parse(colorString) {
1381
+ const trimmed = colorString.trim();
1382
+ const hexMatch = /^#?([a-f\d]{6})$/i.exec(trimmed);
1383
+ if (hexMatch) {
1384
+ const hex = '#' + hexMatch[1];
1385
+ const rgb = this.hexToRgb(hex);
1386
+ if (!rgb)
1387
+ return null;
1388
+ return {
1389
+ hex,
1390
+ rgb,
1391
+ hsl: this.rgbToHsl(rgb.r, rgb.g, rgb.b),
1392
+ alpha: 1
1393
+ };
1394
+ }
1395
+ const rgbMatch = /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)$/i.exec(trimmed);
1396
+ if (rgbMatch) {
1397
+ const r = parseInt(rgbMatch[1]);
1398
+ const g = parseInt(rgbMatch[2]);
1399
+ const b = parseInt(rgbMatch[3]);
1400
+ const alpha = rgbMatch[4] ? parseFloat(rgbMatch[4]) : 1;
1401
+ return {
1402
+ hex: this.rgbToHex(r, g, b),
1403
+ rgb: { r, g, b },
1404
+ hsl: this.rgbToHsl(r, g, b),
1405
+ alpha
1406
+ };
1407
+ }
1408
+ const hslMatch = /^hsla?\((\d+),\s*(\d+)%?,\s*(\d+)%?(?:,\s*([\d.]+))?\)$/i.exec(trimmed);
1409
+ if (hslMatch) {
1410
+ const h = parseInt(hslMatch[1]);
1411
+ const s = parseInt(hslMatch[2]);
1412
+ const l = parseInt(hslMatch[3]);
1413
+ const alpha = hslMatch[4] ? parseFloat(hslMatch[4]) : 1;
1414
+ const rgb = this.hslToRgb(h, s, l);
1415
+ return {
1416
+ hex: this.rgbToHex(rgb.r, rgb.g, rgb.b),
1417
+ rgb,
1418
+ hsl: { h, s, l },
1419
+ alpha
1420
+ };
1421
+ }
1422
+ return null;
1423
+ }
1424
+ static isValid(colorString) {
1425
+ return this.parse(colorString) !== null;
1426
+ }
1427
+ }
1428
+
1429
+ const DEFAULT_COLOR_PRESETS = [
1430
+ {
1431
+ label: 'Brand Colors',
1432
+ colors: [
1433
+ { label: 'Primary', value: '#7c3aed' },
1434
+ { label: 'Secondary', value: '#6366f1' },
1435
+ { label: 'Success', value: '#10b981' },
1436
+ { label: 'Error', value: '#ef4444' },
1437
+ { label: 'Warning', value: '#f59e0b' },
1438
+ { label: 'Info', value: '#3b82f6' }
1439
+ ]
1440
+ },
1441
+ {
1442
+ label: 'Grays',
1443
+ colors: [
1444
+ { value: '#ffffff' },
1445
+ { value: '#f3f4f6' },
1446
+ { value: '#d1d5db' },
1447
+ { value: '#9ca3af' },
1448
+ { value: '#6b7280' },
1449
+ { value: '#374151' },
1450
+ { value: '#1f2937' },
1451
+ { value: '#000000' }
1452
+ ]
1453
+ },
1454
+ {
1455
+ label: 'Common',
1456
+ colors: [
1457
+ { value: '#ff0000' },
1458
+ { value: '#ff7f00' },
1459
+ { value: '#ffff00' },
1460
+ { value: '#00ff00' },
1461
+ { value: '#0000ff' },
1462
+ { value: '#4b0082' },
1463
+ { value: '#9400d3' },
1464
+ { value: '#ff1493' }
1465
+ ]
1466
+ }
1467
+ ];
1468
+
1469
+ class ColorPickerComponent {
1470
+ configService = inject(StudioConfigService);
1471
+ pickerDefaults = computed(() => this.configService.config().components?.colorPicker, ...(ngDevMode ? [{ debugName: "pickerDefaults" }] : []));
1472
+ colorAreaCanvas = viewChild('colorArea', ...(ngDevMode ? [{ debugName: "colorAreaCanvas" }] : []));
1473
+ variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
1474
+ sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
1475
+ variant = withConfigDefault(this.variantInput, computed(() => this.pickerDefaults()?.variant), 'inline');
1476
+ size = withConfigDefault(this.sizeInput, computed(() => this.pickerDefaults()?.size), 'md');
1477
+ format = input('hex', ...(ngDevMode ? [{ debugName: "format" }] : []));
1478
+ showAlpha = input(false, ...(ngDevMode ? [{ debugName: "showAlpha" }] : []));
1479
+ showPresets = input(true, ...(ngDevMode ? [{ debugName: "showPresets" }] : []));
1480
+ showFormatToggle = input(true, ...(ngDevMode ? [{ debugName: "showFormatToggle" }] : []));
1481
+ showCopyButton = input(true, ...(ngDevMode ? [{ debugName: "showCopyButton" }] : []));
1482
+ presets = input(...(ngDevMode ? [undefined, { debugName: "presets" }] : []));
1483
+ label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : []));
1484
+ hint = input(undefined, ...(ngDevMode ? [{ debugName: "hint" }] : []));
1485
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
1486
+ error = input(false, ...(ngDevMode ? [{ debugName: "error" }] : []));
1487
+ errorMessage = input(undefined, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
1488
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1489
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
1490
+ colorChange = output();
1491
+ colorValueChange = output();
1492
+ copied = output();
1493
+ currentColor = signal(this.createColorValue('#000000'), ...(ngDevMode ? [{ debugName: "currentColor" }] : []));
1494
+ hue = signal(0, ...(ngDevMode ? [{ debugName: "hue" }] : []));
1495
+ saturation = signal(100, ...(ngDevMode ? [{ debugName: "saturation" }] : []));
1496
+ lightness = signal(50, ...(ngDevMode ? [{ debugName: "lightness" }] : []));
1497
+ alpha = signal(1, ...(ngDevMode ? [{ debugName: "alpha" }] : []));
1498
+ currentFormat = signal('hex', ...(ngDevMode ? [{ debugName: "currentFormat" }] : []));
1499
+ generatedId = `studio-color-picker-${Math.random().toString(36).substr(2, 9)}`;
1500
+ onChange = () => { };
1501
+ onTouched = () => { };
1502
+ isDragging = false;
1503
+ constructor() {
1504
+ effect(() => {
1505
+ this.currentFormat.set(this.format());
1506
+ });
1507
+ effect(() => {
1508
+ this.renderColorArea();
1509
+ });
1510
+ }
1511
+ ngAfterViewInit() {
1512
+ this.renderColorArea();
1513
+ }
1514
+ displayColor = computed(() => {
1515
+ const color = this.currentColor();
1516
+ return ColorConverter.format(color, this.currentFormat());
1517
+ }, ...(ngDevMode ? [{ debugName: "displayColor" }] : []));
1518
+ effectivePresets = computed(() => {
1519
+ const custom = this.presets();
1520
+ return custom && custom.length > 0 ? custom : DEFAULT_COLOR_PRESETS;
1521
+ }, ...(ngDevMode ? [{ debugName: "effectivePresets" }] : []));
1522
+ 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" }] : []));
1523
+ writeValue(value) {
1524
+ if (!value)
1525
+ return;
1526
+ const colorValue = ColorConverter.parse(value);
1527
+ if (colorValue) {
1528
+ this.currentColor.set(colorValue);
1529
+ this.hue.set(colorValue.hsl.h);
1530
+ this.saturation.set(colorValue.hsl.s);
1531
+ this.lightness.set(colorValue.hsl.l);
1532
+ this.alpha.set(colorValue.alpha);
1533
+ }
1534
+ }
1535
+ registerOnChange(fn) {
1536
+ this.onChange = fn;
1537
+ }
1538
+ registerOnTouched(fn) {
1539
+ this.onTouched = fn;
1540
+ }
1541
+ setDisabledState(isDisabled) { }
1542
+ onHueChange(event) {
1543
+ const value = +event.target.value;
1544
+ this.hue.set(value);
1545
+ this.updateColor();
1546
+ }
1547
+ onAlphaChange(event) {
1548
+ const value = +event.target.value;
1549
+ this.alpha.set(value / 100);
1550
+ this.updateColor();
1551
+ }
1552
+ onColorAreaMouseDown(event) {
1553
+ if (this.disabled() || this.readonly())
1554
+ return;
1555
+ this.isDragging = true;
1556
+ this.updateColorArea(event);
1557
+ const onMouseMove = (e) => {
1558
+ if (this.isDragging) {
1559
+ this.updateColorArea(e);
1560
+ }
1561
+ };
1562
+ const onMouseUp = () => {
1563
+ this.isDragging = false;
1564
+ document.removeEventListener('mousemove', onMouseMove);
1565
+ document.removeEventListener('mouseup', onMouseUp);
1566
+ };
1567
+ document.addEventListener('mousemove', onMouseMove);
1568
+ document.addEventListener('mouseup', onMouseUp);
1569
+ }
1570
+ updateColorArea(event) {
1571
+ const canvas = this.colorAreaCanvas()?.nativeElement;
1572
+ if (!canvas)
1573
+ return;
1574
+ const rect = canvas.getBoundingClientRect();
1575
+ const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
1576
+ const y = Math.max(0, Math.min(event.clientY - rect.top, rect.height));
1577
+ this.saturation.set((x / rect.width) * 100);
1578
+ this.lightness.set(100 - (y / rect.height) * 100);
1579
+ this.updateColor();
1580
+ }
1581
+ updateColor() {
1582
+ const h = this.hue();
1583
+ const s = this.saturation();
1584
+ const l = this.lightness();
1585
+ const rgb = ColorConverter.hslToRgb(h, s, l);
1586
+ const hex = ColorConverter.rgbToHex(rgb.r, rgb.g, rgb.b);
1587
+ const colorValue = {
1588
+ hex,
1589
+ rgb,
1590
+ hsl: { h, s, l },
1591
+ alpha: this.alpha()
1592
+ };
1593
+ this.currentColor.set(colorValue);
1594
+ const formatted = ColorConverter.format(colorValue, this.currentFormat());
1595
+ this.onChange(formatted);
1596
+ this.colorChange.emit(formatted);
1597
+ this.colorValueChange.emit(colorValue);
1598
+ }
1599
+ renderColorArea() {
1600
+ const canvas = this.colorAreaCanvas()?.nativeElement;
1601
+ if (!canvas)
1602
+ return;
1603
+ const ctx = canvas.getContext('2d');
1604
+ if (!ctx)
1605
+ return;
1606
+ const width = canvas.width;
1607
+ const height = canvas.height;
1608
+ const hue = this.hue();
1609
+ const horizGradient = ctx.createLinearGradient(0, 0, width, 0);
1610
+ horizGradient.addColorStop(0, 'white');
1611
+ horizGradient.addColorStop(1, `hsl(${hue}, 100%, 50%)`);
1612
+ ctx.fillStyle = horizGradient;
1613
+ ctx.fillRect(0, 0, width, height);
1614
+ const vertGradient = ctx.createLinearGradient(0, 0, 0, height);
1615
+ vertGradient.addColorStop(0, 'transparent');
1616
+ vertGradient.addColorStop(1, 'black');
1617
+ ctx.fillStyle = vertGradient;
1618
+ ctx.fillRect(0, 0, width, height);
1619
+ }
1620
+ toggleFormat() {
1621
+ const formats = ['hex', 'rgb', 'hsl'];
1622
+ const current = this.currentFormat();
1623
+ const index = formats.indexOf(current);
1624
+ const next = formats[(index + 1) % formats.length];
1625
+ this.currentFormat.set(next);
1626
+ }
1627
+ async copyColor() {
1628
+ const color = this.displayColor();
1629
+ try {
1630
+ await navigator.clipboard.writeText(color);
1631
+ this.copied.emit(color);
1632
+ }
1633
+ catch (error) {
1634
+ console.error('Copy failed:', error);
1635
+ }
1636
+ }
1637
+ selectPreset(preset) {
1638
+ this.writeValue(preset.value);
1639
+ this.updateColor();
1640
+ }
1641
+ isPresetGroup(item) {
1642
+ return item && 'colors' in item && Array.isArray(item.colors);
1643
+ }
1644
+ createColorValue(hex) {
1645
+ const rgb = ColorConverter.hexToRgb(hex) || { r: 0, g: 0, b: 0 };
1646
+ const hsl = ColorConverter.rgbToHsl(rgb.r, rgb.g, rgb.b);
1647
+ return {
1648
+ hex,
1649
+ rgb,
1650
+ hsl,
1651
+ alpha: 1
1652
+ };
1653
+ }
1654
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ColorPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1655
+ 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: [
1656
+ {
1657
+ provide: NG_VALUE_ACCESSOR,
1658
+ useExisting: forwardRef(() => ColorPickerComponent),
1659
+ multi: true
1660
+ }
1661
+ ], 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 });
1662
+ }
1663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ColorPickerComponent, decorators: [{
1664
+ type: Component,
1665
+ args: [{ selector: 'studio-color-picker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
1666
+ {
1667
+ provide: NG_VALUE_ACCESSOR,
1668
+ useExisting: forwardRef(() => ColorPickerComponent),
1669
+ multi: true
1670
+ }
1671
+ ], host: {
1672
+ '[class]': 'hostClasses()',
1673
+ }, 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"] }]
1674
+ }], 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"] }] } });
1675
+
1281
1676
  /**
1282
1677
  * Service for programmatic control of Drawer components
1283
1678
  *
@@ -2322,6 +2717,117 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2322
2717
  }, 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
2718
  }], 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
2719
 
2720
+ /**
2721
+ * RadioButton component for selecting a single option from a group
2722
+ *
2723
+ * @example
2724
+ * <studio-radio-button
2725
+ * [(ngModel)]="selectedValue"
2726
+ * [value]="'option1'"
2727
+ * label="Option 1"
2728
+ * name="options"
2729
+ * />
2730
+ */
2731
+ class RadioButtonComponent {
2732
+ configService = inject(StudioConfigService);
2733
+ radioDefaults = computed(() => this.configService.config().components?.radioButton, ...(ngDevMode ? [{ debugName: "radioDefaults" }] : []));
2734
+ size = input(this.radioDefaults()?.size ?? 'md', ...(ngDevMode ? [{ debugName: "size" }] : []));
2735
+ color = input(this.radioDefaults()?.color ?? 'primary', ...(ngDevMode ? [{ debugName: "color" }] : []));
2736
+ variant = input(this.radioDefaults()?.variant ?? 'default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
2737
+ radius = input(this.radioDefaults()?.radius ?? 'full', ...(ngDevMode ? [{ debugName: "radius" }] : []));
2738
+ label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
2739
+ labelPosition = input(this.radioDefaults()?.labelPosition ?? 'right', ...(ngDevMode ? [{ debugName: "labelPosition" }] : []));
2740
+ description = input(...(ngDevMode ? [undefined, { debugName: "description" }] : []));
2741
+ hint = input(...(ngDevMode ? [undefined, { debugName: "hint" }] : []));
2742
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
2743
+ error = input(false, ...(ngDevMode ? [{ debugName: "error" }] : []));
2744
+ errorMessage = input(...(ngDevMode ? [undefined, { debugName: "errorMessage" }] : []));
2745
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
2746
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
2747
+ name = input(...(ngDevMode ? [undefined, { debugName: "name" }] : []));
2748
+ tabIndex = input(0, ...(ngDevMode ? [{ debugName: "tabIndex" }] : []));
2749
+ value = input(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
2750
+ changed = output();
2751
+ internalValue = signal(null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
2752
+ isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : []));
2753
+ radioId = signal(`studio-radio-${Math.random().toString(36).substr(2, 9)}`, ...(ngDevMode ? [{ debugName: "radioId" }] : []));
2754
+ hostClasses = computed(() => ({
2755
+ 'studio-radio-wrapper': true,
2756
+ [`studio-radio-wrapper--${this.size()}`]: true,
2757
+ 'studio-radio-wrapper--disabled': this.disabled(),
2758
+ 'studio-radio-wrapper--error': this.error(),
2759
+ 'studio-radio-wrapper--focused': this.isFocused(),
2760
+ 'studio-radio-wrapper--label-left': this.labelPosition() === 'left'
2761
+ }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
2762
+ radioClasses = computed(() => ({
2763
+ 'studio-radio': true,
2764
+ [`studio-radio--${this.size()}`]: true,
2765
+ [`studio-radio--${this.color()}`]: true,
2766
+ [`studio-radio--${this.variant()}`]: true,
2767
+ [`studio-radio--radius-${this.radius()}`]: true,
2768
+ 'studio-radio--checked': this.isChecked(),
2769
+ 'studio-radio--disabled': this.disabled(),
2770
+ 'studio-radio--error': this.error()
2771
+ }), ...(ngDevMode ? [{ debugName: "radioClasses" }] : []));
2772
+ showError = computed(() => this.error() && this.errorMessage(), ...(ngDevMode ? [{ debugName: "showError" }] : []));
2773
+ showHint = computed(() => !this.error() && this.hint(), ...(ngDevMode ? [{ debugName: "showHint" }] : []));
2774
+ isChecked = computed(() => this.internalValue() === this.value(), ...(ngDevMode ? [{ debugName: "isChecked" }] : []));
2775
+ onChange = () => { };
2776
+ onTouched = () => { };
2777
+ writeValue(value) {
2778
+ this.internalValue.set(value);
2779
+ }
2780
+ registerOnChange(fn) {
2781
+ this.onChange = fn;
2782
+ }
2783
+ registerOnTouched(fn) {
2784
+ this.onTouched = fn;
2785
+ }
2786
+ setDisabledState(isDisabled) { }
2787
+ handleChange(event) {
2788
+ if (this.disabled() || this.readonly()) {
2789
+ event.preventDefault();
2790
+ return;
2791
+ }
2792
+ const inputValue = this.value();
2793
+ this.internalValue.set(inputValue);
2794
+ this.onChange(inputValue);
2795
+ this.changed.emit(inputValue);
2796
+ }
2797
+ handleFocus() {
2798
+ this.isFocused.set(true);
2799
+ }
2800
+ handleBlur() {
2801
+ this.isFocused.set(false);
2802
+ this.onTouched();
2803
+ }
2804
+ handleLabelClick(event) {
2805
+ if (this.disabled() || this.readonly()) {
2806
+ event.preventDefault();
2807
+ }
2808
+ }
2809
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: RadioButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2810
+ 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: [{
2811
+ provide: NG_VALUE_ACCESSOR,
2812
+ useExisting: forwardRef(() => RadioButtonComponent),
2813
+ multi: true
2814
+ }], 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"] }] });
2815
+ }
2816
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: RadioButtonComponent, decorators: [{
2817
+ type: Component,
2818
+ args: [{ selector: 'studio-radio-button', standalone: true, imports: [CommonModule], providers: [{
2819
+ provide: NG_VALUE_ACCESSOR,
2820
+ useExisting: forwardRef(() => RadioButtonComponent),
2821
+ multi: true
2822
+ }], host: {
2823
+ '[class]': 'hostClasses()',
2824
+ '[attr.data-size]': 'size()',
2825
+ '[attr.data-color]': 'color()',
2826
+ '[attr.data-disabled]': 'disabled()',
2827
+ '[attr.data-error]': 'error()'
2828
+ }, 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"] }]
2829
+ }], 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"] }] } });
2830
+
2325
2831
  class SelectComponent {
2326
2832
  configService = inject(StudioConfigService);
2327
2833
  selectDefaults = computed(() => this.configService.config().components?.select, ...(ngDevMode ? [{ debugName: "selectDefaults" }] : []));
@@ -2722,6 +3228,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2722
3228
  *
2723
3229
  * @example
2724
3230
  * <studio-switch [(checked)]="isEnabled" label="Enable feature" />
3231
+ * <studio-switch [(ngModel)]="isEnabled" label="Enable feature" />
2725
3232
  */
2726
3233
  class SwitchComponent {
2727
3234
  configService = inject(StudioConfigService);
@@ -2737,11 +3244,25 @@ class SwitchComponent {
2737
3244
  size = withConfigDefault(this.sizeInput, computed(() => this.switchDefaults()?.size), 'md');
2738
3245
  color = withConfigDefault(this.colorInput, computed(() => this.switchDefaults()?.color), 'primary');
2739
3246
  checkedChange = output();
3247
+ internalChecked = signal(false, ...(ngDevMode ? [{ debugName: "internalChecked" }] : []));
3248
+ onChange = () => { };
3249
+ onTouched = () => { };
2740
3250
  iconSize = computed(() => {
2741
3251
  const sizeMap = { sm: 10, md: 12, lg: 14 };
2742
3252
  return sizeMap[this.size()];
2743
3253
  }, ...(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" }] : []));
3254
+ 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" }] : []));
3255
+ writeValue(value) {
3256
+ this.internalChecked.set(value ?? false);
3257
+ this.checked.set(value ?? false);
3258
+ }
3259
+ registerOnChange(fn) {
3260
+ this.onChange = fn;
3261
+ }
3262
+ registerOnTouched(fn) {
3263
+ this.onTouched = fn;
3264
+ }
3265
+ setDisabledState(isDisabled) { }
2745
3266
  handleClick() {
2746
3267
  if (this.disabled())
2747
3268
  return;
@@ -2754,12 +3275,21 @@ class SwitchComponent {
2754
3275
  this.toggle();
2755
3276
  }
2756
3277
  toggle() {
2757
- const newValue = !this.checked();
3278
+ const newValue = !this.internalChecked();
3279
+ this.internalChecked.set(newValue);
2758
3280
  this.checked.set(newValue);
3281
+ this.onChange(newValue);
3282
+ this.onTouched();
2759
3283
  this.checkedChange.emit(newValue);
2760
3284
  }
2761
3285
  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: `
3286
+ 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: [
3287
+ {
3288
+ provide: NG_VALUE_ACCESSOR,
3289
+ useExisting: forwardRef(() => SwitchComponent),
3290
+ multi: true
3291
+ }
3292
+ ], ngImport: i0, template: `
2763
3293
  <span class="studio-switch__container">
2764
3294
  @if (label() && labelPosition() === 'left') {
2765
3295
  <span class="studio-switch__label studio-switch__label--left">
@@ -2770,7 +3300,7 @@ class SwitchComponent {
2770
3300
  <span class="studio-switch__track">
2771
3301
  <span class="studio-switch__thumb">
2772
3302
  @if (showIcons()) {
2773
- @if (checked()) {
3303
+ @if (internalChecked()) {
2774
3304
  <studio-icon name="check" [size]="iconSize()" color="inherit" />
2775
3305
  } @else {
2776
3306
  <studio-icon name="x" [size]="iconSize()" color="inherit" />
@@ -2789,10 +3319,16 @@ class SwitchComponent {
2789
3319
  }
2790
3320
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SwitchComponent, decorators: [{
2791
3321
  type: Component,
2792
- args: [{ selector: 'studio-switch', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
3322
+ args: [{ selector: 'studio-switch', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
3323
+ {
3324
+ provide: NG_VALUE_ACCESSOR,
3325
+ useExisting: forwardRef(() => SwitchComponent),
3326
+ multi: true
3327
+ }
3328
+ ], host: {
2793
3329
  '[class]': 'hostClasses()',
2794
3330
  '[attr.role]': '"switch"',
2795
- '[attr.aria-checked]': 'checked()',
3331
+ '[attr.aria-checked]': 'internalChecked()',
2796
3332
  '[attr.aria-disabled]': 'disabled() ? "true" : null',
2797
3333
  '[attr.aria-label]': 'ariaLabel() || label()',
2798
3334
  '(click)': 'handleClick()',
@@ -2810,7 +3346,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2810
3346
  <span class="studio-switch__track">
2811
3347
  <span class="studio-switch__thumb">
2812
3348
  @if (showIcons()) {
2813
- @if (checked()) {
3349
+ @if (internalChecked()) {
2814
3350
  <studio-icon name="check" [size]="iconSize()" color="inherit" />
2815
3351
  } @else {
2816
3352
  <studio-icon name="x" [size]="iconSize()" color="inherit" />
@@ -3344,6 +3880,215 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
3344
3880
  `, styles: [":host{display:inline-block}:host(.studio-button-toggle-group--disabled){opacity:.6;pointer-events:none}\n"] }]
3345
3881
  }], 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
3882
 
3883
+ class InspectorComponent {
3884
+ configService = inject(StudioConfigService);
3885
+ componentSize = input('sm', ...(ngDevMode ? [{ debugName: "componentSize" }] : []));
3886
+ componentVariant = input('outline', ...(ngDevMode ? [{ debugName: "componentVariant" }] : []));
3887
+ compact = input(false, ...(ngDevMode ? [{ debugName: "compact" }] : []));
3888
+ showIcons = input(true, ...(ngDevMode ? [{ debugName: "showIcons" }] : []));
3889
+ showDefaultIndicator = input(true, ...(ngDevMode ? [{ debugName: "showDefaultIndicator" }] : []));
3890
+ collapsible = input(true, ...(ngDevMode ? [{ debugName: "collapsible" }] : []));
3891
+ expandedByDefault = input(true, ...(ngDevMode ? [{ debugName: "expandedByDefault" }] : []));
3892
+ expandedSectionsInput = input([], ...(ngDevMode ? [{ debugName: "expandedSectionsInput", alias: 'expandedSections' }] : [{ alias: 'expandedSections' }]));
3893
+ showGroupLabels = input(true, ...(ngDevMode ? [{ debugName: "showGroupLabels" }] : []));
3894
+ groupDivider = input('line', ...(ngDevMode ? [{ debugName: "groupDivider" }] : []));
3895
+ groupDividerSpacing = input('md', ...(ngDevMode ? [{ debugName: "groupDividerSpacing" }] : []));
3896
+ labelWidth = input('auto', ...(ngDevMode ? [{ debugName: "labelWidth" }] : []));
3897
+ fullWidth = input(true, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
3898
+ spacing = input('md', ...(ngDevMode ? [{ debugName: "spacing" }] : []));
3899
+ sectionTemplate = input(undefined, ...(ngDevMode ? [{ debugName: "sectionTemplate" }] : []));
3900
+ parameterTemplates = input(undefined, ...(ngDevMode ? [{ debugName: "parameterTemplates" }] : []));
3901
+ ariaLabel = input('Inspector panel', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
3902
+ ariaDescribedBy = input(undefined, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
3903
+ sectionToggled = output();
3904
+ parameterFocused = output();
3905
+ parameterBlurred = output();
3906
+ values = signal(null, ...(ngDevMode ? [{ debugName: "values" }] : []));
3907
+ expandedSections = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedSections" }] : []));
3908
+ onChange = () => { };
3909
+ onTouched = () => { };
3910
+ constructor() {
3911
+ effect(() => {
3912
+ const inputSections = this.expandedSectionsInput();
3913
+ if (inputSections.length > 0) {
3914
+ this.expandedSections.set(new Set(inputSections));
3915
+ }
3916
+ });
3917
+ }
3918
+ hostClasses = computed(() => classNames('studio-inspector', this.compact() && 'studio-inspector--compact', `studio-inspector--spacing-${this.spacing()}`), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
3919
+ isSectionExpanded(componentId) {
3920
+ return this.expandedSections().has(componentId);
3921
+ }
3922
+ toggleSection(componentId) {
3923
+ if (!this.collapsible())
3924
+ return;
3925
+ const expanded = new Set(this.expandedSections());
3926
+ if (expanded.has(componentId)) {
3927
+ expanded.delete(componentId);
3928
+ }
3929
+ else {
3930
+ expanded.add(componentId);
3931
+ }
3932
+ this.expandedSections.set(expanded);
3933
+ this.sectionToggled.emit({
3934
+ id: componentId,
3935
+ expanded: expanded.has(componentId)
3936
+ });
3937
+ }
3938
+ onParameterChange(componentId, groupId, parameterId, newValue) {
3939
+ const updated = structuredClone(this.values());
3940
+ if (!updated)
3941
+ return;
3942
+ const section = updated.sections.find(c => c.id === componentId);
3943
+ if (!section)
3944
+ return;
3945
+ let parameter;
3946
+ if (groupId) {
3947
+ const group = section.groups?.find(g => g.id === groupId);
3948
+ parameter = group?.parameters.find(p => p.id === parameterId);
3949
+ }
3950
+ else {
3951
+ parameter = section.parameters?.find(p => p.id === parameterId);
3952
+ }
3953
+ if (parameter) {
3954
+ parameter.value = newValue;
3955
+ }
3956
+ this.values.set(updated);
3957
+ this.onChange(updated);
3958
+ this.onTouched();
3959
+ }
3960
+ onCheckboxChange(componentId, groupId, parameterId, optionValue, checked) {
3961
+ const updated = structuredClone(this.values());
3962
+ if (!updated)
3963
+ return;
3964
+ const section = updated.sections.find(c => c.id === componentId);
3965
+ if (!section)
3966
+ return;
3967
+ let parameter;
3968
+ if (groupId) {
3969
+ const group = section.groups?.find(g => g.id === groupId);
3970
+ parameter = group?.parameters.find(p => p.id === parameterId);
3971
+ }
3972
+ else {
3973
+ parameter = section.parameters?.find(p => p.id === parameterId);
3974
+ }
3975
+ if (parameter && parameter.type === 'checkbox') {
3976
+ const currentValues = Array.isArray(parameter.value) ? parameter.value : [];
3977
+ if (checked) {
3978
+ if (!currentValues.includes(optionValue)) {
3979
+ parameter.value = [...currentValues, optionValue];
3980
+ }
3981
+ }
3982
+ else {
3983
+ parameter.value = currentValues.filter(v => v !== optionValue);
3984
+ }
3985
+ }
3986
+ this.values.set(updated);
3987
+ this.onChange(updated);
3988
+ this.onTouched();
3989
+ }
3990
+ onRadioChange(componentId, groupId, parameterId, newValue) {
3991
+ this.onParameterChange(componentId, groupId, parameterId, newValue);
3992
+ }
3993
+ getRadioName(componentId, groupId, parameterId) {
3994
+ return `${componentId}-${groupId || 'root'}-${parameterId}`;
3995
+ }
3996
+ isChecked(parameter, optionValue) {
3997
+ if (parameter.type === 'checkbox') {
3998
+ return Array.isArray(parameter.value) && parameter.value.includes(optionValue);
3999
+ }
4000
+ else if (parameter.type === 'radio') {
4001
+ return parameter.value === optionValue;
4002
+ }
4003
+ return false;
4004
+ }
4005
+ isRadioChecked(parameter, optionValue) {
4006
+ return parameter.value === optionValue;
4007
+ }
4008
+ isDefault(parameter, optionValue) {
4009
+ return parameter.default !== undefined && parameter.default === optionValue;
4010
+ }
4011
+ trackBySectionId(_, section) {
4012
+ return section.id;
4013
+ }
4014
+ trackByGroupId(_, group) {
4015
+ return group.id;
4016
+ }
4017
+ trackByParameterId(_, param) {
4018
+ return param.id;
4019
+ }
4020
+ trackByOptionValue(_, option) {
4021
+ return option.value;
4022
+ }
4023
+ writeValue(value) {
4024
+ this.values.set(value);
4025
+ this.initializeExpandedSections();
4026
+ }
4027
+ registerOnChange(fn) {
4028
+ this.onChange = fn;
4029
+ }
4030
+ registerOnTouched(fn) {
4031
+ this.onTouched = fn;
4032
+ }
4033
+ setDisabledState(_) { }
4034
+ initializeExpandedSections() {
4035
+ const expanded = new Set();
4036
+ const inputSections = this.expandedSectionsInput();
4037
+ if (inputSections.length > 0) {
4038
+ inputSections.forEach(id => expanded.add(id));
4039
+ }
4040
+ else if (this.expandedByDefault()) {
4041
+ this.values()?.sections.forEach(c => {
4042
+ if (c.expanded !== false) {
4043
+ expanded.add(c.id);
4044
+ }
4045
+ });
4046
+ }
4047
+ else {
4048
+ this.values()?.sections.forEach(c => {
4049
+ if (c.expanded === true) {
4050
+ expanded.add(c.id);
4051
+ }
4052
+ });
4053
+ }
4054
+ this.expandedSections.set(expanded);
4055
+ }
4056
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: InspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4057
+ 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: [
4058
+ {
4059
+ provide: NG_VALUE_ACCESSOR,
4060
+ useExisting: forwardRef(() => InspectorComponent),
4061
+ multi: true
4062
+ }
4063
+ ], 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\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [size]=\"componentSize()\"\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\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [size]=\"componentSize()\"\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: 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: 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 });
4064
+ }
4065
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: InspectorComponent, decorators: [{
4066
+ type: Component,
4067
+ args: [{ selector: 'studio-inspector', standalone: true, imports: [
4068
+ CommonModule,
4069
+ FormsModule,
4070
+ ButtonComponent,
4071
+ IconComponent,
4072
+ InputComponent,
4073
+ CheckboxComponent,
4074
+ RadioButtonComponent,
4075
+ ColorPickerComponent,
4076
+ SelectComponent,
4077
+ TextareaComponent,
4078
+ SwitchComponent
4079
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
4080
+ {
4081
+ provide: NG_VALUE_ACCESSOR,
4082
+ useExisting: forwardRef(() => InspectorComponent),
4083
+ multi: true
4084
+ }
4085
+ ], host: {
4086
+ '[class]': 'hostClasses()',
4087
+ '[attr.role]': '"region"',
4088
+ '[attr.aria-label]': 'ariaLabel()'
4089
+ }, 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\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [size]=\"componentSize()\"\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\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [size]=\"componentSize()\"\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"] }]
4090
+ }], 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"] }] } });
4091
+
3347
4092
  /**
3348
4093
  * Theme toggle switch with sun/moon icons
3349
4094
  *
@@ -3872,5 +4617,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
3872
4617
  * Generated bundle index. Do not edit.
3873
4618
  */
3874
4619
 
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 };
4620
+ export { BadgeComponent, BadgeWrapperComponent, ButtonComponent, ButtonGroupComponent, ButtonToggleGroupComponent, CheckboxComponent, ColorPickerComponent, DEFAULT_COLOR_PRESETS, DrawerComponent, DrawerService, IconComponent, InputComponent, InspectorComponent, MASK_PRESETS, MaskDirective, MaskEngine, MenuComponent, NavbarComponent, RadioButtonComponent, STUDIO_CONFIG, SelectComponent, SidebarComponent, StudioConfigService, SwitchComponent, TextareaComponent, ThemeSwitchComponent, classNames, isSafeUrl, loadGoogleFont, loadGoogleFonts, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
3876
4621
  //# sourceMappingURL=eduboxpro-studio.mjs.map