@eduboxpro/studio 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output, ElementRef, forwardRef, viewChild, DOCUMENT as DOCUMENT$1, DestroyRef, contentChild, model, HostListener, PLATFORM_ID, Renderer2, Directive } from '@angular/core';
2
+ import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output, ElementRef, forwardRef, viewChild, DOCUMENT as DOCUMENT$1, DestroyRef, Injector, contentChild, model, afterNextRender, HostListener, PLATFORM_ID, Renderer2, Directive } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { DOCUMENT, CommonModule, NgTemplateOutlet, isPlatformBrowser } from '@angular/common';
5
5
  import * as LucideIcons from 'lucide-angular';
6
6
  import { icons, LucideAngularModule, LucideIconProvider, LUCIDE_ICONS } from 'lucide-angular';
7
7
  import * as i1$1 from '@angular/forms';
8
8
  import { NG_VALUE_ACCESSOR, FormsModule, NG_VALIDATORS } from '@angular/forms';
9
+ import { autoUpdate, offset, flip, shift, arrow, computePosition } from '@floating-ui/dom';
9
10
  import { Router, RouterLink, RouterLinkActive, NavigationEnd } from '@angular/router';
10
11
  import { trigger, state, transition, style, animate } from '@angular/animations';
11
12
  import { filter } from 'rxjs/operators';
@@ -1673,6 +1674,477 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
1673
1674
  }, template: "@if (label()) {\n <label [for]=\"generatedId\" class=\"studio-color-picker__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-color-picker__required\">*</span>\n }\n </label>\n}\n\n<div class=\"studio-color-picker__picker\">\n <div class=\"studio-color-picker__preview\">\n <div\n class=\"studio-color-picker__preview-color\"\n [style.background-color]=\"displayColor()\"\n ></div>\n <div class=\"studio-color-picker__preview-info\">\n <span class=\"studio-color-picker__preview-value\">{{ displayColor() }}</span>\n @if (showFormatToggle()) {\n <button\n type=\"button\"\n class=\"studio-color-picker__format-btn\"\n (click)=\"toggleFormat()\"\n [disabled]=\"disabled() || readonly()\"\n >\n {{ currentFormat().toUpperCase() }}\n </button>\n }\n </div>\n @if (showCopyButton()) {\n <button\n type=\"button\"\n class=\"studio-color-picker__copy-btn\"\n (click)=\"copyColor()\"\n [disabled]=\"disabled() || readonly()\"\n aria-label=\"Copy color\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect>\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path>\n </svg>\n </button>\n }\n </div>\n\n <div class=\"studio-color-picker__area\">\n <canvas\n #colorArea\n class=\"studio-color-picker__canvas\"\n width=\"280\"\n height=\"180\"\n (mousedown)=\"onColorAreaMouseDown($event)\"\n ></canvas>\n <div\n class=\"studio-color-picker__cursor\"\n [style.left.%]=\"saturation()\"\n [style.top.%]=\"100 - lightness()\"\n ></div>\n </div>\n\n <div class=\"studio-color-picker__sliders\">\n <div class=\"studio-color-picker__slider\">\n <div class=\"studio-color-picker__slider-label\">Hue</div>\n <input\n type=\"range\"\n class=\"studio-color-picker__hue-slider\"\n min=\"0\"\n max=\"360\"\n [value]=\"hue()\"\n (input)=\"onHueChange($event)\"\n [disabled]=\"disabled() || readonly()\"\n aria-label=\"Hue\"\n />\n </div>\n\n @if (showAlpha()) {\n <div class=\"studio-color-picker__slider\">\n <div class=\"studio-color-picker__slider-label\">Opacity</div>\n <input\n type=\"range\"\n class=\"studio-color-picker__alpha-slider\"\n min=\"0\"\n max=\"100\"\n [value]=\"alpha() * 100\"\n (input)=\"onAlphaChange($event)\"\n [disabled]=\"disabled() || readonly()\"\n aria-label=\"Opacity\"\n />\n <span class=\"studio-color-picker__alpha-value\">{{ (alpha() * 100).toFixed(0) }}%</span>\n </div>\n }\n </div>\n\n @if (showPresets() && effectivePresets().length > 0) {\n <div class=\"studio-color-picker__presets\">\n @for (preset of effectivePresets(); track $index) {\n @if (isPresetGroup(preset)) {\n <div class=\"studio-color-picker__preset-group\">\n <div class=\"studio-color-picker__preset-group-label\">{{ preset.label }}</div>\n <div class=\"studio-color-picker__preset-swatches\">\n @for (color of preset.colors; track color.value) {\n <button\n type=\"button\"\n class=\"studio-color-picker__preset-swatch\"\n [style.background-color]=\"color.value\"\n [title]=\"color.label || color.value\"\n (click)=\"selectPreset(color)\"\n [disabled]=\"disabled() || readonly()\"\n ></button>\n }\n </div>\n </div>\n } @else {\n <button\n type=\"button\"\n class=\"studio-color-picker__preset-swatch\"\n [style.background-color]=\"preset.value\"\n [title]=\"preset.label || preset.value\"\n (click)=\"selectPreset(preset)\"\n [disabled]=\"disabled() || readonly()\"\n ></button>\n }\n }\n </div>\n }\n</div>\n\n@if (hint() && !error()) {\n <span class=\"studio-color-picker__hint\">\n {{ hint() }}\n </span>\n}\n\n@if (error() && errorMessage()) {\n <span class=\"studio-color-picker__error\" role=\"alert\">\n {{ errorMessage() }}\n </span>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:.5rem;font-family:var(--studio-font-family)}.studio-color-picker__label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary)}.studio-color-picker__label .studio-color-picker__required{color:var(--studio-error);margin-left:.125rem}.studio-color-picker__picker{display:flex;flex-direction:column;gap:1rem;padding:1rem;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md)}.studio-color-picker__preview{display:flex;align-items:center;gap:.75rem}.studio-color-picker__preview-color{width:3rem;height:3rem;border-radius:var(--studio-radius-sm);border:1px solid var(--studio-border-primary);flex-shrink:0}.studio-color-picker__preview-info{flex:1;display:flex;align-items:center;gap:.5rem}.studio-color-picker__preview-value{font-family:var(--studio-font-mono, monospace);font-size:.875rem;color:var(--studio-text-primary)}.studio-color-picker__format-btn{padding:.25rem .5rem;background:var(--studio-bg-secondary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-sm);font-size:.75rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast)}.studio-color-picker__format-btn:hover:not(:disabled){background:var(--studio-bg-tertiary);color:var(--studio-text-primary)}.studio-color-picker__format-btn:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__copy-btn{padding:.5rem;background:none;border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--studio-transition-fast)}.studio-color-picker__copy-btn:hover:not(:disabled){background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-color-picker__copy-btn:active:not(:disabled){transform:scale(.95)}.studio-color-picker__copy-btn:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__area{position:relative;width:100%;aspect-ratio:28/18;border-radius:var(--studio-radius-sm);overflow:hidden;border:1px solid var(--studio-border-primary)}.studio-color-picker__canvas{display:block;width:100%;height:100%;cursor:crosshair}.studio-color-picker__cursor{position:absolute;width:16px;height:16px;border:2px solid white;border-radius:50%;transform:translate(-50%,-50%);pointer-events:none;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003}.studio-color-picker__sliders{display:flex;flex-direction:column;gap:.75rem}.studio-color-picker__slider{display:flex;flex-direction:column;gap:.5rem}.studio-color-picker__slider-label{font-size:.75rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-secondary)}.studio-color-picker__hue-slider{-webkit-appearance:none;appearance:none;width:100%;height:12px;border-radius:6px;background:linear-gradient(to right,red,#ff0 17%,#0f0 33%,#0ff,#00f 67%,#f0f 83%,red);outline:none;cursor:pointer}.studio-color-picker__hue-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__hue-slider::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__hue-slider:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__alpha-slider{-webkit-appearance:none;appearance:none;width:100%;height:12px;border-radius:6px;background:linear-gradient(to right,transparent 0%,var(--studio-text-primary) 100%);outline:none;cursor:pointer;position:relative}.studio-color-picker__alpha-slider:before{content:\"\";position:absolute;inset:0;border-radius:6px;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:10px 10px;background-position:0 0,0 5px,5px -5px,-5px 0px;z-index:-1}.studio-color-picker__alpha-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__alpha-slider::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid var(--studio-border-primary);cursor:pointer;box-shadow:0 2px 4px #0003}.studio-color-picker__alpha-slider:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__alpha-value{font-size:.75rem;color:var(--studio-text-secondary);margin-left:auto}.studio-color-picker__presets{display:flex;flex-direction:column;gap:.75rem}.studio-color-picker__preset-group{display:flex;flex-direction:column;gap:.5rem}.studio-color-picker__preset-group-label{font-size:.75rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-secondary)}.studio-color-picker__preset-swatches{display:flex;flex-wrap:wrap;gap:.375rem}.studio-color-picker__preset-swatch{width:2rem;height:2rem;border-radius:var(--studio-radius-sm);border:1px solid var(--studio-border-primary);cursor:pointer;transition:all var(--studio-transition-fast);padding:0}.studio-color-picker__preset-swatch:hover:not(:disabled){transform:scale(1.1);box-shadow:0 2px 8px #00000026}.studio-color-picker__preset-swatch:active:not(:disabled){transform:scale(1.05)}.studio-color-picker__preset-swatch:disabled{opacity:.5;cursor:not-allowed}.studio-color-picker__hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-color-picker__error{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:var(--studio-error);line-height:1.4}:host(.studio-color-picker--disabled) .studio-color-picker__picker{opacity:.6;pointer-events:none}:host(.studio-color-picker--error) .studio-color-picker__picker{border-color:var(--studio-error)}:host(.studio-color-picker--sm) .studio-color-picker__preview-color{width:2.5rem;height:2.5rem}:host(.studio-color-picker--sm) .studio-color-picker__picker{padding:.75rem}:host(.studio-color-picker--lg) .studio-color-picker__preview-color{width:3.5rem;height:3.5rem}:host(.studio-color-picker--lg) .studio-color-picker__picker{padding:1.25rem}\n"] }]
1674
1675
  }], ctorParameters: () => [], propDecorators: { colorAreaCanvas: [{ type: i0.ViewChild, args: ['colorArea', { isSignal: true }] }], variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], showAlpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlpha", required: false }] }], showPresets: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPresets", required: false }] }], showFormatToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFormatToggle", required: false }] }], showCopyButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCopyButton", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], colorChange: [{ type: i0.Output, args: ["colorChange"] }], colorValueChange: [{ type: i0.Output, args: ["colorValueChange"] }], copied: [{ type: i0.Output, args: ["copied"] }] } });
1675
1676
 
