@eduboxpro/studio 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
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, model } from '@angular/core';
2
+ import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output, ElementRef, forwardRef, DOCUMENT as DOCUMENT$1, DestroyRef, contentChild, viewChild, model, HostListener, Renderer2, Directive } from '@angular/core';
3
3
  import * as i1$1 from '@angular/common';
4
- import { DOCUMENT, CommonModule } from '@angular/common';
4
+ import { DOCUMENT, CommonModule, NgTemplateOutlet } from '@angular/common';
5
5
  import * as i1 from 'lucide-angular';
6
- import { icons, LucideAngularModule, LucideIconProvider, LUCIDE_ICONS, Laptop, MessageSquare, List, Grid3x3, Strikethrough, Underline, Italic, Bold, AlignJustify, AlignRight, AlignCenter, AlignLeft, Moon, Sun, ShoppingCart, Loader2, Loader, RotateCw, RefreshCw, Printer, Save, Image, Folder, FileText, File, HelpCircle, XCircle, CheckCircle, Info, AlertTriangle, AlertCircle, LogOut, LogIn, Unlock, Lock, EyeOff, Eye, Clock, Calendar, Bell, MoreHorizontal, MoreVertical, Menu, Home, Share2, Copy, Link, ExternalLink, Filter, Search, X, Check, Minus, Plus, Edit, Trash2, User, Settings, Star, Heart, Phone, Mail, Upload, Download, ChevronRight, ChevronLeft, ChevronUp, ChevronDown, ArrowLeft, ArrowRight } from 'lucide-angular';
7
- import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
+ import { icons, LucideAngularModule, LucideIconProvider, LUCIDE_ICONS, Circle, Apple, Globe, Laptop, MessageSquare, List, Grid3x3, Strikethrough, Underline, Italic, Bold, AlignJustify, AlignRight, AlignCenter, AlignLeft, Moon, Sun, ShoppingCart, Loader2, Loader, RotateCw, RefreshCw, Printer, Save, Image, Folder, FileText, File, HelpCircle, XCircle, CheckCircle, Info, AlertTriangle, AlertCircle, LogOut, LogIn, Unlock, Lock, EyeOff, Eye, Clock, Calendar, Bell, MoreHorizontal, MoreVertical, Menu, Home, Share2, Copy, Link, ExternalLink, Filter, Search, X, Check, Minus, Plus, Edit, Trash2, User, Settings, Star, Heart, Phone, Mail, Upload, Download, ChevronRight, ChevronLeft, ChevronUp, ChevronDown, ArrowLeft, ArrowRight } from 'lucide-angular';
7
+ import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
8
8
 