1677
+ class PopoverComponent {
1678
+ document = inject(DOCUMENT$1);
1679
+ destroyRef = inject(DestroyRef);
1680
+ injector = inject(Injector);
1681
+ configService = inject(StudioConfigService);
1682
+ popoverDefaults = computed(() => this.configService.config().components?.popover, ...(ngDevMode ? [{ debugName: "popoverDefaults" }] : []));
1683
+ headerTemplate = contentChild('popoverHeader', ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
1684
+ footerTemplate = contentChild('popoverFooter', ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
1685
+ contentTemplate = contentChild('popoverContent', ...(ngDevMode ? [{ debugName: "contentTemplate" }] : []));
1686
+ triggerEl = viewChild('popoverTrigger', ...(ngDevMode ? [{ debugName: "triggerEl" }] : []));
1687
+ panelEl = viewChild('popoverPanel', ...(ngDevMode ? [{ debugName: "panelEl" }] : []));
1688
+ arrowEl = viewChild('popoverArrow', ...(ngDevMode ? [{ debugName: "arrowEl" }] : []));
1689
+ id = input('studio-popover-' + Math.random().toString(36).substring(2, 11), ...(ngDevMode ? [{ debugName: "id" }] : []));
1690
+ visible = model(false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
1691
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1692
+ triggerInput = input(undefined, ...(ngDevMode ? [{ debugName: "triggerInput", alias: 'trigger' }] : [{ alias: 'trigger' }]));
1693
+ openDelay = input(0, ...(ngDevMode ? [{ debugName: "openDelay" }] : []));
1694
+ closeDelay = input(200, ...(ngDevMode ? [{ debugName: "closeDelay" }] : []));
1695
+ trigger = withConfigDefault(this.triggerInput, computed(() => this.popoverDefaults()?.trigger), 'click');
1696
+ positionInput = input(undefined, ...(ngDevMode ? [{ debugName: "positionInput", alias: 'position' }] : [{ alias: 'position' }]));
1697
+ offset = input(8, ...(ngDevMode ? [{ debugName: "offset" }] : []));
1698
+ preventOverflow = input(true, ...(ngDevMode ? [{ debugName: "preventOverflow" }] : []));
1699
+ flipValue = input(true, ...(ngDevMode ? [{ debugName: "flipValue" }] : []));
1700
+ position = withConfigDefault(this.positionInput, computed(() => this.popoverDefaults()?.position), 'bottom');
1701
+ variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
1702
+ sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
1703
+ width = input('auto', ...(ngDevMode ? [{ debugName: "width" }] : []));
1704
+ minWidth = input(undefined, ...(ngDevMode ? [{ debugName: "minWidth" }] : []));
1705
+ maxWidth = input(undefined, ...(ngDevMode ? [{ debugName: "maxWidth" }] : []));
1706
+ maxHeight = input(undefined, ...(ngDevMode ? [{ debugName: "maxHeight" }] : []));
1707
+ padding = input(undefined, ...(ngDevMode ? [{ debugName: "padding" }] : []));
1708
+ variant = withConfigDefault(this.variantInput, computed(() => this.popoverDefaults()?.variant), 'default');
1709
+ size = withConfigDefault(this.sizeInput, computed(() => this.popoverDefaults()?.size), 'md');
1710
+ arrow = input(true, ...(ngDevMode ? [{ debugName: "arrow" }] : []));
1711
+ arrowSize = input(8, ...(ngDevMode ? [{ debugName: "arrowSize" }] : []));
1712
+ closeOnClickOutside = input(true, ...(ngDevMode ? [{ debugName: "closeOnClickOutside" }] : []));
1713
+ closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : []));
1714
+ closeOnScroll = input(false, ...(ngDevMode ? [{ debugName: "closeOnScroll" }] : []));
1715
+ showOverlay = input(false, ...(ngDevMode ? [{ debugName: "showOverlay" }] : []));
1716
+ overlayOpacity = input(0.5, ...(ngDevMode ? [{ debugName: "overlayOpacity" }] : []));
1717
+ animationInput = input(undefined, ...(ngDevMode ? [{ debugName: "animationInput", alias: 'animation' }] : [{ alias: 'animation' }]));
1718
+ animationDuration = input(200, ...(ngDevMode ? [{ debugName: "animationDuration" }] : []));
1719
+ animation = withConfigDefault(this.animationInput, computed(() => this.popoverDefaults()?.animation), 'fade');
1720
+ showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
1721
+ showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
1722
+ showCloseButton = input(false, ...(ngDevMode ? [{ debugName: "showCloseButton" }] : []));
1723
+ content = input(undefined, ...(ngDevMode ? [{ debugName: "content" }] : []));
1724
+ zIndex = input(1000, ...(ngDevMode ? [{ debugName: "zIndex" }] : []));
1725
+ ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
1726
+ role = input('dialog', ...(ngDevMode ? [{ debugName: "role" }] : []));
1727
+ visibleChange = output();
1728
+ opened = output();
1729
+ closed = output();
1730
+ positionChanged = output();
1731
+ cleanup;
1732
+ openTimeout;
1733
+ closeTimeout;
1734
+ isHovered = signal(false, ...(ngDevMode ? [{ debugName: "isHovered" }] : []));
1735
+ isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : []));
1736
+ hostClasses = computed(() => classNames('studio-popover', 'studio-popover--' + this.variant(), 'studio-popover--' + this.size(), 'studio-popover--' + this.animation(), this.visible() && 'studio-popover--visible', this.showOverlay() && 'studio-popover--with-overlay'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1737
+ constructor() {
1738
+ effect(() => {
1739
+ if (this.visible()) {
1740
+ this.handleOpen();
1741
+ }
1742
+ else {
1743
+ this.handleClose();
1744
+ }
1745
+ });
1746
+ afterNextRender(() => {
1747
+ this.setupPositioning();
1748
+ }, { injector: this.injector });
1749
+ this.destroyRef.onDestroy(() => {
1750
+ this.cleanup?.();
1751
+ this.clearTimeouts();
1752
+ });
1753
+ }
1754
+ setupPositioning() {
1755
+ const triggerElement = this.triggerEl()?.nativeElement;
1756
+ const panelElement = this.panelEl()?.nativeElement;
1757
+ if (!triggerElement || !panelElement)
1758
+ return;
1759
+ this.cleanup?.();
1760
+ this.cleanup = autoUpdate(triggerElement, panelElement, () => {
1761
+ this.updatePosition();
1762
+ });
1763
+ }
1764
+ async updatePosition() {
1765
+ const triggerElement = this.triggerEl()?.nativeElement;
1766
+ const panelElement = this.panelEl()?.nativeElement;
1767
+ const arrowElement = this.arrowEl()?.nativeElement;
1768
+ if (!triggerElement || !panelElement || !this.visible())
1769
+ return;
1770
+ const middleware = [
1771
+ offset(this.offset()),
1772
+ this.flipValue() && flip(),
1773
+ this.preventOverflow() && shift({ padding: 8 }),
1774
+ arrowElement && this.arrow() && arrow({ element: arrowElement })
1775
+ ].filter(Boolean);
1776
+ const { x, y, placement, middlewareData } = await computePosition(triggerElement, panelElement, {
1777
+ placement: this.position(),
1778
+ middleware
1779
+ });
1780
+ Object.assign(panelElement.style, {
1781
+ left: x + 'px',
1782
+ top: y + 'px',
1783
+ });
1784
+ if (arrowElement && middlewareData.arrow && this.arrow()) {
1785
+ const { x: arrowX, y: arrowY } = middlewareData.arrow;
1786
+ const staticSide = {
1787
+ top: 'bottom',
1788
+ right: 'left',
1789
+ bottom: 'top',
1790
+ left: 'right',
1791
+ }[placement.split('-')[0]];
1792
+ Object.assign(arrowElement.style, {
1793
+ left: arrowX != null ? arrowX + 'px' : '',
1794
+ top: arrowY != null ? arrowY + 'px' : '',
1795
+ right: '',
1796
+ bottom: '',
1797
+ [staticSide]: '-' + (this.arrowSize() / 2) + 'px',
1798
+ });
1799
+ }
1800
+ this.positionChanged.emit(placement);
1801
+ }
1802
+ handleOpen() {
1803
+ if (this.closeOnScroll()) {
1804
+ this.document.addEventListener('scroll', this.handleScrollBind, true);
1805
+ }
1806
+ this.opened.emit();
1807
+ setTimeout(() => this.updatePosition(), 0);
1808
+ }
1809
+ handleClose() {
1810
+ if (this.closeOnScroll()) {
1811
+ this.document.removeEventListener('scroll', this.handleScrollBind, true);
1812
+ }
1813
+ this.closed.emit();
1814
+ }
1815
+ handleScrollBind = this.handleScroll.bind(this);
1816
+ handleScroll() {
1817
+ if (this.visible()) {
1818
+ this.close();
1819
+ }
1820
+ }
1821
+ open() {
1822
+ if (this.disabled())
1823
+ return;
1824
+ this.visible.set(true);
1825
+ this.visibleChange.emit(true);
1826
+ }
1827
+ close() {
1828
+ this.visible.set(false);
1829
+ this.visibleChange.emit(false);
1830
+ }
1831
+ toggle() {
1832
+ if (this.visible()) {
1833
+ this.close();
1834
+ }
1835
+ else {
1836
+ this.open();
1837
+ }
1838
+ }
1839
+ handleTriggerClick() {
1840
+ if (this.trigger() === 'click' || this.trigger() === 'manual') {
1841
+ this.toggle();
1842
+ }
1843
+ }
1844
+ handleTriggerMouseEnter() {
1845
+ if (this.trigger() === 'hover') {
1846
+ this.clearTimeouts();
1847
+ this.isHovered.set(true);
1848
+ this.openTimeout = window.setTimeout(() => {
1849
+ this.open();
1850
+ }, this.openDelay());
1851
+ }
1852
+ }
1853
+ handleTriggerMouseLeave() {
1854
+ if (this.trigger() === 'hover') {
1855
+ this.clearTimeouts();
1856
+ this.isHovered.set(false);
1857
+ this.closeTimeout = window.setTimeout(() => {
1858
+ if (!this.isHovered()) {
1859
+ this.close();
1860
+ }
1861
+ }, this.closeDelay());
1862
+ }
1863
+ }
1864
+ handlePanelMouseEnter() {
1865
+ if (this.trigger() === 'hover') {
1866
+ this.clearTimeouts();
1867
+ this.isHovered.set(true);
1868
+ }
1869
+ }
1870
+ handlePanelMouseLeave() {
1871
+ if (this.trigger() === 'hover') {
1872
+ this.isHovered.set(false);
1873
+ this.closeTimeout = window.setTimeout(() => {
1874
+ if (!this.isHovered()) {
1875
+ this.close();
1876
+ }
1877
+ }, this.closeDelay());
1878
+ }
1879
+ }
1880
+ handleTriggerFocus() {
1881
+ if (this.trigger() === 'focus') {
1882
+ this.isFocused.set(true);
1883
+ this.open();
1884
+ }
1885
+ }
1886
+ handleTriggerBlur() {
1887
+ if (this.trigger() === 'focus') {
1888
+ this.isFocused.set(false);
1889
+ setTimeout(() => {
1890
+ if (!this.isFocused()) {
1891
+ this.close();
1892
+ }
1893
+ }, 100);
1894
+ }
1895
+ }
1896
+ handleBackdropClick() {
1897
+ if (this.closeOnClickOutside()) {
1898
+ this.close();
1899
+ }
1900
+ }
1901
+ handleDocumentClick(event) {
1902
+ if (!this.visible() || !this.closeOnClickOutside())
1903
+ return;
1904
+ const target = event.target;
1905
+ const panel = this.panelEl()?.nativeElement;
1906
+ const trigger = this.triggerEl()?.nativeElement;
1907
+ if (panel && !panel.contains(target) && trigger && !trigger.contains(target)) {
1908
+ this.close();
1909
+ }
1910
+ }
1911
+ handleEscapeKey(event) {
1912
+ if (this.visible() && this.closeOnEscape()) {
1913
+ event.preventDefault();
1914
+ this.close();
1915
+ }
1916
+ }
1917
+ clearTimeouts() {
1918
+ if (this.openTimeout) {
1919
+ window.clearTimeout(this.openTimeout);
1920
+ this.openTimeout = undefined;
1921
+ }
1922
+ if (this.closeTimeout) {
1923
+ window.clearTimeout(this.closeTimeout);
1924
+ this.closeTimeout = undefined;
1925
+ }
1926
+ }
1927
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1928
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: PopoverComponent, isStandalone: true, selector: "studio-popover", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, triggerInput: { classPropertyName: "triggerInput", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, positionInput: { classPropertyName: "positionInput", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, preventOverflow: { classPropertyName: "preventOverflow", publicName: "preventOverflow", isSignal: true, isRequired: false, transformFunction: null }, flipValue: { classPropertyName: "flipValue", publicName: "flipValue", isSignal: true, isRequired: false, transformFunction: null }, variantInput: { classPropertyName: "variantInput", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, sizeInput: { classPropertyName: "sizeInput", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, arrow: { classPropertyName: "arrow", publicName: "arrow", isSignal: true, isRequired: false, transformFunction: null }, arrowSize: { classPropertyName: "arrowSize", publicName: "arrowSize", isSignal: true, isRequired: false, transformFunction: null }, closeOnClickOutside: { classPropertyName: "closeOnClickOutside", publicName: "closeOnClickOutside", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeOnScroll: { classPropertyName: "closeOnScroll", publicName: "closeOnScroll", isSignal: true, isRequired: false, transformFunction: null }, showOverlay: { classPropertyName: "showOverlay", publicName: "showOverlay", isSignal: true, isRequired: false, transformFunction: null }, overlayOpacity: { classPropertyName: "overlayOpacity", publicName: "overlayOpacity", isSignal: true, isRequired: false, transformFunction: null }, animationInput: { classPropertyName: "animationInput", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange", visibleChange: "visibleChange", opened: "opened", closed: "closed", positionChanged: "positionChanged" }, host: { listeners: { "document:click": "handleDocumentClick($event)", "document:keydown.escape": "handleEscapeKey($event)" }, properties: { "class": "hostClasses()", "attr.data-visible": "visible()" } }, queries: [{ propertyName: "headerTemplate", first: true, predicate: ["popoverHeader"], descendants: true, isSignal: true }, { propertyName: "footerTemplate", first: true, predicate: ["popoverFooter"], descendants: true, isSignal: true }, { propertyName: "contentTemplate", first: true, predicate: ["popoverContent"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["popoverTrigger"], descendants: true, isSignal: true }, { propertyName: "panelEl", first: true, predicate: ["popoverPanel"], descendants: true, isSignal: true }, { propertyName: "arrowEl", first: true, predicate: ["popoverArrow"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (showOverlay() && visible()) {\n <div\n class=\"studio-popover__overlay\"\n [style.opacity]=\"overlayOpacity()\"\n [style.z-index]=\"zIndex()\"\n (click)=\"handleBackdropClick()\"\n ></div>\n}\n\n<div\n #popoverTrigger\n class=\"studio-popover__trigger\"\n (click)=\"handleTriggerClick()\"\n (mouseenter)=\"handleTriggerMouseEnter()\"\n (mouseleave)=\"handleTriggerMouseLeave()\"\n (focus)=\"handleTriggerFocus()\"\n (blur)=\"handleTriggerBlur()\"\n>\n <ng-content />\n</div>\n\n@if (visible()) {\n <div\n #popoverPanel\n class=\"studio-popover__panel\"\n [style.z-index]=\"zIndex() + 1\"\n [style.width]=\"width() === 'auto' ? 'auto' : width() === 'trigger' && triggerEl()?.nativeElement ? triggerEl()!.nativeElement.offsetWidth + 'px' : width()\"\n [style.min-width]=\"minWidth() ? (typeof minWidth() === 'number' ? minWidth() + 'px' : minWidth()) : undefined\"\n [style.max-width]=\"maxWidth() ? (typeof maxWidth() === 'number' ? maxWidth() + 'px' : maxWidth()) : undefined\"\n [style.max-height]=\"maxHeight() ? (typeof maxHeight() === 'number' ? maxHeight() + 'px' : maxHeight()) : undefined\"\n [style.padding]=\"padding()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"ariaLabel()\"\n (mouseenter)=\"handlePanelMouseEnter()\"\n (mouseleave)=\"handlePanelMouseLeave()\"\n >\n @if (arrow()) {\n <div #popoverArrow class=\"studio-popover__arrow\" [style.width.px]=\"arrowSize()\" [style.height.px]=\"arrowSize()\"></div>\n }\n\n @if (showHeader() && (headerTemplate() || showCloseButton())) {\n <div class=\"studio-popover__header\">\n @if (headerTemplate()) {\n <ng-container *ngTemplateOutlet=\"headerTemplate()!\" />\n }\n \n @if (showCloseButton()) {\n <button\n type=\"button\"\n class=\"studio-popover__close\"\n (click)=\"close()\"\n aria-label=\"Close\"\n >\n <studio-icon name=\"x\" [size]=\"18\" />\n </button>\n }\n </div>\n }\n\n <div class=\"studio-popover__content\">\n @if (contentTemplate()) {\n <ng-container *ngTemplateOutlet=\"contentTemplate()!\" />\n } @else if (content()) {\n {{ content() }}\n } @else {\n <ng-content select=\"[popoverContent]\" />\n }\n </div>\n\n @if (showFooter() && footerTemplate()) {\n <div class=\"studio-popover__footer\">\n <ng-container *ngTemplateOutlet=\"footerTemplate()!\" />\n </div>\n }\n </div>\n}\n", styles: [":host{display:inline-block;font-family:var(--studio-font-family)}.studio-popover__trigger{display:inline-flex;cursor:pointer}.studio-popover__overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);opacity:0;transition:opacity var(--studio-transition-base)}:host(.studio-popover--visible) .studio-popover__overlay{opacity:var(--popover-overlay-opacity, .5)}.studio-popover__panel{position:absolute;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);box-shadow:var(--studio-shadow-lg);opacity:0;visibility:hidden;transition:opacity var(--popover-animation-duration, .2s) ease-out,transform var(--popover-animation-duration, .2s) ease-out,visibility 0ms var(--popover-animation-duration, .2s);will-change:transform,opacity}:host(.studio-popover--visible) .studio-popover__panel{opacity:1;visibility:visible;transition:opacity var(--popover-animation-duration, .2s) ease-out,transform var(--popover-animation-duration, .2s) ease-out,visibility 0ms}:host(.studio-popover--fade) .studio-popover__panel{transform:scale(.95)}:host(.studio-popover--fade.studio-popover--visible) .studio-popover__panel{transform:scale(1)}:host(.studio-popover--scale) .studio-popover__panel{transform:scale(.8)}:host(.studio-popover--scale.studio-popover--visible) .studio-popover__panel{transform:scale(1)}:host(.studio-popover--slide) .studio-popover__panel{transform:translateY(-8px)}:host(.studio-popover--slide.studio-popover--visible) .studio-popover__panel{transform:translateY(0)}:host(.studio-popover--none) .studio-popover__panel{transition:none}:host(.studio-popover--bordered) .studio-popover__panel{border:2px solid var(--studio-border-secondary);box-shadow:none}:host(.studio-popover--shadow) .studio-popover__panel{border:none;box-shadow:var(--studio-shadow-xl)}:host(.studio-popover--minimal) .studio-popover__panel{border:none;box-shadow:var(--studio-shadow-sm)}:host(.studio-popover--sm) .studio-popover__panel{font-size:var(--studio-font-size-sm)}:host(.studio-popover--md) .studio-popover__panel{font-size:var(--studio-font-size-base)}:host(.studio-popover--lg) .studio-popover__panel{font-size:var(--studio-font-size-lg)}.studio-popover__arrow{position:absolute;background:var(--studio-bg-primary);transform:rotate(45deg);border:1px solid var(--studio-border-primary);border-right:none;border-bottom:none;z-index:-1}:host(.studio-popover--bordered) .studio-popover__arrow{border-color:var(--studio-border-secondary);border-width:2px}:host(.studio-popover--shadow) .studio-popover__arrow,:host(.studio-popover--minimal) .studio-popover__arrow{border:none}.studio-popover__header{display:flex;align-items:center;justify-content:space-between;gap:var(--studio-spacing-md);padding:var(--studio-spacing-md) var(--studio-spacing-md) var(--studio-spacing-sm);border-bottom:1px solid var(--studio-border-primary)}.studio-popover__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast);flex-shrink:0}.studio-popover__close:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-popover__close:active{transform:scale(.95)}.studio-popover__content{padding:var(--studio-spacing-md);color:var(--studio-text-primary)}.studio-popover__header+.studio-popover__content{padding-top:var(--studio-spacing-md)}.studio-popover__footer{padding:var(--studio-spacing-sm) var(--studio-spacing-md) var(--studio-spacing-md);border-top:1px solid var(--studio-border-primary);display:flex;align-items:center;gap:var(--studio-spacing-sm)}:host(.studio-popover--sm) .studio-popover__content{padding:var(--studio-spacing-sm)}:host(.studio-popover--lg) .studio-popover__content{padding:var(--studio-spacing-lg)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1929
+ }
1930
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: PopoverComponent, decorators: [{
1931
+ type: Component,
1932
+ args: [{ selector: 'studio-popover', standalone: true, imports: [NgTemplateOutlet, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1933
+ '[class]': 'hostClasses()',
1934
+ '[attr.data-visible]': 'visible()',
1935
+ }, template: "@if (showOverlay() && visible()) {\n <div\n class=\"studio-popover__overlay\"\n [style.opacity]=\"overlayOpacity()\"\n [style.z-index]=\"zIndex()\"\n (click)=\"handleBackdropClick()\"\n ></div>\n}\n\n<div\n #popoverTrigger\n class=\"studio-popover__trigger\"\n (click)=\"handleTriggerClick()\"\n (mouseenter)=\"handleTriggerMouseEnter()\"\n (mouseleave)=\"handleTriggerMouseLeave()\"\n (focus)=\"handleTriggerFocus()\"\n (blur)=\"handleTriggerBlur()\"\n>\n <ng-content />\n</div>\n\n@if (visible()) {\n <div\n #popoverPanel\n class=\"studio-popover__panel\"\n [style.z-index]=\"zIndex() + 1\"\n [style.width]=\"width() === 'auto' ? 'auto' : width() === 'trigger' && triggerEl()?.nativeElement ? triggerEl()!.nativeElement.offsetWidth + 'px' : width()\"\n [style.min-width]=\"minWidth() ? (typeof minWidth() === 'number' ? minWidth() + 'px' : minWidth()) : undefined\"\n [style.max-width]=\"maxWidth() ? (typeof maxWidth() === 'number' ? maxWidth() + 'px' : maxWidth()) : undefined\"\n [style.max-height]=\"maxHeight() ? (typeof maxHeight() === 'number' ? maxHeight() + 'px' : maxHeight()) : undefined\"\n [style.padding]=\"padding()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"ariaLabel()\"\n (mouseenter)=\"handlePanelMouseEnter()\"\n (mouseleave)=\"handlePanelMouseLeave()\"\n >\n @if (arrow()) {\n <div #popoverArrow class=\"studio-popover__arrow\" [style.width.px]=\"arrowSize()\" [style.height.px]=\"arrowSize()\"></div>\n }\n\n @if (showHeader() && (headerTemplate() || showCloseButton())) {\n <div class=\"studio-popover__header\">\n @if (headerTemplate()) {\n <ng-container *ngTemplateOutlet=\"headerTemplate()!\" />\n }\n \n @if (showCloseButton()) {\n <button\n type=\"button\"\n class=\"studio-popover__close\"\n (click)=\"close()\"\n aria-label=\"Close\"\n >\n <studio-icon name=\"x\" [size]=\"18\" />\n </button>\n }\n </div>\n }\n\n <div class=\"studio-popover__content\">\n @if (contentTemplate()) {\n <ng-container *ngTemplateOutlet=\"contentTemplate()!\" />\n } @else if (content()) {\n {{ content() }}\n } @else {\n <ng-content select=\"[popoverContent]\" />\n }\n </div>\n\n @if (showFooter() && footerTemplate()) {\n <div class=\"studio-popover__footer\">\n <ng-container *ngTemplateOutlet=\"footerTemplate()!\" />\n </div>\n }\n </div>\n}\n", styles: [":host{display:inline-block;font-family:var(--studio-font-family)}.studio-popover__trigger{display:inline-flex;cursor:pointer}.studio-popover__overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);opacity:0;transition:opacity var(--studio-transition-base)}:host(.studio-popover--visible) .studio-popover__overlay{opacity:var(--popover-overlay-opacity, .5)}.studio-popover__panel{position:absolute;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);box-shadow:var(--studio-shadow-lg);opacity:0;visibility:hidden;transition:opacity var(--popover-animation-duration, .2s) ease-out,transform var(--popover-animation-duration, .2s) ease-out,visibility 0ms var(--popover-animation-duration, .2s);will-change:transform,opacity}:host(.studio-popover--visible) .studio-popover__panel{opacity:1;visibility:visible;transition:opacity var(--popover-animation-duration, .2s) ease-out,transform var(--popover-animation-duration, .2s) ease-out,visibility 0ms}:host(.studio-popover--fade) .studio-popover__panel{transform:scale(.95)}:host(.studio-popover--fade.studio-popover--visible) .studio-popover__panel{transform:scale(1)}:host(.studio-popover--scale) .studio-popover__panel{transform:scale(.8)}:host(.studio-popover--scale.studio-popover--visible) .studio-popover__panel{transform:scale(1)}:host(.studio-popover--slide) .studio-popover__panel{transform:translateY(-8px)}:host(.studio-popover--slide.studio-popover--visible) .studio-popover__panel{transform:translateY(0)}:host(.studio-popover--none) .studio-popover__panel{transition:none}:host(.studio-popover--bordered) .studio-popover__panel{border:2px solid var(--studio-border-secondary);box-shadow:none}:host(.studio-popover--shadow) .studio-popover__panel{border:none;box-shadow:var(--studio-shadow-xl)}:host(.studio-popover--minimal) .studio-popover__panel{border:none;box-shadow:var(--studio-shadow-sm)}:host(.studio-popover--sm) .studio-popover__panel{font-size:var(--studio-font-size-sm)}:host(.studio-popover--md) .studio-popover__panel{font-size:var(--studio-font-size-base)}:host(.studio-popover--lg) .studio-popover__panel{font-size:var(--studio-font-size-lg)}.studio-popover__arrow{position:absolute;background:var(--studio-bg-primary);transform:rotate(45deg);border:1px solid var(--studio-border-primary);border-right:none;border-bottom:none;z-index:-1}:host(.studio-popover--bordered) .studio-popover__arrow{border-color:var(--studio-border-secondary);border-width:2px}:host(.studio-popover--shadow) .studio-popover__arrow,:host(.studio-popover--minimal) .studio-popover__arrow{border:none}.studio-popover__header{display:flex;align-items:center;justify-content:space-between;gap:var(--studio-spacing-md);padding:var(--studio-spacing-md) var(--studio-spacing-md) var(--studio-spacing-sm);border-bottom:1px solid var(--studio-border-primary)}.studio-popover__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast);flex-shrink:0}.studio-popover__close:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-popover__close:active{transform:scale(.95)}.studio-popover__content{padding:var(--studio-spacing-md);color:var(--studio-text-primary)}.studio-popover__header+.studio-popover__content{padding-top:var(--studio-spacing-md)}.studio-popover__footer{padding:var(--studio-spacing-sm) var(--studio-spacing-md) var(--studio-spacing-md);border-top:1px solid var(--studio-border-primary);display:flex;align-items:center;gap:var(--studio-spacing-sm)}:host(.studio-popover--sm) .studio-popover__content{padding:var(--studio-spacing-sm)}:host(.studio-popover--lg) .studio-popover__content{padding:var(--studio-spacing-lg)}\n"] }]
1936
+ }], ctorParameters: () => [], propDecorators: { headerTemplate: [{ type: i0.ContentChild, args: ['popoverHeader', { isSignal: true }] }], footerTemplate: [{ type: i0.ContentChild, args: ['popoverFooter', { isSignal: true }] }], contentTemplate: [{ type: i0.ContentChild, args: ['popoverContent', { isSignal: true }] }], triggerEl: [{ type: i0.ViewChild, args: ['popoverTrigger', { isSignal: true }] }], panelEl: [{ type: i0.ViewChild, args: ['popoverPanel', { isSignal: true }] }], arrowEl: [{ type: i0.ViewChild, args: ['popoverArrow', { isSignal: true }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], triggerInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], positionInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], preventOverflow: [{ type: i0.Input, args: [{ isSignal: true, alias: "preventOverflow", required: false }] }], flipValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "flipValue", required: false }] }], variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], arrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrow", required: false }] }], arrowSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowSize", required: false }] }], closeOnClickOutside: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClickOutside", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], closeOnScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnScroll", required: false }] }], showOverlay: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOverlay", required: false }] }], overlayOpacity: [{ type: i0.Input, args: [{ isSignal: true, alias: "overlayOpacity", required: false }] }], animationInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "animation", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], visibleChange: [{ type: i0.Output, args: ["visibleChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], positionChanged: [{ type: i0.Output, args: ["positionChanged"] }], handleDocumentClick: [{
1937
+ type: HostListener,
1938
+ args: ['document:click', ['$event']]
1939
+ }], handleEscapeKey: [{
1940
+ type: HostListener,
1941
+ args: ['document:keydown.escape', ['$event']]
1942
+ }] } });
1943
+
1944
+ class ColorPickerCompactComponent {
1945
+ configService = inject(StudioConfigService);
1946
+ trigger = input('click', ...(ngDevMode ? [{ debugName: "trigger" }] : []));
1947
+ position = input('bottom-start', ...(ngDevMode ? [{ debugName: "position" }] : []));
1948
+ popoverWidth = input('280px', ...(ngDevMode ? [{ debugName: "popoverWidth" }] : []));
1949
+ showArrow = input(false, ...(ngDevMode ? [{ debugName: "showArrow" }] : []));
1950
+ closeOnClickOutside = input(true, ...(ngDevMode ? [{ debugName: "closeOnClickOutside" }] : []));
1951
+ triggerSize = input('32px', ...(ngDevMode ? [{ debugName: "triggerSize" }] : []));
1952
+ triggerRadius = input('var(--studio-radius-sm)', ...(ngDevMode ? [{ debugName: "triggerRadius" }] : []));
1953
+ showCurrentColor = input(false, ...(ngDevMode ? [{ debugName: "showCurrentColor" }] : []));
1954
+ format = input('hex', ...(ngDevMode ? [{ debugName: "format" }] : []));
1955
+ showAlpha = input(false, ...(ngDevMode ? [{ debugName: "showAlpha" }] : []));
1956
+ showPresets = input(true, ...(ngDevMode ? [{ debugName: "showPresets" }] : []));
1957
+ showFormatToggle = input(false, ...(ngDevMode ? [{ debugName: "showFormatToggle" }] : []));
1958
+ showCopyButton = input(false, ...(ngDevMode ? [{ debugName: "showCopyButton" }] : []));
1959
+ presets = input(undefined, ...(ngDevMode ? [{ debugName: "presets" }] : []));
1960
+ showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
1961
+ applyLabel = input('OK', ...(ngDevMode ? [{ debugName: "applyLabel" }] : []));
1962
+ cancelLabel = input('Отмена', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : []));
1963
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1964
+ ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
1965
+ colorChange = output();
1966
+ currentValue = signal('#000000', ...(ngDevMode ? [{ debugName: "currentValue" }] : []));
1967
+ tempValue = signal('#000000', ...(ngDevMode ? [{ debugName: "tempValue" }] : []));
1968
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
1969
+ hostClasses = computed(() => classNames('color-picker-compact', this.disabled() && 'color-picker-compact--disabled'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1970
+ onChange = () => { };
1971
+ onTouched = () => { };
1972
+ constructor() {
1973
+ effect(() => {
1974
+ // Sync temp value when popover opens
1975
+ if (this.isOpen()) {
1976
+ this.tempValue.set(this.currentValue());
1977
+ }
1978
+ });
1979
+ }
1980
+ handleApply() {
1981
+ this.currentValue.set(this.tempValue());
1982
+ this.onChange(this.tempValue());
1983
+ this.colorChange.emit(this.tempValue());
1984
+ this.onTouched();
1985
+ this.isOpen.set(false);
1986
+ }
1987
+ handleCancel() {
1988
+ this.tempValue.set(this.currentValue());
1989
+ this.isOpen.set(false);
1990
+ }
1991
+ writeValue(value) {
1992
+ if (value) {
1993
+ this.currentValue.set(value);
1994
+ this.tempValue.set(value);
1995
+ }
1996
+ }
1997
+ registerOnChange(fn) {
1998
+ this.onChange = fn;
1999
+ }
2000
+ registerOnTouched(fn) {
2001
+ this.onTouched = fn;
2002
+ }
2003
+ setDisabledState(isDisabled) { }
2004
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ColorPickerCompactComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2005
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: ColorPickerCompactComponent, isStandalone: true, selector: "studio-color-picker-compact", inputs: { trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, popoverWidth: { classPropertyName: "popoverWidth", publicName: "popoverWidth", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, closeOnClickOutside: { classPropertyName: "closeOnClickOutside", publicName: "closeOnClickOutside", isSignal: true, isRequired: false, transformFunction: null }, triggerSize: { classPropertyName: "triggerSize", publicName: "triggerSize", isSignal: true, isRequired: false, transformFunction: null }, triggerRadius: { classPropertyName: "triggerRadius", publicName: "triggerRadius", isSignal: true, isRequired: false, transformFunction: null }, showCurrentColor: { classPropertyName: "showCurrentColor", publicName: "showCurrentColor", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, showAlpha: { classPropertyName: "showAlpha", publicName: "showAlpha", isSignal: true, isRequired: false, transformFunction: null }, showPresets: { classPropertyName: "showPresets", publicName: "showPresets", isSignal: true, isRequired: false, transformFunction: null }, showFormatToggle: { classPropertyName: "showFormatToggle", publicName: "showFormatToggle", isSignal: true, isRequired: false, transformFunction: null }, showCopyButton: { classPropertyName: "showCopyButton", publicName: "showCopyButton", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, applyLabel: { classPropertyName: "applyLabel", publicName: "applyLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { colorChange: "colorChange" }, host: { properties: { "class": "hostClasses()" } }, providers: [
2006
+ {
2007
+ provide: NG_VALUE_ACCESSOR,
2008
+ useExisting: forwardRef(() => ColorPickerCompactComponent),
2009
+ multi: true
2010
+ }
2011
+ ], ngImport: i0, template: `
2012
+ <studio-popover
2013
+ [trigger]="trigger()"
2014
+ [position]="position()"
2015
+ [width]="popoverWidth()"
2016
+ [arrow]="showArrow()"
2017
+ [closeOnClickOutside]="false"
2018
+ [(visible)]="isOpen"
2019
+ [showFooter]="showFooter()"
2020
+ >
2021
+ <div
2022
+ class="color-picker-compact__trigger"
2023
+ [class.color-picker-compact__trigger--disabled]="disabled()"
2024
+ [style.width]="triggerSize()"
2025
+ [style.height]="triggerSize()"
2026
+ [style.border-radius]="triggerRadius()"
2027
+ [style.background]="currentValue()"
2028
+ [attr.aria-label]="ariaLabel() || 'Select color'"
2029
+ [attr.role]="'button'"
2030
+ [attr.tabindex]="disabled() ? -1 : 0"
2031
+ >
2032
+ @if (showCurrentColor()) {
2033
+ <span class="color-picker-compact__color-text">{{ currentValue() }}</span>
2034
+ }
2035
+ </div>
2036
+
2037
+ <div popoverContent>
2038
+ <studio-color-picker
2039
+ [(ngModel)]="tempValue"
2040
+ [format]="format()"
2041
+ [showAlpha]="showAlpha()"
2042
+ [showPresets]="showPresets()"
2043
+ [showFormatToggle]="showFormatToggle()"
2044
+ [showCopyButton]="showCopyButton()"
2045
+ [presets]="presets()"
2046
+ [disabled]="disabled()"
2047
+ />
2048
+ </div>
2049
+
2050
+ @if (showFooter()) {
2051
+ <ng-template #popoverFooter>
2052
+ <div class="color-picker-compact__footer">
2053
+ <studio-button
2054
+ variant="outline"
2055
+ size="sm"
2056
+ (click)="handleCancel()"
2057
+ [fullWidth]="true"
2058
+ >
2059
+ {{ cancelLabel() }}
2060
+ </studio-button>
2061
+ <studio-button
2062
+ size="sm"
2063
+ (click)="handleApply()"
2064
+ [fullWidth]="true"
2065
+ >
2066
+ {{ applyLabel() }}
2067
+ </studio-button>
2068
+ </div>
2069
+ </ng-template>
2070
+ }
2071
+ </studio-popover>
2072
+ `, isInline: true, styles: [":host{display:inline-block}.color-picker-compact__trigger{position:relative;cursor:pointer;border:2px solid var(--studio-border-primary);transition:all var(--studio-transition-fast);overflow:hidden;&--disabled{cursor:not-allowed;opacity:.5}}.color-picker-compact__trigger:hover:not(.color-picker-compact__trigger--disabled){border-color:var(--studio-border-secondary);transform:scale(1.05)}.color-picker-compact__trigger:active:not(.color-picker-compact__trigger--disabled){transform:scale(.95)}.color-picker-compact__trigger:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}.color-picker-compact__color-text{position:absolute;bottom:0;left:0;right:0;padding:.125rem .25rem;background:#0009;color:#fff;font-size:.625rem;text-align:center;font-family:var(--studio-font-family-mono, monospace)}.color-picker-compact__footer{display:flex;gap:.75rem;padding:1rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: PopoverComponent, selector: "studio-popover", inputs: ["id", "visible", "disabled", "trigger", "openDelay", "closeDelay", "position", "offset", "preventOverflow", "flipValue", "variant", "size", "width", "minWidth", "maxWidth", "maxHeight", "padding", "arrow", "arrowSize", "closeOnClickOutside", "closeOnEscape", "closeOnScroll", "showOverlay", "overlayOpacity", "animation", "animationDuration", "showHeader", "showFooter", "showCloseButton", "content", "zIndex", "ariaLabel", "role"], outputs: ["visibleChange", "opened", "closed", "positionChanged"] }, { kind: "component", type: ColorPickerComponent, selector: "studio-color-picker", inputs: ["variant", "size", "format", "showAlpha", "showPresets", "showFormatToggle", "showCopyButton", "presets", "label", "hint", "required", "error", "errorMessage", "disabled", "readonly"], outputs: ["colorChange", "colorValueChange", "copied"] }, { kind: "component", type: ButtonComponent, selector: "studio-button", inputs: ["variant", "size", "color", "radius", "shadow", "compact", "disabled", "loading", "loadingText", "fullWidth", "type", "icon", "iconPosition", "href", "target", "badge", "badgeColor", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2073
+ }
2074
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ColorPickerCompactComponent, decorators: [{
2075
+ type: Component,
2076
+ args: [{ selector: 'studio-color-picker-compact', standalone: true, imports: [FormsModule, PopoverComponent, ColorPickerComponent, ButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2077
+ {
2078
+ provide: NG_VALUE_ACCESSOR,
2079
+ useExisting: forwardRef(() => ColorPickerCompactComponent),
2080
+ multi: true
2081
+ }
2082
+ ], host: {
2083
+ '[class]': 'hostClasses()',
2084
+ }, template: `
2085
+ <studio-popover
2086
+ [trigger]="trigger()"
2087
+ [position]="position()"
2088
+ [width]="popoverWidth()"
2089
+ [arrow]="showArrow()"
2090
+ [closeOnClickOutside]="false"
2091
+ [(visible)]="isOpen"
2092
+ [showFooter]="showFooter()"
2093
+ >
2094
+ <div
2095
+ class="color-picker-compact__trigger"
2096
+ [class.color-picker-compact__trigger--disabled]="disabled()"
2097
+ [style.width]="triggerSize()"
2098
+ [style.height]="triggerSize()"
2099
+ [style.border-radius]="triggerRadius()"
2100
+ [style.background]="currentValue()"
2101
+ [attr.aria-label]="ariaLabel() || 'Select color'"
2102
+ [attr.role]="'button'"
2103
+ [attr.tabindex]="disabled() ? -1 : 0"
2104
+ >
2105
+ @if (showCurrentColor()) {
2106
+ <span class="color-picker-compact__color-text">{{ currentValue() }}</span>
2107
+ }
2108
+ </div>
2109
+
2110
+ <div popoverContent>
2111
+ <studio-color-picker
2112
+ [(ngModel)]="tempValue"
2113
+ [format]="format()"
2114
+ [showAlpha]="showAlpha()"
2115
+ [showPresets]="showPresets()"
2116
+ [showFormatToggle]="showFormatToggle()"
2117
+ [showCopyButton]="showCopyButton()"
2118
+ [presets]="presets()"
2119
+ [disabled]="disabled()"
2120
+ />
2121
+ </div>
2122
+
2123
+ @if (showFooter()) {
2124
+ <ng-template #popoverFooter>
2125
+ <div class="color-picker-compact__footer">
2126
+ <studio-button
2127
+ variant="outline"
2128
+ size="sm"
2129
+ (click)="handleCancel()"
2130
+ [fullWidth]="true"
2131
+ >
2132
+ {{ cancelLabel() }}
2133
+ </studio-button>
2134
+ <studio-button
2135
+ size="sm"
2136
+ (click)="handleApply()"
2137
+ [fullWidth]="true"
2138
+ >
2139
+ {{ applyLabel() }}
2140
+ </studio-button>
2141
+ </div>
2142
+ </ng-template>
2143
+ }
2144
+ </studio-popover>
2145
+ `, styles: [":host{display:inline-block}.color-picker-compact__trigger{position:relative;cursor:pointer;border:2px solid var(--studio-border-primary);transition:all var(--studio-transition-fast);overflow:hidden;&--disabled{cursor:not-allowed;opacity:.5}}.color-picker-compact__trigger:hover:not(.color-picker-compact__trigger--disabled){border-color:var(--studio-border-secondary);transform:scale(1.05)}.color-picker-compact__trigger:active:not(.color-picker-compact__trigger--disabled){transform:scale(.95)}.color-picker-compact__trigger:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}.color-picker-compact__color-text{position:absolute;bottom:0;left:0;right:0;padding:.125rem .25rem;background:#0009;color:#fff;font-size:.625rem;text-align:center;font-family:var(--studio-font-family-mono, monospace)}.color-picker-compact__footer{display:flex;gap:.75rem;padding:1rem}\n"] }]
2146
+ }], ctorParameters: () => [], propDecorators: { trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], popoverWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "popoverWidth", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], closeOnClickOutside: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClickOutside", required: false }] }], triggerSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerSize", required: false }] }], triggerRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerRadius", required: false }] }], showCurrentColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCurrentColor", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], showAlpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlpha", required: false }] }], showPresets: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPresets", required: false }] }], showFormatToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFormatToggle", required: false }] }], showCopyButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCopyButton", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], applyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "applyLabel", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], colorChange: [{ type: i0.Output, args: ["colorChange"] }] } });
2147
+
1676
2148
  /**
1677
2149
  * Service for programmatic control of Drawer components
1678
2150
  *
@@ -2103,6 +2575,106 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2103
2575
  args: ['keydown', ['$event']]
2104
2576
  }] } });
2105
2577
 
2578
+ class DropdownComponent {
2579
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
2580
+ trigger = input('click', ...(ngDevMode ? [{ debugName: "trigger" }] : []));
2581
+ position = input('bottom-start', ...(ngDevMode ? [{ debugName: "position" }] : []));
2582
+ width = input('auto', ...(ngDevMode ? [{ debugName: "width" }] : []));
2583
+ minWidth = input('200px', ...(ngDevMode ? [{ debugName: "minWidth" }] : []));
2584
+ itemClick = output();
2585
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
2586
+ hostClasses = computed(() => classNames('studio-dropdown'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
2587
+ handleItemClick(item) {
2588
+ if (item.disabled)
2589
+ return;
2590
+ item.onClick?.();
2591
+ this.itemClick.emit(item);
2592
+ this.isOpen.set(false);
2593
+ }
2594
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: DropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2595
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: DropdownComponent, isStandalone: true, selector: "studio-dropdown", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
2596
+ <studio-popover
2597
+ [trigger]="trigger()"
2598
+ [position]="position()"
2599
+ [width]="width()"
2600
+ [minWidth]="minWidth()"
2601
+ [arrow]="false"
2602
+ [closeOnClickOutside]="true"
2603
+ [(visible)]="isOpen"
2604
+ >
2605
+ <ng-content />
2606
+
2607
+ <div popoverContent style="padding: 0.25rem;">
2608
+ @for (item of items(); track item.id) {
2609
+ @if (item.divider) {
2610
+ <div class="dropdown__divider"></div>
2611
+ } @else {
2612
+ <button
2613
+ type="button"
2614
+ class="dropdown__item"
2615
+ [class.dropdown__item--disabled]="item.disabled"
2616
+ [class.dropdown__item--danger]="item.danger"
2617
+ [disabled]="item.disabled"
2618
+ (click)="handleItemClick(item)"
2619
+ >
2620
+ @if (item.icon) {
2621
+ <studio-icon [name]="item.icon" [size]="16" class="dropdown__icon" />
2622
+ }
2623
+ <span class="dropdown__label">{{ item.label }}</span>
2624
+ @if (item.shortcut) {
2625
+ <span class="dropdown__shortcut">{{ item.shortcut }}</span>
2626
+ }
2627
+ </button>
2628
+ }
2629
+ }
2630
+ </div>
2631
+ </studio-popover>
2632
+ `, isInline: true, styles: [":host{display:inline-block}.dropdown__item{width:100%;display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-primary);font-size:.875rem;cursor:pointer;transition:all var(--studio-transition-fast);text-align:left;&--disabled{opacity:.5;cursor:not-allowed}&--danger{color:var(--studio-error)}}.dropdown__item:hover:not(:disabled){background:var(--studio-bg-secondary)}.dropdown__item:active:not(:disabled){transform:scale(.98)}.dropdown__icon{flex-shrink:0;color:var(--studio-text-secondary)}.dropdown__label{flex:1}.dropdown__shortcut{font-size:.75rem;color:var(--studio-text-tertiary);font-family:var(--studio-font-family-mono, monospace)}.dropdown__divider{height:1px;background:var(--studio-border-primary);margin:.25rem 0}\n"], dependencies: [{ kind: "component", type: PopoverComponent, selector: "studio-popover", inputs: ["id", "visible", "disabled", "trigger", "openDelay", "closeDelay", "position", "offset", "preventOverflow", "flipValue", "variant", "size", "width", "minWidth", "maxWidth", "maxHeight", "padding", "arrow", "arrowSize", "closeOnClickOutside", "closeOnEscape", "closeOnScroll", "showOverlay", "overlayOpacity", "animation", "animationDuration", "showHeader", "showFooter", "showCloseButton", "content", "zIndex", "ariaLabel", "role"], outputs: ["visibleChange", "opened", "closed", "positionChanged"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2633
+ }
2634
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: DropdownComponent, decorators: [{
2635
+ type: Component,
2636
+ args: [{ selector: 'studio-dropdown', standalone: true, imports: [PopoverComponent, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
2637
+ '[class]': 'hostClasses()',
2638
+ }, template: `
2639
+ <studio-popover
2640
+ [trigger]="trigger()"
2641
+ [position]="position()"
2642
+ [width]="width()"
2643
+ [minWidth]="minWidth()"
2644
+ [arrow]="false"
2645
+ [closeOnClickOutside]="true"
2646
+ [(visible)]="isOpen"
2647
+ >
2648
+ <ng-content />
2649
+
2650
+ <div popoverContent style="padding: 0.25rem;">
2651
+ @for (item of items(); track item.id) {
2652
+ @if (item.divider) {
2653
+ <div class="dropdown__divider"></div>
2654
+ } @else {
2655
+ <button
2656
+ type="button"
2657
+ class="dropdown__item"
2658
+ [class.dropdown__item--disabled]="item.disabled"
2659
+ [class.dropdown__item--danger]="item.danger"
2660
+ [disabled]="item.disabled"
2661
+ (click)="handleItemClick(item)"
2662
+ >
2663
+ @if (item.icon) {
2664
+ <studio-icon [name]="item.icon" [size]="16" class="dropdown__icon" />
2665
+ }
2666
+ <span class="dropdown__label">{{ item.label }}</span>
2667
+ @if (item.shortcut) {
2668
+ <span class="dropdown__shortcut">{{ item.shortcut }}</span>
2669
+ }
2670
+ </button>
2671
+ }
2672
+ }
2673
+ </div>
2674
+ </studio-popover>
2675
+ `, styles: [":host{display:inline-block}.dropdown__item{width:100%;display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-primary);font-size:.875rem;cursor:pointer;transition:all var(--studio-transition-fast);text-align:left;&--disabled{opacity:.5;cursor:not-allowed}&--danger{color:var(--studio-error)}}.dropdown__item:hover:not(:disabled){background:var(--studio-bg-secondary)}.dropdown__item:active:not(:disabled){transform:scale(.98)}.dropdown__icon{flex-shrink:0;color:var(--studio-text-secondary)}.dropdown__label{flex:1}.dropdown__shortcut{font-size:.75rem;color:var(--studio-text-tertiary);font-family:var(--studio-font-family-mono, monospace)}.dropdown__divider{height:1px;background:var(--studio-border-primary);margin:.25rem 0}\n"] }]
2676
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }] } });
2677
+
2106
2678
  /**
2107
2679
  * Input component with form control support, variants, and accessibility
2108
2680
  *
@@ -2657,6 +3229,223 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2657
3229
  args: ['keydown', ['$event']]
2658
3230
  }] } });
2659
3231
 
3232
+ class ModalComponent {
3233
+ destroyRef = inject(DestroyRef);
3234
+ // Inputs
3235
+ visible = model(false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
3236
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
3237
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
3238
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
3239
+ animation = input('scale', ...(ngDevMode ? [{ debugName: "animation" }] : []));
3240
+ position = input('center', ...(ngDevMode ? [{ debugName: "position" }] : []));
3241
+ showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
3242
+ showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
3243
+ showCloseButton = input(true, ...(ngDevMode ? [{ debugName: "showCloseButton" }] : []));
3244
+ closeOnOverlayClick = input(true, ...(ngDevMode ? [{ debugName: "closeOnOverlayClick" }] : []));
3245
+ closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : []));
3246
+ // Outputs
3247
+ visibleChange = output();
3248
+ opened = output();
3249
+ closed = output();
3250
+ // Template refs
3251
+ headerTemplate = contentChild('modalHeader', ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
3252
+ footerTemplate = contentChild('modalFooter', ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
3253
+ modalPanel = viewChild('modalPanel', ...(ngDevMode ? [{ debugName: "modalPanel" }] : []));
3254
+ // Computed
3255
+ hostClasses = computed(() => classNames('studio-modal', 'modal--' + this.size(), 'modal--' + this.variant(), 'modal--' + this.animation(), 'modal--' + this.position()), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
3256
+ constructor() {
3257
+ afterNextRender(() => {
3258
+ this.setupFocusTrap();
3259
+ });
3260
+ effect(() => {
3261
+ if (this.visible()) {
3262
+ this.handleOpen();
3263
+ }
3264
+ else {
3265
+ this.handleClose();
3266
+ }
3267
+ });
3268
+ }
3269
+ handleEscape(event) {
3270
+ if (this.closeOnEscape() && this.visible()) {
3271
+ event.preventDefault();
3272
+ this.close();
3273
+ }
3274
+ }
3275
+ handleOverlayClick() {
3276
+ if (this.closeOnOverlayClick()) {
3277
+ this.close();
3278
+ }
3279
+ }
3280
+ close() {
3281
+ this.visible.set(false);
3282
+ }
3283
+ open() {
3284
+ this.visible.set(true);
3285
+ }
3286
+ handleOpen() {
3287
+ // Prevent body scroll
3288
+ document.body.style.overflow = 'hidden';
3289
+ this.opened.emit();
3290
+ // Focus first focusable element
3291
+ setTimeout(() => {
3292
+ const panel = this.modalPanel()?.nativeElement;
3293
+ if (panel) {
3294
+ const focusable = panel.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
3295
+ focusable?.focus();
3296
+ }
3297
+ }, 100);
3298
+ }
3299
+ handleClose() {
3300
+ // Restore body scroll
3301
+ document.body.style.overflow = '';
3302
+ this.closed.emit();
3303
+ }
3304
+ setupFocusTrap() {
3305
+ // Simple focus trap: keep focus within modal when it's open
3306
+ const handleTab = (e) => {
3307
+ if (!this.visible() || e.key !== 'Tab')
3308
+ return;
3309
+ const panel = this.modalPanel()?.nativeElement;
3310
+ if (!panel)
3311
+ return;
3312
+ const focusableElements = panel.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
3313
+ const firstElement = focusableElements[0];
3314
+ const lastElement = focusableElements[focusableElements.length - 1];
3315
+ if (e.shiftKey && document.activeElement === firstElement) {
3316
+ lastElement?.focus();
3317
+ e.preventDefault();
3318
+ }
3319
+ else if (!e.shiftKey && document.activeElement === lastElement) {
3320
+ firstElement?.focus();
3321
+ e.preventDefault();
3322
+ }
3323
+ };
3324
+ document.addEventListener('keydown', handleTab);
3325
+ this.destroyRef.onDestroy(() => {
3326
+ document.removeEventListener('keydown', handleTab);
3327
+ document.body.style.overflow = ''; // Cleanup on destroy
3328
+ });
3329
+ }
3330
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3331
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: ModalComponent, isStandalone: true, selector: "studio-modal", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, animation: { classPropertyName: "animation", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeOnOverlayClick: { classPropertyName: "closeOnOverlayClick", publicName: "closeOnOverlayClick", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange", visibleChange: "visibleChange", opened: "opened", closed: "closed" }, host: { listeners: { "document:keydown.escape": "handleEscape($event)" }, properties: { "class": "hostClasses()" } }, queries: [{ propertyName: "headerTemplate", first: true, predicate: ["modalHeader"], descendants: true, isSignal: true }, { propertyName: "footerTemplate", first: true, predicate: ["modalFooter"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "modalPanel", first: true, predicate: ["modalPanel"], descendants: true, isSignal: true }], ngImport: i0, template: `
3332
+ @if (visible()) {
3333
+ <!-- Overlay -->
3334
+ <div
3335
+ class="studio-modal__overlay"
3336
+ [class.studio-modal__overlay--visible]="visible()"
3337
+ (click)="handleOverlayClick()"
3338
+ ></div>
3339
+
3340
+ <!-- Modal -->
3341
+ <div
3342
+ #modalPanel
3343
+ class="studio-modal__panel"
3344
+ [class.studio-modal__panel--visible]="visible()"
3345
+ role="dialog"
3346
+ [attr.aria-modal]="true"
3347
+ [attr.aria-labelledby]="showHeader() ? 'modal-title' : null"
3348
+ >
3349
+ <!-- Header -->
3350
+ @if (showHeader()) {
3351
+ <div class="studio-modal__header">
3352
+ @if (headerTemplate()) {
3353
+ <ng-container *ngTemplateOutlet="headerTemplate()!" />
3354
+ } @else {
3355
+ <h3 id="modal-title" class="studio-modal__title">{{ title() }}</h3>
3356
+ }
3357
+
3358
+ @if (showCloseButton()) {
3359
+ <button
3360
+ type="button"
3361
+ class="studio-modal__close"
3362
+ (click)="close()"
3363
+ aria-label="Close"
3364
+ >
3365
+ <studio-icon name="x" [size]="20" />
3366
+ </button>
3367
+ }
3368
+ </div>
3369
+ }
3370
+
3371
+ <!-- Content -->
3372
+ <div class="studio-modal__content">
3373
+ <ng-content />
3374
+ </div>
3375
+
3376
+ <!-- Footer -->
3377
+ @if (showFooter() && footerTemplate()) {
3378
+ <div class="studio-modal__footer">
3379
+ <ng-container *ngTemplateOutlet="footerTemplate()!" />
3380
+ </div>
3381
+ }
3382
+ </div>
3383
+ }
3384
+ `, isInline: true, styles: [":host{display:contents;font-family:var(--studio-font-family)}.studio-modal__overlay{position:fixed;inset:0;background:#00000080;z-index:1000;opacity:0;transition:opacity var(--studio-transition-normal);&--visible{opacity:1}}.studio-modal__panel{position:fixed;z-index:1001;background:var(--studio-bg-primary);border-radius:var(--studio-radius-lg);box-shadow:var(--studio-shadow-xl);display:flex;flex-direction:column;max-height:90vh;opacity:0;transform:scale(.95);transition:opacity var(--studio-transition-normal),transform var(--studio-transition-normal);&--visible{opacity:1;transform:scale(1)}}:host(.modal--center) .studio-modal__panel{top:50%;left:50%;transform:translate(-50%,-50%) scale(.95);&--visible{transform:translate(-50%,-50%) scale(1)}}:host(.modal--top) .studio-modal__panel{top:5vh;left:50%;transform:translate(-50%,-20px) scale(.95);&--visible{transform:translate(-50%) scale(1)}}:host(.modal--bottom) .studio-modal__panel{bottom:5vh;left:50%;transform:translate(-50%,20px) scale(.95);&--visible{transform:translate(-50%) scale(1)}}:host(.modal--sm) .studio-modal__panel{width:90%;max-width:400px}:host(.modal--md) .studio-modal__panel{width:90%;max-width:600px}:host(.modal--lg) .studio-modal__panel{width:90%;max-width:800px}:host(.modal--xl) .studio-modal__panel{width:90%;max-width:1200px}:host(.modal--full) .studio-modal__panel{width:95vw;height:95vh;max-width:none;max-height:none}:host(.modal--bordered) .studio-modal__panel{border:1px solid var(--studio-border-primary)}:host(.modal--minimal) .studio-modal__panel{box-shadow:var(--studio-shadow-md)}:host(.modal--fade) .studio-modal__panel{transform:translate(-50%,-50%);&--visible{transform:translate(-50%,-50%)}}:host(.modal--slide-down) .studio-modal__panel{transform:translate(-50%,-60%);&--visible{transform:translate(-50%,-50%)}}:host(.modal--none) .studio-modal__panel{transition:none}:host(.modal--none) .studio-modal__overlay{transition:none}.studio-modal__header{display:flex;align-items:center;justify-content:space-between;padding:1.5rem;border-bottom:1px solid var(--studio-border-primary);flex-shrink:0}.studio-modal__title{margin:0;font-size:1.25rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast)}.studio-modal__close:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-modal__close:active{transform:scale(.95)}.studio-modal__content{padding:1.5rem;overflow-y:auto;flex:1}.studio-modal__footer{padding:1.5rem;border-top:1px solid var(--studio-border-primary);display:flex;gap:.75rem;justify-content:flex-end;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3385
+ }
3386
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ModalComponent, decorators: [{
3387
+ type: Component,
3388
+ args: [{ selector: 'studio-modal', standalone: true, imports: [CommonModule, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
3389
+ '[class]': 'hostClasses()',
3390
+ }, template: `
3391
+ @if (visible()) {
3392
+ <!-- Overlay -->
3393
+ <div
3394
+ class="studio-modal__overlay"
3395
+ [class.studio-modal__overlay--visible]="visible()"
3396
+ (click)="handleOverlayClick()"
3397
+ ></div>
3398
+
3399
+ <!-- Modal -->
3400
+ <div
3401
+ #modalPanel
3402
+ class="studio-modal__panel"
3403
+ [class.studio-modal__panel--visible]="visible()"
3404
+ role="dialog"
3405
+ [attr.aria-modal]="true"
3406
+ [attr.aria-labelledby]="showHeader() ? 'modal-title' : null"
3407
+ >
3408
+ <!-- Header -->
3409
+ @if (showHeader()) {
3410
+ <div class="studio-modal__header">
3411
+ @if (headerTemplate()) {
3412
+ <ng-container *ngTemplateOutlet="headerTemplate()!" />
3413
+ } @else {
3414
+ <h3 id="modal-title" class="studio-modal__title">{{ title() }}</h3>
3415
+ }
3416
+
3417
+ @if (showCloseButton()) {
3418
+ <button
3419
+ type="button"
3420
+ class="studio-modal__close"
3421
+ (click)="close()"
3422
+ aria-label="Close"
3423
+ >
3424
+ <studio-icon name="x" [size]="20" />
3425
+ </button>
3426
+ }
3427
+ </div>
3428
+ }
3429
+
3430
+ <!-- Content -->
3431
+ <div class="studio-modal__content">
3432
+ <ng-content />
3433
+ </div>
3434
+
3435
+ <!-- Footer -->
3436
+ @if (showFooter() && footerTemplate()) {
3437
+ <div class="studio-modal__footer">
3438
+ <ng-container *ngTemplateOutlet="footerTemplate()!" />
3439
+ </div>
3440
+ }
3441
+ </div>
3442
+ }
3443
+ `, styles: [":host{display:contents;font-family:var(--studio-font-family)}.studio-modal__overlay{position:fixed;inset:0;background:#00000080;z-index:1000;opacity:0;transition:opacity var(--studio-transition-normal);&--visible{opacity:1}}.studio-modal__panel{position:fixed;z-index:1001;background:var(--studio-bg-primary);border-radius:var(--studio-radius-lg);box-shadow:var(--studio-shadow-xl);display:flex;flex-direction:column;max-height:90vh;opacity:0;transform:scale(.95);transition:opacity var(--studio-transition-normal),transform var(--studio-transition-normal);&--visible{opacity:1;transform:scale(1)}}:host(.modal--center) .studio-modal__panel{top:50%;left:50%;transform:translate(-50%,-50%) scale(.95);&--visible{transform:translate(-50%,-50%) scale(1)}}:host(.modal--top) .studio-modal__panel{top:5vh;left:50%;transform:translate(-50%,-20px) scale(.95);&--visible{transform:translate(-50%) scale(1)}}:host(.modal--bottom) .studio-modal__panel{bottom:5vh;left:50%;transform:translate(-50%,20px) scale(.95);&--visible{transform:translate(-50%) scale(1)}}:host(.modal--sm) .studio-modal__panel{width:90%;max-width:400px}:host(.modal--md) .studio-modal__panel{width:90%;max-width:600px}:host(.modal--lg) .studio-modal__panel{width:90%;max-width:800px}:host(.modal--xl) .studio-modal__panel{width:90%;max-width:1200px}:host(.modal--full) .studio-modal__panel{width:95vw;height:95vh;max-width:none;max-height:none}:host(.modal--bordered) .studio-modal__panel{border:1px solid var(--studio-border-primary)}:host(.modal--minimal) .studio-modal__panel{box-shadow:var(--studio-shadow-md)}:host(.modal--fade) .studio-modal__panel{transform:translate(-50%,-50%);&--visible{transform:translate(-50%,-50%)}}:host(.modal--slide-down) .studio-modal__panel{transform:translate(-50%,-60%);&--visible{transform:translate(-50%,-50%)}}:host(.modal--none) .studio-modal__panel{transition:none}:host(.modal--none) .studio-modal__overlay{transition:none}.studio-modal__header{display:flex;align-items:center;justify-content:space-between;padding:1.5rem;border-bottom:1px solid var(--studio-border-primary);flex-shrink:0}.studio-modal__title{margin:0;font-size:1.25rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--studio-radius-sm);color:var(--studio-text-secondary);cursor:pointer;transition:all var(--studio-transition-fast)}.studio-modal__close:hover{background:var(--studio-bg-secondary);color:var(--studio-text-primary)}.studio-modal__close:active{transform:scale(.95)}.studio-modal__content{padding:1.5rem;overflow-y:auto;flex:1}.studio-modal__footer{padding:1.5rem;border-top:1px solid var(--studio-border-primary);display:flex;gap:.75rem;justify-content:flex-end;flex-shrink:0}\n"] }]
3444
+ }], ctorParameters: () => [], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], animation: [{ type: i0.Input, args: [{ isSignal: true, alias: "animation", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], closeOnOverlayClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnOverlayClick", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], visibleChange: [{ type: i0.Output, args: ["visibleChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], headerTemplate: [{ type: i0.ContentChild, args: ['modalHeader', { isSignal: true }] }], footerTemplate: [{ type: i0.ContentChild, args: ['modalFooter', { isSignal: true }] }], modalPanel: [{ type: i0.ViewChild, args: ['modalPanel', { isSignal: true }] }], handleEscape: [{
3445
+ type: HostListener,
3446
+ args: ['document:keydown.escape', ['$event']]
3447
+ }] } });
3448
+
2660
3449
  /**
2661
3450
  * Navbar component - Primitive component for navigation headers
2662
3451
  *
@@ -3368,6 +4157,86 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
3368
4157
  * Switch component
3369
4158
  */