9
9
  /**
10
10
  * Injection token for Studio configuration
@@ -455,7 +455,10 @@ function provideStudioIcons() {
455
455
  Grid3x3,
456
456
  List,
457
457
  MessageSquare,
458
- Laptop
458
+ Laptop,
459
+ Globe,
460
+ Apple,
461
+ Circle
459
462
  })
460
463
  }
461
464
  ]);
@@ -1177,6 +1180,436 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
1177
1180
  }, template: "<label\n [for]=\"checkboxId()\"\n [ngClass]=\"hostClasses()\"\n (click)=\"handleLabelClick($event)\"\n>\n <!-- Checkbox input -->\n <input\n type=\"checkbox\"\n [id]=\"checkboxId()\"\n [name]=\"name()\"\n [checked]=\"internalChecked()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [tabIndex]=\"tabIndex()\"\n [attr.aria-checked]=\"ariaChecked()\"\n [attr.aria-label]=\"label() || undefined\"\n [attr.aria-describedby]=\"showHint() || showError() ? checkboxId() + '-description' : undefined\"\n [attr.aria-invalid]=\"error()\"\n [attr.aria-required]=\"required()\"\n class=\"studio-checkbox__input\"\n (change)=\"handleChange($event)\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n />\n\n <!-- Custom checkbox -->\n <span [ngClass]=\"checkboxClasses()\">\n <!-- Checkmark icon -->\n @if (internalChecked() && !indeterminate()) {\n <svg\n class=\"studio-checkbox__icon\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M13.3333 4L6 11.3333L2.66666 8\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n\n <!-- Indeterminate icon -->\n @if (indeterminate()) {\n <svg\n class=\"studio-checkbox__icon studio-checkbox__icon--indeterminate\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M4 8H12\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n </span>\n\n <!-- Label content -->\n @if (label() || description()) {\n <span class=\"studio-checkbox__label-wrapper\">\n @if (label()) {\n <span class=\"studio-checkbox__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-checkbox__required\" aria-hidden=\"true\">*</span>\n }\n </span>\n }\n\n @if (description()) {\n <span class=\"studio-checkbox__description\">\n {{ description() }}\n </span>\n }\n </span>\n }\n</label>\n\n<!-- Helper text / Error message -->\n@if (showHint() || showError()) {\n <div\n [id]=\"checkboxId() + '-description'\"\n class=\"studio-checkbox__info\"\n >\n @if (showError()) {\n <span class=\"studio-checkbox__error\">\n {{ errorMessage() }}\n </span>\n }\n\n @if (showHint()) {\n <span class=\"studio-checkbox__hint\">\n {{ hint() }}\n </span>\n }\n </div>\n}\n", styles: [":host{display:inline-flex;flex-direction:column;font-family:var(--studio-font-family)!important}.studio-checkbox-wrapper{display:inline-flex;align-items:flex-start;gap:var(--studio-spacing-sm);cursor:pointer;-webkit-user-select:none;user-select:none;position:relative}.studio-checkbox-wrapper--label-left{flex-direction:row-reverse}.studio-checkbox-wrapper--disabled{cursor:not-allowed;opacity:.5}.studio-checkbox-wrapper--sm{font-size:var(--studio-font-size-sm)}.studio-checkbox-wrapper--md{font-size:var(--studio-font-size-base)}.studio-checkbox-wrapper--lg{font-size:var(--studio-font-size-lg)}.studio-checkbox__input{position:absolute;opacity:0;pointer-events:none;width:0;height:0}.studio-checkbox{position:relative;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;border:2px solid var(--studio-border-primary);background-color:var(--studio-bg-primary);transition:all var(--studio-transition-base)}.studio-checkbox--sm{width:1rem;height:1rem}.studio-checkbox--md{width:1.25rem;height:1.25rem}.studio-checkbox--lg{width:1.5rem;height:1.5rem}.studio-checkbox--radius-none{border-radius:0}.studio-checkbox--radius-sm{border-radius:var(--studio-radius-sm)}.studio-checkbox--radius-md{border-radius:var(--studio-radius-md)}.studio-checkbox--radius-lg{border-radius:var(--studio-radius-lg)}.studio-checkbox--radius-full{border-radius:var(--studio-radius-full)}.studio-checkbox--default.studio-checkbox--checked,.studio-checkbox--default.studio-checkbox--indeterminate{border-color:transparent}.studio-checkbox--default.studio-checkbox--checked.studio-checkbox--primary,.studio-checkbox--default.studio-checkbox--indeterminate.studio-checkbox--primary{background-color:var(--studio-primary);color:var(--studio-text-inverse)}.studio-checkbox--default.studio-checkbox--checked.studio-checkbox--secondary,.studio-checkbox--default.studio-checkbox--indeterminate.studio-checkbox--secondary{background-color:var(--studio-secondary);color:var(--studio-text-inverse)}.studio-checkbox--default.studio-checkbox--checked.studio-checkbox--success,.studio-checkbox--default.studio-checkbox--indeterminate.studio-checkbox--success{background-color:var(--studio-success);color:var(--studio-text-inverse)}.studio-checkbox--default.studio-checkbox--checked.studio-checkbox--error,.studio-checkbox--default.studio-checkbox--indeterminate.studio-checkbox--error{background-color:var(--studio-error);color:var(--studio-text-inverse)}.studio-checkbox--outlined.studio-checkbox--checked,.studio-checkbox--outlined.studio-checkbox--indeterminate{background-color:transparent}.studio-checkbox--outlined.studio-checkbox--checked.studio-checkbox--primary,.studio-checkbox--outlined.studio-checkbox--indeterminate.studio-checkbox--primary{border-color:var(--studio-primary);color:var(--studio-primary)}.studio-checkbox--outlined.studio-checkbox--checked.studio-checkbox--secondary,.studio-checkbox--outlined.studio-checkbox--indeterminate.studio-checkbox--secondary{border-color:var(--studio-secondary);color:var(--studio-secondary)}.studio-checkbox--outlined.studio-checkbox--checked.studio-checkbox--success,.studio-checkbox--outlined.studio-checkbox--indeterminate.studio-checkbox--success{border-color:var(--studio-success);color:var(--studio-success)}.studio-checkbox--outlined.studio-checkbox--checked.studio-checkbox--error,.studio-checkbox--outlined.studio-checkbox--indeterminate.studio-checkbox--error{border-color:var(--studio-error);color:var(--studio-error)}.studio-checkbox--filled.studio-checkbox--primary{background-color:var(--studio-primary-bg);border-color:var(--studio-primary-bg)}.studio-checkbox--filled.studio-checkbox--secondary{background-color:var(--studio-secondary-bg);border-color:var(--studio-secondary-bg)}.studio-checkbox--filled.studio-checkbox--success{background-color:var(--studio-success-bg);border-color:var(--studio-success-bg)}.studio-checkbox--filled.studio-checkbox--error{background-color:var(--studio-error-bg);border-color:var(--studio-error-bg)}.studio-checkbox--filled.studio-checkbox--checked.studio-checkbox--primary,.studio-checkbox--filled.studio-checkbox--indeterminate.studio-checkbox--primary{background-color:var(--studio-primary);border-color:var(--studio-primary);color:var(--studio-text-inverse)}.studio-checkbox--filled.studio-checkbox--checked.studio-checkbox--secondary,.studio-checkbox--filled.studio-checkbox--indeterminate.studio-checkbox--secondary{background-color:var(--studio-secondary);border-color:var(--studio-secondary);color:var(--studio-text-inverse)}.studio-checkbox--filled.studio-checkbox--checked.studio-checkbox--success,.studio-checkbox--filled.studio-checkbox--indeterminate.studio-checkbox--success{background-color:var(--studio-success);border-color:var(--studio-success);color:var(--studio-text-inverse)}.studio-checkbox--filled.studio-checkbox--checked.studio-checkbox--error,.studio-checkbox--filled.studio-checkbox--indeterminate.studio-checkbox--error{background-color:var(--studio-error);border-color:var(--studio-error);color:var(--studio-text-inverse)}.studio-checkbox--error:not(.studio-checkbox--checked):not(.studio-checkbox--indeterminate){border-color:var(--studio-error)}.studio-checkbox:hover:not(.studio-checkbox--disabled){border-color:var(--studio-border-secondary)}.studio-checkbox__input:focus-visible+.studio-checkbox{outline:2px solid var(--studio-primary);outline-offset:2px}.studio-checkbox__icon{width:100%;height:100%;opacity:0;transform:scale(.8);transition:all var(--studio-transition-fast)}.studio-checkbox--checked .studio-checkbox__icon,.studio-checkbox--indeterminate .studio-checkbox__icon{opacity:1;transform:scale(1)}.studio-checkbox__label-wrapper{display:flex;flex-direction:column;gap:var(--studio-spacing-xs)}.studio-checkbox__label{font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);line-height:var(--studio-line-height-normal)}.studio-checkbox__description{font-size:var(--studio-font-size-sm);color:var(--studio-text-secondary);line-height:var(--studio-line-height-normal)}.studio-checkbox__required{color:var(--studio-error);margin-left:var(--studio-spacing-xs)}.studio-checkbox__info{display:flex;flex-direction:column;gap:var(--studio-spacing-xs);margin-top:var(--studio-spacing-xs);padding-left:calc(var(--studio-spacing-sm) + 1.25rem)}.studio-checkbox-wrapper--label-left+.studio-checkbox__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1.25rem)}.studio-checkbox-wrapper--sm .studio-checkbox__info{padding-left:calc(var(--studio-spacing-sm) + 1rem)}.studio-checkbox-wrapper--sm.studio-checkbox-wrapper--label-left .studio-checkbox__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1rem)}.studio-checkbox-wrapper--lg .studio-checkbox__info{padding-left:calc(var(--studio-spacing-sm) + 1.5rem)}.studio-checkbox-wrapper--lg.studio-checkbox-wrapper--label-left .studio-checkbox__info{padding-left:0;padding-right:calc(var(--studio-spacing-sm) + 1.5rem)}.studio-checkbox__hint{font-size:var(--studio-font-size-xs);color:var(--studio-text-secondary);line-height:var(--studio-line-height-normal)}.studio-checkbox__error{font-size:var(--studio-font-size-xs);color:var(--studio-error);line-height:var(--studio-line-height-normal)}\n"] }]
1178
1181
  }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
1179
1182
 
1183
+ /**
1184
+ * Service for programmatic control of Drawer components
1185
+ *
1186
+ * @example
1187
+ * ```typescript
1188
+ * // In component
1189
+ * private drawerService = inject(DrawerService);
1190
+ *
1191
+ * openSettings() {
1192
+ * this.drawerService.open('settings-drawer');
1193
+ * }
1194
+ * ```
1195
+ */
1196
+ class DrawerService {
1197
+ drawers = new Map();
1198
+ /**
1199
+ * Register a drawer with the service
1200
+ * Called automatically by DrawerComponent
1201
+ */
1202
+ register(id, signal) {
1203
+ this.drawers.set(id, signal);
1204
+ }
1205
+ /**
1206
+ * Unregister a drawer from the service
1207
+ * Called automatically on component destroy
1208
+ */
1209
+ unregister(id) {
1210
+ this.drawers.delete(id);
1211
+ }
1212
+ /**
1213
+ * Open a drawer by ID
1214
+ */
1215
+ open(id) {
1216
+ const drawer = this.drawers.get(id);
1217
+ if (drawer) {
1218
+ drawer.set(true);
1219
+ }
1220
+ else {
1221
+ console.warn(`[DrawerService] Drawer with id="${id}" not found`);
1222
+ }
1223
+ }
1224
+ /**
1225
+ * Close a drawer by ID
1226
+ */
1227
+ close(id) {
1228
+ const drawer = this.drawers.get(id);
1229
+ if (drawer) {
1230
+ drawer.set(false);
1231
+ }
1232
+ else {
1233
+ console.warn(`[DrawerService] Drawer with id="${id}" not found`);
1234
+ }
1235
+ }
1236
+ /**
1237
+ * Toggle a drawer by ID
1238
+ */
1239
+ toggle(id) {
1240
+ const drawer = this.drawers.get(id);
1241
+ if (drawer) {
1242
+ drawer.update(v => !v);
1243
+ }
1244
+ else {
1245
+ console.warn(`[DrawerService] Drawer with id="${id}" not found`);
1246
+ }
1247
+ }
1248
+ /**
1249
+ * Close all registered drawers
1250
+ */
1251
+ closeAll() {
1252
+ this.drawers.forEach(signal => signal.set(false));
1253
+ }
1254
+ /**
1255
+ * Check if a drawer is open
1256
+ */
1257
+ isOpen(id) {
1258
+ const drawer = this.drawers.get(id);
1259
+ return drawer ? drawer() : false;
1260
+ }
1261
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: DrawerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1262
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: DrawerService, providedIn: 'root' });
1263
+ }
1264
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: DrawerService, decorators: [{
1265
+ type: Injectable,
1266
+ args: [{ providedIn: 'root' }]
1267
+ }] });
1268
+
1269
+ class DrawerComponent {
1270
+ document = inject(DOCUMENT$1);
1271
+ destroyRef = inject(DestroyRef);
1272
+ configService = inject(StudioConfigService);
1273
+ drawerService = inject(DrawerService);
1274
+ drawerDefaults = computed(() => this.configService.config().components?.drawer, ...(ngDevMode ? [{ debugName: "drawerDefaults" }] : []));
1275
+ // Template references
1276
+ headerTemplate = contentChild('headerTemplate', ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
1277
+ footerTemplate = contentChild('footerTemplate', ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
1278
+ panelEl = viewChild('drawerPanel', ...(ngDevMode ? [{ debugName: "panelEl" }] : []));
1279
+ // Core
1280
+ id = input(`studio-drawer-${Math.random().toString(36).substr(2, 9)}`, ...(ngDevMode ? [{ debugName: "id" }] : []));
1281
+ visible = model(false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
1282
+ // Position & Size
1283
+ positionInput = input(undefined, ...(ngDevMode ? [{ debugName: "positionInput", alias: 'position' }] : [{ alias: 'position' }]));
1284
+ sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
1285
+ customWidth = input(undefined, ...(ngDevMode ? [{ debugName: "customWidth" }] : []));
1286
+ customHeight = input(undefined, ...(ngDevMode ? [{ debugName: "customHeight" }] : []));
1287
+ position = withConfigDefault(this.positionInput, computed(() => this.drawerDefaults()?.position), 'right');
1288
+ size = withConfigDefault(this.sizeInput, computed(() => this.drawerDefaults()?.size), 'md');
1289
+ // Behavior
1290
+ modalInput = input(undefined, ...(ngDevMode ? [{ debugName: "modalInput", alias: 'modal' }] : [{ alias: 'modal' }]));
1291
+ closeOnEscapeInput = input(undefined, ...(ngDevMode ? [{ debugName: "closeOnEscapeInput", alias: 'closeOnEscape' }] : [{ alias: 'closeOnEscape' }]));
1292
+ closeOnBackdropClickInput = input(undefined, ...(ngDevMode ? [{ debugName: "closeOnBackdropClickInput", alias: 'closeOnBackdropClick' }] : [{ alias: 'closeOnBackdropClick' }]));
1293
+ blockScrollInput = input(undefined, ...(ngDevMode ? [{ debugName: "blockScrollInput", alias: 'blockScroll' }] : [{ alias: 'blockScroll' }]));
1294
+ modal = withConfigDefault(this.modalInput, computed(() => this.drawerDefaults()?.modal), true);
1295
+ closeOnEscape = withConfigDefault(this.closeOnEscapeInput, computed(() => this.drawerDefaults()?.closeOnEscape), true);
1296
+ closeOnBackdropClick = withConfigDefault(this.closeOnBackdropClickInput, computed(() => this.drawerDefaults()?.closeOnBackdropClick), true);
1297
+ blockScroll = withConfigDefault(this.blockScrollInput, computed(() => this.drawerDefaults()?.blockScroll), true);
1298
+ // UI Elements
1299
+ header = input(undefined, ...(ngDevMode ? [{ debugName: "header" }] : []));
1300
+ showHeaderInput = input(undefined, ...(ngDevMode ? [{ debugName: "showHeaderInput", alias: 'showHeader' }] : [{ alias: 'showHeader' }]));
1301
+ showCloseButtonInput = input(undefined, ...(ngDevMode ? [{ debugName: "showCloseButtonInput", alias: 'showCloseButton' }] : [{ alias: 'showCloseButton' }]));
1302
+ closeButtonPositionInput = input(undefined, ...(ngDevMode ? [{ debugName: "closeButtonPositionInput", alias: 'closeButtonPosition' }] : [{ alias: 'closeButtonPosition' }]));
1303
+ showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
1304
+ showHeader = withConfigDefault(this.showHeaderInput, computed(() => this.drawerDefaults()?.showHeader ?? true), true);
1305
+ showCloseButton = withConfigDefault(this.showCloseButtonInput, computed(() => this.drawerDefaults()?.showCloseButton), true);
1306
+ closeButtonPosition = withConfigDefault(this.closeButtonPositionInput, computed(() => this.drawerDefaults()?.closeButtonPosition), 'right');
1307
+ // Swipe Gestures
1308
+ swipeToCloseInput = input(undefined, ...(ngDevMode ? [{ debugName: "swipeToCloseInput", alias: 'swipeToClose' }] : [{ alias: 'swipeToClose' }]));
1309
+ swipeThresholdInput = input(undefined, ...(ngDevMode ? [{ debugName: "swipeThresholdInput", alias: 'swipeThreshold' }] : [{ alias: 'swipeThreshold' }]));
1310
+ swipeToClose = withConfigDefault(this.swipeToCloseInput, computed(() => this.drawerDefaults()?.swipeToClose), true);
1311
+ swipeThreshold = withConfigDefault(this.swipeThresholdInput, computed(() => this.drawerDefaults()?.swipeThreshold), 50);
1312
+ // Animation
1313
+ animationDurationInput = input(undefined, ...(ngDevMode ? [{ debugName: "animationDurationInput", alias: 'animationDuration' }] : [{ alias: 'animationDuration' }]));
1314
+ animationEasingInput = input(undefined, ...(ngDevMode ? [{ debugName: "animationEasingInput", alias: 'animationEasing' }] : [{ alias: 'animationEasing' }]));
1315
+ disableAnimationInput = input(undefined, ...(ngDevMode ? [{ debugName: "disableAnimationInput", alias: 'disableAnimation' }] : [{ alias: 'disableAnimation' }]));
1316
+ animationDuration = withConfigDefault(this.animationDurationInput, computed(() => this.drawerDefaults()?.animationDuration), 300);
1317
+ animationEasing = withConfigDefault(this.animationEasingInput, computed(() => this.drawerDefaults()?.animationEasing), 'ease-out');
1318
+ disableAnimation = withConfigDefault(this.disableAnimationInput, computed(() => this.drawerDefaults()?.disableAnimation), false);
1319
+ // Styling
1320
+ radiusInput = input(undefined, ...(ngDevMode ? [{ debugName: "radiusInput", alias: 'radius' }] : [{ alias: 'radius' }]));
1321
+ shadowInput = input(undefined, ...(ngDevMode ? [{ debugName: "shadowInput", alias: 'shadow' }] : [{ alias: 'shadow' }]));
1322
+ shadowSizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "shadowSizeInput", alias: 'shadowSize' }] : [{ alias: 'shadowSize' }]));
1323
+ radius = withConfigDefault(this.radiusInput, computed(() => this.drawerDefaults()?.radius), 'none');
1324
+ shadow = withConfigDefault(this.shadowInput, computed(() => this.drawerDefaults()?.shadow), true);
1325
+ shadowSize = withConfigDefault(this.shadowSizeInput, computed(() => this.drawerDefaults()?.shadowSize), 'lg');
1326
+ // Accessibility
1327
+ ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
1328
+ ariaLabelledBy = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabelledBy" }] : []));
1329
+ ariaDescribedBy = input(undefined, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
1330
+ autoFocusInput = input(undefined, ...(ngDevMode ? [{ debugName: "autoFocusInput", alias: 'autoFocus' }] : [{ alias: 'autoFocus' }]));
1331
+ restoreFocusInput = input(undefined, ...(ngDevMode ? [{ debugName: "restoreFocusInput", alias: 'restoreFocus' }] : [{ alias: 'restoreFocus' }]));
1332
+ roleInput = input(undefined, ...(ngDevMode ? [{ debugName: "roleInput", alias: 'role' }] : [{ alias: 'role' }]));
1333
+ autoFocus = withConfigDefault(this.autoFocusInput, computed(() => this.drawerDefaults()?.autoFocus), true);
1334
+ restoreFocus = withConfigDefault(this.restoreFocusInput, computed(() => this.drawerDefaults()?.restoreFocus), true);
1335
+ role = withConfigDefault(this.roleInput, computed(() => this.drawerDefaults()?.role), 'dialog');
1336
+ // Outputs
1337
+ visibleChange = output();
1338
+ opened = output();
1339
+ closed = output();
1340
+ backdropClick = output();
1341
+ // Internal state
1342
+ previousActiveElement;
1343
+ touchStartX = 0;
1344
+ touchStartY = 0;
1345
+ isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
1346
+ scrollbarWidth = 0;
1347
+ hostClasses = computed(() => classNames('studio-drawer', `studio-drawer--${this.position()}`, `studio-drawer--${this.size()}`, this.visible() && 'studio-drawer--visible', this.modal() && 'studio-drawer--modal', this.shadow() && `studio-drawer--shadow-${this.shadowSize()}`, this.isDragging() && 'studio-drawer--dragging', (this.position() === 'left' || this.position() === 'right') && `studio-drawer--radius-${this.radius()}`), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1348
+ constructor() {
1349
+ // Register with DrawerService
1350
+ effect(() => {
1351
+ this.drawerService.register(this.id(), this.visible);
1352
+ });
1353
+ // Handle visibility changes
1354
+ effect(() => {
1355
+ if (this.visible()) {
1356
+ this.handleOpen();
1357
+ }
1358
+ else {
1359
+ this.handleClose();
1360
+ }
1361
+ });
1362
+ // Cleanup on destroy
1363
+ this.destroyRef.onDestroy(() => {
1364
+ this.drawerService.unregister(this.id());
1365
+ this.unlockBodyScroll();
1366
+ });
1367
+ }
1368
+ handleOpen() {
1369
+ if (this.blockScroll() && this.modal()) {
1370
+ this.lockBodyScroll();
1371
+ }
1372
+ if (this.autoFocus()) {
1373
+ this.setupFocusTrap();
1374
+ }
1375
+ this.opened.emit();
1376
+ }
1377
+ handleClose() {
1378
+ if (this.blockScroll() && this.modal()) {
1379
+ this.unlockBodyScroll();
1380
+ }
1381
+ if (this.restoreFocus()) {
1382
+ this.restorePreviousFocus();
1383
+ }
1384
+ this.closed.emit();
1385
+ }
1386
+ open() {
1387
+ this.visible.set(true);
1388
+ this.visibleChange.emit(true);
1389
+ }
1390
+ close() {
1391
+ this.visible.set(false);
1392
+ this.visibleChange.emit(false);
1393
+ }
1394
+ toggle() {
1395
+ this.visible.update(v => !v);
1396
+ this.visibleChange.emit(this.visible());
1397
+ }
1398
+ handleBackdropClick() {
1399
+ this.backdropClick.emit();
1400
+ if (this.closeOnBackdropClick()) {
1401
+ this.close();
1402
+ }
1403
+ }
1404
+ handleEscapeKey(event) {
1405
+ if (this.visible() && this.closeOnEscape()) {
1406
+ event.preventDefault();
1407
+ this.close();
1408
+ }
1409
+ }
1410
+ // Touch gesture handling
1411
+ onTouchStart(event) {
1412
+ if (!this.swipeToClose() || !this.visible())
1413
+ return;
1414
+ const target = event.target;
1415
+ const panel = this.panelEl()?.nativeElement;
1416
+ // Only start drag if touching the panel
1417
+ if (!panel?.contains(target))
1418
+ return;
1419
+ this.touchStartX = event.touches[0].clientX;
1420
+ this.touchStartY = event.touches[0].clientY;
1421
+ this.isDragging.set(true);
1422
+ }
1423
+ onTouchMove(event) {
1424
+ if (!this.isDragging())
1425
+ return;
1426
+ const deltaX = event.touches[0].clientX - this.touchStartX;
1427
+ const deltaY = event.touches[0].clientY - this.touchStartY;
1428
+ const pos = this.position();
1429
+ // Apply drag transform based on position
1430
+ let shouldAllowDrag = false;
1431
+ if (pos === 'right' && deltaX > 0) {
1432
+ shouldAllowDrag = true;
1433
+ this.applyDragTransform(deltaX, 0);
1434
+ }
1435
+ else if (pos === 'left' && deltaX < 0) {
1436
+ shouldAllowDrag = true;
1437
+ this.applyDragTransform(deltaX, 0);
1438
+ }
1439
+ else if (pos === 'bottom' && deltaY > 0) {
1440
+ shouldAllowDrag = true;
1441
+ this.applyDragTransform(0, deltaY);
1442
+ }
1443
+ else if (pos === 'top' && deltaY < 0) {
1444
+ shouldAllowDrag = true;
1445
+ this.applyDragTransform(0, deltaY);
1446
+ }
1447
+ // Prevent scroll while dragging
1448
+ if (shouldAllowDrag && (Math.abs(deltaX) > 10 || Math.abs(deltaY) > 10)) {
1449
+ event.preventDefault();
1450
+ }
1451
+ }
1452
+ onTouchEnd(event) {
1453
+ if (!this.isDragging())
1454
+ return;
1455
+ const deltaX = event.changedTouches[0].clientX - this.touchStartX;
1456
+ const deltaY = event.changedTouches[0].clientY - this.touchStartY;
1457
+ const threshold = this.swipeThreshold();
1458
+ const pos = this.position();
1459
+ let shouldClose = false;
1460
+ if (pos === 'right' && deltaX > threshold)
1461
+ shouldClose = true;
1462
+ if (pos === 'left' && deltaX < -threshold)
1463
+ shouldClose = true;
1464
+ if (pos === 'bottom' && deltaY > threshold)
1465
+ shouldClose = true;
1466
+ if (pos === 'top' && deltaY < -threshold)
1467
+ shouldClose = true;
1468
+ if (shouldClose) {
1469
+ this.close();
1470
+ }
1471
+ else {
1472
+ this.resetTransform();
1473
+ }
1474
+ this.isDragging.set(false);
1475
+ }
1476
+ applyDragTransform(deltaX, deltaY) {
1477
+ const panel = this.panelEl()?.nativeElement;
1478
+ if (!panel)
1479
+ return;
1480
+ const pos = this.position();
1481
+ if (pos === 'right') {
1482
+ const translateX = Math.max(0, deltaX);
1483
+ panel.style.transform = `translateX(${translateX}px)`;
1484
+ panel.style.transition = 'none';
1485
+ }
1486
+ else if (pos === 'left') {
1487
+ const translateX = Math.min(0, deltaX);
1488
+ panel.style.transform = `translateX(${translateX}px)`;
1489
+ panel.style.transition = 'none';
1490
+ }
1491
+ else if (pos === 'bottom') {
1492
+ const translateY = Math.max(0, deltaY);
1493
+ panel.style.transform = `translateY(${translateY}px)`;
1494
+ panel.style.transition = 'none';
1495
+ }
1496
+ else if (pos === 'top') {
1497
+ const translateY = Math.min(0, deltaY);
1498
+ panel.style.transform = `translateY(${translateY}px)`;
1499
+ panel.style.transition = 'none';
1500
+ }
1501
+ }
1502
+ resetTransform() {
1503
+ const panel = this.panelEl()?.nativeElement;
1504
+ if (!panel)
1505
+ return;
1506
+ panel.style.transition = '';
1507
+ panel.style.transform = '';
1508
+ }
1509
+ // Body scroll lock
1510
+ lockBodyScroll() {
1511
+ this.scrollbarWidth = window.innerWidth - this.document.documentElement.clientWidth;
1512
+ this.document.body.style.overflow = 'hidden';
1513
+ this.document.body.style.paddingRight = `${this.scrollbarWidth}px`;
1514
+ }
1515
+ unlockBodyScroll() {
1516
+ this.document.body.style.overflow = '';
1517
+ this.document.body.style.paddingRight = '';
1518
+ }
1519
+ // Focus management
1520
+ setupFocusTrap() {
1521
+ this.previousActiveElement = this.document.activeElement;
1522
+ // Move focus to drawer after render
1523
+ setTimeout(() => {
1524
+ const panel = this.panelEl()?.nativeElement;
1525
+ if (!panel)
1526
+ return;
1527
+ const firstFocusable = this.getFirstFocusableElement(panel);
1528
+ if (firstFocusable) {
1529
+ firstFocusable.focus();
1530
+ }
1531
+ else {
1532
+ panel.focus();
1533
+ }
1534
+ }, 0);
1535
+ }
1536
+ restorePreviousFocus() {
1537
+ if (this.previousActiveElement) {
1538
+ this.previousActiveElement.focus();
1539
+ this.previousActiveElement = undefined;
1540
+ }
1541
+ }
1542
+ getFirstFocusableElement(container) {
1543
+ const focusableSelectors = [
1544
+ 'a[href]',
1545
+ 'button:not([disabled])',
1546
+ 'textarea:not([disabled])',
1547
+ 'input:not([disabled])',
1548
+ 'select:not([disabled])',
1549
+ '[tabindex]:not([tabindex="-1"])'
1550
+ ].join(', ');
1551
+ return container.querySelector(focusableSelectors);
1552
+ }
1553
+ handleKeydown(event) {
1554
+ if (!this.visible())
1555
+ return;
1556
+ if (event.key === 'Tab') {
1557
+ this.trapFocus(event);
1558
+ }
1559
+ }
1560
+ trapFocus(event) {
1561
+ const panel = this.panelEl()?.nativeElement;
1562
+ if (!panel)
1563
+ return;
1564
+ const focusableElements = panel.querySelectorAll([
1565
+ 'a[href]',
1566
+ 'button:not([disabled])',
1567
+ 'textarea:not([disabled])',
1568
+ 'input:not([disabled])',
1569
+ 'select:not([disabled])',
1570
+ '[tabindex]:not([tabindex="-1"])'
1571
+ ].join(', '));
1572
+ const firstElement = focusableElements[0];
1573
+ const lastElement = focusableElements[focusableElements.length - 1];
1574
+ if (event.shiftKey) {
1575
+ if (this.document.activeElement === firstElement) {
1576
+ event.preventDefault();
1577
+ lastElement?.focus();
1578
+ }
1579
+ }
1580
+ else {
1581
+ if (this.document.activeElement === lastElement) {
1582
+ event.preventDefault();
1583
+ firstElement?.focus();
1584
+ }
1585
+ }
1586
+ }
1587
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: DrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1588
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: DrawerComponent, isStandalone: true, selector: "studio-drawer", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, positionInput: { classPropertyName: "positionInput", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, sizeInput: { classPropertyName: "sizeInput", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, customWidth: { classPropertyName: "customWidth", publicName: "customWidth", isSignal: true, isRequired: false, transformFunction: null }, customHeight: { classPropertyName: "customHeight", publicName: "customHeight", isSignal: true, isRequired: false, transformFunction: null }, modalInput: { classPropertyName: "modalInput", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscapeInput: { classPropertyName: "closeOnEscapeInput", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropClickInput: { classPropertyName: "closeOnBackdropClickInput", publicName: "closeOnBackdropClick", isSignal: true, isRequired: false, transformFunction: null }, blockScrollInput: { classPropertyName: "blockScrollInput", publicName: "blockScroll", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, showHeaderInput: { classPropertyName: "showHeaderInput", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, showCloseButtonInput: { classPropertyName: "showCloseButtonInput", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeButtonPositionInput: { classPropertyName: "closeButtonPositionInput", publicName: "closeButtonPosition", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, swipeToCloseInput: { classPropertyName: "swipeToCloseInput", publicName: "swipeToClose", isSignal: true, isRequired: false, transformFunction: null }, swipeThresholdInput: { classPropertyName: "swipeThresholdInput", publicName: "swipeThreshold", isSignal: true, isRequired: false, transformFunction: null }, animationDurationInput: { classPropertyName: "animationDurationInput", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null }, animationEasingInput: { classPropertyName: "animationEasingInput", publicName: "animationEasing", isSignal: true, isRequired: false, transformFunction: null }, disableAnimationInput: { classPropertyName: "disableAnimationInput", publicName: "disableAnimation", isSignal: true, isRequired: false, transformFunction: null }, radiusInput: { classPropertyName: "radiusInput", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, shadowInput: { classPropertyName: "shadowInput", publicName: "shadow", isSignal: true, isRequired: false, transformFunction: null }, shadowSizeInput: { classPropertyName: "shadowSizeInput", publicName: "shadowSize", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, autoFocusInput: { classPropertyName: "autoFocusInput", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, restoreFocusInput: { classPropertyName: "restoreFocusInput", publicName: "restoreFocus", isSignal: true, isRequired: false, transformFunction: null }, roleInput: { classPropertyName: "roleInput", publicName: "role", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange", visibleChange: "visibleChange", opened: "opened", closed: "closed", backdropClick: "backdropClick" }, host: { listeners: { "document:keydown.escape": "handleEscapeKey($event)", "touchstart": "onTouchStart($event)", "touchmove": "onTouchMove($event)", "touchend": "onTouchEnd($event)", "keydown": "handleKeydown($event)" }, properties: { "class": "hostClasses()", "attr.data-visible": "visible()" } }, queries: [{ propertyName: "headerTemplate", first: true, predicate: ["headerTemplate"], descendants: true, isSignal: true }, { propertyName: "footerTemplate", first: true, predicate: ["footerTemplate"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "panelEl", first: true, predicate: ["drawerPanel"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (visible()) {\n <!-- Backdrop -->\n @if (modal()) {\n <div\n class=\"studio-drawer__backdrop\"\n (click)=\"handleBackdropClick()\">\n </div>\n }\n\n <!-- Drawer Panel -->\n <div\n #drawerPanel\n class=\"studio-drawer__panel\"\n [attr.role]=\"role()\"\n [attr.aria-modal]=\"modal()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n [attr.tabindex]=\"-1\"\n [style.width]=\"customWidth()\"\n [style.height]=\"customHeight()\"\n [style.--drawer-animation-duration]=\"animationDuration() + 'ms'\"\n [style.--drawer-animation-timing]=\"animationEasing()\">\n\n <!-- Header -->\n @if (showHeader() && (headerTemplate() || header() || showCloseButton())) {\n <div class=\"studio-drawer__header\">\n @if (headerTemplate(); as tmpl) {\n <!-- Custom template -->\n <ng-container *ngTemplateOutlet=\"tmpl\" />\n } @else if (header()) {\n <!-- Simple string header -->\n <div class=\"studio-drawer__header-content\">\n @if (showCloseButton() && closeButtonPosition() === 'left') {\n <button\n type=\"button\"\n class=\"studio-drawer__close\"\n (click)=\"close()\"\n aria-label=\"Close drawer\">\n <studio-icon name=\"x\" [size]=\"20\" />\n </button>\n }\n\n <h2 class=\"studio-drawer__title\">{{ header() }}</h2>\n\n @if (showCloseButton() && closeButtonPosition() === 'right') {\n <button\n type=\"button\"\n class=\"studio-drawer__close\"\n (click)=\"close()\"\n aria-label=\"Close drawer\">\n <studio-icon name=\"x\" [size]=\"20\" />\n </button>\n }\n </div>\n } @else {\n <!-- Named slot fallback -->\n <div class=\"studio-drawer__header-content\">\n @if (showCloseButton() && closeButtonPosition() === 'left') {\n <button\n type=\"button\"\n class=\"studio-drawer__close\"\n (click)=\"close()\"\n aria-label=\"Close drawer\">\n <studio-icon name=\"x\" [size]=\"20\" />\n </button>\n }\n\n <ng-content select=\"[drawerHeader]\" />\n\n @if (showCloseButton() && closeButtonPosition() === 'right') {\n <button\n type=\"button\"\n class=\"studio-drawer__close\"\n (click)=\"close()\"\n aria-label=\"Close drawer\">\n <studio-icon name=\"x\" [size]=\"20\" />\n </button>\n }\n </div>\n }\n </div>\n }\n\n <!-- Content -->\n <div class=\"studio-drawer__content\">\n <ng-content />\n </div>\n\n <!-- Footer -->\n @if (showFooter() && footerTemplate()) {\n <div class=\"studio-drawer__footer\">\n <ng-container *ngTemplateOutlet=\"footerTemplate()!\" />\n </div>\n } @else if (showFooter()) {\n <div class=\"studio-drawer__footer\">\n <ng-content select=\"[drawerFooter]\" />\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;pointer-events:none;font-family:var(--studio-font-family)}:host(.studio-drawer--visible){pointer-events:auto}.studio-drawer__backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:var(--studio-drawer-backdrop-bg, rgba(0, 0, 0, .5));-webkit-backdrop-filter:blur(var(--studio-drawer-backdrop-blur, 2px));backdrop-filter:blur(var(--studio-drawer-backdrop-blur, 2px));z-index:var(--studio-drawer-z-index, 1000);opacity:0;transition:opacity var(--drawer-animation-duration, .3s) var(--drawer-animation-timing, ease-out)}:host(.studio-drawer--visible) .studio-drawer__backdrop{opacity:1}.studio-drawer__panel{position:fixed;background:var(--studio-drawer-bg, var(--studio-bg-primary));color:var(--studio-drawer-text-color, var(--studio-text-primary));z-index:calc(var(--studio-drawer-z-index, 1000) + 1);overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;outline:none;transition:transform var(--drawer-animation-duration, .3s) var(--drawer-animation-timing, ease-out)}.studio-drawer__panel::-webkit-scrollbar{width:var(--studio-drawer-scrollbar-width, 8px)}.studio-drawer__panel::-webkit-scrollbar-track{background:var(--studio-drawer-scrollbar-track-bg, transparent)}.studio-drawer__panel::-webkit-scrollbar-thumb{background:var(--studio-drawer-scrollbar-thumb-bg, rgba(0, 0, 0, .2));border-radius:var(--studio-drawer-scrollbar-thumb-radius, 4px)}.studio-drawer__panel::-webkit-scrollbar-thumb:hover{background:var(--studio-drawer-scrollbar-thumb-hover-bg, rgba(0, 0, 0, .3))}:host(.studio-drawer--left) .studio-drawer__panel{top:0;left:0;height:100%;border-right:var(--studio-drawer-border-width, 1px) solid var(--studio-drawer-border-color, var(--studio-border-primary));transform:translate(-100%)}:host(.studio-drawer--left.studio-drawer--visible) .studio-drawer__panel{transform:translate(0)}:host(.studio-drawer--right) .studio-drawer__panel{top:0;right:0;height:100%;border-left:var(--studio-drawer-border-width, 1px) solid var(--studio-drawer-border-color, var(--studio-border-primary));transform:translate(100%)}:host(.studio-drawer--right.studio-drawer--visible) .studio-drawer__panel{transform:translate(0)}:host(.studio-drawer--top) .studio-drawer__panel{top:0;left:0;width:100%;border-bottom:var(--studio-drawer-border-width, 1px) solid var(--studio-drawer-border-color, var(--studio-border-primary));transform:translateY(-100%)}:host(.studio-drawer--top.studio-drawer--visible) .studio-drawer__panel{transform:translateY(0)}:host(.studio-drawer--bottom) .studio-drawer__panel{bottom:0;left:0;width:100%;border-top:var(--studio-drawer-border-width, 1px) solid var(--studio-drawer-border-color, var(--studio-border-primary));transform:translateY(100%)}:host(.studio-drawer--bottom.studio-drawer--visible) .studio-drawer__panel{transform:translateY(0)}:host(.studio-drawer--left.studio-drawer--sm) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--sm) .studio-drawer__panel{width:var(--studio-drawer-width-sm, 20rem);max-width:var(--studio-drawer-max-width, 90vw)}:host(.studio-drawer--left.studio-drawer--md) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--md) .studio-drawer__panel{width:var(--studio-drawer-width-md, 28rem);max-width:var(--studio-drawer-max-width, 90vw)}:host(.studio-drawer--left.studio-drawer--lg) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--lg) .studio-drawer__panel{width:var(--studio-drawer-width-lg, 36rem);max-width:var(--studio-drawer-max-width, 90vw)}:host(.studio-drawer--left.studio-drawer--xl) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--xl) .studio-drawer__panel{width:var(--studio-drawer-width-xl, 48rem);max-width:var(--studio-drawer-max-width, 90vw)}:host(.studio-drawer--left.studio-drawer--full) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--full) .studio-drawer__panel{width:100vw;max-width:none}:host(.studio-drawer--top.studio-drawer--sm) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--sm) .studio-drawer__panel{height:var(--studio-drawer-height-sm, 12rem);max-height:var(--studio-drawer-max-height, 90vh)}:host(.studio-drawer--top.studio-drawer--md) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--md) .studio-drawer__panel{height:var(--studio-drawer-height-md, 20rem);max-height:var(--studio-drawer-max-height, 90vh)}:host(.studio-drawer--top.studio-drawer--lg) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--lg) .studio-drawer__panel{height:var(--studio-drawer-height-lg, 32rem);max-height:var(--studio-drawer-max-height, 90vh)}:host(.studio-drawer--top.studio-drawer--xl) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--xl) .studio-drawer__panel{height:var(--studio-drawer-height-xl, 48rem);max-height:var(--studio-drawer-max-height, 90vh)}:host(.studio-drawer--top.studio-drawer--full) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--full) .studio-drawer__panel{height:100vh;max-height:none}:host(.studio-drawer--left.studio-drawer--radius-sm) .studio-drawer__panel{border-radius:0 var(--studio-radius-sm) var(--studio-radius-sm) 0}:host(.studio-drawer--left.studio-drawer--radius-md) .studio-drawer__panel{border-radius:0 var(--studio-radius-md) var(--studio-radius-md) 0}:host(.studio-drawer--left.studio-drawer--radius-lg) .studio-drawer__panel{border-radius:0 var(--studio-radius-lg) var(--studio-radius-lg) 0}:host(.studio-drawer--right.studio-drawer--radius-sm) .studio-drawer__panel{border-radius:var(--studio-radius-sm) 0 0 var(--studio-radius-sm)}:host(.studio-drawer--right.studio-drawer--radius-md) .studio-drawer__panel{border-radius:var(--studio-radius-md) 0 0 var(--studio-radius-md)}:host(.studio-drawer--right.studio-drawer--radius-lg) .studio-drawer__panel{border-radius:var(--studio-radius-lg) 0 0 var(--studio-radius-lg)}:host(.studio-drawer--shadow-sm) .studio-drawer__panel{box-shadow:var(--studio-drawer-shadow-sm, var(--studio-shadow-sm))}:host(.studio-drawer--shadow-md) .studio-drawer__panel{box-shadow:var(--studio-drawer-shadow-md, var(--studio-shadow-md))}:host(.studio-drawer--shadow-lg) .studio-drawer__panel{box-shadow:var(--studio-drawer-shadow-lg, var(--studio-shadow-lg))}:host(.studio-drawer--shadow-xl) .studio-drawer__panel{box-shadow:var(--studio-drawer-shadow-xl, 0 12px 32px rgba(0, 0, 0, .2))}.studio-drawer__header{flex-shrink:0;padding:var(--studio-drawer-header-padding-y, var(--studio-spacing-md)) var(--studio-drawer-header-padding-x, var(--studio-spacing-lg));border-bottom:1px solid var(--studio-drawer-divider-color, var(--studio-border-primary))}.studio-drawer__header-content{display:flex;align-items:center;gap:var(--studio-drawer-header-gap, var(--studio-spacing-md))}.studio-drawer__title{flex:1;margin:0;font-size:var(--studio-drawer-title-font-size, 1.25rem);font-weight:var(--studio-drawer-title-font-weight, var(--studio-font-weight-semibold, 600));line-height:var(--studio-drawer-title-line-height, 1.5);color:var(--studio-drawer-title-color, var(--studio-text-primary))}.studio-drawer__close{display:flex;align-items:center;justify-content:center;width:var(--studio-drawer-close-button-size, 2.5rem);height:var(--studio-drawer-close-button-size, 2.5rem);padding:0;background:none;border:none;border-radius:var(--studio-drawer-close-button-radius, var(--studio-radius-md));color:var(--studio-drawer-close-button-color, var(--studio-text-secondary));cursor:pointer;transition:all var(--studio-transition-fast);flex-shrink:0}.studio-drawer__close:hover{background:var(--studio-drawer-close-button-hover-bg, var(--studio-bg-secondary));color:var(--studio-drawer-close-button-hover-color, var(--studio-text-primary))}.studio-drawer__close:active{transform:scale(.95)}.studio-drawer__close:focus-visible{outline:2px solid var(--studio-drawer-focus-ring-color, var(--studio-primary));outline-offset:var(--studio-drawer-focus-ring-offset, 2px)}.studio-drawer__content{flex:1;padding:var(--studio-drawer-content-padding-y, var(--studio-spacing-lg)) var(--studio-drawer-content-padding-x, var(--studio-spacing-lg));overflow-y:auto;overflow-x:hidden}.studio-drawer__footer{flex-shrink:0;padding:var(--studio-drawer-footer-padding-y, var(--studio-spacing-md)) var(--studio-drawer-footer-padding-x, var(--studio-spacing-lg));border-top:1px solid var(--studio-drawer-divider-color, var(--studio-border-primary));display:flex;align-items:center;gap:var(--studio-drawer-footer-gap, var(--studio-spacing-sm))}:host(.studio-drawer--dragging) .studio-drawer__panel{transition:none!important}@media (max-width: 640px){:host(.studio-drawer--left.studio-drawer--md) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--md) .studio-drawer__panel,:host(.studio-drawer--left.studio-drawer--lg) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--lg) .studio-drawer__panel,:host(.studio-drawer--left.studio-drawer--xl) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--xl) .studio-drawer__panel{width:100vw;max-width:none}.studio-drawer__header,.studio-drawer__content,.studio-drawer__footer{padding-left:var(--studio-spacing-md);padding-right:var(--studio-spacing-md)}}\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 });
1589
+ }
1590
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: DrawerComponent, decorators: [{
1591
+ type: Component,
1592
+ args: [{ selector: 'studio-drawer', standalone: true, imports: [NgTemplateOutlet, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1593
+ '[class]': 'hostClasses()',
1594
+ '[attr.data-visible]': 'visible()',
1595
+ }, template: "@if (visible()) {\n <!-- Backdrop -->\n @if (modal()) {\n <div\n class=\"studio-drawer__backdrop\"\n (click)=\"handleBackdropClick()\">\n </div>\n }\n\n <!-- Drawer Panel -->\n <div\n #drawerPanel\n class=\"studio-drawer__panel\"\n [attr.role]=\"role()\"\n [attr.aria-modal]=\"modal()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n [attr.tabindex]=\"-1\"\n [style.width]=\"customWidth()\"\n [style.height]=\"customHeight()\"\n [style.--drawer-animation-duration]=\"animationDuration() + 'ms'\"\n [style.--drawer-animation-timing]=\"animationEasing()\">\n\n <!-- Header -->\n @if (showHeader() && (headerTemplate() || header() || showCloseButton())) {\n <div class=\"studio-drawer__header\">\n @if (headerTemplate(); as tmpl) {\n <!-- Custom template -->\n <ng-container *ngTemplateOutlet=\"tmpl\" />\n } @else if (header()) {\n <!-- Simple string header -->\n <div class=\"studio-drawer__header-content\">\n @if (showCloseButton() && closeButtonPosition() === 'left') {\n <button\n type=\"button\"\n class=\"studio-drawer__close\"\n (click)=\"close()\"\n aria-label=\"Close drawer\">\n <studio-icon name=\"x\" [size]=\"20\" />\n </button>\n }\n\n <h2 class=\"studio-drawer__title\">{{ header() }}</h2>\n\n @if (showCloseButton() && closeButtonPosition() === 'right') {\n <button\n type=\"button\"\n class=\"studio-drawer__close\"\n (click)=\"close()\"\n aria-label=\"Close drawer\">\n <studio-icon name=\"x\" [size]=\"20\" />\n </button>\n }\n </div>\n } @else {\n <!-- Named slot fallback -->\n <div class=\"studio-drawer__header-content\">\n @if (showCloseButton() && closeButtonPosition() === 'left') {\n <button\n type=\"button\"\n class=\"studio-drawer__close\"\n (click)=\"close()\"\n aria-label=\"Close drawer\">\n <studio-icon name=\"x\" [size]=\"20\" />\n </button>\n }\n\n <ng-content select=\"[drawerHeader]\" />\n\n @if (showCloseButton() && closeButtonPosition() === 'right') {\n <button\n type=\"button\"\n class=\"studio-drawer__close\"\n (click)=\"close()\"\n aria-label=\"Close drawer\">\n <studio-icon name=\"x\" [size]=\"20\" />\n </button>\n }\n </div>\n }\n </div>\n }\n\n <!-- Content -->\n <div class=\"studio-drawer__content\">\n <ng-content />\n </div>\n\n <!-- Footer -->\n @if (showFooter() && footerTemplate()) {\n <div class=\"studio-drawer__footer\">\n <ng-container *ngTemplateOutlet=\"footerTemplate()!\" />\n </div>\n } @else if (showFooter()) {\n <div class=\"studio-drawer__footer\">\n <ng-content select=\"[drawerFooter]\" />\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;pointer-events:none;font-family:var(--studio-font-family)}:host(.studio-drawer--visible){pointer-events:auto}.studio-drawer__backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:var(--studio-drawer-backdrop-bg, rgba(0, 0, 0, .5));-webkit-backdrop-filter:blur(var(--studio-drawer-backdrop-blur, 2px));backdrop-filter:blur(var(--studio-drawer-backdrop-blur, 2px));z-index:var(--studio-drawer-z-index, 1000);opacity:0;transition:opacity var(--drawer-animation-duration, .3s) var(--drawer-animation-timing, ease-out)}:host(.studio-drawer--visible) .studio-drawer__backdrop{opacity:1}.studio-drawer__panel{position:fixed;background:var(--studio-drawer-bg, var(--studio-bg-primary));color:var(--studio-drawer-text-color, var(--studio-text-primary));z-index:calc(var(--studio-drawer-z-index, 1000) + 1);overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;outline:none;transition:transform var(--drawer-animation-duration, .3s) var(--drawer-animation-timing, ease-out)}.studio-drawer__panel::-webkit-scrollbar{width:var(--studio-drawer-scrollbar-width, 8px)}.studio-drawer__panel::-webkit-scrollbar-track{background:var(--studio-drawer-scrollbar-track-bg, transparent)}.studio-drawer__panel::-webkit-scrollbar-thumb{background:var(--studio-drawer-scrollbar-thumb-bg, rgba(0, 0, 0, .2));border-radius:var(--studio-drawer-scrollbar-thumb-radius, 4px)}.studio-drawer__panel::-webkit-scrollbar-thumb:hover{background:var(--studio-drawer-scrollbar-thumb-hover-bg, rgba(0, 0, 0, .3))}:host(.studio-drawer--left) .studio-drawer__panel{top:0;left:0;height:100%;border-right:var(--studio-drawer-border-width, 1px) solid var(--studio-drawer-border-color, var(--studio-border-primary));transform:translate(-100%)}:host(.studio-drawer--left.studio-drawer--visible) .studio-drawer__panel{transform:translate(0)}:host(.studio-drawer--right) .studio-drawer__panel{top:0;right:0;height:100%;border-left:var(--studio-drawer-border-width, 1px) solid var(--studio-drawer-border-color, var(--studio-border-primary));transform:translate(100%)}:host(.studio-drawer--right.studio-drawer--visible) .studio-drawer__panel{transform:translate(0)}:host(.studio-drawer--top) .studio-drawer__panel{top:0;left:0;width:100%;border-bottom:var(--studio-drawer-border-width, 1px) solid var(--studio-drawer-border-color, var(--studio-border-primary));transform:translateY(-100%)}:host(.studio-drawer--top.studio-drawer--visible) .studio-drawer__panel{transform:translateY(0)}:host(.studio-drawer--bottom) .studio-drawer__panel{bottom:0;left:0;width:100%;border-top:var(--studio-drawer-border-width, 1px) solid var(--studio-drawer-border-color, var(--studio-border-primary));transform:translateY(100%)}:host(.studio-drawer--bottom.studio-drawer--visible) .studio-drawer__panel{transform:translateY(0)}:host(.studio-drawer--left.studio-drawer--sm) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--sm) .studio-drawer__panel{width:var(--studio-drawer-width-sm, 20rem);max-width:var(--studio-drawer-max-width, 90vw)}:host(.studio-drawer--left.studio-drawer--md) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--md) .studio-drawer__panel{width:var(--studio-drawer-width-md, 28rem);max-width:var(--studio-drawer-max-width, 90vw)}:host(.studio-drawer--left.studio-drawer--lg) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--lg) .studio-drawer__panel{width:var(--studio-drawer-width-lg, 36rem);max-width:var(--studio-drawer-max-width, 90vw)}:host(.studio-drawer--left.studio-drawer--xl) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--xl) .studio-drawer__panel{width:var(--studio-drawer-width-xl, 48rem);max-width:var(--studio-drawer-max-width, 90vw)}:host(.studio-drawer--left.studio-drawer--full) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--full) .studio-drawer__panel{width:100vw;max-width:none}:host(.studio-drawer--top.studio-drawer--sm) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--sm) .studio-drawer__panel{height:var(--studio-drawer-height-sm, 12rem);max-height:var(--studio-drawer-max-height, 90vh)}:host(.studio-drawer--top.studio-drawer--md) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--md) .studio-drawer__panel{height:var(--studio-drawer-height-md, 20rem);max-height:var(--studio-drawer-max-height, 90vh)}:host(.studio-drawer--top.studio-drawer--lg) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--lg) .studio-drawer__panel{height:var(--studio-drawer-height-lg, 32rem);max-height:var(--studio-drawer-max-height, 90vh)}:host(.studio-drawer--top.studio-drawer--xl) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--xl) .studio-drawer__panel{height:var(--studio-drawer-height-xl, 48rem);max-height:var(--studio-drawer-max-height, 90vh)}:host(.studio-drawer--top.studio-drawer--full) .studio-drawer__panel,:host(.studio-drawer--bottom.studio-drawer--full) .studio-drawer__panel{height:100vh;max-height:none}:host(.studio-drawer--left.studio-drawer--radius-sm) .studio-drawer__panel{border-radius:0 var(--studio-radius-sm) var(--studio-radius-sm) 0}:host(.studio-drawer--left.studio-drawer--radius-md) .studio-drawer__panel{border-radius:0 var(--studio-radius-md) var(--studio-radius-md) 0}:host(.studio-drawer--left.studio-drawer--radius-lg) .studio-drawer__panel{border-radius:0 var(--studio-radius-lg) var(--studio-radius-lg) 0}:host(.studio-drawer--right.studio-drawer--radius-sm) .studio-drawer__panel{border-radius:var(--studio-radius-sm) 0 0 var(--studio-radius-sm)}:host(.studio-drawer--right.studio-drawer--radius-md) .studio-drawer__panel{border-radius:var(--studio-radius-md) 0 0 var(--studio-radius-md)}:host(.studio-drawer--right.studio-drawer--radius-lg) .studio-drawer__panel{border-radius:var(--studio-radius-lg) 0 0 var(--studio-radius-lg)}:host(.studio-drawer--shadow-sm) .studio-drawer__panel{box-shadow:var(--studio-drawer-shadow-sm, var(--studio-shadow-sm))}:host(.studio-drawer--shadow-md) .studio-drawer__panel{box-shadow:var(--studio-drawer-shadow-md, var(--studio-shadow-md))}:host(.studio-drawer--shadow-lg) .studio-drawer__panel{box-shadow:var(--studio-drawer-shadow-lg, var(--studio-shadow-lg))}:host(.studio-drawer--shadow-xl) .studio-drawer__panel{box-shadow:var(--studio-drawer-shadow-xl, 0 12px 32px rgba(0, 0, 0, .2))}.studio-drawer__header{flex-shrink:0;padding:var(--studio-drawer-header-padding-y, var(--studio-spacing-md)) var(--studio-drawer-header-padding-x, var(--studio-spacing-lg));border-bottom:1px solid var(--studio-drawer-divider-color, var(--studio-border-primary))}.studio-drawer__header-content{display:flex;align-items:center;gap:var(--studio-drawer-header-gap, var(--studio-spacing-md))}.studio-drawer__title{flex:1;margin:0;font-size:var(--studio-drawer-title-font-size, 1.25rem);font-weight:var(--studio-drawer-title-font-weight, var(--studio-font-weight-semibold, 600));line-height:var(--studio-drawer-title-line-height, 1.5);color:var(--studio-drawer-title-color, var(--studio-text-primary))}.studio-drawer__close{display:flex;align-items:center;justify-content:center;width:var(--studio-drawer-close-button-size, 2.5rem);height:var(--studio-drawer-close-button-size, 2.5rem);padding:0;background:none;border:none;border-radius:var(--studio-drawer-close-button-radius, var(--studio-radius-md));color:var(--studio-drawer-close-button-color, var(--studio-text-secondary));cursor:pointer;transition:all var(--studio-transition-fast);flex-shrink:0}.studio-drawer__close:hover{background:var(--studio-drawer-close-button-hover-bg, var(--studio-bg-secondary));color:var(--studio-drawer-close-button-hover-color, var(--studio-text-primary))}.studio-drawer__close:active{transform:scale(.95)}.studio-drawer__close:focus-visible{outline:2px solid var(--studio-drawer-focus-ring-color, var(--studio-primary));outline-offset:var(--studio-drawer-focus-ring-offset, 2px)}.studio-drawer__content{flex:1;padding:var(--studio-drawer-content-padding-y, var(--studio-spacing-lg)) var(--studio-drawer-content-padding-x, var(--studio-spacing-lg));overflow-y:auto;overflow-x:hidden}.studio-drawer__footer{flex-shrink:0;padding:var(--studio-drawer-footer-padding-y, var(--studio-spacing-md)) var(--studio-drawer-footer-padding-x, var(--studio-spacing-lg));border-top:1px solid var(--studio-drawer-divider-color, var(--studio-border-primary));display:flex;align-items:center;gap:var(--studio-drawer-footer-gap, var(--studio-spacing-sm))}:host(.studio-drawer--dragging) .studio-drawer__panel{transition:none!important}@media (max-width: 640px){:host(.studio-drawer--left.studio-drawer--md) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--md) .studio-drawer__panel,:host(.studio-drawer--left.studio-drawer--lg) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--lg) .studio-drawer__panel,:host(.studio-drawer--left.studio-drawer--xl) .studio-drawer__panel,:host(.studio-drawer--right.studio-drawer--xl) .studio-drawer__panel{width:100vw;max-width:none}.studio-drawer__header,.studio-drawer__content,.studio-drawer__footer{padding-left:var(--studio-spacing-md);padding-right:var(--studio-spacing-md)}}\n"] }]
1596
+ }], ctorParameters: () => [], propDecorators: { headerTemplate: [{ type: i0.ContentChild, args: ['headerTemplate', { isSignal: true }] }], footerTemplate: [{ type: i0.ContentChild, args: ['footerTemplate', { isSignal: true }] }], panelEl: [{ type: i0.ViewChild, args: ['drawerPanel', { 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"] }], positionInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], customWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "customWidth", required: false }] }], customHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "customHeight", required: false }] }], modalInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], closeOnEscapeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], closeOnBackdropClickInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdropClick", required: false }] }], blockScrollInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "blockScroll", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], showHeaderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], showCloseButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], closeButtonPositionInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeButtonPosition", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], swipeToCloseInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "swipeToClose", required: false }] }], swipeThresholdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "swipeThreshold", required: false }] }], animationDurationInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }], animationEasingInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationEasing", required: false }] }], disableAnimationInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableAnimation", required: false }] }], radiusInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], shadowInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "shadow", required: false }] }], shadowSizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "shadowSize", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledBy", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], autoFocusInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], restoreFocusInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "restoreFocus", required: false }] }], roleInput: [{ 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"] }], backdropClick: [{ type: i0.Output, args: ["backdropClick"] }], handleEscapeKey: [{
1597
+ type: HostListener,
1598
+ args: ['document:keydown.escape', ['$event']]
1599
+ }], onTouchStart: [{
1600
+ type: HostListener,
1601
+ args: ['touchstart', ['$event']]
1602
+ }], onTouchMove: [{
1603
+ type: HostListener,
1604
+ args: ['touchmove', ['$event']]
1605
+ }], onTouchEnd: [{
1606
+ type: HostListener,
1607
+ args: ['touchend', ['$event']]
1608
+ }], handleKeydown: [{
1609
+ type: HostListener,
1610
+ args: ['keydown', ['$event']]
1611
+ }] } });
1612
+
1180
1613
  /**
1181
1614
  * Input component with form control support, variants, and accessibility
1182
1615
  *
@@ -1332,6 +1765,281 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
1332
1765
  }, template: "@if (label() && !floatingLabel()) {\n <label [for]=\"id() || generatedId\" class=\"studio-input__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-input__required\">*</span>\n }\n </label>\n}\n\n<div class=\"studio-input__container\">\n @if (prefixIcon()) {\n <span class=\"studio-input__prefix\">\n <studio-icon [name]=\"prefixIcon()!\" [size]=\"16\" />\n </span>\n }\n\n @if (label() && floatingLabel()) {\n <label [for]=\"id() || generatedId\" class=\"studio-input__label--floating\">\n {{ label() }}\n @if (required()) {\n <span>*</span>\n }\n </label>\n }\n\n <input\n #inputElement\n class=\"studio-input__field\"\n [type]=\"computedType()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"computedPlaceholder()\"\n [required]=\"required()\"\n [attr.maxlength]=\"maxLength()\"\n [attr.minlength]=\"minLength()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [step]=\"step()\"\n [pattern]=\"pattern()\"\n [attr.inputmode]=\"inputmode()\"\n [attr.autocomplete]=\"autocomplete()\"\n [name]=\"name()\"\n [id]=\"id() || generatedId\"\n [attr.aria-label]=\"ariaLabel() || (!label() ? placeholder() : null)\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"ariaDescribedByValue()\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleFocus($event)\"\n (blur)=\"handleBlur($event)\"\n (keydown.enter)=\"handleEnter($event)\"\n />\n\n @if (loading()) {\n <span class=\"studio-input__loading\">\n <studio-icon name=\"loader-2\" [size]=\"16\" class=\"studio-icon--spin\" />\n </span>\n }\n\n @if (clearable() && value() && !disabled() && !loading()) {\n <button\n type=\"button\"\n class=\"studio-input__clear\"\n (click)=\"handleClear()\"\n [attr.aria-label]=\"'Clear input'\"\n tabindex=\"-1\"\n >\n <studio-icon name=\"x\" [size]=\"14\" />\n </button>\n }\n\n @if (type() === 'password' && showPasswordToggle() && !loading()) {\n <button\n type=\"button\"\n class=\"studio-input__toggle-password\"\n (click)=\"togglePasswordVisibility()\"\n [attr.aria-label]=\"isPasswordVisible() ? 'Hide password' : 'Show password'\"\n tabindex=\"-1\"\n >\n <studio-icon [name]=\"isPasswordVisible() ? 'eye-off' : 'eye'\" [size]=\"16\" />\n </button>\n }\n\n @if (suffixIcon() && !loading() && !clearable() && !(type() === 'password' && showPasswordToggle())) {\n <span class=\"studio-input__suffix\">\n <studio-icon [name]=\"suffixIcon()!\" [size]=\"16\" />\n </span>\n }\n </div>\n\n@if (hint() && !error()) {\n <span class=\"studio-input__hint\" [id]=\"hintId\">\n {{ hint() }}\n </span>\n}\n\n@if (error() && errorMessage()) {\n <span class=\"studio-input__error\" [id]=\"errorId\" role=\"alert\">\n <studio-icon name=\"alert-circle\" [size]=\"14\" />\n {{ errorMessage() }}\n </span>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:.375rem;font-family:var(--studio-font-family)}:host(.studio-input--full-width){width:100%}.studio-input__label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);margin-bottom:.25rem}.studio-input__label .studio-input__required{color:var(--studio-error);margin-left:.125rem}.studio-input__container{position:relative;display:flex;align-items:center;transition:all var(--studio-transition-fast)}.studio-input__field{flex:1;width:100%;font-family:inherit;font-size:1rem;color:var(--studio-text-primary);background:transparent;border:none;outline:none;transition:all var(--studio-transition-fast)}.studio-input__field::placeholder{color:var(--studio-text-tertiary)}.studio-input__field:disabled{cursor:not-allowed;opacity:.6}.studio-input__field:read-only{cursor:default}.studio-input__prefix,.studio-input__suffix{display:flex;align-items:center;justify-content:center;color:var(--studio-text-secondary);flex-shrink:0}.studio-input__clear,.studio-input__toggle-password{display:flex;align-items:center;justify-content:center;background:none;border:none;padding:.25rem;color:var(--studio-text-secondary);cursor:pointer;border-radius:var(--studio-radius-sm);transition:all var(--studio-transition-fast);flex-shrink:0}.studio-input__clear:hover,.studio-input__toggle-password:hover{color:var(--studio-text-primary);background:var(--studio-bg-secondary)}.studio-input__clear:active,.studio-input__toggle-password:active{transform:scale(.95)}.studio-input__loading{display:flex;align-items:center;color:var(--studio-primary);flex-shrink:0}.studio-input__loading .studio-icon--spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-input__hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-input__error{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:var(--studio-error);line-height:1.4}:host(.studio-input--outline) .studio-input__container{border:1px solid var(--studio-border-primary);background:var(--studio-bg-primary);border-radius:var(--studio-radius-md)}:host(.studio-input--outline) .studio-input__container:hover:not(:has(.studio-input__field:disabled)){border-color:var(--studio-primary)}:host(.studio-input--outline.studio-input--focused) .studio-input__container{border-color:var(--studio-primary);box-shadow:0 0 0 3px var(--studio-primary-bg)}:host(.studio-input--outline.studio-input--error) .studio-input__container{border-color:var(--studio-error)}:host(.studio-input--outline.studio-input--error) .studio-input__container:hover{border-color:var(--studio-error)}:host(.studio-input--outline.studio-input--error.studio-input--focused) .studio-input__container{box-shadow:0 0 0 3px #ef44441a}:host(.studio-input--outline.studio-input--disabled) .studio-input__container{background:var(--studio-bg-secondary);border-color:var(--studio-border-secondary)}:host(.studio-input--filled) .studio-input__container{background:var(--studio-bg-secondary);border:none;border-bottom:2px solid var(--studio-border-primary);border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0}:host(.studio-input--filled) .studio-input__container:hover:not(:has(.studio-input__field:disabled)){background:var(--studio-bg-tertiary)}:host(.studio-input--filled.studio-input--focused) .studio-input__container{border-bottom-color:var(--studio-primary);background:var(--studio-bg-tertiary)}:host(.studio-input--filled.studio-input--error) .studio-input__container{border-bottom-color:var(--studio-error)}:host(.studio-input--filled.studio-input--disabled) .studio-input__container{background:var(--studio-bg-secondary);opacity:.6}:host(.studio-input--underline) .studio-input__container{background:transparent;border:none;border-bottom:1px solid var(--studio-border-primary);border-radius:0}:host(.studio-input--underline) .studio-input__container:hover:not(:has(.studio-input__field:disabled)){border-bottom-color:var(--studio-primary)}:host(.studio-input--underline.studio-input--focused) .studio-input__container{border-bottom:2px solid var(--studio-primary)}:host(.studio-input--underline.studio-input--error) .studio-input__container{border-bottom-color:var(--studio-error)}:host(.studio-input--underline.studio-input--disabled) .studio-input__container{border-bottom-style:dashed;opacity:.6}:host(.studio-input--sm) .studio-input__field{height:2rem;font-size:.875rem;padding:0 .75rem}:host(.studio-input--sm) .studio-input__prefix{padding-left:.75rem}:host(.studio-input--sm) .studio-input__suffix,:host(.studio-input--sm) .studio-input__clear,:host(.studio-input--sm) .studio-input__toggle-password,:host(.studio-input--sm) .studio-input__loading{padding-right:.5rem}:host(.studio-input--md) .studio-input__field{height:2.5rem;font-size:1rem;padding:0 1rem}:host(.studio-input--md) .studio-input__prefix{padding-left:1rem}:host(.studio-input--md) .studio-input__suffix,:host(.studio-input--md) .studio-input__clear,:host(.studio-input--md) .studio-input__toggle-password,:host(.studio-input--md) .studio-input__loading{padding-right:.75rem}:host(.studio-input--lg) .studio-input__field{height:3rem;font-size:1.125rem;padding:0 1.25rem}:host(.studio-input--lg) .studio-input__prefix{padding-left:1.25rem}:host(.studio-input--lg) .studio-input__suffix,:host(.studio-input--lg) .studio-input__clear,:host(.studio-input--lg) .studio-input__toggle-password,:host(.studio-input--lg) .studio-input__loading{padding-right:1rem}.studio-input__label--floating{position:absolute;top:50%;left:1rem;transform:translateY(-50%);font-size:1rem;color:var(--studio-text-tertiary);pointer-events:none;transition:all var(--studio-transition-fast);background:var(--studio-bg-primary);padding:0 .25rem}:host(.studio-input--filled) .studio-input__label--floating{background:transparent}:host(.studio-input--focused) .studio-input__label--floating,:host(.studio-input--has-value) .studio-input__label--floating{top:0;font-size:.75rem;color:var(--studio-primary)}:host(.studio-input--error) .studio-input__label--floating{color:var(--studio-error)}:host(.studio-input--radius-none) .studio-input__container{border-radius:0}:host(.studio-input--radius-sm) .studio-input__container{border-radius:var(--studio-radius-sm)}:host(.studio-input--radius-md) .studio-input__container{border-radius:var(--studio-radius-md)}:host(.studio-input--radius-lg) .studio-input__container{border-radius:var(--studio-radius-lg)}:host(.studio-input--radius-full) .studio-input__container{border-radius:9999px}:host(.studio-input--filled.studio-input--radius-none) .studio-input__container{border-radius:0}:host(.studio-input--filled.studio-input--radius-sm) .studio-input__container{border-radius:var(--studio-radius-sm) var(--studio-radius-sm) 0 0}:host(.studio-input--filled.studio-input--radius-md) .studio-input__container{border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0}:host(.studio-input--filled.studio-input--radius-lg) .studio-input__container{border-radius:var(--studio-radius-lg) var(--studio-radius-lg) 0 0}:host(.studio-input--filled.studio-input--radius-full) .studio-input__container{border-radius:9999px 9999px 0 0}\n"] }]
1333
1766
  }], ctorParameters: () => [], propDecorators: { inputEl: [{ type: i0.ViewChild, args: ['inputElement', { isSignal: true }] }], variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], radiusInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], inputmode: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputmode", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], pattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "pattern", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], prefixIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefixIcon", required: false }] }], suffixIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffixIcon", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], showPasswordToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPasswordToggle", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], focused: [{ type: i0.Output, args: ["focused"] }], blurred: [{ type: i0.Output, args: ["blurred"] }], cleared: [{ type: i0.Output, args: ["cleared"] }], entered: [{ type: i0.Output, args: ["entered"] }] } });
1334
1767
 
1768
+ class SelectComponent {
1769
+ configService = inject(StudioConfigService);
1770
+ selectDefaults = computed(() => this.configService.config().components?.select, ...(ngDevMode ? [{ debugName: "selectDefaults" }] : []));
1771
+ triggerEl = viewChild('triggerButton', ...(ngDevMode ? [{ debugName: "triggerEl" }] : []));
1772
+ dropdownEl = viewChild('dropdownPanel', ...(ngDevMode ? [{ debugName: "dropdownEl" }] : []));
1773
+ variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
1774
+ sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
1775
+ radiusInput = input(undefined, ...(ngDevMode ? [{ debugName: "radiusInput", alias: 'radius' }] : [{ alias: 'radius' }]));
1776
+ variant = withConfigDefault(this.variantInput, computed(() => this.selectDefaults()?.variant), 'outline');
1777
+ size = withConfigDefault(this.sizeInput, computed(() => this.selectDefaults()?.size), 'md');
1778
+ radius = withConfigDefault(this.radiusInput, computed(() => this.selectDefaults()?.radius), 'md');
1779
+ options = input.required(...(ngDevMode ? [{ debugName: "options" }] : []));
1780
+ placeholder = input('Select option...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
1781
+ multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
1782
+ searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
1783
+ clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : []));
1784
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1785
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1786
+ label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : []));
1787
+ floatingLabel = input(false, ...(ngDevMode ? [{ debugName: "floatingLabel" }] : []));
1788
+ hint = input(undefined, ...(ngDevMode ? [{ debugName: "hint" }] : []));
1789
+ error = input(false, ...(ngDevMode ? [{ debugName: "error" }] : []));
1790
+ errorMessage = input(undefined, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
1791
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
1792
+ prefixIcon = input(undefined, ...(ngDevMode ? [{ debugName: "prefixIcon" }] : []));
1793
+ suffixIcon = input('chevron-down', ...(ngDevMode ? [{ debugName: "suffixIcon" }] : []));
1794
+ fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
1795
+ maxHeight = input('300px', ...(ngDevMode ? [{ debugName: "maxHeight" }] : []));
1796
+ position = input('bottom', ...(ngDevMode ? [{ debugName: "position" }] : []));
1797
+ searchPlaceholder = input('Search...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : []));
1798
+ valueChange = output();
1799
+ searchChange = output();
1800
+ opened = output();
1801
+ closed = output();
1802
+ optionSelected = output();
1803
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
1804
+ searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
1805
+ selectedValue = signal(null, ...(ngDevMode ? [{ debugName: "selectedValue" }] : []));
1806
+ highlightedIndex = signal(0, ...(ngDevMode ? [{ debugName: "highlightedIndex" }] : []));
1807
+ isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : []));
1808
+ isTouched = signal(false, ...(ngDevMode ? [{ debugName: "isTouched" }] : []));
1809
+ generatedId = `studio-select-${Math.random().toString(36).substr(2, 9)}`;
1810
+ onChange = () => { };
1811
+ onTouched = () => { };
1812
+ constructor() {
1813
+ effect(() => {
1814
+ if (this.isOpen()) {
1815
+ this.setupClickOutside();
1816
+ }
1817
+ else {
1818
+ this.cleanupClickOutside();
1819
+ }
1820
+ });
1821
+ }
1822
+ flattenedOptions = computed(() => {
1823
+ const opts = this.options();
1824
+ if (!opts || opts.length === 0)
1825
+ return [];
1826
+ if (this.isOptionGroup(opts[0])) {
1827
+ return opts.flatMap(g => g.options);
1828
+ }
1829
+ return opts;
1830
+ }, ...(ngDevMode ? [{ debugName: "flattenedOptions" }] : []));
1831
+ filteredOptions = computed(() => {
1832
+ const query = this.searchQuery().toLowerCase().trim();
1833
+ const opts = this.flattenedOptions();
1834
+ if (!query)
1835
+ return opts;
1836
+ return opts.filter(opt => opt.label.toLowerCase().includes(query) ||
1837
+ opt.description?.toLowerCase().includes(query));
1838
+ }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : []));
1839
+ selectedOptions = computed(() => {
1840
+ const value = this.selectedValue();
1841
+ const opts = this.flattenedOptions();
1842
+ if (this.multiple()) {
1843
+ const values = value || [];
1844
+ return opts.filter(opt => values.includes(opt.value));
1845
+ }
1846
+ return opts.find(opt => this.compareValues(opt.value, value)) || null;
1847
+ }, ...(ngDevMode ? [{ debugName: "selectedOptions" }] : []));
1848
+ displayValue = computed(() => {
1849
+ const selected = this.selectedOptions();
1850
+ if (this.multiple() && Array.isArray(selected)) {
1851
+ return selected.map(opt => opt.label).join(', ');
1852
+ }
1853
+ if (selected && !Array.isArray(selected)) {
1854
+ return selected.label;
1855
+ }
1856
+ return '';
1857
+ }, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
1858
+ hasValue = computed(() => {
1859
+ const val = this.selectedValue();
1860
+ return this.multiple()
1861
+ ? Array.isArray(val) && val.length > 0
1862
+ : val !== null && val !== undefined;
1863
+ }, ...(ngDevMode ? [{ debugName: "hasValue" }] : []));
1864
+ hostClasses = computed(() => classNames('studio-select', `studio-select--${this.variant()}`, `studio-select--${this.size()}`, `studio-select--radius-${this.radius()}`, this.isOpen() && 'studio-select--open', this.disabled() && 'studio-select--disabled', this.loading() && 'studio-select--loading', this.error() && 'studio-select--error', this.isFocused() && 'studio-select--focused', this.hasValue() && 'studio-select--has-value', this.fullWidth() && 'studio-select--full-width'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1865
+ toggle() {
1866
+ if (!this.disabled() && !this.loading()) {
1867
+ this.isOpen.update(v => !v);
1868
+ if (this.isOpen()) {
1869
+ this.opened.emit();
1870
+ setTimeout(() => this.focusSearchInput(), 0);
1871
+ }
1872
+ else {
1873
+ this.closed.emit();
1874
+ this.searchQuery.set('');
1875
+ }
1876
+ }
1877
+ }
1878
+ close() {
1879
+ if (this.isOpen()) {
1880
+ this.isOpen.set(false);
1881
+ this.closed.emit();
1882
+ this.searchQuery.set('');
1883
+ this.isTouched.set(true);
1884
+ this.onTouched();
1885
+ }
1886
+ }
1887
+ selectOption(option) {
1888
+ if (option.disabled)
1889
+ return;
1890
+ if (this.multiple()) {
1891
+ const current = (this.selectedValue() || []);
1892
+ const isSelected = current.includes(option.value);
1893
+ if (isSelected) {
1894
+ this.selectedValue.set(current.filter(v => v !== option.value));
1895
+ }
1896
+ else {
1897
+ this.selectedValue.set([...current, option.value]);
1898
+ }
1899
+ }
1900
+ else {
1901
+ this.selectedValue.set(option.value);
1902
+ this.close();
1903
+ }
1904
+ this.onChange(this.selectedValue());
1905
+ this.valueChange.emit(this.selectedValue());
1906
+ this.optionSelected.emit(option);
1907
+ }
1908
+ clear(event) {
1909
+ event.stopPropagation();
1910
+ this.selectedValue.set(this.multiple() ? [] : null);
1911
+ this.onChange(this.selectedValue());
1912
+ this.valueChange.emit(this.selectedValue());
1913
+ }
1914
+ isSelected(option) {
1915
+ if (this.multiple()) {
1916
+ const values = this.selectedValue() || [];
1917
+ return values.includes(option.value);
1918
+ }
1919
+ return this.compareValues(option.value, this.selectedValue());
1920
+ }
1921
+ handleSearch(event) {
1922
+ const query = event.target.value;
1923
+ this.searchQuery.set(query);
1924
+ this.searchChange.emit(query);
1925
+ }
1926
+ handleKeydown(event) {
1927
+ switch (event.key) {
1928
+ case 'ArrowDown':
1929
+ event.preventDefault();
1930
+ if (!this.isOpen()) {
1931
+ this.toggle();
1932
+ }
1933
+ else {
1934
+ this.highlightNext();
1935
+ }
1936
+ break;
1937
+ case 'ArrowUp':
1938
+ event.preventDefault();
1939
+ if (this.isOpen()) {
1940
+ this.highlightPrevious();
1941
+ }
1942
+ break;
1943
+ case 'Enter':
1944
+ case ' ':
1945
+ event.preventDefault();
1946
+ if (this.isOpen()) {
1947
+ this.selectHighlighted();
1948
+ }
1949
+ else {
1950
+ this.toggle();
1951
+ }
1952
+ break;
1953
+ case 'Escape':
1954
+ if (this.isOpen()) {
1955
+ event.preventDefault();
1956
+ this.close();
1957
+ }
1958
+ break;
1959
+ }
1960
+ }
1961
+ highlightNext() {
1962
+ const opts = this.filteredOptions();
1963
+ const current = this.highlightedIndex();
1964
+ this.highlightedIndex.set(Math.min(current + 1, opts.length - 1));
1965
+ }
1966
+ highlightPrevious() {
1967
+ const current = this.highlightedIndex();
1968
+ this.highlightedIndex.set(Math.max(current - 1, 0));
1969
+ }
1970
+ selectHighlighted() {
1971
+ const opts = this.filteredOptions();
1972
+ const index = this.highlightedIndex();
1973
+ if (opts[index]) {
1974
+ this.selectOption(opts[index]);
1975
+ }
1976
+ }
1977
+ compareValues(a, b) {
1978
+ return a === b;
1979
+ }
1980
+ isOptionGroup(item) {
1981
+ return item && 'options' in item && Array.isArray(item.options);
1982
+ }
1983
+ focusSearchInput() {
1984
+ if (this.searchable()) {
1985
+ const searchInput = this.dropdownEl()?.nativeElement.querySelector('input');
1986
+ searchInput?.focus();
1987
+ }
1988
+ }
1989
+ clickOutsideListener;
1990
+ setupClickOutside() {
1991
+ this.clickOutsideListener = (event) => {
1992
+ const target = event.target;
1993
+ const trigger = this.triggerEl()?.nativeElement;
1994
+ const dropdown = this.dropdownEl()?.nativeElement;
1995
+ if (trigger && !trigger.contains(target) && dropdown && !dropdown.contains(target)) {
1996
+ this.close();
1997
+ }
1998
+ };
1999
+ setTimeout(() => {
2000
+ document.addEventListener('click', this.clickOutsideListener);
2001
+ }, 0);
2002
+ }
2003
+ cleanupClickOutside() {
2004
+ if (this.clickOutsideListener) {
2005
+ document.removeEventListener('click', this.clickOutsideListener);
2006
+ this.clickOutsideListener = undefined;
2007
+ }
2008
+ }
2009
+ writeValue(value) {
2010
+ this.selectedValue.set(value);
2011
+ }
2012
+ registerOnChange(fn) {
2013
+ this.onChange = fn;
2014
+ }
2015
+ registerOnTouched(fn) {
2016
+ this.onTouched = fn;
2017
+ }
2018
+ setDisabledState(isDisabled) {
2019
+ }
2020
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2021
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: SelectComponent, isStandalone: true, selector: "studio-select", inputs: { variantInput: { classPropertyName: "variantInput", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, sizeInput: { classPropertyName: "sizeInput", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, radiusInput: { classPropertyName: "radiusInput", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, floatingLabel: { classPropertyName: "floatingLabel", publicName: "floatingLabel", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, prefixIcon: { classPropertyName: "prefixIcon", publicName: "prefixIcon", isSignal: true, isRequired: false, transformFunction: null }, suffixIcon: { classPropertyName: "suffixIcon", publicName: "suffixIcon", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", searchChange: "searchChange", opened: "opened", closed: "closed", optionSelected: "optionSelected" }, host: { properties: { "class": "hostClasses()", "attr.data-open": "isOpen()" } }, providers: [
2022
+ {
2023
+ provide: NG_VALUE_ACCESSOR,
2024
+ useExisting: forwardRef(() => SelectComponent),
2025
+ multi: true
2026
+ }
2027
+ ], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerButton"], descendants: true, isSignal: true }, { propertyName: "dropdownEl", first: true, predicate: ["dropdownPanel"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (label() && !floatingLabel()) {\n <label [for]=\"generatedId\" class=\"studio-select__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-select__required\">*</span>\n }\n </label>\n}\n\n<div class=\"studio-select__control\">\n @if (prefixIcon()) {\n <span class=\"studio-select__prefix\">\n <studio-icon [name]=\"prefixIcon()!\" [size]=\"16\" />\n </span>\n }\n\n @if (label() && floatingLabel()) {\n <label [for]=\"generatedId\" class=\"studio-select__label--floating\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-select__required\">*</span>\n }\n </label>\n }\n\n <button\n #triggerButton\n type=\"button\"\n [id]=\"generatedId\"\n class=\"studio-select__trigger\"\n [disabled]=\"disabled() || loading()\"\n (click)=\"toggle()\"\n (keydown)=\"handleKeydown($event)\"\n (focus)=\"isFocused.set(true)\"\n (blur)=\"isFocused.set(false)\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n >\n @if (hasValue()) {\n <span class=\"studio-select__value\">{{ displayValue() }}</span>\n } @else {\n <span class=\"studio-select__placeholder\">{{ placeholder() }}</span>\n }\n </button>\n\n @if (clearable() && hasValue() && !disabled() && !loading()) {\n <button\n type=\"button\"\n class=\"studio-select__clear\"\n (click)=\"clear($event)\"\n aria-label=\"Clear selection\"\n tabindex=\"-1\"\n >\n <studio-icon name=\"x\" [size]=\"14\" />\n </button>\n }\n\n @if (loading()) {\n <span class=\"studio-select__loading\">\n <studio-icon name=\"loader-2\" [size]=\"16\" class=\"studio-icon--spin\" />\n </span>\n } @else {\n <span class=\"studio-select__suffix\">\n <studio-icon\n [name]=\"suffixIcon()\"\n [size]=\"16\"\n />\n </span>\n }\n</div>\n\n@if (isOpen()) {\n <div\n #dropdownPanel\n class=\"studio-select__dropdown\"\n [attr.data-position]=\"position()\"\n [style.max-height]=\"maxHeight()\"\n >\n @if (searchable()) {\n <div class=\"studio-select__search\">\n <input\n type=\"text\"\n [placeholder]=\"searchPlaceholder()\"\n [value]=\"searchQuery()\"\n (input)=\"handleSearch($event)\"\n />\n </div>\n }\n\n <div class=\"studio-select__options\" role=\"listbox\">\n @if (filteredOptions().length === 0) {\n <div class=\"studio-select__empty\">\n No options found\n </div>\n }\n\n @for (option of filteredOptions(); track option.value; let idx = $index) {\n <div\n class=\"studio-select__option\"\n [class.studio-select__option--selected]=\"isSelected(option)\"\n [class.studio-select__option--disabled]=\"option.disabled\"\n [class.studio-select__option--highlighted]=\"highlightedIndex() === idx\"\n (click)=\"selectOption(option)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(option)\"\n >\n @if (multiple()) {\n <input\n type=\"checkbox\"\n class=\"studio-select__checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n tabindex=\"-1\"\n />\n }\n\n @if (option.icon) {\n <studio-icon [name]=\"option.icon\" [size]=\"18\" class=\"studio-select__option-icon\" />\n }\n\n <div class=\"studio-select__option-content\">\n <div class=\"studio-select__option-label\">\n {{ option.label }}\n </div>\n @if (option.description) {\n <div class=\"studio-select__option-description\">\n {{ option.description }}\n </div>\n }\n </div>\n\n @if (!multiple() && isSelected(option)) {\n <studio-icon name=\"check\" [size]=\"16\" class=\"studio-select__check-icon\" />\n }\n </div>\n }\n </div>\n </div>\n}\n\n@if (hint() && !error()) {\n <div class=\"studio-select__hint\">{{ hint() }}</div>\n}\n\n@if (error() && errorMessage()) {\n <div class=\"studio-select__error\">{{ errorMessage() }}</div>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:.375rem;font-family:var(--studio-font-family);position:relative}:host(.studio-select--full-width){width:100%}.studio-select__label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);margin-bottom:.25rem}.studio-select__label .studio-select__required{color:var(--studio-error);margin-left:.125rem}.studio-select__control{position:relative;display:flex;align-items:center;transition:all var(--studio-transition-fast)}.studio-select__prefix,.studio-select__suffix{display:flex;align-items:center;justify-content:center;color:var(--studio-text-secondary);flex-shrink:0}.studio-select__suffix{transition:var(--studio-transition-fast)}:host(.studio-select--open) .studio-select__suffix{transform:rotate(180deg)}.studio-select__trigger{flex:1;width:100%;display:flex;align-items:center;background:transparent;border:none;padding:0;font-family:inherit;text-align:left;color:var(--studio-text-primary);cursor:pointer;outline:none;transition:var(--studio-transition-fast)}.studio-select__trigger:disabled{cursor:not-allowed;opacity:.6}.studio-select__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--studio-text-primary)}.studio-select__placeholder{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--studio-text-tertiary)}.studio-select__clear,.studio-select__loading{display:flex;align-items:center;justify-content:center;flex-shrink:0}.studio-select__clear{background:none;border:none;padding:.25rem;color:var(--studio-text-secondary);cursor:pointer;border-radius:var(--studio-radius-sm);transition:all var(--studio-transition-fast)}.studio-select__clear:hover{color:var(--studio-text-primary);background:var(--studio-bg-secondary)}.studio-select__clear:active{transform:scale(.95)}.studio-select__loading{color:var(--studio-primary)}.studio-select__loading .studio-icon--spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-select__dropdown{position:absolute;top:100%;left:0;right:0;z-index:var(--studio-z-dropdown, 1000);background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);box-shadow:var(--studio-shadow-lg);margin-top:.25rem;overflow:hidden;display:flex;flex-direction:column}.studio-select__search{padding:.5rem;border-bottom:1px solid var(--studio-border-primary);flex-shrink:0}.studio-select__search input{width:100%;padding:.5rem;border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-sm);font-family:inherit;font-size:.875rem;color:var(--studio-text-primary);background:var(--studio-bg-primary);outline:none;transition:var(--studio-transition-fast)}.studio-select__search input:focus{border-color:var(--studio-primary);box-shadow:0 0 0 3px var(--studio-primary-bg)}.studio-select__search input::placeholder{color:var(--studio-text-tertiary)}.studio-select__options{overflow-y:auto;flex:1}.studio-select__option{display:flex;align-items:center;gap:.75rem;padding:.625rem .75rem;cursor:pointer;transition:var(--studio-transition-fast);color:var(--studio-text-primary)}.studio-select__option:hover{background:var(--studio-bg-secondary)}.studio-select__option--selected{background:var(--studio-primary-bg);color:var(--studio-primary)}.studio-select__option--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.studio-select__option input[type=checkbox]{margin:0;cursor:pointer}.studio-select__option-icon{flex-shrink:0;color:var(--studio-text-secondary)}.studio-select__option-content{flex:1;min-width:0}.studio-select__option-label{font-size:.875rem;color:inherit}.studio-select__option-description{font-size:.75rem;color:var(--studio-text-secondary);margin-top:.125rem}.studio-select__empty{padding:1rem;text-align:center;color:var(--studio-text-tertiary);font-size:.875rem}.studio-select__hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-select__error{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:var(--studio-error);line-height:1.4}.studio-select__label--floating{position:absolute;top:50%;left:1rem;transform:translateY(-50%);font-size:1rem;color:var(--studio-text-tertiary);pointer-events:none;transition:all var(--studio-transition-fast);background:var(--studio-bg-primary);padding:0 .25rem;z-index:1}:host(.studio-select--focused) .studio-select__label--floating,:host(.studio-select--has-value) .studio-select__label--floating{top:0;font-size:.75rem;color:var(--studio-primary)}:host(.studio-select--error) .studio-select__label--floating{color:var(--studio-error)}:host(.studio-select--outline) .studio-select__control{border:1px solid var(--studio-border-primary);background:var(--studio-bg-primary);border-radius:var(--studio-radius-md)}:host(.studio-select--outline) .studio-select__control:hover:not(:has(.studio-select__trigger:disabled)){border-color:var(--studio-primary)}:host(.studio-select--outline.studio-select--focused) .studio-select__control{border-color:var(--studio-primary);box-shadow:0 0 0 3px var(--studio-primary-bg)}:host(.studio-select--outline.studio-select--error) .studio-select__control{border-color:var(--studio-error)}:host(.studio-select--outline.studio-select--error) .studio-select__control:hover{border-color:var(--studio-error)}:host(.studio-select--outline.studio-select--error.studio-select--focused) .studio-select__control{box-shadow:0 0 0 3px #ef44441a}:host(.studio-select--outline.studio-select--disabled) .studio-select__control{background:var(--studio-bg-secondary);border-color:var(--studio-border-secondary)}:host(.studio-select--filled) .studio-select__control{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-select--filled) .studio-select__control:hover:not(:has(.studio-select__trigger:disabled)){background:var(--studio-bg-tertiary)}:host(.studio-select--filled.studio-select--focused) .studio-select__control{border-bottom-color:var(--studio-primary);background:var(--studio-bg-tertiary)}:host(.studio-select--filled.studio-select--error) .studio-select__control{border-bottom-color:var(--studio-error)}:host(.studio-select--filled.studio-select--disabled) .studio-select__control{background:var(--studio-bg-secondary);opacity:.6}:host(.studio-select--underline) .studio-select__control{background:transparent;border:none;border-bottom:1px solid var(--studio-border-primary);border-radius:0}:host(.studio-select--underline) .studio-select__control:hover:not(:has(.studio-select__trigger:disabled)){border-bottom-color:var(--studio-primary)}:host(.studio-select--underline.studio-select--focused) .studio-select__control{border-bottom:2px solid var(--studio-primary)}:host(.studio-select--underline.studio-select--error) .studio-select__control{border-bottom-color:var(--studio-error)}:host(.studio-select--underline.studio-select--disabled) .studio-select__control{border-bottom-style:dashed;opacity:.6}:host(.studio-select--sm) .studio-select__trigger{height:2rem;font-size:.875rem;padding:0 .75rem}:host(.studio-select--sm) .studio-select__prefix{padding-left:.75rem}:host(.studio-select--sm) .studio-select__suffix,:host(.studio-select--sm) .studio-select__clear,:host(.studio-select--sm) .studio-select__loading{padding-right:.5rem}:host(.studio-select--md) .studio-select__trigger{height:2.5rem;font-size:1rem;padding:0 1rem}:host(.studio-select--md) .studio-select__prefix{padding-left:1rem}:host(.studio-select--md) .studio-select__suffix,:host(.studio-select--md) .studio-select__clear,:host(.studio-select--md) .studio-select__loading{padding-right:.75rem}:host(.studio-select--lg) .studio-select__trigger{height:3rem;font-size:1.125rem;padding:0 1.25rem}:host(.studio-select--lg) .studio-select__prefix{padding-left:1.25rem}:host(.studio-select--lg) .studio-select__suffix,:host(.studio-select--lg) .studio-select__clear,:host(.studio-select--lg) .studio-select__loading{padding-right:1rem}:host(.studio-select--radius-none) .studio-select__control{border-radius:0}:host(.studio-select--radius-sm) .studio-select__control{border-radius:var(--studio-radius-sm)}:host(.studio-select--radius-md) .studio-select__control{border-radius:var(--studio-radius-md)}:host(.studio-select--radius-lg) .studio-select__control{border-radius:var(--studio-radius-lg)}:host(.studio-select--radius-full) .studio-select__control{border-radius:9999px}:host(.studio-select--filled.studio-select--radius-none) .studio-select__control{border-radius:0}:host(.studio-select--filled.studio-select--radius-sm) .studio-select__control{border-radius:var(--studio-radius-sm) var(--studio-radius-sm) 0 0}:host(.studio-select--filled.studio-select--radius-md) .studio-select__control{border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0}:host(.studio-select--filled.studio-select--radius-lg) .studio-select__control{border-radius:var(--studio-radius-lg) var(--studio-radius-lg) 0 0}:host(.studio-select--filled.studio-select--radius-full) .studio-select__control{border-radius:9999px 9999px 0 0}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2028
+ }
2029
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SelectComponent, decorators: [{
2030
+ type: Component,
2031
+ args: [{ selector: 'studio-select', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2032
+ {
2033
+ provide: NG_VALUE_ACCESSOR,
2034
+ useExisting: forwardRef(() => SelectComponent),
2035
+ multi: true
2036
+ }
2037
+ ], host: {
2038
+ '[class]': 'hostClasses()',
2039
+ '[attr.data-open]': 'isOpen()',
2040
+ }, template: "@if (label() && !floatingLabel()) {\n <label [for]=\"generatedId\" class=\"studio-select__label\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-select__required\">*</span>\n }\n </label>\n}\n\n<div class=\"studio-select__control\">\n @if (prefixIcon()) {\n <span class=\"studio-select__prefix\">\n <studio-icon [name]=\"prefixIcon()!\" [size]=\"16\" />\n </span>\n }\n\n @if (label() && floatingLabel()) {\n <label [for]=\"generatedId\" class=\"studio-select__label--floating\">\n {{ label() }}\n @if (required()) {\n <span class=\"studio-select__required\">*</span>\n }\n </label>\n }\n\n <button\n #triggerButton\n type=\"button\"\n [id]=\"generatedId\"\n class=\"studio-select__trigger\"\n [disabled]=\"disabled() || loading()\"\n (click)=\"toggle()\"\n (keydown)=\"handleKeydown($event)\"\n (focus)=\"isFocused.set(true)\"\n (blur)=\"isFocused.set(false)\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n >\n @if (hasValue()) {\n <span class=\"studio-select__value\">{{ displayValue() }}</span>\n } @else {\n <span class=\"studio-select__placeholder\">{{ placeholder() }}</span>\n }\n </button>\n\n @if (clearable() && hasValue() && !disabled() && !loading()) {\n <button\n type=\"button\"\n class=\"studio-select__clear\"\n (click)=\"clear($event)\"\n aria-label=\"Clear selection\"\n tabindex=\"-1\"\n >\n <studio-icon name=\"x\" [size]=\"14\" />\n </button>\n }\n\n @if (loading()) {\n <span class=\"studio-select__loading\">\n <studio-icon name=\"loader-2\" [size]=\"16\" class=\"studio-icon--spin\" />\n </span>\n } @else {\n <span class=\"studio-select__suffix\">\n <studio-icon\n [name]=\"suffixIcon()\"\n [size]=\"16\"\n />\n </span>\n }\n</div>\n\n@if (isOpen()) {\n <div\n #dropdownPanel\n class=\"studio-select__dropdown\"\n [attr.data-position]=\"position()\"\n [style.max-height]=\"maxHeight()\"\n >\n @if (searchable()) {\n <div class=\"studio-select__search\">\n <input\n type=\"text\"\n [placeholder]=\"searchPlaceholder()\"\n [value]=\"searchQuery()\"\n (input)=\"handleSearch($event)\"\n />\n </div>\n }\n\n <div class=\"studio-select__options\" role=\"listbox\">\n @if (filteredOptions().length === 0) {\n <div class=\"studio-select__empty\">\n No options found\n </div>\n }\n\n @for (option of filteredOptions(); track option.value; let idx = $index) {\n <div\n class=\"studio-select__option\"\n [class.studio-select__option--selected]=\"isSelected(option)\"\n [class.studio-select__option--disabled]=\"option.disabled\"\n [class.studio-select__option--highlighted]=\"highlightedIndex() === idx\"\n (click)=\"selectOption(option)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(option)\"\n >\n @if (multiple()) {\n <input\n type=\"checkbox\"\n class=\"studio-select__checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n tabindex=\"-1\"\n />\n }\n\n @if (option.icon) {\n <studio-icon [name]=\"option.icon\" [size]=\"18\" class=\"studio-select__option-icon\" />\n }\n\n <div class=\"studio-select__option-content\">\n <div class=\"studio-select__option-label\">\n {{ option.label }}\n </div>\n @if (option.description) {\n <div class=\"studio-select__option-description\">\n {{ option.description }}\n </div>\n }\n </div>\n\n @if (!multiple() && isSelected(option)) {\n <studio-icon name=\"check\" [size]=\"16\" class=\"studio-select__check-icon\" />\n }\n </div>\n }\n </div>\n </div>\n}\n\n@if (hint() && !error()) {\n <div class=\"studio-select__hint\">{{ hint() }}</div>\n}\n\n@if (error() && errorMessage()) {\n <div class=\"studio-select__error\">{{ errorMessage() }}</div>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:.375rem;font-family:var(--studio-font-family);position:relative}:host(.studio-select--full-width){width:100%}.studio-select__label{display:block;font-size:.875rem;font-weight:var(--studio-font-weight-medium);color:var(--studio-text-primary);margin-bottom:.25rem}.studio-select__label .studio-select__required{color:var(--studio-error);margin-left:.125rem}.studio-select__control{position:relative;display:flex;align-items:center;transition:all var(--studio-transition-fast)}.studio-select__prefix,.studio-select__suffix{display:flex;align-items:center;justify-content:center;color:var(--studio-text-secondary);flex-shrink:0}.studio-select__suffix{transition:var(--studio-transition-fast)}:host(.studio-select--open) .studio-select__suffix{transform:rotate(180deg)}.studio-select__trigger{flex:1;width:100%;display:flex;align-items:center;background:transparent;border:none;padding:0;font-family:inherit;text-align:left;color:var(--studio-text-primary);cursor:pointer;outline:none;transition:var(--studio-transition-fast)}.studio-select__trigger:disabled{cursor:not-allowed;opacity:.6}.studio-select__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--studio-text-primary)}.studio-select__placeholder{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--studio-text-tertiary)}.studio-select__clear,.studio-select__loading{display:flex;align-items:center;justify-content:center;flex-shrink:0}.studio-select__clear{background:none;border:none;padding:.25rem;color:var(--studio-text-secondary);cursor:pointer;border-radius:var(--studio-radius-sm);transition:all var(--studio-transition-fast)}.studio-select__clear:hover{color:var(--studio-text-primary);background:var(--studio-bg-secondary)}.studio-select__clear:active{transform:scale(.95)}.studio-select__loading{color:var(--studio-primary)}.studio-select__loading .studio-icon--spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-select__dropdown{position:absolute;top:100%;left:0;right:0;z-index:var(--studio-z-dropdown, 1000);background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);box-shadow:var(--studio-shadow-lg);margin-top:.25rem;overflow:hidden;display:flex;flex-direction:column}.studio-select__search{padding:.5rem;border-bottom:1px solid var(--studio-border-primary);flex-shrink:0}.studio-select__search input{width:100%;padding:.5rem;border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-sm);font-family:inherit;font-size:.875rem;color:var(--studio-text-primary);background:var(--studio-bg-primary);outline:none;transition:var(--studio-transition-fast)}.studio-select__search input:focus{border-color:var(--studio-primary);box-shadow:0 0 0 3px var(--studio-primary-bg)}.studio-select__search input::placeholder{color:var(--studio-text-tertiary)}.studio-select__options{overflow-y:auto;flex:1}.studio-select__option{display:flex;align-items:center;gap:.75rem;padding:.625rem .75rem;cursor:pointer;transition:var(--studio-transition-fast);color:var(--studio-text-primary)}.studio-select__option:hover{background:var(--studio-bg-secondary)}.studio-select__option--selected{background:var(--studio-primary-bg);color:var(--studio-primary)}.studio-select__option--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.studio-select__option input[type=checkbox]{margin:0;cursor:pointer}.studio-select__option-icon{flex-shrink:0;color:var(--studio-text-secondary)}.studio-select__option-content{flex:1;min-width:0}.studio-select__option-label{font-size:.875rem;color:inherit}.studio-select__option-description{font-size:.75rem;color:var(--studio-text-secondary);margin-top:.125rem}.studio-select__empty{padding:1rem;text-align:center;color:var(--studio-text-tertiary);font-size:.875rem}.studio-select__hint{font-size:.75rem;color:var(--studio-text-secondary);line-height:1.4}.studio-select__error{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:var(--studio-error);line-height:1.4}.studio-select__label--floating{position:absolute;top:50%;left:1rem;transform:translateY(-50%);font-size:1rem;color:var(--studio-text-tertiary);pointer-events:none;transition:all var(--studio-transition-fast);background:var(--studio-bg-primary);padding:0 .25rem;z-index:1}:host(.studio-select--focused) .studio-select__label--floating,:host(.studio-select--has-value) .studio-select__label--floating{top:0;font-size:.75rem;color:var(--studio-primary)}:host(.studio-select--error) .studio-select__label--floating{color:var(--studio-error)}:host(.studio-select--outline) .studio-select__control{border:1px solid var(--studio-border-primary);background:var(--studio-bg-primary);border-radius:var(--studio-radius-md)}:host(.studio-select--outline) .studio-select__control:hover:not(:has(.studio-select__trigger:disabled)){border-color:var(--studio-primary)}:host(.studio-select--outline.studio-select--focused) .studio-select__control{border-color:var(--studio-primary);box-shadow:0 0 0 3px var(--studio-primary-bg)}:host(.studio-select--outline.studio-select--error) .studio-select__control{border-color:var(--studio-error)}:host(.studio-select--outline.studio-select--error) .studio-select__control:hover{border-color:var(--studio-error)}:host(.studio-select--outline.studio-select--error.studio-select--focused) .studio-select__control{box-shadow:0 0 0 3px #ef44441a}:host(.studio-select--outline.studio-select--disabled) .studio-select__control{background:var(--studio-bg-secondary);border-color:var(--studio-border-secondary)}:host(.studio-select--filled) .studio-select__control{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-select--filled) .studio-select__control:hover:not(:has(.studio-select__trigger:disabled)){background:var(--studio-bg-tertiary)}:host(.studio-select--filled.studio-select--focused) .studio-select__control{border-bottom-color:var(--studio-primary);background:var(--studio-bg-tertiary)}:host(.studio-select--filled.studio-select--error) .studio-select__control{border-bottom-color:var(--studio-error)}:host(.studio-select--filled.studio-select--disabled) .studio-select__control{background:var(--studio-bg-secondary);opacity:.6}:host(.studio-select--underline) .studio-select__control{background:transparent;border:none;border-bottom:1px solid var(--studio-border-primary);border-radius:0}:host(.studio-select--underline) .studio-select__control:hover:not(:has(.studio-select__trigger:disabled)){border-bottom-color:var(--studio-primary)}:host(.studio-select--underline.studio-select--focused) .studio-select__control{border-bottom:2px solid var(--studio-primary)}:host(.studio-select--underline.studio-select--error) .studio-select__control{border-bottom-color:var(--studio-error)}:host(.studio-select--underline.studio-select--disabled) .studio-select__control{border-bottom-style:dashed;opacity:.6}:host(.studio-select--sm) .studio-select__trigger{height:2rem;font-size:.875rem;padding:0 .75rem}:host(.studio-select--sm) .studio-select__prefix{padding-left:.75rem}:host(.studio-select--sm) .studio-select__suffix,:host(.studio-select--sm) .studio-select__clear,:host(.studio-select--sm) .studio-select__loading{padding-right:.5rem}:host(.studio-select--md) .studio-select__trigger{height:2.5rem;font-size:1rem;padding:0 1rem}:host(.studio-select--md) .studio-select__prefix{padding-left:1rem}:host(.studio-select--md) .studio-select__suffix,:host(.studio-select--md) .studio-select__clear,:host(.studio-select--md) .studio-select__loading{padding-right:.75rem}:host(.studio-select--lg) .studio-select__trigger{height:3rem;font-size:1.125rem;padding:0 1.25rem}:host(.studio-select--lg) .studio-select__prefix{padding-left:1.25rem}:host(.studio-select--lg) .studio-select__suffix,:host(.studio-select--lg) .studio-select__clear,:host(.studio-select--lg) .studio-select__loading{padding-right:1rem}:host(.studio-select--radius-none) .studio-select__control{border-radius:0}:host(.studio-select--radius-sm) .studio-select__control{border-radius:var(--studio-radius-sm)}:host(.studio-select--radius-md) .studio-select__control{border-radius:var(--studio-radius-md)}:host(.studio-select--radius-lg) .studio-select__control{border-radius:var(--studio-radius-lg)}:host(.studio-select--radius-full) .studio-select__control{border-radius:9999px}:host(.studio-select--filled.studio-select--radius-none) .studio-select__control{border-radius:0}:host(.studio-select--filled.studio-select--radius-sm) .studio-select__control{border-radius:var(--studio-radius-sm) var(--studio-radius-sm) 0 0}:host(.studio-select--filled.studio-select--radius-md) .studio-select__control{border-radius:var(--studio-radius-md) var(--studio-radius-md) 0 0}:host(.studio-select--filled.studio-select--radius-lg) .studio-select__control{border-radius:var(--studio-radius-lg) var(--studio-radius-lg) 0 0}:host(.studio-select--filled.studio-select--radius-full) .studio-select__control{border-radius:9999px 9999px 0 0}\n"] }]
2041
+ }], ctorParameters: () => [], propDecorators: { triggerEl: [{ type: i0.ViewChild, args: ['triggerButton', { isSignal: true }] }], dropdownEl: [{ type: i0.ViewChild, args: ['dropdownPanel', { isSignal: true }] }], variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], radiusInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], prefixIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefixIcon", required: false }] }], suffixIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffixIcon", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], optionSelected: [{ type: i0.Output, args: ["optionSelected"] }] } });
2042
+
1335
2043
  /**
1336
2044
  * Toggle switch component with customizable size and color
1337
2045
  *
@@ -2049,6 +2757,433 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2049
2757
  * Domain-specific components for educational platforms
2050
2758
  */