3370
4159
 
4160
+ class TabsComponent {
4161
+ tabs = input.required(...(ngDevMode ? [{ debugName: "tabs" }] : []));
4162
+ activeTab = signal('', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
4163
+ variant = input('line', ...(ngDevMode ? [{ debugName: "variant" }] : []));
4164
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
4165
+ orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
4166
+ tabChange = output();
4167
+ hostClasses = computed(() => classNames('tabs', 'tabs--' + this.variant(), 'tabs--' + this.size(), this.orientation() === 'vertical' && 'tabs--vertical'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
4168
+ iconSize = computed(() => {
4169
+ const sizeMap = { sm: 14, md: 16, lg: 18 };
4170
+ return sizeMap[this.size()];
4171
+ }, ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
4172
+ constructor() {
4173
+ effect(() => {
4174
+ // Set first tab as active by default when tabs change
4175
+ const tabsList = this.tabs();
4176
+ const firstTab = tabsList[0];
4177
+ if (firstTab && !this.activeTab()) {
4178
+ this.activeTab.set(firstTab.id);
4179
+ }
4180
+ });
4181
+ }
4182
+ selectTab(tabId) {
4183
+ this.activeTab.set(tabId);
4184
+ this.tabChange.emit(tabId);
4185
+ }
4186
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4187
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: TabsComponent, isStandalone: true, selector: "studio-tabs", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { tabChange: "tabChange" }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
4188
+ <div class="tabs__header" [class.tabs__header--vertical]="orientation() === 'vertical'">
4189
+ @for (tab of tabs(); track tab.id) {
4190
+ <button
4191
+ type="button"
4192
+ class="tabs__tab"
4193
+ [class.tabs__tab--active]="activeTab() === tab.id"
4194
+ [class.tabs__tab--disabled]="tab.disabled"
4195
+ [disabled]="tab.disabled"
4196
+ (click)="selectTab(tab.id)"
4197
+ >
4198
+ @if (tab.icon) {
4199
+ <studio-icon [name]="tab.icon" [size]="iconSize()" />
4200
+ }
4201
+ <span>{{ tab.label }}</span>
4202
+ </button>
4203
+ }
4204
+ </div>
4205
+
4206
+ <div class="tabs__content">
4207
+ <ng-content />
4208
+ </div>
4209
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;font-family:var(--studio-font-family)}:host(.tabs--vertical){flex-direction:row}.tabs__header{display:flex;gap:.25rem;border-bottom:2px solid var(--studio-border-primary);&--vertical{flex-direction:column;border-bottom:none;border-right:2px solid var(--studio-border-primary);padding-right:1rem}}.tabs__tab{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;background:none;border:none;border-bottom:2px solid transparent;color:var(--studio-text-secondary);font-size:.875rem;font-weight:var(--studio-font-weight-medium);cursor:pointer;transition:all var(--studio-transition-fast);position:relative;margin-bottom:-2px;&--active{color:var(--studio-primary);border-bottom-color:var(--studio-primary)}&--disabled{opacity:.5;cursor:not-allowed}}.tabs__tab:hover:not(:disabled){color:var(--studio-text-primary);background:var(--studio-bg-secondary)}:host(.tabs--pills) .tabs__header{border-bottom:none}:host(.tabs--pills) .tabs__tab{border-radius:var(--studio-radius-md);border-bottom:none;margin-bottom:0;&--active{background:var(--studio-primary);color:#fff}}:host(.tabs--enclosed) .tabs__tab{border:1px solid transparent;border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0;margin-bottom:-1px;&--active{border-color:var(--studio-border-primary);border-bottom-color:var(--studio-bg-primary);background:var(--studio-bg-primary)}}:host(.tabs--sm) .tabs__tab{padding:.5rem .75rem;font-size:.8125rem}:host(.tabs--lg) .tabs__tab{padding:1rem 1.25rem;font-size:1rem}.tabs__content{padding:1.5rem 0}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4210
+ }
4211
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TabsComponent, decorators: [{
4212
+ type: Component,
4213
+ args: [{ selector: 'studio-tabs', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
4214
+ '[class]': 'hostClasses()',
4215
+ }, template: `
4216
+ <div class="tabs__header" [class.tabs__header--vertical]="orientation() === 'vertical'">
4217
+ @for (tab of tabs(); track tab.id) {
4218
+ <button
4219
+ type="button"
4220
+ class="tabs__tab"
4221
+ [class.tabs__tab--active]="activeTab() === tab.id"
4222
+ [class.tabs__tab--disabled]="tab.disabled"
4223
+ [disabled]="tab.disabled"
4224
+ (click)="selectTab(tab.id)"
4225
+ >
4226
+ @if (tab.icon) {
4227
+ <studio-icon [name]="tab.icon" [size]="iconSize()" />
4228
+ }
4229
+ <span>{{ tab.label }}</span>
4230
+ </button>
4231
+ }
4232
+ </div>
4233
+
4234
+ <div class="tabs__content">
4235
+ <ng-content />
4236
+ </div>
4237
+ `, styles: [":host{display:flex;flex-direction:column;font-family:var(--studio-font-family)}:host(.tabs--vertical){flex-direction:row}.tabs__header{display:flex;gap:.25rem;border-bottom:2px solid var(--studio-border-primary);&--vertical{flex-direction:column;border-bottom:none;border-right:2px solid var(--studio-border-primary);padding-right:1rem}}.tabs__tab{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;background:none;border:none;border-bottom:2px solid transparent;color:var(--studio-text-secondary);font-size:.875rem;font-weight:var(--studio-font-weight-medium);cursor:pointer;transition:all var(--studio-transition-fast);position:relative;margin-bottom:-2px;&--active{color:var(--studio-primary);border-bottom-color:var(--studio-primary)}&--disabled{opacity:.5;cursor:not-allowed}}.tabs__tab:hover:not(:disabled){color:var(--studio-text-primary);background:var(--studio-bg-secondary)}:host(.tabs--pills) .tabs__header{border-bottom:none}:host(.tabs--pills) .tabs__tab{border-radius:var(--studio-radius-md);border-bottom:none;margin-bottom:0;&--active{background:var(--studio-primary);color:#fff}}:host(.tabs--enclosed) .tabs__tab{border:1px solid transparent;border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0;margin-bottom:-1px;&--active{border-color:var(--studio-border-primary);border-bottom-color:var(--studio-bg-primary);background:var(--studio-bg-primary)}}:host(.tabs--sm) .tabs__tab{padding:.5rem .75rem;font-size:.8125rem}:host(.tabs--lg) .tabs__tab{padding:1rem 1.25rem;font-size:1rem}.tabs__content{padding:1.5rem 0}\n"] }]
4238
+ }], ctorParameters: () => [], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], tabChange: [{ type: i0.Output, args: ["tabChange"] }] } });
4239
+
3371
4240
  /**
3372
4241
  * Textarea component for multi-line text input
3373
4242
  *
@@ -3717,6 +4586,73 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
3717
4586
  }, template: "<div class=\"studio-textarea-container\">\n <!-- Label (static or floating) -->\n @if (label() && !floatingLabel()) {\n <label\n [for]=\"textareaId()\"\n class=\"studio-textarea-label\"\n [class.studio-textarea-label--required]=\"required()\"\n >\n {{ label() }}\n @if (required()) {\n <span class=\"studio-textarea-label__required\">*</span>\n }\n </label>\n }\n\n <!-- Textarea wrapper -->\n <div class=\"studio-textarea-input-wrapper\">\n <!-- Floating label -->\n @if (floatingLabel() && label()) {\n <label\n [for]=\"textareaId()\"\n class=\"studio-textarea-label studio-textarea-label--floating\"\n [class.studio-textarea-label--floating-up]=\"showFloatingLabelUp()\"\n [class.studio-textarea-label--required]=\"required()\"\n >\n {{ label() }}\n @if (required()) {\n <span class=\"studio-textarea-label__required\">*</span>\n }\n </label>\n }\n\n <!-- Textarea element -->\n <textarea\n #textarea\n [id]=\"textareaId()\"\n [class]=\"textareaClasses()\"\n [value]=\"internalValue()\"\n [placeholder]=\"computedPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [rows]=\"rows()\"\n [attr.maxlength]=\"maxLength()\"\n [attr.minlength]=\"minLength()\"\n [required]=\"required()\"\n [name]=\"name()\"\n [autocomplete]=\"autocomplete()\"\n [spellcheck]=\"spellcheck()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-required]=\"required()\"\n [attr.aria-invalid]=\"error()\"\n [attr.aria-describedby]=\"showHint() || showError() ? textareaId() + '-description' : undefined\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleFocus($event)\"\n (blur)=\"handleBlur($event)\"\n (keypress)=\"handleKeyPress($event)\"\n ></textarea>\n\n <!-- Clear button -->\n @if (clearable() && internalValue().length > 0 && !disabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"studio-textarea-clear\"\n [attr.aria-label]=\"'Clear textarea'\"\n (click)=\"handleClear()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n }\n\n <!-- Loading indicator -->\n @if (loading()) {\n <div class=\"studio-textarea-loading\">\n <svg\n class=\"studio-textarea-spinner\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n </div>\n }\n\n <!-- Character counter -->\n @if (showCharCount()) {\n <div\n class=\"studio-textarea-char-count\"\n [class.studio-textarea-char-count--exceeded]=\"isCharLimitExceeded()\"\n [attr.data-position]=\"charCountPosition()\"\n >\n {{ charCountText() }}\n </div>\n }\n </div>\n\n <!-- Helper text / Error message -->\n @if (showError()) {\n <div\n class=\"studio-textarea-message studio-textarea-message--error\"\n [id]=\"textareaId() + '-description'\"\n role=\"alert\"\n >\n {{ errorMessage() }}\n </div>\n } @else if (showHint()) {\n <div\n class=\"studio-textarea-message studio-textarea-message--hint\"\n [id]=\"textareaId() + '-description'\"\n >\n {{ hint() }}\n </div>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;gap:.375rem;font-family:var(--studio-font-family)}:host(.studio-textarea-wrapper--full-width){width:100%}.studio-textarea-label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);margin-bottom:.25rem}.studio-textarea-label__required{color:var(--studio-error);margin-left:.125rem}.studio-textarea-label--floating{position:absolute;top:.75rem;left:.75rem;pointer-events:none;background:transparent;padding:0 .25rem;z-index:1;transition:all .2s ease}.studio-textarea-label--floating-up{top:-.5rem;font-size:.75rem;background:var(--studio-background);color:var(--studio-primary)}.studio-textarea-input-wrapper{position:relative;display:flex;flex-direction:column;transition:all var(--studio-transition-fast)}.studio-textarea{width:100%;padding:.75rem;font-size:1rem;font-family:inherit;color:var(--studio-text-primary);background:transparent;border:none;outline:none;resize:vertical;transition:all var(--studio-transition-fast)}.studio-textarea::placeholder{color:var(--studio-text-tertiary)}.studio-textarea:disabled{cursor:not-allowed;opacity:.6}.studio-textarea:read-only{cursor:default}.studio-textarea-clear,.studio-textarea-loading{position:absolute;top:.5rem;right:.5rem;display:flex;align-items:center;justify-content:center}.studio-textarea-clear{padding:.25rem;background:none;border:none;color:var(--studio-text-secondary);cursor:pointer;border-radius:var(--studio-radius-sm);transition:all var(--studio-transition-fast)}.studio-textarea-clear:hover{background:var(--studio-background-hover);color:var(--studio-text-primary)}.studio-textarea-clear svg{width:1rem;height:1rem}.studio-textarea-spinner{width:1rem;height:1rem;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-textarea-char-count{position:absolute;bottom:.5rem;font-size:.75rem;color:var(--studio-text-muted);pointer-events:none}.studio-textarea-char-count[data-position=bottom-right]{right:.75rem}.studio-textarea-char-count[data-position=bottom-left]{left:.75rem}.studio-textarea-char-count--exceeded{color:var(--studio-error);font-weight:500}.studio-textarea-message{font-size:.75rem;line-height:1.4}.studio-textarea-message--hint{color:var(--studio-text-secondary)}.studio-textarea-message--error{color:var(--studio-error)}:host(.studio-textarea-wrapper--outline) .studio-textarea-input-wrapper{border:1px solid var(--studio-border-primary);background:var(--studio-bg-primary);border-radius:var(--studio-radius-md)}:host(.studio-textarea-wrapper--outline) .studio-textarea-input-wrapper:hover:not(:has(.studio-textarea:disabled)){border-color:var(--studio-primary)}:host(.studio-textarea-wrapper--outline.studio-textarea-wrapper--focused) .studio-textarea-input-wrapper{border-color:var(--studio-primary);box-shadow:0 0 0 3px var(--studio-primary-bg)}:host(.studio-textarea-wrapper--outline.studio-textarea-wrapper--error) .studio-textarea-input-wrapper{border-color:var(--studio-error)}:host(.studio-textarea-wrapper--outline.studio-textarea-wrapper--error) .studio-textarea-input-wrapper:hover{border-color:var(--studio-error)}:host(.studio-textarea-wrapper--outline.studio-textarea-wrapper--disabled) .studio-textarea-input-wrapper{background:var(--studio-bg-secondary);border-color:var(--studio-border-secondary)}:host(.studio-textarea-wrapper--filled) .studio-textarea-input-wrapper{background:var(--studio-bg-secondary);border:none;border-bottom:2px solid var(--studio-border-primary);border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0}:host(.studio-textarea-wrapper--filled) .studio-textarea-input-wrapper:hover:not(:has(.studio-textarea:disabled)){background:var(--studio-bg-tertiary)}:host(.studio-textarea-wrapper--filled.studio-textarea-wrapper--focused) .studio-textarea-input-wrapper{border-bottom-color:var(--studio-primary);background:var(--studio-bg-tertiary)}:host(.studio-textarea-wrapper--filled.studio-textarea-wrapper--error) .studio-textarea-input-wrapper{border-bottom-color:var(--studio-error)}:host(.studio-textarea-wrapper--filled.studio-textarea-wrapper--disabled) .studio-textarea-input-wrapper{background:var(--studio-bg-secondary);opacity:.6}:host(.studio-textarea-wrapper--underline) .studio-textarea-input-wrapper{background:transparent;border:none;border-bottom:2px solid var(--studio-border-primary);border-radius:0}:host(.studio-textarea-wrapper--underline) .studio-textarea-input-wrapper .studio-textarea{padding-left:0;padding-right:0}:host(.studio-textarea-wrapper--underline) .studio-textarea-input-wrapper:hover:not(:has(.studio-textarea:disabled)){border-bottom-color:var(--studio-primary)}:host(.studio-textarea-wrapper--underline.studio-textarea-wrapper--focused) .studio-textarea-input-wrapper{border-bottom-color:var(--studio-primary)}:host(.studio-textarea-wrapper--underline.studio-textarea-wrapper--error) .studio-textarea-input-wrapper{border-bottom-color:var(--studio-error)}:host(.studio-textarea-wrapper--sm) .studio-textarea{padding:.5rem .75rem;font-size:.875rem}:host(.studio-textarea-wrapper--md) .studio-textarea{padding:.75rem;font-size:1rem}:host(.studio-textarea-wrapper--lg) .studio-textarea{padding:1rem;font-size:1.125rem}\n"] }]
3718
4587
  }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], minRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "minRows", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }], autoResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoResize", required: false }] }], resize: [{ type: i0.Input, args: [{ isSignal: true, alias: "resize", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], showCharCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCharCount", required: false }] }], charCountPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "charCountPosition", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], spellcheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "spellcheck", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }], focused: [{ type: i0.Output, args: ["focused"] }], blurred: [{ type: i0.Output, args: ["blurred"] }], keyPressed: [{ type: i0.Output, args: ["keyPressed"] }], textareaEl: [{ type: i0.ViewChild, args: ['textarea', { isSignal: true }] }] } });
3719
4588
 
4589
+ class TooltipComponent {
4590
+ content = input.required(...(ngDevMode ? [{ debugName: "content" }] : []));
4591
+ trigger = input('hover', ...(ngDevMode ? [{ debugName: "trigger" }] : []));
4592
+ position = input('top', ...(ngDevMode ? [{ debugName: "position" }] : []));
4593
+ openDelay = input(200, ...(ngDevMode ? [{ debugName: "openDelay" }] : []));
4594
+ closeDelay = input(100, ...(ngDevMode ? [{ debugName: "closeDelay" }] : []));
4595
+ arrow = input(true, ...(ngDevMode ? [{ debugName: "arrow" }] : []));
4596
+ arrowSize = input(6, ...(ngDevMode ? [{ debugName: "arrowSize" }] : []));
4597
+ maxWidth = input('300px', ...(ngDevMode ? [{ debugName: "maxWidth" }] : []));
4598
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
4599
+ hostClasses = computed(() => classNames('studio-tooltip'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
4600
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4601
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.12", type: TooltipComponent, isStandalone: true, selector: "studio-tooltip", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: true, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, arrow: { classPropertyName: "arrow", publicName: "arrow", isSignal: true, isRequired: false, transformFunction: null }, arrowSize: { classPropertyName: "arrowSize", publicName: "arrowSize", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
4602
+ <studio-popover
4603
+ [trigger]="trigger()"
4604
+ [position]="position()"
4605
+ [openDelay]="openDelay()"
4606
+ [closeDelay]="closeDelay()"
4607
+ [arrow]="arrow()"
4608
+ [arrowSize]="arrowSize()"
4609
+ [variant]="'minimal'"
4610
+ [size]="'sm'"
4611
+ [animation]="'fade'"
4612
+ [animationDuration]="150"
4613
+ [showHeader]="false"
4614
+ [showFooter]="false"
4615
+ [closeOnClickOutside]="false"
4616
+ [closeOnEscape]="false"
4617
+ [disabled]="disabled()"
4618
+ [maxWidth]="maxWidth()"
4619
+ [padding]="'0.5rem 0.75rem'"
4620
+ >
4621
+ <ng-content />
4622
+ <div popoverContent [innerHTML]="content() || ''"></div>
4623
+ </studio-popover>
4624
+ `, isInline: true, styles: [":host{display:inline-block}\n"], dependencies: [{ kind: "component", type: PopoverComponent, selector: "studio-popover", inputs: ["id", "visible", "disabled", "trigger", "openDelay", "closeDelay", "position", "offset", "preventOverflow", "flipValue", "variant", "size", "width", "minWidth", "maxWidth", "maxHeight", "padding", "arrow", "arrowSize", "closeOnClickOutside", "closeOnEscape", "closeOnScroll", "showOverlay", "overlayOpacity", "animation", "animationDuration", "showHeader", "showFooter", "showCloseButton", "content", "zIndex", "ariaLabel", "role"], outputs: ["visibleChange", "opened", "closed", "positionChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4625
+ }
4626
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TooltipComponent, decorators: [{
4627
+ type: Component,
4628
+ args: [{ selector: 'studio-tooltip', standalone: true, imports: [PopoverComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
4629
+ '[class]': 'hostClasses()',
4630
+ }, template: `
4631
+ <studio-popover
4632
+ [trigger]="trigger()"
4633
+ [position]="position()"
4634
+ [openDelay]="openDelay()"
4635
+ [closeDelay]="closeDelay()"
4636
+ [arrow]="arrow()"
4637
+ [arrowSize]="arrowSize()"
4638
+ [variant]="'minimal'"
4639
+ [size]="'sm'"
4640
+ [animation]="'fade'"
4641
+ [animationDuration]="150"
4642
+ [showHeader]="false"
4643
+ [showFooter]="false"
4644
+ [closeOnClickOutside]="false"
4645
+ [closeOnEscape]="false"
4646
+ [disabled]="disabled()"
4647
+ [maxWidth]="maxWidth()"
4648
+ [padding]="'0.5rem 0.75rem'"
4649
+ >
4650
+ <ng-content />
4651
+ <div popoverContent [innerHTML]="content() || ''"></div>
4652
+ </studio-popover>
4653
+ `, styles: [":host{display:inline-block}\n"] }]
4654
+ }], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: true }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], arrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrow", required: false }] }], arrowSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowSize", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
4655
+
3720
4656
  /**
3721
4657
  * Primitives (Atoms)
3722
4658
  * Basic building blocks
@@ -4060,7 +4996,7 @@ class InspectorComponent {
4060
4996
  useExisting: forwardRef(() => InspectorComponent),
4061
4997
  multi: true
4062
4998
  }
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 });
4999
+ ], ngImport: i0, template: "@if (values()) {\n <div class=\"studio-inspector__container\">\n @for (section of values()!.sections; track trackBySectionId($index, section)) {\n <div class=\"studio-inspector__section\"\n [class.studio-inspector__section--expanded]=\"isSectionExpanded(section.id)\"\n [class.studio-inspector__section--collapsed]=\"!isSectionExpanded(section.id)\">\n\n <studio-button\n variant=\"ghost\"\n [fullWidth]=\"true\"\n class=\"studio-inspector__section-header\"\n [class.studio-inspector__section-header--collapsible]=\"collapsible()\"\n [disabled]=\"!collapsible()\"\n [attr.aria-expanded]=\"isSectionExpanded(section.id)\"\n [attr.aria-controls]=\"'section-content-' + section.id\"\n (click)=\"toggleSection(section.id)\">\n\n @if (showIcons() && section.icon) {\n <studio-icon\n [name]=\"section.icon\"\n [size]=\"16\"\n class=\"studio-inspector__section-icon\"\n />\n }\n\n <span class=\"studio-inspector__section-title\">{{ section.title }}</span>\n\n @if (collapsible()) {\n <studio-icon\n [name]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"studio-inspector__section-toggle\"\n />\n }\n </studio-button>\n\n @if (isSectionExpanded(section.id)) {\n <div\n class=\"studio-inspector__section-content\"\n [id]=\"'section-content-' + section.id\">\n\n @if (section.groups) {\n @for (group of section.groups; track trackByGroupId($index, group); let isLast = $last) {\n <div class=\"studio-inspector__group\">\n\n @if (showGroupLabels() && group.label) {\n <div class=\"studio-inspector__group-label\">{{ group.label }}</div>\n }\n\n @for (param of group.parameters; track trackByParameterId($index, param)) {\n <div class=\"studio-inspector__parameter\">\n @if (param.type !== 'boolean' && param.type !== 'checkbox' && param.type !== 'radio') {\n <div class=\"studio-inspector__parameter-label\">{{ param.label }}</div>\n }\n\n @if (param.type === 'text') {\n <studio-input\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'number') {\n <div class=\"studio-inspector__number-input\">\n <studio-input\n type=\"number\"\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [min]=\"param.min\"\n [max]=\"param.max\"\n [step]=\"param.step\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [fullWidth]=\"fullWidth()\"\n />\n @if (param.suffix) {\n <span class=\"studio-inspector__suffix\">{{ param.suffix }}</span>\n }\n </div>\n }\n\n @if (param.type === 'textarea') {\n <studio-textarea\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'color') {\n <studio-color-picker-compact\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'select') {\n <studio-select\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [options]=\"param.options || []\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'boolean') {\n <studio-switch\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [label]=\"param.label\"\n [size]=\"componentSize()\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'checkbox') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <studio-checkbox\n [ngModel]=\"isChecked(param, option.value)\"\n [name]=\"section.id + '-' + group.id + '-' + param.id + '-' + option.value\"\n (ngModelChange)=\"onCheckboxChange(section.id, group.id, param.id, option.value, $event)\"\n [label]=\"option.label\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n }\n </div>\n }\n\n @if (param.type === 'radio') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <div class=\"studio-inspector__option\">\n <studio-radio-button\n [ngModel]=\"param.value\"\n (ngModelChange)=\"onRadioChange(section.id, group.id, param.id, $event)\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n [name]=\"getRadioName(section.id, group.id, param.id)\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n @if (showDefaultIndicator() && isDefault(param, option.value)) {\n <span class=\"studio-inspector__default-indicator\">(default)</span>\n }\n </div>\n }\n </div>\n }\n\n @if (param.hint) {\n <div class=\"studio-inspector__parameter-hint\">{{ param.hint }}</div>\n }\n </div>\n }\n\n @if (!isLast && groupDivider() !== 'none') {\n <div class=\"studio-inspector__group-divider\"\n [class.studio-inspector__group-divider--line]=\"groupDivider() === 'line'\"\n [class.studio-inspector__group-divider--space]=\"groupDivider() === 'space'\">\n </div>\n }\n </div>\n }\n }\n\n @if (section.parameters) {\n @for (param of section.parameters; track trackByParameterId($index, param)) {\n <div class=\"studio-inspector__parameter\">\n @if (param.type !== 'boolean' && param.type !== 'checkbox' && param.type !== 'radio') {\n <div class=\"studio-inspector__parameter-label\">{{ param.label }}</div>\n }\n\n @if (param.type === 'text') {\n <studio-input\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'number') {\n <div class=\"studio-inspector__number-input\">\n <studio-input\n type=\"number\"\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [min]=\"param.min\"\n [max]=\"param.max\"\n [step]=\"param.step\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [fullWidth]=\"fullWidth()\"\n />\n @if (param.suffix) {\n <span class=\"studio-inspector__suffix\">{{ param.suffix }}</span>\n }\n </div>\n }\n\n @if (param.type === 'textarea') {\n <studio-textarea\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'color') {\n <studio-color-picker-compact\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'select') {\n <studio-select\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [options]=\"param.options || []\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'boolean') {\n <studio-switch\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [label]=\"param.label\"\n [size]=\"componentSize()\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'checkbox') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <studio-checkbox\n [ngModel]=\"isChecked(param, option.value)\"\n [name]=\"section.id + '-' + param.id + '-' + option.value\"\n (ngModelChange)=\"onCheckboxChange(section.id, null, param.id, option.value, $event)\"\n [label]=\"option.label\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n }\n </div>\n }\n\n @if (param.type === 'radio') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <div class=\"studio-inspector__option\">\n <studio-radio-button\n [ngModel]=\"param.value\"\n (ngModelChange)=\"onRadioChange(section.id, null, param.id, $event)\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n [name]=\"getRadioName(section.id, null, param.id)\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n @if (showDefaultIndicator() && isDefault(param, option.value)) {\n <span class=\"studio-inspector__default-indicator\">(default)</span>\n }\n </div>\n }\n </div>\n }\n\n @if (param.hint) {\n <div class=\"studio-inspector__parameter-hint\">{{ param.hint }}</div>\n }\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;font-family:var(--studio-font-family)}.studio-inspector__container{display:flex;flex-direction:column;gap:.75rem}.studio-inspector__section{background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);overflow:hidden}.studio-inspector__section-header{width:100%;display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:var(--studio-bg-secondary);border:none;border-bottom:1px solid var(--studio-border-primary);cursor:pointer;transition:background var(--studio-transition-fast);text-align:left}.studio-inspector__section-header--collapsible:hover{background:var(--studio-bg-tertiary)}.studio-inspector__section-header:disabled{cursor:default}.studio-inspector__section-icon{color:var(--studio-text-secondary);flex-shrink:0}.studio-inspector__section-title{flex:1;font-size:.875rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-inspector__section-toggle{color:var(--studio-text-secondary);flex-shrink:0;transition:transform var(--studio-transition-fast)}.studio-inspector__section--collapsed .studio-inspector__section-toggle{transform:rotate(-90deg)}.studio-inspector__section--collapsed .studio-inspector__section-content{display:none}.studio-inspector__section--expanded .studio-inspector__section-toggle{transform:rotate(0)}.studio-inspector__section-content{padding:1rem;display:flex;flex-direction:column;gap:.75rem}.studio-inspector__group{display:flex;flex-direction:column;gap:.75rem}.studio-inspector__group-label{font-size:.75rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-secondary);text-transform:uppercase;letter-spacing:.05em}.studio-inspector__group-divider--line{height:1px;background:var(--studio-border-primary);margin:.5rem 0}.studio-inspector__group-divider--space{height:.5rem}.studio-inspector__parameter{display:flex;flex-direction:column;gap:.5rem}.studio-inspector__parameter-label{font-size:.8125rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary)}.studio-inspector__parameter-hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-inspector__number-input{display:flex;align-items:center;gap:.5rem}.studio-inspector__suffix{font-size:.875rem;color:var(--studio-text-secondary);flex-shrink:0}.studio-inspector__options{display:flex;flex-direction:column;gap:.5rem}.studio-inspector__option{display:flex;align-items:center;gap:.5rem}.studio-inspector__default-indicator{font-size:.75rem;color:var(--studio-text-tertiary);font-style:italic}:host(.studio-inspector--compact) .studio-inspector__container{gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__section-header{padding:.625rem .75rem}:host(.studio-inspector--compact) .studio-inspector__section-content{padding:.75rem;gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__group{gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__parameter{gap:.375rem}:host(.studio-inspector--spacing-sm) .studio-inspector__section-content{gap:.5rem}:host(.studio-inspector--spacing-sm) .studio-inspector__group{gap:.5rem}:host(.studio-inspector--spacing-sm) .studio-inspector__parameter{gap:.375rem}:host(.studio-inspector--spacing-lg) .studio-inspector__section-content{gap:1rem}:host(.studio-inspector--spacing-lg) .studio-inspector__group{gap:1rem}:host(.studio-inspector--spacing-lg) .studio-inspector__parameter{gap:.625rem}:host(.studio-inspector--spacing-lg) .studio-inspector__group-divider--space{height:1rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ButtonComponent, selector: "studio-button", inputs: ["variant", "size", "color", "radius", "shadow", "compact", "disabled", "loading", "loadingText", "fullWidth", "type", "icon", "iconPosition", "href", "target", "badge", "badgeColor", "ariaLabel"], outputs: ["clicked"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }, { kind: "component", type: InputComponent, selector: "studio-input", inputs: ["variant", "size", "radius", "disabled", "readonly", "loading", "type", "inputmode", "autocomplete", "placeholder", "maxLength", "minLength", "min", "max", "step", "pattern", "label", "floatingLabel", "hint", "required", "error", "errorMessage", "prefixIcon", "suffixIcon", "clearable", "showPasswordToggle", "fullWidth", "autoFocus", "name", "id", "ariaLabel"], outputs: ["valueChange", "focused", "blurred", "cleared", "entered"] }, { kind: "component", type: CheckboxComponent, selector: "studio-checkbox", inputs: ["size", "color", "variant", "radius", "label", "labelPosition", "description", "hint", "required", "error", "errorMessage", "disabled", "readonly", "indeterminate", "name", "tabIndex", "value"], outputs: ["changed"] }, { kind: "component", type: RadioButtonComponent, selector: "studio-radio-button", inputs: ["size", "color", "variant", "radius", "label", "labelPosition", "description", "hint", "required", "error", "errorMessage", "disabled", "readonly", "name", "tabIndex", "value"], outputs: ["changed"] }, { kind: "component", type: ColorPickerCompactComponent, selector: "studio-color-picker-compact", inputs: ["trigger", "position", "popoverWidth", "showArrow", "closeOnClickOutside", "triggerSize", "triggerRadius", "showCurrentColor", "format", "showAlpha", "showPresets", "showFormatToggle", "showCopyButton", "presets", "showFooter", "applyLabel", "cancelLabel", "disabled", "ariaLabel"], outputs: ["colorChange"] }, { kind: "component", type: SelectComponent, selector: "studio-select", inputs: ["variant", "size", "radius", "options", "placeholder", "multiple", "searchable", "clearable", "disabled", "loading", "label", "floatingLabel", "hint", "error", "errorMessage", "required", "prefixIcon", "suffixIcon", "fullWidth", "maxHeight", "position", "searchPlaceholder"], outputs: ["valueChange", "searchChange", "opened", "closed", "optionSelected"] }, { kind: "component", type: TextareaComponent, selector: "studio-textarea", inputs: ["variant", "size", "color", "radius", "label", "floatingLabel", "placeholder", "hint", "rows", "minRows", "maxRows", "autoResize", "resize", "maxLength", "showCharCount", "charCountPosition", "required", "minLength", "error", "errorMessage", "disabled", "readonly", "fullWidth", "name", "autocomplete", "spellcheck", "clearable", "loading"], outputs: ["changed", "focused", "blurred", "keyPressed"] }, { kind: "component", type: SwitchComponent, selector: "studio-switch", inputs: ["checked", "disabled", "label", "labelPosition", "showIcons", "ariaLabel", "size", "color"], outputs: ["checkedChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4064
5000
  }
4065
5001
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: InspectorComponent, decorators: [{
4066
5002
  type: Component,
@@ -4072,7 +5008,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
4072
5008
  InputComponent,
4073
5009
  CheckboxComponent,
4074
5010
  RadioButtonComponent,
4075
- ColorPickerComponent,
5011
+ ColorPickerCompactComponent,
4076
5012
  SelectComponent,
4077
5013
  TextareaComponent,
4078
5014
  SwitchComponent
@@ -4086,7 +5022,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
4086
5022
  '[class]': 'hostClasses()',
4087
5023
  '[attr.role]': '"region"',
4088
5024
  '[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"] }]
5025
+ }, template: "@if (values()) {\n <div class=\"studio-inspector__container\">\n @for (section of values()!.sections; track trackBySectionId($index, section)) {\n <div class=\"studio-inspector__section\"\n [class.studio-inspector__section--expanded]=\"isSectionExpanded(section.id)\"\n [class.studio-inspector__section--collapsed]=\"!isSectionExpanded(section.id)\">\n\n <studio-button\n variant=\"ghost\"\n [fullWidth]=\"true\"\n class=\"studio-inspector__section-header\"\n [class.studio-inspector__section-header--collapsible]=\"collapsible()\"\n [disabled]=\"!collapsible()\"\n [attr.aria-expanded]=\"isSectionExpanded(section.id)\"\n [attr.aria-controls]=\"'section-content-' + section.id\"\n (click)=\"toggleSection(section.id)\">\n\n @if (showIcons() && section.icon) {\n <studio-icon\n [name]=\"section.icon\"\n [size]=\"16\"\n class=\"studio-inspector__section-icon\"\n />\n }\n\n <span class=\"studio-inspector__section-title\">{{ section.title }}</span>\n\n @if (collapsible()) {\n <studio-icon\n [name]=\"'chevron-down'\"\n [size]=\"16\"\n class=\"studio-inspector__section-toggle\"\n />\n }\n </studio-button>\n\n @if (isSectionExpanded(section.id)) {\n <div\n class=\"studio-inspector__section-content\"\n [id]=\"'section-content-' + section.id\">\n\n @if (section.groups) {\n @for (group of section.groups; track trackByGroupId($index, group); let isLast = $last) {\n <div class=\"studio-inspector__group\">\n\n @if (showGroupLabels() && group.label) {\n <div class=\"studio-inspector__group-label\">{{ group.label }}</div>\n }\n\n @for (param of group.parameters; track trackByParameterId($index, param)) {\n <div class=\"studio-inspector__parameter\">\n @if (param.type !== 'boolean' && param.type !== 'checkbox' && param.type !== 'radio') {\n <div class=\"studio-inspector__parameter-label\">{{ param.label }}</div>\n }\n\n @if (param.type === 'text') {\n <studio-input\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'number') {\n <div class=\"studio-inspector__number-input\">\n <studio-input\n type=\"number\"\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [min]=\"param.min\"\n [max]=\"param.max\"\n [step]=\"param.step\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [fullWidth]=\"fullWidth()\"\n />\n @if (param.suffix) {\n <span class=\"studio-inspector__suffix\">{{ param.suffix }}</span>\n }\n </div>\n }\n\n @if (param.type === 'textarea') {\n <studio-textarea\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'color') {\n <studio-color-picker-compact\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'select') {\n <studio-select\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [options]=\"param.options || []\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'boolean') {\n <studio-switch\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + group.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, group.id, param.id, $event)\"\n [label]=\"param.label\"\n [size]=\"componentSize()\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'checkbox') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <studio-checkbox\n [ngModel]=\"isChecked(param, option.value)\"\n [name]=\"section.id + '-' + group.id + '-' + param.id + '-' + option.value\"\n (ngModelChange)=\"onCheckboxChange(section.id, group.id, param.id, option.value, $event)\"\n [label]=\"option.label\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n }\n </div>\n }\n\n @if (param.type === 'radio') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <div class=\"studio-inspector__option\">\n <studio-radio-button\n [ngModel]=\"param.value\"\n (ngModelChange)=\"onRadioChange(section.id, group.id, param.id, $event)\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n [name]=\"getRadioName(section.id, group.id, param.id)\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n @if (showDefaultIndicator() && isDefault(param, option.value)) {\n <span class=\"studio-inspector__default-indicator\">(default)</span>\n }\n </div>\n }\n </div>\n }\n\n @if (param.hint) {\n <div class=\"studio-inspector__parameter-hint\">{{ param.hint }}</div>\n }\n </div>\n }\n\n @if (!isLast && groupDivider() !== 'none') {\n <div class=\"studio-inspector__group-divider\"\n [class.studio-inspector__group-divider--line]=\"groupDivider() === 'line'\"\n [class.studio-inspector__group-divider--space]=\"groupDivider() === 'space'\">\n </div>\n }\n </div>\n }\n }\n\n @if (section.parameters) {\n @for (param of section.parameters; track trackByParameterId($index, param)) {\n <div class=\"studio-inspector__parameter\">\n @if (param.type !== 'boolean' && param.type !== 'checkbox' && param.type !== 'radio') {\n <div class=\"studio-inspector__parameter-label\">{{ param.label }}</div>\n }\n\n @if (param.type === 'text') {\n <studio-input\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'number') {\n <div class=\"studio-inspector__number-input\">\n <studio-input\n type=\"number\"\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [min]=\"param.min\"\n [max]=\"param.max\"\n [step]=\"param.step\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [fullWidth]=\"fullWidth()\"\n />\n @if (param.suffix) {\n <span class=\"studio-inspector__suffix\">{{ param.suffix }}</span>\n }\n </div>\n }\n\n @if (param.type === 'textarea') {\n <studio-textarea\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [readonly]=\"param.readonly || false\"\n [maxLength]=\"param.maxLength\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'color') {\n <studio-color-picker-compact\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'select') {\n <studio-select\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [variant]=\"componentVariant()\"\n [size]=\"componentSize()\"\n [options]=\"param.options || []\"\n [placeholder]=\"param.placeholder || ''\"\n [disabled]=\"param.disabled || false\"\n [fullWidth]=\"fullWidth()\"\n />\n }\n\n @if (param.type === 'boolean') {\n <studio-switch\n [ngModel]=\"param.value\"\n [name]=\"section.id + '-' + param.id\"\n (ngModelChange)=\"onParameterChange(section.id, null, param.id, $event)\"\n [label]=\"param.label\"\n [size]=\"componentSize()\"\n [disabled]=\"param.disabled || false\"\n />\n }\n\n @if (param.type === 'checkbox') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <studio-checkbox\n [ngModel]=\"isChecked(param, option.value)\"\n [name]=\"section.id + '-' + param.id + '-' + option.value\"\n (ngModelChange)=\"onCheckboxChange(section.id, null, param.id, option.value, $event)\"\n [label]=\"option.label\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n }\n </div>\n }\n\n @if (param.type === 'radio') {\n <div class=\"studio-inspector__options\">\n @for (option of param.options; track trackByOptionValue($index, option)) {\n <div class=\"studio-inspector__option\">\n <studio-radio-button\n [ngModel]=\"param.value\"\n (ngModelChange)=\"onRadioChange(section.id, null, param.id, $event)\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n [name]=\"getRadioName(section.id, null, param.id)\"\n [disabled]=\"param.disabled || option.disabled || false\"\n [size]=\"componentSize()\"\n />\n @if (showDefaultIndicator() && isDefault(param, option.value)) {\n <span class=\"studio-inspector__default-indicator\">(default)</span>\n }\n </div>\n }\n </div>\n }\n\n @if (param.hint) {\n <div class=\"studio-inspector__parameter-hint\">{{ param.hint }}</div>\n }\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;font-family:var(--studio-font-family)}.studio-inspector__container{display:flex;flex-direction:column;gap:.75rem}.studio-inspector__section{background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);overflow:hidden}.studio-inspector__section-header{width:100%;display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:var(--studio-bg-secondary);border:none;border-bottom:1px solid var(--studio-border-primary);cursor:pointer;transition:background var(--studio-transition-fast);text-align:left}.studio-inspector__section-header--collapsible:hover{background:var(--studio-bg-tertiary)}.studio-inspector__section-header:disabled{cursor:default}.studio-inspector__section-icon{color:var(--studio-text-secondary);flex-shrink:0}.studio-inspector__section-title{flex:1;font-size:.875rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-inspector__section-toggle{color:var(--studio-text-secondary);flex-shrink:0;transition:transform var(--studio-transition-fast)}.studio-inspector__section--collapsed .studio-inspector__section-toggle{transform:rotate(-90deg)}.studio-inspector__section--collapsed .studio-inspector__section-content{display:none}.studio-inspector__section--expanded .studio-inspector__section-toggle{transform:rotate(0)}.studio-inspector__section-content{padding:1rem;display:flex;flex-direction:column;gap:.75rem}.studio-inspector__group{display:flex;flex-direction:column;gap:.75rem}.studio-inspector__group-label{font-size:.75rem;font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-secondary);text-transform:uppercase;letter-spacing:.05em}.studio-inspector__group-divider--line{height:1px;background:var(--studio-border-primary);margin:.5rem 0}.studio-inspector__group-divider--space{height:.5rem}.studio-inspector__parameter{display:flex;flex-direction:column;gap:.5rem}.studio-inspector__parameter-label{font-size:.8125rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary)}.studio-inspector__parameter-hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-inspector__number-input{display:flex;align-items:center;gap:.5rem}.studio-inspector__suffix{font-size:.875rem;color:var(--studio-text-secondary);flex-shrink:0}.studio-inspector__options{display:flex;flex-direction:column;gap:.5rem}.studio-inspector__option{display:flex;align-items:center;gap:.5rem}.studio-inspector__default-indicator{font-size:.75rem;color:var(--studio-text-tertiary);font-style:italic}:host(.studio-inspector--compact) .studio-inspector__container{gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__section-header{padding:.625rem .75rem}:host(.studio-inspector--compact) .studio-inspector__section-content{padding:.75rem;gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__group{gap:.5rem}:host(.studio-inspector--compact) .studio-inspector__parameter{gap:.375rem}:host(.studio-inspector--spacing-sm) .studio-inspector__section-content{gap:.5rem}:host(.studio-inspector--spacing-sm) .studio-inspector__group{gap:.5rem}:host(.studio-inspector--spacing-sm) .studio-inspector__parameter{gap:.375rem}:host(.studio-inspector--spacing-lg) .studio-inspector__section-content{gap:1rem}:host(.studio-inspector--spacing-lg) .studio-inspector__group{gap:1rem}:host(.studio-inspector--spacing-lg) .studio-inspector__parameter{gap:.625rem}:host(.studio-inspector--spacing-lg) .studio-inspector__group-divider--space{height:1rem}\n"] }]
4090
5026
  }], ctorParameters: () => [], propDecorators: { componentSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentSize", required: false }] }], componentVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentVariant", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], showIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcons", required: false }] }], showDefaultIndicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDefaultIndicator", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], expandedByDefault: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedByDefault", required: false }] }], expandedSectionsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedSections", required: false }] }], showGroupLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGroupLabels", required: false }] }], groupDivider: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupDivider", required: false }] }], groupDividerSpacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupDividerSpacing", required: false }] }], labelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelWidth", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], spacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "spacing", required: false }] }], sectionTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionTemplate", required: false }] }], parameterTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterTemplates", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], sectionToggled: [{ type: i0.Output, args: ["sectionToggled"] }], parameterFocused: [{ type: i0.Output, args: ["parameterFocused"] }], parameterBlurred: [{ type: i0.Output, args: ["parameterBlurred"] }] } });
4091
5027
 
4092
5028
  /**
@@ -4617,5 +5553,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
4617
5553
  * Generated bundle index. Do not edit.
4618
5554
  */
4619
5555
 
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 };
5556
+ export { BadgeComponent, BadgeWrapperComponent, ButtonComponent, ButtonGroupComponent, ButtonToggleGroupComponent, CheckboxComponent, ColorPickerCompactComponent, ColorPickerComponent, DEFAULT_COLOR_PRESETS, DrawerComponent, DrawerService, DropdownComponent, IconComponent, InputComponent, InspectorComponent, MASK_PRESETS, MaskDirective, MaskEngine, MenuComponent, ModalComponent, NavbarComponent, PopoverComponent, RadioButtonComponent, STUDIO_CONFIG, SelectComponent, SidebarComponent, StudioConfigService, SwitchComponent, TabsComponent, TextareaComponent, ThemeSwitchComponent, TooltipComponent, classNames, isSafeUrl, loadGoogleFont, loadGoogleFonts, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
4621
5557
  //# sourceMappingURL=eduboxpro-studio.mjs.map