2051
2759
 
2760
+ class MaskEngine {
2761
+ config;
2762
+ tokens;
2763
+ patterns = {
2764
+ '9': /\d/,
2765
+ 'A': /[a-zA-Zа-яА-Я]/,
2766
+ '*': /[a-zA-Z0-9]/,
2767
+ '#': /./,
2768
+ 'X': /[a-zA-Z0-9а-яА-Я]/,
2769
+ };
2770
+ constructor(config) {
2771
+ this.config = config;
2772
+ this.tokens = this.parsePattern(config.pattern);
2773
+ }
2774
+ process(value, cursorPos) {
2775
+ if (!value) {
2776
+ return {
2777
+ value: '',
2778
+ raw: '',
2779
+ cursor: 0,
2780
+ isComplete: false
2781
+ };
2782
+ }
2783
+ const cleaned = this.extractRaw(value);
2784
+ const formatted = this.applyMask(cleaned);
2785
+ const newCursor = cursorPos !== undefined
2786
+ ? this.calculateCursor(cursorPos, value, formatted)
2787
+ : formatted.length;
2788
+ const displayValue = this.config.guide && this.config.showOnFocus
2789
+ ? this.applyGuide(formatted)
2790
+ : formatted;
2791
+ return {
2792
+ value: displayValue,
2793
+ raw: cleaned,
2794
+ cursor: newCursor,
2795
+ isComplete: this.checkComplete(cleaned)
2796
+ };
2797
+ }
2798
+ getPlaceholder() {
2799
+ if (!this.tokens || this.tokens.length === 0)
2800
+ return '';
2801
+ return this.tokens
2802
+ .map(token => {
2803
+ if (token.type === 'static' && token.char)
2804
+ return token.char;
2805
+ return this.config.placeholder || '_';
2806
+ })
2807
+ .join('');
2808
+ }
2809
+ parsePattern(pattern) {
2810
+ const tokens = [];
2811
+ let i = 0;
2812
+ while (i < pattern.length) {
2813
+ const char = pattern[i];
2814
+ if (char === '\\' && i + 1 < pattern.length) {
2815
+ tokens.push({
2816
+ type: 'static',
2817
+ char: pattern[i + 1]
2818
+ });
2819
+ i += 2;
2820
+ continue;
2821
+ }
2822
+ if (char === '?' && tokens.length > 0) {
2823
+ tokens[tokens.length - 1].optional = true;
2824
+ i++;
2825
+ continue;
2826
+ }
2827
+ if (char in this.patterns) {
2828
+ tokens.push({
2829
+ type: this.getTokenType(char),
2830
+ pattern: this.patterns[char]
2831
+ });
2832
+ i++;
2833
+ }
2834
+ else {
2835
+ tokens.push({
2836
+ type: 'static',
2837
+ char
2838
+ });
2839
+ i++;
2840
+ }
2841
+ }
2842
+ return tokens;
2843
+ }
2844
+ getTokenType(char) {
2845
+ const typeMap = {
2846
+ '9': 'digit',
2847
+ 'A': 'letter',
2848
+ '*': 'alphanumeric',
2849
+ '#': 'any',
2850
+ 'X': 'mixed'
2851
+ };
2852
+ return typeMap[char] || 'any';
2853
+ }
2854
+ applyMask(raw) {
2855
+ if (!raw || !this.tokens)
2856
+ return '';
2857
+ let result = '';
2858
+ let rawIndex = 0;
2859
+ for (const token of this.tokens) {
2860
+ if (rawIndex >= raw.length) {
2861
+ break;
2862
+ }
2863
+ if (token.type === 'static' && token.char) {
2864
+ result += token.char;
2865
+ if (raw[rawIndex] === token.char) {
2866
+ rawIndex++;
2867
+ }
2868
+ }
2869
+ else {
2870
+ const char = raw[rawIndex];
2871
+ if (token.pattern?.test(char)) {
2872
+ result += char;
2873
+ rawIndex++;
2874
+ }
2875
+ else if (!token.optional) {
2876
+ break;
2877
+ }
2878
+ }
2879
+ }
2880
+ return result;
2881
+ }
2882
+ extractRaw(value) {
2883
+ if (!value || !this.tokens)
2884
+ return '';
2885
+ const staticChars = this.tokens
2886
+ .filter(t => t.type === 'static' && t.char)
2887
+ .map(t => t.char)
2888
+ .filter(Boolean);
2889
+ return value
2890
+ .split('')
2891
+ .filter(char => !staticChars.includes(char))
2892
+ .join('');
2893
+ }
2894
+ applyGuide(value) {
2895
+ if (!this.tokens || this.tokens.length === 0)
2896
+ return value;
2897
+ const placeholder = this.config.placeholder || '_';
2898
+ let result = value;
2899
+ const currentLength = value.replace(/[^a-zA-Z0-9а-яА-Я]/g, '').length;
2900
+ let addedCount = 0;
2901
+ for (let i = 0; i < this.tokens.length; i++) {
2902
+ const token = this.tokens[i];
2903
+ if (addedCount >= currentLength) {
2904
+ if (token.type === 'static' && token.char) {
2905
+ result += token.char;
2906
+ }
2907
+ else {
2908
+ result += placeholder;
2909
+ addedCount++;
2910
+ }
2911
+ }
2912
+ }
2913
+ return result;
2914
+ }
2915
+ calculateCursor(oldCursor, oldValue, newValue) {
2916
+ const diff = newValue.length - oldValue.length;
2917
+ let newCursor = oldCursor + diff;
2918
+ while (newCursor < newValue.length) {
2919
+ const charAtCursor = newValue[newCursor];
2920
+ const isStatic = this.tokens.some((t, i) => t.type === 'static' && t.char === charAtCursor && i === newCursor);
2921
+ if (!isStatic)
2922
+ break;
2923
+ newCursor++;
2924
+ }
2925
+ return Math.max(0, Math.min(newValue.length, newCursor));
2926
+ }
2927
+ checkComplete(raw) {
2928
+ const requiredTokens = this.tokens.filter(t => t.type !== 'static' && !t.optional);
2929
+ return raw.length >= requiredTokens.length;
2930
+ }
2931
+ }
2932
+
2933
+ const MASK_PRESETS = {
2934
+ 'phone': {
2935
+ pattern: '+7 (999) 999-99-99',
2936
+ placeholder: '_',
2937
+ guide: true
2938
+ },
2939
+ 'phone-ru': {
2940
+ pattern: '+7 (999) 999-99-99',
2941
+ placeholder: '_',
2942
+ guide: true
2943
+ },
2944
+ 'phone-kz': {
2945
+ pattern: '+7 (999) 999-99-99',
2946
+ placeholder: '_',
2947
+ guide: true
2948
+ },
2949
+ 'date': {
2950
+ pattern: '99.99.9999',
2951
+ placeholder: '_',
2952
+ guide: true
2953
+ },
2954
+ 'datetime': {
2955
+ pattern: '99.99.9999 99:99',
2956
+ placeholder: '_',
2957
+ guide: true
2958
+ },
2959
+ 'time': {
2960
+ pattern: '99:99',
2961
+ placeholder: '_',
2962
+ guide: true
2963
+ },
2964
+ 'card': {
2965
+ pattern: '9999 9999 9999 9999',
2966
+ placeholder: 'X',
2967
+ guide: true
2968
+ },
2969
+ 'inn': {
2970
+ pattern: '999999999999',
2971
+ placeholder: '_',
2972
+ guide: false
2973
+ },
2974
+ 'snils': {
2975
+ pattern: '999-999-999 99',
2976
+ placeholder: '_',
2977
+ guide: true
2978
+ },
2979
+ 'passport-ru': {
2980
+ pattern: '99 99 999999',
2981
+ placeholder: '_',
2982
+ guide: true
2983
+ }
2984
+ };
2985
+
2986
+ class MaskDirective {
2987
+ el = inject((ElementRef));
2988
+ renderer = inject(Renderer2);
2989
+ destroyRef = inject(DestroyRef);
2990
+ mask = input('', ...(ngDevMode ? [{ debugName: "mask", alias: 'studioMask',
2991
+ transform: (value) => {
2992
+ if (!value)
2993
+ return '';
2994
+ if (value in MASK_PRESETS) {
2995
+ return MASK_PRESETS[value].pattern;
2996
+ }
2997
+ return value;
2998
+ } }] : [{
2999
+ alias: 'studioMask',
3000
+ transform: (value) => {
3001
+ if (!value)
3002
+ return '';
3003
+ if (value in MASK_PRESETS) {
3004
+ return MASK_PRESETS[value].pattern;
3005
+ }
3006
+ return value;
3007
+ }
3008
+ }]));
3009
+ maskPlaceholder = input('_', ...(ngDevMode ? [{ debugName: "maskPlaceholder" }] : []));
3010
+ maskGuide = input(true, ...(ngDevMode ? [{ debugName: "maskGuide" }] : []));
3011
+ maskShowOnHover = input(false, ...(ngDevMode ? [{ debugName: "maskShowOnHover" }] : []));
3012
+ maskShowOnFocus = input(true, ...(ngDevMode ? [{ debugName: "maskShowOnFocus" }] : []));
3013
+ maskClearIncomplete = input(false, ...(ngDevMode ? [{ debugName: "maskClearIncomplete" }] : []));
3014
+ maskAutoUnmask = input(false, ...(ngDevMode ? [{ debugName: "maskAutoUnmask" }] : []));
3015
+ config = computed(() => ({
3016
+ pattern: this.mask(),
3017
+ placeholder: this.maskPlaceholder(),
3018
+ guide: this.maskGuide(),
3019
+ showOnHover: this.maskShowOnHover(),
3020
+ showOnFocus: this.maskShowOnFocus(),
3021
+ clearIncomplete: this.maskClearIncomplete(),
3022
+ autoUnmask: this.maskAutoUnmask()
3023
+ }), ...(ngDevMode ? [{ debugName: "config" }] : []));
3024
+ engine = signal(null, ...(ngDevMode ? [{ debugName: "engine" }] : []));
3025
+ isComplete = signal(false, ...(ngDevMode ? [{ debugName: "isComplete" }] : []));
3026
+ isActive = signal(false, ...(ngDevMode ? [{ debugName: "isActive" }] : []));
3027
+ onChange = () => { };
3028
+ onTouched = () => { };
3029
+ constructor() {
3030
+ effect(() => {
3031
+ const maskPattern = this.mask();
3032
+ if (!maskPattern)
3033
+ return;
3034
+ const cfg = this.config();
3035
+ const newEngine = new MaskEngine(cfg);
3036
+ this.engine.set(newEngine);
3037
+ this.updatePlaceholder();
3038
+ });
3039
+ }
3040
+ onInput(event) {
3041
+ const eng = this.engine();
3042
+ if (!eng)
3043
+ return;
3044
+ const element = this.el.nativeElement;
3045
+ const cursorPos = element.selectionStart ?? 0;
3046
+ const result = eng.process(element.value, cursorPos);
3047
+ if (element.value !== result.value) {
3048
+ this.renderer.setProperty(element, 'value', result.value);
3049
+ element.setSelectionRange(result.cursor, result.cursor);
3050
+ }
3051
+ this.isComplete.set(result.isComplete);
3052
+ const outputValue = this.config().autoUnmask ? result.raw : result.value;
3053
+ this.onChange(outputValue);
3054
+ }
3055
+ onFocus() {
3056
+ this.isActive.set(true);
3057
+ if (this.maskShowOnFocus() && this.maskGuide()) {
3058
+ const eng = this.engine();
3059
+ if (!eng)
3060
+ return;
3061
+ const element = this.el.nativeElement;
3062
+ if (!element.value) {
3063
+ const result = eng.process('', 0);
3064
+ this.renderer.setProperty(element, 'value', result.value);
3065
+ element.setSelectionRange(0, 0);
3066
+ }
3067
+ }
3068
+ }
3069
+ onBlur() {
3070
+ this.isActive.set(false);
3071
+ this.onTouched();
3072
+ if (this.maskClearIncomplete() && !this.isComplete()) {
3073
+ this.renderer.setProperty(this.el.nativeElement, 'value', '');
3074
+ this.onChange('');
3075
+ }
3076
+ }
3077
+ onPaste(event) {
3078
+ event.preventDefault();
3079
+ const eng = this.engine();
3080
+ if (!eng)
3081
+ return;
3082
+ const pastedText = event.clipboardData?.getData('text') || '';
3083
+ const element = this.el.nativeElement;
3084
+ const cursorPos = element.selectionStart ?? 0;
3085
+ const currentValue = element.value;
3086
+ const before = currentValue.slice(0, cursorPos);
3087
+ const after = currentValue.slice(element.selectionEnd ?? cursorPos);
3088
+ const newValue = before + pastedText + after;
3089
+ const result = eng.process(newValue, cursorPos + pastedText.length);
3090
+ this.renderer.setProperty(element, 'value', result.value);
3091
+ element.setSelectionRange(result.cursor, result.cursor);
3092
+ const outputValue = this.config().autoUnmask ? result.raw : result.value;
3093
+ this.onChange(outputValue);
3094
+ }
3095
+ writeValue(value) {
3096
+ const eng = this.engine();
3097
+ if (!eng)
3098
+ return;
3099
+ if (value) {
3100
+ const result = eng.process(value);
3101
+ this.renderer.setProperty(this.el.nativeElement, 'value', result.value);
3102
+ this.isComplete.set(result.isComplete);
3103
+ }
3104
+ else {
3105
+ this.renderer.setProperty(this.el.nativeElement, 'value', '');
3106
+ this.isComplete.set(false);
3107
+ }
3108
+ }
3109
+ registerOnChange(fn) {
3110
+ this.onChange = fn;
3111
+ }
3112
+ registerOnTouched(fn) {
3113
+ this.onTouched = fn;
3114
+ }
3115
+ validate(control) {
3116
+ if (!control.value)
3117
+ return null;
3118
+ const complete = this.isComplete();
3119
+ return complete ? null : { maskIncomplete: { value: control.value } };
3120
+ }
3121
+ updatePlaceholder() {
3122
+ if (!this.maskShowOnFocus())
3123
+ return;
3124
+ const eng = this.engine();
3125
+ if (!eng)
3126
+ return;
3127
+ try {
3128
+ const placeholderText = eng.getPlaceholder();
3129
+ if (placeholderText) {
3130
+ this.renderer.setAttribute(this.el.nativeElement, 'placeholder', placeholderText);
3131
+ }
3132
+ }
3133
+ catch (e) {
3134
+ console.warn('Failed to update placeholder:', e);
3135
+ }
3136
+ }
3137
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: MaskDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3138
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.12", type: MaskDirective, isStandalone: true, selector: "input[studioMask]", inputs: { mask: { classPropertyName: "mask", publicName: "studioMask", isSignal: true, isRequired: false, transformFunction: null }, maskPlaceholder: { classPropertyName: "maskPlaceholder", publicName: "maskPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, maskGuide: { classPropertyName: "maskGuide", publicName: "maskGuide", isSignal: true, isRequired: false, transformFunction: null }, maskShowOnHover: { classPropertyName: "maskShowOnHover", publicName: "maskShowOnHover", isSignal: true, isRequired: false, transformFunction: null }, maskShowOnFocus: { classPropertyName: "maskShowOnFocus", publicName: "maskShowOnFocus", isSignal: true, isRequired: false, transformFunction: null }, maskClearIncomplete: { classPropertyName: "maskClearIncomplete", publicName: "maskClearIncomplete", isSignal: true, isRequired: false, transformFunction: null }, maskAutoUnmask: { classPropertyName: "maskAutoUnmask", publicName: "maskAutoUnmask", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "onInput($event)", "focus": "onFocus()", "blur": "onBlur()", "paste": "onPaste($event)" }, properties: { "attr.data-mask-complete": "isComplete()", "attr.data-mask-active": "isActive()" } }, providers: [
3139
+ {
3140
+ provide: NG_VALUE_ACCESSOR,
3141
+ useExisting: forwardRef(() => MaskDirective),
3142
+ multi: true
3143
+ },
3144
+ {
3145
+ provide: NG_VALIDATORS,
3146
+ useExisting: forwardRef(() => MaskDirective),
3147
+ multi: true
3148
+ }
3149
+ ], ngImport: i0 });
3150
+ }
3151
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: MaskDirective, decorators: [{
3152
+ type: Directive,
3153
+ args: [{
3154
+ selector: 'input[studioMask]',
3155
+ standalone: true,
3156
+ providers: [
3157
+ {
3158
+ provide: NG_VALUE_ACCESSOR,
3159
+ useExisting: forwardRef(() => MaskDirective),
3160
+ multi: true
3161
+ },
3162
+ {
3163
+ provide: NG_VALIDATORS,
3164
+ useExisting: forwardRef(() => MaskDirective),
3165
+ multi: true
3166
+ }
3167
+ ],
3168
+ host: {
3169
+ '[attr.data-mask-complete]': 'isComplete()',
3170
+ '[attr.data-mask-active]': 'isActive()'
3171
+ }
3172
+ }]
3173
+ }], ctorParameters: () => [], propDecorators: { mask: [{ type: i0.Input, args: [{ isSignal: true, alias: "studioMask", required: false }] }], maskPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "maskPlaceholder", required: false }] }], maskGuide: [{ type: i0.Input, args: [{ isSignal: true, alias: "maskGuide", required: false }] }], maskShowOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "maskShowOnHover", required: false }] }], maskShowOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "maskShowOnFocus", required: false }] }], maskClearIncomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "maskClearIncomplete", required: false }] }], maskAutoUnmask: [{ type: i0.Input, args: [{ isSignal: true, alias: "maskAutoUnmask", required: false }] }], onInput: [{
3174
+ type: HostListener,
3175
+ args: ['input', ['$event']]
3176
+ }], onFocus: [{
3177
+ type: HostListener,
3178
+ args: ['focus']
3179
+ }], onBlur: [{
3180
+ type: HostListener,
3181
+ args: ['blur']
3182
+ }], onPaste: [{
3183
+ type: HostListener,
3184
+ args: ['paste', ['$event']]
3185
+ }] } });
3186
+
2052
3187
  /**
2053
3188
  * Public API Surface of @eduboxpro/studio
2054
3189
  */
@@ -2060,5 +3195,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2060
3195
  * Generated bundle index. Do not edit.
2061
3196
  */
2062
3197
 
2063
- export { BadgeComponent, ButtonComponent, ButtonGroupComponent, ButtonToggleGroupComponent, CheckboxComponent, IconComponent, InputComponent, STUDIO_CONFIG, StudioConfigService, SwitchComponent, TextareaComponent, ThemeSwitchComponent, classNames, isSafeUrl, loadGoogleFont, loadGoogleFonts, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
3198
+ export { BadgeComponent, ButtonComponent, ButtonGroupComponent, ButtonToggleGroupComponent, CheckboxComponent, DrawerComponent, DrawerService, IconComponent, InputComponent, MASK_PRESETS, MaskDirective, MaskEngine, STUDIO_CONFIG, SelectComponent, StudioConfigService, SwitchComponent, TextareaComponent, ThemeSwitchComponent, classNames, isSafeUrl, loadGoogleFont, loadGoogleFonts, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
2064
3199
  //# sourceMappingURL=eduboxpro-studio.mjs.map