@eduboxpro/studio 0.1.15 → 0.1.17

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output, PLATFORM_ID, ElementRef, forwardRef, viewChild, DOCUMENT as DOCUMENT$1, DestroyRef, Injector, contentChild, model, afterNextRender, HostListener, Renderer2, Directive } from '@angular/core';
2
+ import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output, PLATFORM_ID, ElementRef, contentChild, viewChild, forwardRef, DOCUMENT as DOCUMENT$1, DestroyRef, Injector, model, afterNextRender, HostListener, TemplateRef, ContentChild, Input, Directive, contentChildren, Renderer2 } from '@angular/core';
3
3
  import * as i1$1 from '@angular/common';
4
4
  import { DOCUMENT, CommonModule, isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
5
5
  import * as LucideIcons from 'lucide-angular';
@@ -8,7 +8,7 @@ import * as i1 from '@angular/router';
8
8
  import { Router, NavigationEnd, RouterModule, RouterLink, RouterLinkActive } from '@angular/router';
9
9
  import { filter } from 'rxjs/operators';
10
10
  import * as i1$2 from '@angular/forms';
11
- import { NG_VALUE_ACCESSOR, FormsModule, NG_VALIDATORS } from '@angular/forms';
11
+ import { FormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
12
12
  import { autoUpdate, offset, flip, shift, arrow, computePosition } from '@floating-ui/dom';
13
13
  import { trigger, state, transition, style, animate } from '@angular/animations';
14
14
 
@@ -1267,6 +1267,656 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
1267
1267
  }, template: `<ng-content select="studio-button" />`, styles: [":host{display:inline-flex;align-items:center;position:relative}:host(.studio-button-group--horizontal){flex-direction:row}:host(.studio-button-group--vertical){flex-direction:column}:host(.studio-button-group--spacing-none){gap:0}:host(.studio-button-group--spacing-xs){gap:var(--studio-spacing-xs)}:host(.studio-button-group--spacing-sm){gap:var(--studio-spacing-sm)}:host(.studio-button-group--spacing-md){gap:var(--studio-spacing-md)}:host(.studio-button-group--spacing-lg){gap:var(--studio-spacing-lg)}:host(.studio-button-group--align-start){justify-content:flex-start}:host(.studio-button-group--align-center){justify-content:center}:host(.studio-button-group--align-end){justify-content:flex-end}:host(.studio-button-group--align-stretch){align-items:stretch}:host(.studio-button-group--align-stretch) ::ng-deep studio-button{flex:1}:host(.studio-button-group--full){width:100%}:host(.studio-button-group--full) ::ng-deep studio-button{flex:1}:host(.studio-button-group--attached){gap:0}:host(.studio-button-group--attached) ::ng-deep studio-button.studio-button-group__item--attached{margin:0;position:relative}:host(.studio-button-group--attached) ::ng-deep studio-button.studio-button-group__item--middle{border-radius:0}:host(.studio-button-group--attached) ::ng-deep studio-button.studio-button-group__item--first:not(.studio-button-group__item--last){border-top-right-radius:0;border-bottom-right-radius:0}:host(.studio-button-group--attached) ::ng-deep studio-button.studio-button-group__item--last:not(.studio-button-group__item--first){border-top-left-radius:0;border-bottom-left-radius:0}:host(.studio-button-group--attached).studio-button-group--horizontal ::ng-deep studio-button.studio-button-group__item--attached:not(:last-child){border-right:1px solid rgba(0,0,0,.1)}:host(.studio-button-group--attached).studio-button-group--horizontal ::ng-deep studio-button.studio-button-group__item--attached.studio-button--outline:not(:last-child){margin-right:-1px}:host(.studio-button-group--vertical){align-items:stretch}:host(.studio-button-group--vertical) ::ng-deep studio-button{width:100%;justify-content:flex-start}:host(.studio-button-group--vertical.studio-button-group--attached) ::ng-deep studio-button.studio-button-group__item--first:not(.studio-button-group__item--last){border-top-right-radius:var(--studio-radius-sm);border-bottom-right-radius:0;border-top-left-radius:var(--studio-radius-sm);border-bottom-left-radius:0}:host(.studio-button-group--vertical.studio-button-group--attached) ::ng-deep studio-button.studio-button-group__item--last:not(.studio-button-group__item--first){border-top-left-radius:0;border-bottom-left-radius:var(--studio-radius-sm);border-top-right-radius:0;border-bottom-right-radius:var(--studio-radius-sm)}:host(.studio-button-group--vertical.studio-button-group--attached) ::ng-deep studio-button.studio-button-group__item--attached:not(:last-child){border-right:none;border-bottom:1px solid rgba(255,255,255,.2)}:host(.studio-button-group--vertical.studio-button-group--attached) ::ng-deep studio-button.studio-button-group__item--middle{border-radius:0}:host(.studio-button-group--vertical.studio-button-group--full) ::ng-deep studio-button{width:100%}\n"] }]
1268
1268
  }], ctorParameters: () => [], propDecorators: { orientationInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], colorInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], radiusInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], attached: [{ type: i0.Input, args: [{ isSignal: true, alias: "attached", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], spacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "spacing", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }] } });
1269
1269
 
1270
+ /**
1271
+ * Card component for displaying content in a container
1272
+ *
1273
+ * @example
1274
+ * <studio-card variant="elevated" color="primary">
1275
+ * <div card-header>Header</div>
1276
+ * <div card-body>Content</div>
1277
+ * <div card-footer>Footer</div>
1278
+ * </studio-card>
1279
+ */
1280
+ class CardComponent {
1281
+ configService = inject(StudioConfigService);
1282
+ cardDefaults = computed(() => this.configService.config().components?.card, ...(ngDevMode ? [{ debugName: "cardDefaults" }] : []));
1283
+ // Style inputs with config defaults
1284
+ variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
1285
+ sizeInput = input(undefined, ...(ngDevMode ? [{ debugName: "sizeInput", alias: 'size' }] : [{ alias: 'size' }]));
1286
+ colorInput = input(undefined, ...(ngDevMode ? [{ debugName: "colorInput", alias: 'color' }] : [{ alias: 'color' }]));
1287
+ radiusInput = input(undefined, ...(ngDevMode ? [{ debugName: "radiusInput", alias: 'radius' }] : [{ alias: 'radius' }]));
1288
+ shadowInput = input(undefined, ...(ngDevMode ? [{ debugName: "shadowInput", alias: 'shadow' }] : [{ alias: 'shadow' }]));
1289
+ paddingInput = input(undefined, ...(ngDevMode ? [{ debugName: "paddingInput", alias: 'padding' }] : [{ alias: 'padding' }]));
1290
+ variant = withConfigDefault(this.variantInput, computed(() => this.cardDefaults()?.variant), 'elevated');
1291
+ size = withConfigDefault(this.sizeInput, computed(() => this.cardDefaults()?.size), 'md');
1292
+ color = withConfigDefault(this.colorInput, computed(() => this.cardDefaults()?.color), 'default');
1293
+ radius = withConfigDefault(this.radiusInput, computed(() => this.cardDefaults()?.radius), 'lg');
1294
+ shadow = withConfigDefault(this.shadowInput, computed(() => this.cardDefaults()?.shadow), 'md');
1295
+ padding = withConfigDefault(this.paddingInput, computed(() => this.cardDefaults()?.padding), 'md');
1296
+ // Layout inputs
1297
+ orientation = input('vertical', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
1298
+ imagePosition = input('top', ...(ngDevMode ? [{ debugName: "imagePosition" }] : []));
1299
+ fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
1300
+ fullHeight = input(false, ...(ngDevMode ? [{ debugName: "fullHeight" }] : []));
1301
+ // Content inputs
1302
+ title = input(...(ngDevMode ? [undefined, { debugName: "title" }] : []));
1303
+ subtitle = input(...(ngDevMode ? [undefined, { debugName: "subtitle" }] : []));
1304
+ avatar = input(...(ngDevMode ? [undefined, { debugName: "avatar" }] : []));
1305
+ icon = input(...(ngDevMode ? [undefined, { debugName: "icon" }] : []));
1306
+ image = input(...(ngDevMode ? [undefined, { debugName: "image" }] : []));
1307
+ imageAlt = input('', ...(ngDevMode ? [{ debugName: "imageAlt" }] : []));
1308
+ imageFit = input('cover', ...(ngDevMode ? [{ debugName: "imageFit" }] : []));
1309
+ // Visibility inputs
1310
+ showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
1311
+ showMedia = input(true, ...(ngDevMode ? [{ debugName: "showMedia" }] : []));
1312
+ showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
1313
+ divider = input(false, ...(ngDevMode ? [{ debugName: "divider" }] : []));
1314
+ // Interaction inputs
1315
+ hoverable = input(false, ...(ngDevMode ? [{ debugName: "hoverable" }] : []));
1316
+ pressable = input(false, ...(ngDevMode ? [{ debugName: "pressable" }] : []));
1317
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1318
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1319
+ href = input(...(ngDevMode ? [undefined, { debugName: "href" }] : []));
1320
+ target = input('_self', ...(ngDevMode ? [{ debugName: "target" }] : []));
1321
+ // Effects
1322
+ blurred = input(false, ...(ngDevMode ? [{ debugName: "blurred" }] : []));
1323
+ blurredFooter = input(false, ...(ngDevMode ? [{ debugName: "blurredFooter" }] : []));
1324
+ animated = input(false, ...(ngDevMode ? [{ debugName: "animated" }] : []));
1325
+ // Outputs
1326
+ clicked = output();
1327
+ headerAction = output();
1328
+ // Template refs
1329
+ headerTemplate = contentChild('cardHeader', ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
1330
+ headerActionsTemplate = contentChild('cardHeaderActions', ...(ngDevMode ? [{ debugName: "headerActionsTemplate" }] : []));
1331
+ mediaTemplate = contentChild('cardMedia', ...(ngDevMode ? [{ debugName: "mediaTemplate" }] : []));
1332
+ bodyTemplate = contentChild('cardBody', ...(ngDevMode ? [{ debugName: "bodyTemplate" }] : []));
1333
+ footerTemplate = contentChild('cardFooter', ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
1334
+ // Computed
1335
+ iconSize = computed(() => {
1336
+ const sizeMap = { sm: 18, md: 20, lg: 24 };
1337
+ return sizeMap[this.size()];
1338
+ }, ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
1339
+ hostClasses = computed(() => classNames('studio-card', `studio-card--${this.variant()}`, `studio-card--${this.size()}`, `studio-card--${this.color()}`, `studio-card--radius-${this.radius()}`, `studio-card--shadow-${this.shadow()}`, `studio-card--padding-${this.padding()}`, `studio-card--${this.orientation()}`, this.imagePosition() !== 'top' && `studio-card--image-${this.imagePosition()}`, this.fullWidth() && 'studio-card--full-width', this.fullHeight() && 'studio-card--full-height', this.hoverable() && 'studio-card--hoverable', this.pressable() && 'studio-card--pressable', this.disabled() && 'studio-card--disabled', this.loading() && 'studio-card--loading', this.blurred() && 'studio-card--blurred', this.blurredFooter() && 'studio-card--blurred-footer', this.animated() && 'studio-card--animated', this.divider() && 'studio-card--divider', this.href() && 'studio-card--clickable'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1340
+ handleClick(event) {
1341
+ if (this.disabled() || this.loading()) {
1342
+ event.preventDefault();
1343
+ event.stopPropagation();
1344
+ return;
1345
+ }
1346
+ const url = this.href();
1347
+ if (url) {
1348
+ const safeUrl = sanitizeUrl(url);
1349
+ if (safeUrl === '#') {
1350
+ return;
1351
+ }
1352
+ const target = this.target();
1353
+ if (target === '_blank') {
1354
+ window.open(safeUrl, '_blank', 'noopener,noreferrer');
1355
+ }
1356
+ else {
1357
+ window.location.href = safeUrl;
1358
+ }
1359
+ }
1360
+ this.clicked.emit(event);
1361
+ }
1362
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1363
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: CardComponent, isStandalone: true, selector: "studio-card", inputs: { variantInput: { classPropertyName: "variantInput", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, sizeInput: { classPropertyName: "sizeInput", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, colorInput: { classPropertyName: "colorInput", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, radiusInput: { classPropertyName: "radiusInput", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, shadowInput: { classPropertyName: "shadowInput", publicName: "shadow", isSignal: true, isRequired: false, transformFunction: null }, paddingInput: { classPropertyName: "paddingInput", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, imagePosition: { classPropertyName: "imagePosition", publicName: "imagePosition", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, fullHeight: { classPropertyName: "fullHeight", publicName: "fullHeight", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, avatar: { classPropertyName: "avatar", publicName: "avatar", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, image: { classPropertyName: "image", publicName: "image", isSignal: true, isRequired: false, transformFunction: null }, imageAlt: { classPropertyName: "imageAlt", publicName: "imageAlt", isSignal: true, isRequired: false, transformFunction: null }, imageFit: { classPropertyName: "imageFit", publicName: "imageFit", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, showMedia: { classPropertyName: "showMedia", publicName: "showMedia", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, divider: { classPropertyName: "divider", publicName: "divider", isSignal: true, isRequired: false, transformFunction: null }, hoverable: { classPropertyName: "hoverable", publicName: "hoverable", isSignal: true, isRequired: false, transformFunction: null }, pressable: { classPropertyName: "pressable", publicName: "pressable", 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 }, href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, blurred: { classPropertyName: "blurred", publicName: "blurred", isSignal: true, isRequired: false, transformFunction: null }, blurredFooter: { classPropertyName: "blurredFooter", publicName: "blurredFooter", isSignal: true, isRequired: false, transformFunction: null }, animated: { classPropertyName: "animated", publicName: "animated", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked", headerAction: "headerAction" }, host: { listeners: { "click": "handleClick($event)" }, properties: { "class": "hostClasses()", "attr.href": "href()", "attr.target": "href() ? target() : null", "attr.rel": "href() && target() === \"_blank\" ? \"noopener noreferrer\" : null", "attr.disabled": "disabled() ? \"\" : null" } }, queries: [{ propertyName: "headerTemplate", first: true, predicate: ["cardHeader"], descendants: true, isSignal: true }, { propertyName: "headerActionsTemplate", first: true, predicate: ["cardHeaderActions"], descendants: true, isSignal: true }, { propertyName: "mediaTemplate", first: true, predicate: ["cardMedia"], descendants: true, isSignal: true }, { propertyName: "bodyTemplate", first: true, predicate: ["cardBody"], descendants: true, isSignal: true }, { propertyName: "footerTemplate", first: true, predicate: ["cardFooter"], descendants: true, isSignal: true }], ngImport: i0, template: `
1364
+ <div class="studio-card__container">
1365
+ <!-- Header -->
1366
+ @if (showHeader() && (headerTemplate() || title() || subtitle())) {
1367
+ <div class="studio-card__header">
1368
+ @if (headerTemplate()) {
1369
+ <ng-container *ngTemplateOutlet="headerTemplate()!" />
1370
+ } @else {
1371
+ <div class="studio-card__header-content">
1372
+ @if (avatar()) {
1373
+ <img [src]="avatar()!" alt="" class="studio-card__avatar" />
1374
+ }
1375
+ @if (icon() && !avatar()) {
1376
+ <div class="studio-card__icon-wrapper">
1377
+ <studio-icon [name]="icon()!" [size]="iconSize()" />
1378
+ </div>
1379
+ }
1380
+ <div class="studio-card__header-text">
1381
+ @if (title()) {
1382
+ <h3 class="studio-card__title">{{ title() }}</h3>
1383
+ }
1384
+ @if (subtitle()) {
1385
+ <p class="studio-card__subtitle">{{ subtitle() }}</p>
1386
+ }
1387
+ </div>
1388
+ </div>
1389
+ @if (headerActionsTemplate()) {
1390
+ <div class="studio-card__header-actions">
1391
+ <ng-container *ngTemplateOutlet="headerActionsTemplate()!" />
1392
+ </div>
1393
+ }
1394
+ }
1395
+ </div>
1396
+ }
1397
+
1398
+ <!-- Media -->
1399
+ @if (showMedia() && (mediaTemplate() || image())) {
1400
+ <div class="studio-card__media">
1401
+ @if (mediaTemplate()) {
1402
+ <ng-container *ngTemplateOutlet="mediaTemplate()!" />
1403
+ } @else if (image()) {
1404
+ <img
1405
+ [src]="image()!"
1406
+ [alt]="imageAlt()"
1407
+ class="studio-card__image"
1408
+ [class.studio-card__image--cover]="imageFit() === 'cover'"
1409
+ [class.studio-card__image--contain]="imageFit() === 'contain'"
1410
+ />
1411
+ }
1412
+ </div>
1413
+ }
1414
+
1415
+ <!-- Body -->
1416
+ <div class="studio-card__body">
1417
+ @if (bodyTemplate()) {
1418
+ <ng-container *ngTemplateOutlet="bodyTemplate()!" />
1419
+ } @else {
1420
+ <ng-content />
1421
+ }
1422
+ </div>
1423
+
1424
+ <!-- Footer -->
1425
+ @if (showFooter() && footerTemplate()) {
1426
+ <div class="studio-card__footer">
1427
+ <ng-container *ngTemplateOutlet="footerTemplate()!" />
1428
+ </div>
1429
+ }
1430
+
1431
+ <!-- Loading overlay -->
1432
+ @if (loading()) {
1433
+ <div class="studio-card__loading">
1434
+ <studio-icon name="loader-2" [size]="24" class="studio-card__spinner" />
1435
+ </div>
1436
+ }
1437
+ </div>
1438
+ `, isInline: true, styles: [":host{display:block;font-family:var(--studio-font-family);position:relative;transition:all var(--studio-transition-normal)}.studio-card__container{display:flex;flex-direction:column;height:100%;overflow:hidden;position:relative}:host(.studio-card--sm) .studio-card__container{min-height:8rem}:host(.studio-card--md) .studio-card__container{min-height:12rem}:host(.studio-card--lg) .studio-card__container{min-height:16rem}:host(.studio-card--radius-none) .studio-card__container{border-radius:var(--studio-radius-none)}:host(.studio-card--radius-sm) .studio-card__container{border-radius:var(--studio-radius-sm)}:host(.studio-card--radius-md) .studio-card__container{border-radius:var(--studio-radius-md)}:host(.studio-card--radius-lg) .studio-card__container{border-radius:var(--studio-radius-lg)}:host(.studio-card--radius-xl) .studio-card__container{border-radius:var(--studio-radius-xl)}:host(.studio-card--shadow-none) .studio-card__container{box-shadow:none}:host(.studio-card--shadow-sm) .studio-card__container{box-shadow:var(--studio-shadow-sm)}:host(.studio-card--shadow-md) .studio-card__container{box-shadow:var(--studio-shadow-md)}:host(.studio-card--shadow-lg) .studio-card__container{box-shadow:var(--studio-shadow-lg)}:host(.studio-card--shadow-xl) .studio-card__container{box-shadow:var(--studio-shadow-xl)}:host(.studio-card--elevated.studio-card--default) .studio-card__container{background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary)}:host(.studio-card--filled.studio-card--default) .studio-card__container{background:var(--studio-bg-secondary);border:1px solid transparent}:host(.studio-card--outlined.studio-card--default) .studio-card__container{background:transparent;border:2px solid var(--studio-border-primary)}:host(.studio-card--ghost.studio-card--default) .studio-card__container{background:transparent;border:1px solid transparent}:host(.studio-card--elevated.studio-card--primary) .studio-card__container{background:var(--studio-primary-bg);border:1px solid var(--studio-primary)}:host(.studio-card--filled.studio-card--primary) .studio-card__container{background:var(--studio-primary);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--primary) .studio-card__container{background:transparent;border:2px solid var(--studio-primary);color:var(--studio-primary)}:host(.studio-card--ghost.studio-card--primary) .studio-card__container{background:var(--studio-primary-bg);border:1px solid transparent;color:var(--studio-primary)}:host(.studio-card--elevated.studio-card--secondary) .studio-card__container{background:var(--studio-bg-primary);border:1px solid var(--studio-text-secondary)}:host(.studio-card--filled.studio-card--secondary) .studio-card__container{background:var(--studio-text-secondary);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--secondary) .studio-card__container{background:transparent;border:2px solid var(--studio-text-secondary);color:var(--studio-text-secondary)}:host(.studio-card--ghost.studio-card--secondary) .studio-card__container{background:var(--studio-bg-secondary);border:1px solid transparent;color:var(--studio-text-secondary)}:host(.studio-card--elevated.studio-card--success) .studio-card__container{background:var(--studio-success-bg);border:1px solid var(--studio-success)}:host(.studio-card--filled.studio-card--success) .studio-card__container{background:var(--studio-success);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--success) .studio-card__container{background:transparent;border:2px solid var(--studio-success);color:var(--studio-success)}:host(.studio-card--ghost.studio-card--success) .studio-card__container{background:var(--studio-success-bg);border:1px solid transparent;color:var(--studio-success)}:host(.studio-card--elevated.studio-card--error) .studio-card__container{background:var(--studio-error-bg);border:1px solid var(--studio-error)}:host(.studio-card--filled.studio-card--error) .studio-card__container{background:var(--studio-error);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--error) .studio-card__container{background:transparent;border:2px solid var(--studio-error);color:var(--studio-error)}:host(.studio-card--ghost.studio-card--error) .studio-card__container{background:var(--studio-error-bg);border:1px solid transparent;color:var(--studio-error)}:host(.studio-card--elevated.studio-card--warning) .studio-card__container{background:var(--studio-warning-bg);border:1px solid var(--studio-warning)}:host(.studio-card--filled.studio-card--warning) .studio-card__container{background:var(--studio-warning);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--warning) .studio-card__container{background:transparent;border:2px solid var(--studio-warning);color:var(--studio-warning)}:host(.studio-card--ghost.studio-card--warning) .studio-card__container{background:var(--studio-warning-bg);border:1px solid transparent;color:var(--studio-warning)}:host(.studio-card--elevated.studio-card--neutral) .studio-card__container{background:var(--studio-bg-tertiary);border:1px solid var(--studio-border-secondary)}:host(.studio-card--filled.studio-card--neutral) .studio-card__container{background:var(--studio-bg-secondary);border:1px solid transparent}:host(.studio-card--outlined.studio-card--neutral) .studio-card__container{background:transparent;border:2px solid var(--studio-border-secondary)}:host(.studio-card--ghost.studio-card--neutral) .studio-card__container{background:transparent;border:1px solid transparent}:host(.studio-card--padding-none) .studio-card__header,:host(.studio-card--padding-none) .studio-card__body,:host(.studio-card--padding-none) .studio-card__footer{padding:0}:host(.studio-card--padding-sm) .studio-card__header,:host(.studio-card--padding-sm) .studio-card__footer{padding:var(--studio-spacing-sm)}:host(.studio-card--padding-sm) .studio-card__body{padding:var(--studio-spacing-sm)}:host(.studio-card--padding-md) .studio-card__header,:host(.studio-card--padding-md) .studio-card__footer{padding:var(--studio-spacing-md)}:host(.studio-card--padding-md) .studio-card__body{padding:var(--studio-spacing-md)}:host(.studio-card--padding-lg) .studio-card__header,:host(.studio-card--padding-lg) .studio-card__footer{padding:var(--studio-spacing-lg)}:host(.studio-card--padding-lg) .studio-card__body{padding:var(--studio-spacing-lg)}.studio-card__header{display:flex;align-items:center;justify-content:space-between;gap:var(--studio-spacing-md);flex-shrink:0}:host(.studio-card--divider) .studio-card__header{border-bottom:1px solid var(--studio-border-primary)}.studio-card__header-content{display:flex;align-items:center;gap:var(--studio-spacing-md);flex:1;min-width:0}.studio-card__avatar{width:2.5rem;height:2.5rem;border-radius:50%;object-fit:cover;flex-shrink:0}.studio-card__icon-wrapper{display:flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border-radius:50%;background:var(--studio-bg-secondary);flex-shrink:0}.studio-card__header-text{flex:1;min-width:0}.studio-card__title{margin:0;font-size:var(--studio-font-size-lg);font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.studio-card__subtitle{margin:.25rem 0 0;font-size:var(--studio-font-size-sm);color:var(--studio-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.studio-card__header-actions{display:flex;align-items:center;gap:var(--studio-spacing-sm);flex-shrink:0}.studio-card__media{flex-shrink:0;overflow:hidden;position:relative}:host(.studio-card--padding-none) .studio-card__media{margin:0}:host(.studio-card--padding-sm) .studio-card__media{margin:var(--studio-spacing-sm);margin-top:0}:host(.studio-card--padding-md) .studio-card__media{margin:var(--studio-spacing-md);margin-top:0}:host(.studio-card--padding-lg) .studio-card__media{margin:var(--studio-spacing-lg);margin-top:0}.studio-card__image{width:100%;height:auto;display:block;border-radius:var(--studio-radius-sm)}.studio-card__image--cover{object-fit:cover;height:12rem}.studio-card__image--contain{object-fit:contain;max-height:16rem}.studio-card__body{flex:1;overflow-y:auto}.studio-card__footer{display:flex;align-items:center;gap:var(--studio-spacing-md);flex-shrink:0}:host(.studio-card--divider) .studio-card__footer{border-top:1px solid var(--studio-border-primary)}:host(.studio-card--blurred-footer) .studio-card__footer{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);background:#ffffff1a;border-top:1px solid rgba(255,255,255,.2)}:host(.studio-card--horizontal) .studio-card__container{flex-direction:row}:host(.studio-card--horizontal) .studio-card__media{width:40%;margin:0}:host(.studio-card--horizontal) .studio-card__body{flex:1}:host(.studio-card--full-width){width:100%}:host(.studio-card--full-height){height:100%}:host(.studio-card--full-height) .studio-card__container{height:100%}:host(.studio-card--hoverable) .studio-card__container{cursor:pointer;transition:all var(--studio-transition-normal)}:host(.studio-card--hoverable:hover:not(.studio-card--disabled)) .studio-card__container{transform:translateY(-2px);box-shadow:var(--studio-shadow-lg)}:host(.studio-card--pressable) .studio-card__container{cursor:pointer;transition:all var(--studio-transition-fast)}:host(.studio-card--pressable:active:not(.studio-card--disabled)) .studio-card__container{transform:scale(.98)}:host(.studio-card--clickable) .studio-card__container{cursor:pointer}:host(.studio-card--disabled){pointer-events:none;opacity:.5}:host(.studio-card--blurred) .studio-card__container{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);background:#ffffff1a!important;border:1px solid rgba(255,255,255,.2)}:host(.studio-card--animated){animation:cardFadeIn .3s ease-out}@keyframes cardFadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.studio-card__loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#ffffffe6;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:10}.studio-card__spinner{animation:spin 1s linear infinite;color:var(--studio-primary)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host(.studio-card--loading) .studio-card__container{pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.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 });
1439
+ }
1440
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: CardComponent, decorators: [{
1441
+ type: Component,
1442
+ args: [{ selector: 'studio-card', standalone: true, imports: [CommonModule, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1443
+ '[class]': 'hostClasses()',
1444
+ '[attr.href]': 'href()',
1445
+ '[attr.target]': 'href() ? target() : null',
1446
+ '[attr.rel]': 'href() && target() === "_blank" ? "noopener noreferrer" : null',
1447
+ '[attr.disabled]': 'disabled() ? "" : null',
1448
+ '(click)': 'handleClick($event)'
1449
+ }, template: `
1450
+ <div class="studio-card__container">
1451
+ <!-- Header -->
1452
+ @if (showHeader() && (headerTemplate() || title() || subtitle())) {
1453
+ <div class="studio-card__header">
1454
+ @if (headerTemplate()) {
1455
+ <ng-container *ngTemplateOutlet="headerTemplate()!" />
1456
+ } @else {
1457
+ <div class="studio-card__header-content">
1458
+ @if (avatar()) {
1459
+ <img [src]="avatar()!" alt="" class="studio-card__avatar" />
1460
+ }
1461
+ @if (icon() && !avatar()) {
1462
+ <div class="studio-card__icon-wrapper">
1463
+ <studio-icon [name]="icon()!" [size]="iconSize()" />
1464
+ </div>
1465
+ }
1466
+ <div class="studio-card__header-text">
1467
+ @if (title()) {
1468
+ <h3 class="studio-card__title">{{ title() }}</h3>
1469
+ }
1470
+ @if (subtitle()) {
1471
+ <p class="studio-card__subtitle">{{ subtitle() }}</p>
1472
+ }
1473
+ </div>
1474
+ </div>
1475
+ @if (headerActionsTemplate()) {
1476
+ <div class="studio-card__header-actions">
1477
+ <ng-container *ngTemplateOutlet="headerActionsTemplate()!" />
1478
+ </div>
1479
+ }
1480
+ }
1481
+ </div>
1482
+ }
1483
+
1484
+ <!-- Media -->
1485
+ @if (showMedia() && (mediaTemplate() || image())) {
1486
+ <div class="studio-card__media">
1487
+ @if (mediaTemplate()) {
1488
+ <ng-container *ngTemplateOutlet="mediaTemplate()!" />
1489
+ } @else if (image()) {
1490
+ <img
1491
+ [src]="image()!"
1492
+ [alt]="imageAlt()"
1493
+ class="studio-card__image"
1494
+ [class.studio-card__image--cover]="imageFit() === 'cover'"
1495
+ [class.studio-card__image--contain]="imageFit() === 'contain'"
1496
+ />
1497
+ }
1498
+ </div>
1499
+ }
1500
+
1501
+ <!-- Body -->
1502
+ <div class="studio-card__body">
1503
+ @if (bodyTemplate()) {
1504
+ <ng-container *ngTemplateOutlet="bodyTemplate()!" />
1505
+ } @else {
1506
+ <ng-content />
1507
+ }
1508
+ </div>
1509
+
1510
+ <!-- Footer -->
1511
+ @if (showFooter() && footerTemplate()) {
1512
+ <div class="studio-card__footer">
1513
+ <ng-container *ngTemplateOutlet="footerTemplate()!" />
1514
+ </div>
1515
+ }
1516
+
1517
+ <!-- Loading overlay -->
1518
+ @if (loading()) {
1519
+ <div class="studio-card__loading">
1520
+ <studio-icon name="loader-2" [size]="24" class="studio-card__spinner" />
1521
+ </div>
1522
+ }
1523
+ </div>
1524
+ `, styles: [":host{display:block;font-family:var(--studio-font-family);position:relative;transition:all var(--studio-transition-normal)}.studio-card__container{display:flex;flex-direction:column;height:100%;overflow:hidden;position:relative}:host(.studio-card--sm) .studio-card__container{min-height:8rem}:host(.studio-card--md) .studio-card__container{min-height:12rem}:host(.studio-card--lg) .studio-card__container{min-height:16rem}:host(.studio-card--radius-none) .studio-card__container{border-radius:var(--studio-radius-none)}:host(.studio-card--radius-sm) .studio-card__container{border-radius:var(--studio-radius-sm)}:host(.studio-card--radius-md) .studio-card__container{border-radius:var(--studio-radius-md)}:host(.studio-card--radius-lg) .studio-card__container{border-radius:var(--studio-radius-lg)}:host(.studio-card--radius-xl) .studio-card__container{border-radius:var(--studio-radius-xl)}:host(.studio-card--shadow-none) .studio-card__container{box-shadow:none}:host(.studio-card--shadow-sm) .studio-card__container{box-shadow:var(--studio-shadow-sm)}:host(.studio-card--shadow-md) .studio-card__container{box-shadow:var(--studio-shadow-md)}:host(.studio-card--shadow-lg) .studio-card__container{box-shadow:var(--studio-shadow-lg)}:host(.studio-card--shadow-xl) .studio-card__container{box-shadow:var(--studio-shadow-xl)}:host(.studio-card--elevated.studio-card--default) .studio-card__container{background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary)}:host(.studio-card--filled.studio-card--default) .studio-card__container{background:var(--studio-bg-secondary);border:1px solid transparent}:host(.studio-card--outlined.studio-card--default) .studio-card__container{background:transparent;border:2px solid var(--studio-border-primary)}:host(.studio-card--ghost.studio-card--default) .studio-card__container{background:transparent;border:1px solid transparent}:host(.studio-card--elevated.studio-card--primary) .studio-card__container{background:var(--studio-primary-bg);border:1px solid var(--studio-primary)}:host(.studio-card--filled.studio-card--primary) .studio-card__container{background:var(--studio-primary);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--primary) .studio-card__container{background:transparent;border:2px solid var(--studio-primary);color:var(--studio-primary)}:host(.studio-card--ghost.studio-card--primary) .studio-card__container{background:var(--studio-primary-bg);border:1px solid transparent;color:var(--studio-primary)}:host(.studio-card--elevated.studio-card--secondary) .studio-card__container{background:var(--studio-bg-primary);border:1px solid var(--studio-text-secondary)}:host(.studio-card--filled.studio-card--secondary) .studio-card__container{background:var(--studio-text-secondary);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--secondary) .studio-card__container{background:transparent;border:2px solid var(--studio-text-secondary);color:var(--studio-text-secondary)}:host(.studio-card--ghost.studio-card--secondary) .studio-card__container{background:var(--studio-bg-secondary);border:1px solid transparent;color:var(--studio-text-secondary)}:host(.studio-card--elevated.studio-card--success) .studio-card__container{background:var(--studio-success-bg);border:1px solid var(--studio-success)}:host(.studio-card--filled.studio-card--success) .studio-card__container{background:var(--studio-success);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--success) .studio-card__container{background:transparent;border:2px solid var(--studio-success);color:var(--studio-success)}:host(.studio-card--ghost.studio-card--success) .studio-card__container{background:var(--studio-success-bg);border:1px solid transparent;color:var(--studio-success)}:host(.studio-card--elevated.studio-card--error) .studio-card__container{background:var(--studio-error-bg);border:1px solid var(--studio-error)}:host(.studio-card--filled.studio-card--error) .studio-card__container{background:var(--studio-error);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--error) .studio-card__container{background:transparent;border:2px solid var(--studio-error);color:var(--studio-error)}:host(.studio-card--ghost.studio-card--error) .studio-card__container{background:var(--studio-error-bg);border:1px solid transparent;color:var(--studio-error)}:host(.studio-card--elevated.studio-card--warning) .studio-card__container{background:var(--studio-warning-bg);border:1px solid var(--studio-warning)}:host(.studio-card--filled.studio-card--warning) .studio-card__container{background:var(--studio-warning);color:#fff;border:1px solid transparent}:host(.studio-card--outlined.studio-card--warning) .studio-card__container{background:transparent;border:2px solid var(--studio-warning);color:var(--studio-warning)}:host(.studio-card--ghost.studio-card--warning) .studio-card__container{background:var(--studio-warning-bg);border:1px solid transparent;color:var(--studio-warning)}:host(.studio-card--elevated.studio-card--neutral) .studio-card__container{background:var(--studio-bg-tertiary);border:1px solid var(--studio-border-secondary)}:host(.studio-card--filled.studio-card--neutral) .studio-card__container{background:var(--studio-bg-secondary);border:1px solid transparent}:host(.studio-card--outlined.studio-card--neutral) .studio-card__container{background:transparent;border:2px solid var(--studio-border-secondary)}:host(.studio-card--ghost.studio-card--neutral) .studio-card__container{background:transparent;border:1px solid transparent}:host(.studio-card--padding-none) .studio-card__header,:host(.studio-card--padding-none) .studio-card__body,:host(.studio-card--padding-none) .studio-card__footer{padding:0}:host(.studio-card--padding-sm) .studio-card__header,:host(.studio-card--padding-sm) .studio-card__footer{padding:var(--studio-spacing-sm)}:host(.studio-card--padding-sm) .studio-card__body{padding:var(--studio-spacing-sm)}:host(.studio-card--padding-md) .studio-card__header,:host(.studio-card--padding-md) .studio-card__footer{padding:var(--studio-spacing-md)}:host(.studio-card--padding-md) .studio-card__body{padding:var(--studio-spacing-md)}:host(.studio-card--padding-lg) .studio-card__header,:host(.studio-card--padding-lg) .studio-card__footer{padding:var(--studio-spacing-lg)}:host(.studio-card--padding-lg) .studio-card__body{padding:var(--studio-spacing-lg)}.studio-card__header{display:flex;align-items:center;justify-content:space-between;gap:var(--studio-spacing-md);flex-shrink:0}:host(.studio-card--divider) .studio-card__header{border-bottom:1px solid var(--studio-border-primary)}.studio-card__header-content{display:flex;align-items:center;gap:var(--studio-spacing-md);flex:1;min-width:0}.studio-card__avatar{width:2.5rem;height:2.5rem;border-radius:50%;object-fit:cover;flex-shrink:0}.studio-card__icon-wrapper{display:flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border-radius:50%;background:var(--studio-bg-secondary);flex-shrink:0}.studio-card__header-text{flex:1;min-width:0}.studio-card__title{margin:0;font-size:var(--studio-font-size-lg);font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.studio-card__subtitle{margin:.25rem 0 0;font-size:var(--studio-font-size-sm);color:var(--studio-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.studio-card__header-actions{display:flex;align-items:center;gap:var(--studio-spacing-sm);flex-shrink:0}.studio-card__media{flex-shrink:0;overflow:hidden;position:relative}:host(.studio-card--padding-none) .studio-card__media{margin:0}:host(.studio-card--padding-sm) .studio-card__media{margin:var(--studio-spacing-sm);margin-top:0}:host(.studio-card--padding-md) .studio-card__media{margin:var(--studio-spacing-md);margin-top:0}:host(.studio-card--padding-lg) .studio-card__media{margin:var(--studio-spacing-lg);margin-top:0}.studio-card__image{width:100%;height:auto;display:block;border-radius:var(--studio-radius-sm)}.studio-card__image--cover{object-fit:cover;height:12rem}.studio-card__image--contain{object-fit:contain;max-height:16rem}.studio-card__body{flex:1;overflow-y:auto}.studio-card__footer{display:flex;align-items:center;gap:var(--studio-spacing-md);flex-shrink:0}:host(.studio-card--divider) .studio-card__footer{border-top:1px solid var(--studio-border-primary)}:host(.studio-card--blurred-footer) .studio-card__footer{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);background:#ffffff1a;border-top:1px solid rgba(255,255,255,.2)}:host(.studio-card--horizontal) .studio-card__container{flex-direction:row}:host(.studio-card--horizontal) .studio-card__media{width:40%;margin:0}:host(.studio-card--horizontal) .studio-card__body{flex:1}:host(.studio-card--full-width){width:100%}:host(.studio-card--full-height){height:100%}:host(.studio-card--full-height) .studio-card__container{height:100%}:host(.studio-card--hoverable) .studio-card__container{cursor:pointer;transition:all var(--studio-transition-normal)}:host(.studio-card--hoverable:hover:not(.studio-card--disabled)) .studio-card__container{transform:translateY(-2px);box-shadow:var(--studio-shadow-lg)}:host(.studio-card--pressable) .studio-card__container{cursor:pointer;transition:all var(--studio-transition-fast)}:host(.studio-card--pressable:active:not(.studio-card--disabled)) .studio-card__container{transform:scale(.98)}:host(.studio-card--clickable) .studio-card__container{cursor:pointer}:host(.studio-card--disabled){pointer-events:none;opacity:.5}:host(.studio-card--blurred) .studio-card__container{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);background:#ffffff1a!important;border:1px solid rgba(255,255,255,.2)}:host(.studio-card--animated){animation:cardFadeIn .3s ease-out}@keyframes cardFadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.studio-card__loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#ffffffe6;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:10}.studio-card__spinner{animation:spin 1s linear infinite;color:var(--studio-primary)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host(.studio-card--loading) .studio-card__container{pointer-events:none}\n"] }]
1525
+ }], propDecorators: { variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], sizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], colorInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], radiusInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], shadowInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "shadow", required: false }] }], paddingInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], imagePosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "imagePosition", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], fullHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullHeight", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], avatar: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatar", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], image: [{ type: i0.Input, args: [{ isSignal: true, alias: "image", required: false }] }], imageAlt: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageAlt", required: false }] }], imageFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageFit", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], showMedia: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMedia", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], divider: [{ type: i0.Input, args: [{ isSignal: true, alias: "divider", required: false }] }], hoverable: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverable", required: false }] }], pressable: [{ type: i0.Input, args: [{ isSignal: true, alias: "pressable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], blurred: [{ type: i0.Input, args: [{ isSignal: true, alias: "blurred", required: false }] }], blurredFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "blurredFooter", required: false }] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }], headerAction: [{ type: i0.Output, args: ["headerAction"] }], headerTemplate: [{ type: i0.ContentChild, args: ['cardHeader', { isSignal: true }] }], headerActionsTemplate: [{ type: i0.ContentChild, args: ['cardHeaderActions', { isSignal: true }] }], mediaTemplate: [{ type: i0.ContentChild, args: ['cardMedia', { isSignal: true }] }], bodyTemplate: [{ type: i0.ContentChild, args: ['cardBody', { isSignal: true }] }], footerTemplate: [{ type: i0.ContentChild, args: ['cardFooter', { isSignal: true }] }] } });
1526
+
1527
+ /**
1528
+ * Card component types
1529
+ */
1530
+
1531
+ class ChatMessageComponent {
1532
+ message = input.required(...(ngDevMode ? [{ debugName: "message" }] : []));
1533
+ currentUserId = input.required(...(ngDevMode ? [{ debugName: "currentUserId" }] : []));
1534
+ showAvatar = input(true, ...(ngDevMode ? [{ debugName: "showAvatar" }] : []));
1535
+ showTimestamp = input(true, ...(ngDevMode ? [{ debugName: "showTimestamp" }] : []));
1536
+ showUserName = input(true, ...(ngDevMode ? [{ debugName: "showUserName" }] : []));
1537
+ compact = input(false, ...(ngDevMode ? [{ debugName: "compact" }] : []));
1538
+ isOwn = computed(() => this.message().userId === this.currentUserId(), ...(ngDevMode ? [{ debugName: "isOwn" }] : []));
1539
+ hostClasses = computed(() => {
1540
+ const classes = ['studio-chat-message'];
1541
+ if (this.isOwn())
1542
+ classes.push('chat-message--own');
1543
+ if (this.message().type === 'system')
1544
+ classes.push('chat-message--system');
1545
+ if (this.compact())
1546
+ classes.push('chat-message--compact');
1547
+ if (this.message().status === 'read')
1548
+ classes.push('chat-message--status-read');
1549
+ if (this.message().status === 'error')
1550
+ classes.push('chat-message--status-error');
1551
+ return classes.join(' ');
1552
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1553
+ getInitials(name) {
1554
+ return name
1555
+ .split(' ')
1556
+ .map(n => n[0])
1557
+ .slice(0, 2)
1558
+ .join('')
1559
+ .toUpperCase();
1560
+ }
1561
+ formatTime(date) {
1562
+ const now = new Date();
1563
+ const messageDate = new Date(date);
1564
+ const diff = now.getTime() - messageDate.getTime();
1565
+ const minutes = Math.floor(diff / 60000);
1566
+ const hours = Math.floor(diff / 3600000);
1567
+ const days = Math.floor(diff / 86400000);
1568
+ if (minutes < 1)
1569
+ return 'Just now';
1570
+ if (minutes < 60)
1571
+ return `${minutes}m ago`;
1572
+ if (hours < 24)
1573
+ return `${hours}h ago`;
1574
+ if (days === 1)
1575
+ return 'Yesterday';
1576
+ if (days < 7)
1577
+ return `${days}d ago`;
1578
+ return messageDate.toLocaleDateString('en-US', {
1579
+ month: 'short',
1580
+ day: 'numeric'
1581
+ });
1582
+ }
1583
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ChatMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1584
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: ChatMessageComponent, isStandalone: true, selector: "studio-chat-message", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: true, transformFunction: null }, showAvatar: { classPropertyName: "showAvatar", publicName: "showAvatar", isSignal: true, isRequired: false, transformFunction: null }, showTimestamp: { classPropertyName: "showTimestamp", publicName: "showTimestamp", isSignal: true, isRequired: false, transformFunction: null }, showUserName: { classPropertyName: "showUserName", publicName: "showUserName", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
1585
+ <div class="chat-message__container">
1586
+ @if (showAvatar() && !isOwn()) {
1587
+ <div class="chat-message__avatar">
1588
+ @if (message().userAvatar) {
1589
+ <img [src]="message().userAvatar" [alt]="message().userName" />
1590
+ } @else {
1591
+ <div class="chat-message__avatar-fallback">
1592
+ {{ getInitials(message().userName) }}
1593
+ </div>
1594
+ }
1595
+ </div>
1596
+ }
1597
+
1598
+ <div class="chat-message__content-wrapper">
1599
+ @if (!isOwn() && showUserName()) {
1600
+ <div class="chat-message__user-name">{{ message().userName }}</div>
1601
+ }
1602
+
1603
+ <div class="chat-message__bubble">
1604
+ @if (message().type === 'system') {
1605
+ <div class="chat-message__system">{{ message().content }}</div>
1606
+ } @else {
1607
+ <div class="chat-message__text">{{ message().content }}</div>
1608
+ }
1609
+
1610
+ @if (message().edited) {
1611
+ <span class="chat-message__edited">(edited)</span>
1612
+ }
1613
+ </div>
1614
+
1615
+ <div class="chat-message__meta">
1616
+ @if (showTimestamp()) {
1617
+ <span class="chat-message__time">{{ formatTime(message().timestamp) }}</span>
1618
+ }
1619
+
1620
+ @if (isOwn() && message().status && message().status !== 'sending') {
1621
+ <span class="chat-message__status">
1622
+ @if (message().status === 'sent') {
1623
+ <studio-icon name="check" [size]="12" />
1624
+ }
1625
+ @if (message().status === 'delivered' || message().status === 'read') {
1626
+ <studio-icon name="check-check" [size]="12" />
1627
+ }
1628
+ @if (message().status === 'error') {
1629
+ <studio-icon name="alert-circle" [size]="12" />
1630
+ }
1631
+ </span>
1632
+ }
1633
+ </div>
1634
+ </div>
1635
+ </div>
1636
+ `, isInline: true, styles: [":host{display:block;margin-bottom:.75rem}:host(.chat-message--own) .chat-message__container{justify-content:flex-end}:host(.chat-message--own) .chat-message__bubble{background:var(--studio-primary);color:#fff}:host(.chat-message--own) .chat-message__meta{justify-content:flex-end}:host(.chat-message--system){text-align:center;margin:1rem 0}:host(.chat-message--system) .chat-message__system{display:inline-block;padding:.25rem .75rem;background:var(--studio-bg-secondary);color:var(--studio-text-secondary);border-radius:var(--studio-radius-full);font-size:.75rem}:host(.chat-message--compact){margin-bottom:.25rem}.chat-message__container{display:flex;gap:.75rem;align-items:flex-end}.chat-message__avatar{width:32px;height:32px;border-radius:50%;overflow:hidden;flex-shrink:0}.chat-message__avatar img{width:100%;height:100%;object-fit:cover}.chat-message__avatar-fallback{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:var(--studio-primary);color:#fff;font-size:.75rem;font-weight:600}.chat-message__content-wrapper{max-width:70%;display:flex;flex-direction:column;gap:.25rem}.chat-message__user-name{font-size:.75rem;font-weight:500;color:var(--studio-text-secondary);padding-left:.75rem}.chat-message__bubble{padding:.625rem .875rem;border-radius:var(--studio-radius-lg);background:var(--studio-bg-secondary);color:var(--studio-text-primary);word-wrap:break-word;position:relative}.chat-message__text{white-space:pre-wrap;line-height:1.5}.chat-message__edited{font-size:.6875rem;color:var(--studio-text-tertiary);margin-left:.25rem}.chat-message__meta{display:flex;align-items:center;gap:.25rem;padding:0 .75rem}.chat-message__time{font-size:.6875rem;color:var(--studio-text-tertiary)}.chat-message__status{display:flex;align-items:center;color:var(--studio-text-tertiary)}:host(.chat-message--own) .chat-message__status{color:var(--studio-text-tertiary)}:host(.chat-message--status-read) .chat-message__status{color:var(--studio-primary)}:host(.chat-message--status-error) .chat-message__status{color:var(--studio-error)}:host(.chat-message--compact) .chat-message__avatar{width:24px;height:24px}:host(.chat-message--compact) .chat-message__bubble{padding:.5rem .75rem;font-size:.875rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1637
+ }
1638
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ChatMessageComponent, decorators: [{
1639
+ type: Component,
1640
+ args: [{ selector: 'studio-chat-message', standalone: true, imports: [CommonModule, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1641
+ '[class]': 'hostClasses()'
1642
+ }, template: `
1643
+ <div class="chat-message__container">
1644
+ @if (showAvatar() && !isOwn()) {
1645
+ <div class="chat-message__avatar">
1646
+ @if (message().userAvatar) {
1647
+ <img [src]="message().userAvatar" [alt]="message().userName" />
1648
+ } @else {
1649
+ <div class="chat-message__avatar-fallback">
1650
+ {{ getInitials(message().userName) }}
1651
+ </div>
1652
+ }
1653
+ </div>
1654
+ }
1655
+
1656
+ <div class="chat-message__content-wrapper">
1657
+ @if (!isOwn() && showUserName()) {
1658
+ <div class="chat-message__user-name">{{ message().userName }}</div>
1659
+ }
1660
+
1661
+ <div class="chat-message__bubble">
1662
+ @if (message().type === 'system') {
1663
+ <div class="chat-message__system">{{ message().content }}</div>
1664
+ } @else {
1665
+ <div class="chat-message__text">{{ message().content }}</div>
1666
+ }
1667
+
1668
+ @if (message().edited) {
1669
+ <span class="chat-message__edited">(edited)</span>
1670
+ }
1671
+ </div>
1672
+
1673
+ <div class="chat-message__meta">
1674
+ @if (showTimestamp()) {
1675
+ <span class="chat-message__time">{{ formatTime(message().timestamp) }}</span>
1676
+ }
1677
+
1678
+ @if (isOwn() && message().status && message().status !== 'sending') {
1679
+ <span class="chat-message__status">
1680
+ @if (message().status === 'sent') {
1681
+ <studio-icon name="check" [size]="12" />
1682
+ }
1683
+ @if (message().status === 'delivered' || message().status === 'read') {
1684
+ <studio-icon name="check-check" [size]="12" />
1685
+ }
1686
+ @if (message().status === 'error') {
1687
+ <studio-icon name="alert-circle" [size]="12" />
1688
+ }
1689
+ </span>
1690
+ }
1691
+ </div>
1692
+ </div>
1693
+ </div>
1694
+ `, styles: [":host{display:block;margin-bottom:.75rem}:host(.chat-message--own) .chat-message__container{justify-content:flex-end}:host(.chat-message--own) .chat-message__bubble{background:var(--studio-primary);color:#fff}:host(.chat-message--own) .chat-message__meta{justify-content:flex-end}:host(.chat-message--system){text-align:center;margin:1rem 0}:host(.chat-message--system) .chat-message__system{display:inline-block;padding:.25rem .75rem;background:var(--studio-bg-secondary);color:var(--studio-text-secondary);border-radius:var(--studio-radius-full);font-size:.75rem}:host(.chat-message--compact){margin-bottom:.25rem}.chat-message__container{display:flex;gap:.75rem;align-items:flex-end}.chat-message__avatar{width:32px;height:32px;border-radius:50%;overflow:hidden;flex-shrink:0}.chat-message__avatar img{width:100%;height:100%;object-fit:cover}.chat-message__avatar-fallback{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:var(--studio-primary);color:#fff;font-size:.75rem;font-weight:600}.chat-message__content-wrapper{max-width:70%;display:flex;flex-direction:column;gap:.25rem}.chat-message__user-name{font-size:.75rem;font-weight:500;color:var(--studio-text-secondary);padding-left:.75rem}.chat-message__bubble{padding:.625rem .875rem;border-radius:var(--studio-radius-lg);background:var(--studio-bg-secondary);color:var(--studio-text-primary);word-wrap:break-word;position:relative}.chat-message__text{white-space:pre-wrap;line-height:1.5}.chat-message__edited{font-size:.6875rem;color:var(--studio-text-tertiary);margin-left:.25rem}.chat-message__meta{display:flex;align-items:center;gap:.25rem;padding:0 .75rem}.chat-message__time{font-size:.6875rem;color:var(--studio-text-tertiary)}.chat-message__status{display:flex;align-items:center;color:var(--studio-text-tertiary)}:host(.chat-message--own) .chat-message__status{color:var(--studio-text-tertiary)}:host(.chat-message--status-read) .chat-message__status{color:var(--studio-primary)}:host(.chat-message--status-error) .chat-message__status{color:var(--studio-error)}:host(.chat-message--compact) .chat-message__avatar{width:24px;height:24px}:host(.chat-message--compact) .chat-message__bubble{padding:.5rem .75rem;font-size:.875rem}\n"] }]
1695
+ }], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], currentUserId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUserId", required: true }] }], showAvatar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAvatar", required: false }] }], showTimestamp: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTimestamp", required: false }] }], showUserName: [{ type: i0.Input, args: [{ isSignal: true, alias: "showUserName", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }] } });
1696
+
1697
+ class ChatInputComponent {
1698
+ placeholder = input('Type a message...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
1699
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1700
+ compact = input(false, ...(ngDevMode ? [{ debugName: "compact" }] : []));
1701
+ messageSubmit = output();
1702
+ typing = output();
1703
+ inputValue = signal('', ...(ngDevMode ? [{ debugName: "inputValue" }] : []));
1704
+ textareaRef = viewChild('textareaRef', ...(ngDevMode ? [{ debugName: "textareaRef" }] : []));
1705
+ typingTimeout;
1706
+ canSend = computed(() => this.inputValue().trim().length > 0 && !this.disabled(), ...(ngDevMode ? [{ debugName: "canSend" }] : []));
1707
+ hostClasses = computed(() => {
1708
+ const classes = ['studio-chat-input'];
1709
+ if (this.compact())
1710
+ classes.push('chat-input--compact');
1711
+ return classes.join(' ');
1712
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1713
+ constructor() {
1714
+ // Auto-resize textarea
1715
+ effect(() => {
1716
+ const textarea = this.textareaRef()?.nativeElement;
1717
+ if (textarea) {
1718
+ textarea.style.height = 'auto';
1719
+ textarea.style.height = textarea.scrollHeight + 'px';
1720
+ }
1721
+ });
1722
+ }
1723
+ onKeyDown(event) {
1724
+ if (event.key === 'Enter' && !event.shiftKey) {
1725
+ event.preventDefault();
1726
+ this.handleSubmit();
1727
+ }
1728
+ }
1729
+ onInput() {
1730
+ // Emit typing indicator
1731
+ this.typing.emit(true);
1732
+ // Clear previous timeout
1733
+ if (this.typingTimeout) {
1734
+ clearTimeout(this.typingTimeout);
1735
+ }
1736
+ // Set new timeout to stop typing after 1 second
1737
+ this.typingTimeout = setTimeout(() => {
1738
+ this.typing.emit(false);
1739
+ }, 1000);
1740
+ // Auto-resize
1741
+ const textarea = this.textareaRef()?.nativeElement;
1742
+ if (textarea) {
1743
+ textarea.style.height = 'auto';
1744
+ textarea.style.height = textarea.scrollHeight + 'px';
1745
+ }
1746
+ }
1747
+ handleSubmit() {
1748
+ const content = this.inputValue().trim();
1749
+ if (content && !this.disabled()) {
1750
+ this.messageSubmit.emit({ content });
1751
+ this.inputValue.set('');
1752
+ // Reset textarea height
1753
+ const textarea = this.textareaRef()?.nativeElement;
1754
+ if (textarea) {
1755
+ textarea.style.height = 'auto';
1756
+ }
1757
+ // Stop typing indicator
1758
+ if (this.typingTimeout) {
1759
+ clearTimeout(this.typingTimeout);
1760
+ }
1761
+ this.typing.emit(false);
1762
+ }
1763
+ }
1764
+ focus() {
1765
+ this.textareaRef()?.nativeElement.focus();
1766
+ }
1767
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ChatInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1768
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.12", type: ChatInputComponent, isStandalone: true, selector: "studio-chat-input", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { messageSubmit: "messageSubmit", typing: "typing" }, host: { properties: { "class": "hostClasses()" } }, viewQueries: [{ propertyName: "textareaRef", first: true, predicate: ["textareaRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
1769
+ <div class="chat-input__container">
1770
+ <textarea
1771
+ #textareaRef
1772
+ class="chat-input__textarea"
1773
+ [placeholder]="placeholder()"
1774
+ [disabled]="disabled()"
1775
+ [(ngModel)]="inputValue"
1776
+ (keydown)="onKeyDown($event)"
1777
+ (input)="onInput()"
1778
+ rows="1"
1779
+ ></textarea>
1780
+
1781
+ <studio-button
1782
+ variant="ghost"
1783
+ size="sm"
1784
+ [disabled]="!canSend()"
1785
+ (click)="handleSubmit()"
1786
+ class="chat-input__send-button"
1787
+ >
1788
+ <studio-icon name="send" [size]="20" />
1789
+ </studio-button>
1790
+ </div>
1791
+ `, isInline: true, styles: [":host{display:block}.chat-input__container{display:flex;align-items:flex-end;gap:.5rem;padding:1rem;background:var(--studio-bg-primary);border-top:1px solid var(--studio-border-primary)}.chat-input__textarea{flex:1;min-height:40px;max-height:120px;padding:.625rem .875rem;border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);background:var(--studio-bg-primary);color:var(--studio-text-primary);font-family:inherit;font-size:.875rem;line-height:1.5;resize:none;overflow-y:auto;transition:border-color .15s ease}.chat-input__textarea:focus{outline:none;border-color:var(--studio-primary)}.chat-input__textarea:disabled{opacity:.5;cursor:not-allowed}.chat-input__textarea::placeholder{color:var(--studio-text-tertiary)}.chat-input__send-button{flex-shrink:0}:host(.chat-input--compact) .chat-input__container{padding:.75rem}:host(.chat-input--compact) .chat-input__textarea{padding:.5rem .75rem;font-size:.8125rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }, { kind: "component", type: ButtonComponent, selector: "studio-button", inputs: ["variant", "size", "color", "radius", "shadow", "compact", "disabled", "loading", "loadingText", "fullWidth", "type", "icon", "iconPosition", "href", "target", "badge", "badgeColor", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1792
+ }
1793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ChatInputComponent, decorators: [{
1794
+ type: Component,
1795
+ args: [{ selector: 'studio-chat-input', standalone: true, imports: [CommonModule, FormsModule, IconComponent, ButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1796
+ '[class]': 'hostClasses()'
1797
+ }, template: `
1798
+ <div class="chat-input__container">
1799
+ <textarea
1800
+ #textareaRef
1801
+ class="chat-input__textarea"
1802
+ [placeholder]="placeholder()"
1803
+ [disabled]="disabled()"
1804
+ [(ngModel)]="inputValue"
1805
+ (keydown)="onKeyDown($event)"
1806
+ (input)="onInput()"
1807
+ rows="1"
1808
+ ></textarea>
1809
+
1810
+ <studio-button
1811
+ variant="ghost"
1812
+ size="sm"
1813
+ [disabled]="!canSend()"
1814
+ (click)="handleSubmit()"
1815
+ class="chat-input__send-button"
1816
+ >
1817
+ <studio-icon name="send" [size]="20" />
1818
+ </studio-button>
1819
+ </div>
1820
+ `, styles: [":host{display:block}.chat-input__container{display:flex;align-items:flex-end;gap:.5rem;padding:1rem;background:var(--studio-bg-primary);border-top:1px solid var(--studio-border-primary)}.chat-input__textarea{flex:1;min-height:40px;max-height:120px;padding:.625rem .875rem;border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);background:var(--studio-bg-primary);color:var(--studio-text-primary);font-family:inherit;font-size:.875rem;line-height:1.5;resize:none;overflow-y:auto;transition:border-color .15s ease}.chat-input__textarea:focus{outline:none;border-color:var(--studio-primary)}.chat-input__textarea:disabled{opacity:.5;cursor:not-allowed}.chat-input__textarea::placeholder{color:var(--studio-text-tertiary)}.chat-input__send-button{flex-shrink:0}:host(.chat-input--compact) .chat-input__container{padding:.75rem}:host(.chat-input--compact) .chat-input__textarea{padding:.5rem .75rem;font-size:.8125rem}\n"] }]
1821
+ }], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], messageSubmit: [{ type: i0.Output, args: ["messageSubmit"] }], typing: [{ type: i0.Output, args: ["typing"] }], textareaRef: [{ type: i0.ViewChild, args: ['textareaRef', { isSignal: true }] }] } });
1822
+
1823
+ /**
1824
+ * Chat component - Flexible chat/messaging component
1825
+ *
1826
+ * @example
1827
+ * <studio-chat
1828
+ * [messages]="messages"
1829
+ * [currentUserId]="currentUser.id"
1830
+ * variant="default"
1831
+ * (messageSubmit)="handleMessage($event)"
1832
+ * />
1833
+ */
1834
+ class ChatComponent {
1835
+ // ========== Required ==========
1836
+ messages = input.required(...(ngDevMode ? [{ debugName: "messages" }] : []));
1837
+ currentUserId = input.required(...(ngDevMode ? [{ debugName: "currentUserId" }] : []));
1838
+ // ========== Appearance ==========
1839
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
1840
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
1841
+ height = input('600px', ...(ngDevMode ? [{ debugName: "height" }] : []));
1842
+ // ========== Behavior ==========
1843
+ placeholder = input('Type a message...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
1844
+ showAvatars = input(true, ...(ngDevMode ? [{ debugName: "showAvatars" }] : []));
1845
+ showTimestamps = input(true, ...(ngDevMode ? [{ debugName: "showTimestamps" }] : []));
1846
+ showUserNames = input(true, ...(ngDevMode ? [{ debugName: "showUserNames" }] : []));
1847
+ enableAutoScroll = input(true, ...(ngDevMode ? [{ debugName: "enableAutoScroll" }] : []));
1848
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1849
+ // ========== Customization ==========
1850
+ class = input('', ...(ngDevMode ? [{ debugName: "class" }] : []));
1851
+ // ========== Outputs ==========
1852
+ messageSubmit = output();
1853
+ typing = output();
1854
+ // ========== State ==========
1855
+ messagesContainerRef = viewChild('messagesContainer', ...(ngDevMode ? [{ debugName: "messagesContainerRef" }] : []));
1856
+ isScrolledUp = signal(false, ...(ngDevMode ? [{ debugName: "isScrolledUp" }] : []));
1857
+ shouldAutoScroll = signal(true, ...(ngDevMode ? [{ debugName: "shouldAutoScroll" }] : []));
1858
+ hostClasses = computed(() => {
1859
+ const classes = ['studio-chat'];
1860
+ classes.push(`studio-chat--${this.variant()}`);
1861
+ classes.push(`studio-chat--${this.size()}`);
1862
+ if (this.disabled())
1863
+ classes.push('studio-chat--disabled');
1864
+ if (this.class())
1865
+ classes.push(this.class());
1866
+ return classes.join(' ');
1867
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
1868
+ isCompact = computed(() => this.variant() === 'compact' || this.variant() === 'minimal', ...(ngDevMode ? [{ debugName: "isCompact" }] : []));
1869
+ constructor() {
1870
+ // Auto-scroll when new messages arrive
1871
+ effect(() => {
1872
+ const messages = this.messages();
1873
+ if (messages.length > 0 && this.shouldAutoScroll() && this.enableAutoScroll()) {
1874
+ setTimeout(() => this.scrollToBottom(), 0);
1875
+ }
1876
+ });
1877
+ }
1878
+ ngAfterViewInit() {
1879
+ this.scrollToBottom();
1880
+ }
1881
+ onScroll() {
1882
+ const container = this.messagesContainerRef()?.nativeElement;
1883
+ if (!container)
1884
+ return;
1885
+ const isAtBottom = container.scrollHeight - container.scrollTop - container.clientHeight < 50;
1886
+ this.isScrolledUp.set(!isAtBottom);
1887
+ this.shouldAutoScroll.set(isAtBottom);
1888
+ }
1889
+ onMessageSubmit(event) {
1890
+ this.messageSubmit.emit(event);
1891
+ this.shouldAutoScroll.set(true);
1892
+ }
1893
+ scrollToBottom() {
1894
+ const container = this.messagesContainerRef()?.nativeElement;
1895
+ if (container) {
1896
+ container.scrollTop = container.scrollHeight;
1897
+ this.isScrolledUp.set(false);
1898
+ this.shouldAutoScroll.set(true);
1899
+ }
1900
+ }
1901
+ onTyping(typing) {
1902
+ this.typing.emit(typing);
1903
+ }
1904
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1905
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: ChatComponent, isStandalone: true, selector: "studio-chat", inputs: { messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: true, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, showAvatars: { classPropertyName: "showAvatars", publicName: "showAvatars", isSignal: true, isRequired: false, transformFunction: null }, showTimestamps: { classPropertyName: "showTimestamps", publicName: "showTimestamps", isSignal: true, isRequired: false, transformFunction: null }, showUserNames: { classPropertyName: "showUserNames", publicName: "showUserNames", isSignal: true, isRequired: false, transformFunction: null }, enableAutoScroll: { classPropertyName: "enableAutoScroll", publicName: "enableAutoScroll", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { messageSubmit: "messageSubmit", typing: "typing" }, host: { properties: { "class": "hostClasses()", "style.height": "height()" } }, viewQueries: [{ propertyName: "messagesContainerRef", first: true, predicate: ["messagesContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"chat__container\">\n <div\n #messagesContainer\n class=\"chat__messages\"\n (scroll)=\"onScroll()\"\n >\n @if (messages().length === 0) {\n <div class=\"chat__empty\">\n <studio-icon name=\"message-circle\" [size]=\"48\" />\n <p>No messages yet</p>\n <small>Start a conversation</small>\n </div>\n } @else {\n @for (message of messages(); track message.id || $index) {\n <studio-chat-message\n [message]=\"message\"\n [currentUserId]=\"currentUserId()\"\n [showAvatar]=\"showAvatars()\"\n [showTimestamp]=\"showTimestamps()\"\n [showUserName]=\"showUserNames()\"\n [compact]=\"isCompact()\"\n />\n }\n }\n </div>\n\n @if (isScrolledUp()) {\n <button\n class=\"chat__scroll-button\"\n (click)=\"scrollToBottom()\"\n type=\"button\"\n >\n <studio-icon name=\"arrow-down\" [size]=\"20\" />\n </button>\n }\n\n <studio-chat-input\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [compact]=\"isCompact()\"\n (messageSubmit)=\"onMessageSubmit($event)\"\n (typing)=\"onTyping($event)\"\n />\n</div>\n", styles: [":host{display:block;position:relative;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-lg);overflow:hidden}.chat__container{display:flex;flex-direction:column;height:100%}.chat__messages{flex:1;overflow-y:auto;padding:1.5rem;display:flex;flex-direction:column;scroll-behavior:smooth}.chat__messages::-webkit-scrollbar{width:6px}.chat__messages::-webkit-scrollbar-track{background:var(--studio-bg-secondary)}.chat__messages::-webkit-scrollbar-thumb{background:var(--studio-border-primary);border-radius:var(--studio-radius-full)}.chat__messages::-webkit-scrollbar-thumb:hover{background:var(--studio-text-tertiary)}.chat__empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;color:var(--studio-text-secondary);padding:3rem 1.5rem}.chat__empty p{margin:0;font-size:1rem;font-weight:500}.chat__empty small{font-size:.875rem;color:var(--studio-text-tertiary)}.chat__scroll-button{position:absolute;bottom:100px;right:1.5rem;width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:50%;box-shadow:0 2px 8px #0000001a;cursor:pointer;transition:all .15s ease;color:var(--studio-text-primary);z-index:10}.chat__scroll-button:hover{background:var(--studio-bg-hover);transform:scale(1.05)}.chat__scroll-button:active{transform:scale(.95)}:host(.studio-chat--compact) .chat__messages{padding:1rem}:host(.studio-chat--compact) .chat__scroll-button{bottom:80px}:host(.studio-chat--minimal){border:none;background:transparent}:host(.studio-chat--minimal) .chat__messages{padding:1rem}:host(.studio-chat--bubbles) .chat__messages{padding:1rem}:host(.studio-chat--sm) .chat__messages{padding:1rem;font-size:.875rem}:host(.studio-chat--sm) .chat__scroll-button{width:36px;height:36px;bottom:90px}:host(.studio-chat--lg) .chat__messages{padding:2rem;font-size:1rem}:host(.studio-chat--lg) .chat__scroll-button{width:44px;height:44px;bottom:110px}:host(.studio-chat--disabled){opacity:.6;pointer-events:none}@media (max-width: 640px){.chat__messages{padding:1rem}.chat__scroll-button{bottom:90px;right:1rem}}@media (prefers-reduced-motion: reduce){.chat__messages{scroll-behavior:auto}.chat__scroll-button{transition:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ChatMessageComponent, selector: "studio-chat-message", inputs: ["message", "currentUserId", "showAvatar", "showTimestamp", "showUserName", "compact"] }, { kind: "component", type: ChatInputComponent, selector: "studio-chat-input", inputs: ["placeholder", "disabled", "compact"], outputs: ["messageSubmit", "typing"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1906
+ }
1907
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ChatComponent, decorators: [{
1908
+ type: Component,
1909
+ args: [{ selector: 'studio-chat', standalone: true, imports: [
1910
+ CommonModule,
1911
+ ChatMessageComponent,
1912
+ ChatInputComponent,
1913
+ IconComponent
1914
+ ], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1915
+ '[class]': 'hostClasses()',
1916
+ '[style.height]': 'height()'
1917
+ }, template: "<div class=\"chat__container\">\n <div\n #messagesContainer\n class=\"chat__messages\"\n (scroll)=\"onScroll()\"\n >\n @if (messages().length === 0) {\n <div class=\"chat__empty\">\n <studio-icon name=\"message-circle\" [size]=\"48\" />\n <p>No messages yet</p>\n <small>Start a conversation</small>\n </div>\n } @else {\n @for (message of messages(); track message.id || $index) {\n <studio-chat-message\n [message]=\"message\"\n [currentUserId]=\"currentUserId()\"\n [showAvatar]=\"showAvatars()\"\n [showTimestamp]=\"showTimestamps()\"\n [showUserName]=\"showUserNames()\"\n [compact]=\"isCompact()\"\n />\n }\n }\n </div>\n\n @if (isScrolledUp()) {\n <button\n class=\"chat__scroll-button\"\n (click)=\"scrollToBottom()\"\n type=\"button\"\n >\n <studio-icon name=\"arrow-down\" [size]=\"20\" />\n </button>\n }\n\n <studio-chat-input\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [compact]=\"isCompact()\"\n (messageSubmit)=\"onMessageSubmit($event)\"\n (typing)=\"onTyping($event)\"\n />\n</div>\n", styles: [":host{display:block;position:relative;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-lg);overflow:hidden}.chat__container{display:flex;flex-direction:column;height:100%}.chat__messages{flex:1;overflow-y:auto;padding:1.5rem;display:flex;flex-direction:column;scroll-behavior:smooth}.chat__messages::-webkit-scrollbar{width:6px}.chat__messages::-webkit-scrollbar-track{background:var(--studio-bg-secondary)}.chat__messages::-webkit-scrollbar-thumb{background:var(--studio-border-primary);border-radius:var(--studio-radius-full)}.chat__messages::-webkit-scrollbar-thumb:hover{background:var(--studio-text-tertiary)}.chat__empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;color:var(--studio-text-secondary);padding:3rem 1.5rem}.chat__empty p{margin:0;font-size:1rem;font-weight:500}.chat__empty small{font-size:.875rem;color:var(--studio-text-tertiary)}.chat__scroll-button{position:absolute;bottom:100px;right:1.5rem;width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:var(--studio-bg-primary);border:1px solid var(--studio-border-primary);border-radius:50%;box-shadow:0 2px 8px #0000001a;cursor:pointer;transition:all .15s ease;color:var(--studio-text-primary);z-index:10}.chat__scroll-button:hover{background:var(--studio-bg-hover);transform:scale(1.05)}.chat__scroll-button:active{transform:scale(.95)}:host(.studio-chat--compact) .chat__messages{padding:1rem}:host(.studio-chat--compact) .chat__scroll-button{bottom:80px}:host(.studio-chat--minimal){border:none;background:transparent}:host(.studio-chat--minimal) .chat__messages{padding:1rem}:host(.studio-chat--bubbles) .chat__messages{padding:1rem}:host(.studio-chat--sm) .chat__messages{padding:1rem;font-size:.875rem}:host(.studio-chat--sm) .chat__scroll-button{width:36px;height:36px;bottom:90px}:host(.studio-chat--lg) .chat__messages{padding:2rem;font-size:1rem}:host(.studio-chat--lg) .chat__scroll-button{width:44px;height:44px;bottom:110px}:host(.studio-chat--disabled){opacity:.6;pointer-events:none}@media (max-width: 640px){.chat__messages{padding:1rem}.chat__scroll-button{bottom:90px;right:1rem}}@media (prefers-reduced-motion: reduce){.chat__messages{scroll-behavior:auto}.chat__scroll-button{transition:none}}\n"] }]
1918
+ }], ctorParameters: () => [], propDecorators: { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: true }] }], currentUserId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUserId", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], showAvatars: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAvatars", required: false }] }], showTimestamps: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTimestamps", required: false }] }], showUserNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "showUserNames", required: false }] }], enableAutoScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableAutoScroll", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], messageSubmit: [{ type: i0.Output, args: ["messageSubmit"] }], typing: [{ type: i0.Output, args: ["typing"] }], messagesContainerRef: [{ type: i0.ViewChild, args: ['messagesContainer', { isSignal: true }] }] } });
1919
+
1270
1920
  /**
1271
1921
  * Checkbox component for selecting boolean values
1272
1922
  *
@@ -4379,6 +5029,452 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
4379
5029
  * Switch component
4380
5030
  */
4381
5031
 
5032
+ /**
5033
+ * Directive for declarative column definition
5034
+ *
5035
+ * @example
5036
+ * <studio-table-column
5037
+ * key="name"
5038
+ * label="Name"
5039
+ * [sortable]="true">
5040
+ * <ng-template let-row>{{ row.name }}</ng-template>
5041
+ * </studio-table-column>
5042
+ */
5043
+ class TableColumnDirective {
5044
+ key;
5045
+ label;
5046
+ field;
5047
+ width;
5048
+ minWidth;
5049
+ maxWidth;
5050
+ sortable;
5051
+ sortFn;
5052
+ filterable;
5053
+ align;
5054
+ fixed;
5055
+ hideOnMobile;
5056
+ priority;
5057
+ cellClass;
5058
+ headerClass;
5059
+ formatter;
5060
+ resizable;
5061
+ template;
5062
+ /**
5063
+ * Convert directive inputs to TableColumn config
5064
+ */
5065
+ toColumnConfig() {
5066
+ return {
5067
+ key: this.key,
5068
+ label: this.label,
5069
+ field: this.field,
5070
+ width: this.width,
5071
+ minWidth: this.minWidth,
5072
+ maxWidth: this.maxWidth,
5073
+ sortable: this.sortable,
5074
+ sortFn: this.sortFn,
5075
+ filterable: this.filterable,
5076
+ align: this.align,
5077
+ fixed: this.fixed,
5078
+ hideOnMobile: this.hideOnMobile,
5079
+ priority: this.priority,
5080
+ cellTemplate: this.template,
5081
+ cellClass: this.cellClass,
5082
+ headerClass: this.headerClass,
5083
+ formatter: this.formatter,
5084
+ resizable: this.resizable
5085
+ };
5086
+ }
5087
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TableColumnDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
5088
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.12", type: TableColumnDirective, isStandalone: true, selector: "studio-table-column", inputs: { key: "key", label: "label", field: "field", width: "width", minWidth: "minWidth", maxWidth: "maxWidth", sortable: "sortable", sortFn: "sortFn", filterable: "filterable", align: "align", fixed: "fixed", hideOnMobile: "hideOnMobile", priority: "priority", cellClass: "cellClass", headerClass: "headerClass", formatter: "formatter", resizable: "resizable" }, queries: [{ propertyName: "template", first: true, predicate: TemplateRef, descendants: true }], ngImport: i0 });
5089
+ }
5090
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TableColumnDirective, decorators: [{
5091
+ type: Directive,
5092
+ args: [{
5093
+ selector: 'studio-table-column',
5094
+ standalone: true
5095
+ }]
5096
+ }], propDecorators: { key: [{
5097
+ type: Input,
5098
+ args: [{ required: true }]
5099
+ }], label: [{
5100
+ type: Input,
5101
+ args: [{ required: true }]
5102
+ }], field: [{
5103
+ type: Input
5104
+ }], width: [{
5105
+ type: Input
5106
+ }], minWidth: [{
5107
+ type: Input
5108
+ }], maxWidth: [{
5109
+ type: Input
5110
+ }], sortable: [{
5111
+ type: Input
5112
+ }], sortFn: [{
5113
+ type: Input
5114
+ }], filterable: [{
5115
+ type: Input
5116
+ }], align: [{
5117
+ type: Input
5118
+ }], fixed: [{
5119
+ type: Input
5120
+ }], hideOnMobile: [{
5121
+ type: Input
5122
+ }], priority: [{
5123
+ type: Input
5124
+ }], cellClass: [{
5125
+ type: Input
5126
+ }], headerClass: [{
5127
+ type: Input
5128
+ }], formatter: [{
5129
+ type: Input
5130
+ }], resizable: [{
5131
+ type: Input
5132
+ }], template: [{
5133
+ type: ContentChild,
5134
+ args: [TemplateRef]
5135
+ }] } });
5136
+
5137
+ /**
5138
+ * Enterprise-grade Table component with full feature set
5139
+ *
5140
+ * @example
5141
+ * <studio-table
5142
+ * [data]="users"
5143
+ * [columns]="columns"
5144
+ * selectionMode="multiple"
5145
+ * [(selected)]="selectedUsers">
5146
+ * </studio-table>
5147
+ */
5148
+ class TableComponent {
5149
+ configService = inject(StudioConfigService);
5150
+ tableDefaults = computed(() => this.configService.config().components?.table, ...(ngDevMode ? [{ debugName: "tableDefaults" }] : []));
5151
+ // Config inputs with defaults
5152
+ variantInput = input(undefined, ...(ngDevMode ? [{ debugName: "variantInput", alias: 'variant' }] : [{ alias: 'variant' }]));
5153
+ densityInput = input(undefined, ...(ngDevMode ? [{ debugName: "densityInput", alias: 'density' }] : [{ alias: 'density' }]));
5154
+ variant = withConfigDefault(this.variantInput, computed(() => this.tableDefaults()?.variant), 'default');
5155
+ density = withConfigDefault(this.densityInput, computed(() => this.tableDefaults()?.density), 'comfortable');
5156
+ // Data inputs
5157
+ data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
5158
+ columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
5159
+ rowKey = input('id', ...(ngDevMode ? [{ debugName: "rowKey" }] : []));
5160
+ // Column directives (declarative mode)
5161
+ columnDirectives = contentChildren(TableColumnDirective, ...(ngDevMode ? [{ debugName: "columnDirectives" }] : []));
5162
+ // Features
5163
+ selectionMode = input('none', ...(ngDevMode ? [{ debugName: "selectionMode" }] : []));
5164
+ sortable = input(true, ...(ngDevMode ? [{ debugName: "sortable" }] : []));
5165
+ sortMode = input('client', ...(ngDevMode ? [{ debugName: "sortMode" }] : []));
5166
+ hoverable = input(true, ...(ngDevMode ? [{ debugName: "hoverable" }] : []));
5167
+ stickyHeader = input(false, ...(ngDevMode ? [{ debugName: "stickyHeader" }] : []));
5168
+ showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
5169
+ // Row expansion
5170
+ expandable = input(false, ...(ngDevMode ? [{ debugName: "expandable" }] : []));
5171
+ expandedRowTemplate = contentChild('expandedRow', ...(ngDevMode ? [{ debugName: "expandedRowTemplate" }] : []));
5172
+ expandMultiple = input(false, ...(ngDevMode ? [{ debugName: "expandMultiple" }] : []));
5173
+ // Loading & Empty states
5174
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
5175
+ loadingRows = input(5, ...(ngDevMode ? [{ debugName: "loadingRows" }] : []));
5176
+ emptyState = input({
5177
+ icon: 'inbox',
5178
+ title: 'No data',
5179
+ message: 'No data available to display'
5180
+ }, ...(ngDevMode ? [{ debugName: "emptyState" }] : []));
5181
+ // Row actions
5182
+ rowActions = input([], ...(ngDevMode ? [{ debugName: "rowActions" }] : []));
5183
+ // Responsive
5184
+ responsive = input(true, ...(ngDevMode ? [{ debugName: "responsive" }] : []));
5185
+ mobileBreakpoint = input(768, ...(ngDevMode ? [{ debugName: "mobileBreakpoint" }] : []));
5186
+ // State models
5187
+ selected = model([], ...(ngDevMode ? [{ debugName: "selected" }] : []));
5188
+ sort = model(null, ...(ngDevMode ? [{ debugName: "sort" }] : []));
5189
+ expanded = model(new Set(), ...(ngDevMode ? [{ debugName: "expanded" }] : []));
5190
+ // Outputs
5191
+ sortChange = output();
5192
+ selectionChange = output();
5193
+ rowClick = output();
5194
+ rowDblClick = output();
5195
+ // Internal state
5196
+ currentSort = signal(null, ...(ngDevMode ? [{ debugName: "currentSort" }] : []));
5197
+ selectedRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedRows" }] : []));
5198
+ expandedRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedRows" }] : []));
5199
+ // Computed columns (merge programmatic + declarative)
5200
+ finalColumns = computed(() => {
5201
+ const programmatic = this.columns();
5202
+ const declarative = this.columnDirectives().map(dir => dir.toColumnConfig());
5203
+ return declarative.length > 0 ? declarative : programmatic;
5204
+ }, ...(ngDevMode ? [{ debugName: "finalColumns" }] : []));
5205
+ // Computed data (sorted, filtered)
5206
+ processedData = computed(() => {
5207
+ let result = [...this.data()];
5208
+ // Apply sorting (client-side only)
5209
+ if (this.sortMode() === 'client' && this.currentSort()) {
5210
+ result = this.applySorting(result);
5211
+ }
5212
+ return result;
5213
+ }, ...(ngDevMode ? [{ debugName: "processedData" }] : []));
5214
+ // Selection helpers
5215
+ allSelected = computed(() => {
5216
+ const data = this.processedData();
5217
+ const selected = this.selectedRows();
5218
+ return data.length > 0 && data.every(row => selected.has(this.getRowKey(row)));
5219
+ }, ...(ngDevMode ? [{ debugName: "allSelected" }] : []));
5220
+ someSelected = computed(() => {
5221
+ const data = this.processedData();
5222
+ const selected = this.selectedRows();
5223
+ return data.some(row => selected.has(this.getRowKey(row))) && !this.allSelected();
5224
+ }, ...(ngDevMode ? [{ debugName: "someSelected" }] : []));
5225
+ hostClasses = computed(() => classNames('studio-table', `studio-table--${this.variant()}`, `studio-table--${this.density()}`, this.hoverable() && 'studio-table--hoverable', this.stickyHeader() && 'studio-table--sticky-header', this.loading() && 'studio-table--loading', this.responsive() && 'studio-table--responsive'), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
5226
+ constructor() {
5227
+ // Sync model signals
5228
+ effect(() => {
5229
+ const sortVal = this.sort();
5230
+ if (sortVal)
5231
+ this.currentSort.set(sortVal);
5232
+ });
5233
+ effect(() => {
5234
+ const current = this.currentSort();
5235
+ if (current)
5236
+ this.sort.set(current);
5237
+ });
5238
+ effect(() => {
5239
+ const selected = this.selected();
5240
+ const keys = new Set(selected.map(row => this.getRowKey(row)));
5241
+ this.selectedRows.set(keys);
5242
+ });
5243
+ effect(() => {
5244
+ const expanded = this.expanded();
5245
+ this.expandedRows.set(expanded);
5246
+ });
5247
+ }
5248
+ // Public API
5249
+ sortBy(column, direction) {
5250
+ if (!column.sortable && !this.sortable())
5251
+ return;
5252
+ const currentSort = this.currentSort();
5253
+ const prevDirection = currentSort?.column === column.key ? currentSort.direction : null;
5254
+ // Toggle: asc -> desc -> null
5255
+ let newDirection = direction || 'asc';
5256
+ if (!direction) {
5257
+ if (prevDirection === 'asc')
5258
+ newDirection = 'desc';
5259
+ else if (prevDirection === 'desc')
5260
+ newDirection = null;
5261
+ }
5262
+ if (newDirection) {
5263
+ this.currentSort.set({ column: column.key, direction: newDirection });
5264
+ this.sortChange.emit({
5265
+ column,
5266
+ direction: newDirection,
5267
+ previousDirection: prevDirection
5268
+ });
5269
+ }
5270
+ else {
5271
+ this.currentSort.set(null);
5272
+ }
5273
+ }
5274
+ selectRow(row) {
5275
+ if (this.selectionMode() === 'none')
5276
+ return;
5277
+ const rowKey = this.getRowKey(row);
5278
+ const selected = new Set(this.selectedRows());
5279
+ if (this.selectionMode() === 'single') {
5280
+ selected.clear();
5281
+ selected.add(rowKey);
5282
+ }
5283
+ else {
5284
+ if (selected.has(rowKey)) {
5285
+ selected.delete(rowKey);
5286
+ }
5287
+ else {
5288
+ selected.add(rowKey);
5289
+ }
5290
+ }
5291
+ this.selectedRows.set(selected);
5292
+ this.updateSelectedModel();
5293
+ this.selectionChange.emit({
5294
+ selected: this.getSelectedRows(),
5295
+ row,
5296
+ isSelected: selected.has(rowKey)
5297
+ });
5298
+ }
5299
+ selectAll(select) {
5300
+ if (this.selectionMode() !== 'multiple')
5301
+ return;
5302
+ const selected = new Set();
5303
+ if (select) {
5304
+ this.processedData().forEach(row => {
5305
+ selected.add(this.getRowKey(row));
5306
+ });
5307
+ }
5308
+ this.selectedRows.set(selected);
5309
+ this.updateSelectedModel();
5310
+ this.selectionChange.emit({
5311
+ selected: this.getSelectedRows(),
5312
+ isSelected: select
5313
+ });
5314
+ }
5315
+ toggleRowExpansion(row) {
5316
+ if (!this.expandable())
5317
+ return;
5318
+ const rowKey = this.getRowKey(row);
5319
+ const expanded = new Set(this.expandedRows());
5320
+ if (!this.expandMultiple()) {
5321
+ expanded.clear();
5322
+ }
5323
+ if (expanded.has(rowKey)) {
5324
+ expanded.delete(rowKey);
5325
+ }
5326
+ else {
5327
+ expanded.add(rowKey);
5328
+ }
5329
+ this.expandedRows.set(expanded);
5330
+ this.expanded.set(expanded);
5331
+ }
5332
+ isRowExpanded(row) {
5333
+ return this.expandedRows().has(this.getRowKey(row));
5334
+ }
5335
+ isRowSelected(row) {
5336
+ return this.selectedRows().has(this.getRowKey(row));
5337
+ }
5338
+ getCellValue(row, column) {
5339
+ if (column.field) {
5340
+ if (typeof column.field === 'function') {
5341
+ return column.field(row);
5342
+ }
5343
+ return row[column.field];
5344
+ }
5345
+ return row[column.key];
5346
+ }
5347
+ getHeaderClass(column) {
5348
+ const classes = ['studio-table__th'];
5349
+ if (column.headerClass)
5350
+ classes.push(column.headerClass);
5351
+ if (column.sortable)
5352
+ classes.push('studio-table__th--sortable');
5353
+ if (this.currentSort()?.column === column.key)
5354
+ classes.push('studio-table__th--sorted');
5355
+ const align = column.align || 'left';
5356
+ classes.push(`studio-table__th--align-${align}`);
5357
+ if (column.fixed)
5358
+ classes.push(`studio-table__th--fixed-${column.fixed}`);
5359
+ if (column.hideOnMobile)
5360
+ classes.push('studio-table__th--hide-mobile');
5361
+ return classes.join(' ');
5362
+ }
5363
+ getCellClass(row, column) {
5364
+ if (typeof column.cellClass === 'function') {
5365
+ return column.cellClass(row);
5366
+ }
5367
+ return column.cellClass || '';
5368
+ }
5369
+ getFullCellClass(row, column) {
5370
+ const classes = ['studio-table__td'];
5371
+ const customClass = this.getCellClass(row, column);
5372
+ if (customClass)
5373
+ classes.push(customClass);
5374
+ const align = column.align || 'left';
5375
+ classes.push(`studio-table__td--align-${align}`);
5376
+ if (column.fixed)
5377
+ classes.push(`studio-table__td--fixed-${column.fixed}`);
5378
+ if (column.hideOnMobile)
5379
+ classes.push('studio-table__td--hide-mobile');
5380
+ return classes.join(' ');
5381
+ }
5382
+ getCellContext(row, column, index) {
5383
+ const value = this.getCellValue(row, column);
5384
+ return {
5385
+ $implicit: value,
5386
+ row,
5387
+ column,
5388
+ index
5389
+ };
5390
+ }
5391
+ getHeaderContext(column) {
5392
+ const currentSort = this.currentSort();
5393
+ return {
5394
+ column,
5395
+ sorted: currentSort?.column === column.key,
5396
+ direction: currentSort?.column === column.key ? currentSort.direction : null
5397
+ };
5398
+ }
5399
+ getSortIcon(column) {
5400
+ const currentSort = this.currentSort();
5401
+ if (currentSort?.column !== column.key)
5402
+ return 'arrow-up-down';
5403
+ return currentSort.direction === 'asc' ? 'arrow-up' : 'arrow-down';
5404
+ }
5405
+ handleRowClick(row, event) {
5406
+ if (event.target.closest('.studio-table__actions'))
5407
+ return;
5408
+ this.rowClick.emit(row);
5409
+ }
5410
+ handleRowDblClick(row) {
5411
+ this.rowDblClick.emit(row);
5412
+ }
5413
+ executeRowAction(action, row, event) {
5414
+ event.stopPropagation();
5415
+ if (action.disabled && action.disabled(row))
5416
+ return;
5417
+ action.handler(row);
5418
+ }
5419
+ isActionVisible(action, row) {
5420
+ return !action.visible || action.visible(row);
5421
+ }
5422
+ isActionDisabled(action, row) {
5423
+ return action.disabled ? action.disabled(row) : false;
5424
+ }
5425
+ // Public helpers for template
5426
+ getRowKey(row) {
5427
+ const keyFn = this.rowKey();
5428
+ if (typeof keyFn === 'function') {
5429
+ return keyFn(row);
5430
+ }
5431
+ return row[keyFn];
5432
+ }
5433
+ getSelectedRows() {
5434
+ const selected = this.selectedRows();
5435
+ return this.processedData().filter(row => selected.has(this.getRowKey(row)));
5436
+ }
5437
+ updateSelectedModel() {
5438
+ this.selected.set(this.getSelectedRows());
5439
+ }
5440
+ applySorting(data) {
5441
+ const sortConfig = this.currentSort();
5442
+ if (!sortConfig)
5443
+ return data;
5444
+ const column = this.finalColumns().find(col => col.key === sortConfig.column);
5445
+ if (!column)
5446
+ return data;
5447
+ return [...data].sort((a, b) => {
5448
+ if (column.sortFn) {
5449
+ return column.sortFn(a, b, sortConfig.direction);
5450
+ }
5451
+ const aVal = this.getCellValue(a, column);
5452
+ const bVal = this.getCellValue(b, column);
5453
+ if (aVal === bVal)
5454
+ return 0;
5455
+ if (aVal == null)
5456
+ return 1;
5457
+ if (bVal == null)
5458
+ return -1;
5459
+ const comparison = aVal < bVal ? -1 : 1;
5460
+ return sortConfig.direction === 'asc' ? comparison : -comparison;
5461
+ });
5462
+ }
5463
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5464
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: TableComponent, isStandalone: true, selector: "studio-table", inputs: { variantInput: { classPropertyName: "variantInput", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, densityInput: { classPropertyName: "densityInput", publicName: "density", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rowKey: { classPropertyName: "rowKey", publicName: "rowKey", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, sortable: { classPropertyName: "sortable", publicName: "sortable", isSignal: true, isRequired: false, transformFunction: null }, sortMode: { classPropertyName: "sortMode", publicName: "sortMode", isSignal: true, isRequired: false, transformFunction: null }, hoverable: { classPropertyName: "hoverable", publicName: "hoverable", isSignal: true, isRequired: false, transformFunction: null }, stickyHeader: { classPropertyName: "stickyHeader", publicName: "stickyHeader", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "expandable", isSignal: true, isRequired: false, transformFunction: null }, expandMultiple: { classPropertyName: "expandMultiple", publicName: "expandMultiple", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingRows: { classPropertyName: "loadingRows", publicName: "loadingRows", isSignal: true, isRequired: false, transformFunction: null }, emptyState: { classPropertyName: "emptyState", publicName: "emptyState", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, mobileBreakpoint: { classPropertyName: "mobileBreakpoint", publicName: "mobileBreakpoint", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange", sort: "sortChange", expanded: "expandedChange", sortChange: "sortChange", selectionChange: "selectionChange", rowClick: "rowClick", rowDblClick: "rowDblClick" }, host: { properties: { "class": "hostClasses()" } }, queries: [{ propertyName: "columnDirectives", predicate: TableColumnDirective, isSignal: true }, { propertyName: "expandedRowTemplate", first: true, predicate: ["expandedRow"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"studio-table__wrapper\">\n <!-- Loading Overlay -->\n @if (loading()) {\n <div class=\"studio-table__loading-overlay\">\n <studio-icon name=\"loader-2\" [size]=\"32\" class=\"studio-table__spinner\" />\n </div>\n }\n\n <!-- Table Container -->\n <div class=\"studio-table__container\">\n <table class=\"studio-table__table\">\n <!-- Header -->\n @if (showHeader()) {\n <thead class=\"studio-table__thead\">\n <tr class=\"studio-table__header-row\">\n <!-- Selection Column -->\n @if (selectionMode() === 'multiple') {\n <th class=\"studio-table__th studio-table__th--selection\">\n <studio-checkbox\n [value]=\"allSelected()\"\n [indeterminate]=\"someSelected()\"\n (changed)=\"selectAll($event)\"\n />\n </th>\n }\n\n <!-- Expansion Column -->\n @if (expandable()) {\n <th class=\"studio-table__th studio-table__th--expand\"></th>\n }\n\n <!-- Data Columns -->\n @for (column of finalColumns(); track column.key) {\n <th\n [class]=\"getHeaderClass(column)\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth\"\n [style.max-width]=\"column.maxWidth\"\n (click)=\"column.sortable && sortBy(column)\">\n\n <div class=\"studio-table__header-content\">\n @if (column.headerTemplate) {\n <ng-container *ngTemplateOutlet=\"column.headerTemplate; context: getHeaderContext(column)\" />\n } @else {\n <span>{{ column.label }}</span>\n @if (column.sortable && sortable()) {\n <studio-icon\n [name]=\"getSortIcon(column)\"\n [size]=\"16\"\n class=\"studio-table__sort-icon\"\n />\n }\n }\n </div>\n </th>\n }\n\n <!-- Actions Column -->\n @if (rowActions().length > 0) {\n <th class=\"studio-table__th studio-table__th--actions\">Actions</th>\n }\n </tr>\n </thead>\n }\n\n <!-- Body -->\n <tbody class=\"studio-table__tbody\">\n <!-- Loading Skeleton -->\n @if (loading()) {\n @for (i of [].constructor(loadingRows()); track i) {\n <tr class=\"studio-table__row studio-table__row--loading\">\n @if (selectionMode() === 'multiple') {\n <td class=\"studio-table__td\">\n <div class=\"studio-table__skeleton studio-table__skeleton--checkbox\"></div>\n </td>\n }\n @if (expandable()) {\n <td class=\"studio-table__td\">\n <div class=\"studio-table__skeleton studio-table__skeleton--icon\"></div>\n </td>\n }\n @for (column of finalColumns(); track column.key) {\n <td class=\"studio-table__td\" [class.studio-table__th--hide-mobile]=\"column.hideOnMobile\">\n <div class=\"studio-table__skeleton\"></div>\n </td>\n }\n @if (rowActions().length > 0) {\n <td class=\"studio-table__td\">\n <div class=\"studio-table__skeleton studio-table__skeleton--icon\"></div>\n </td>\n }\n </tr>\n }\n }\n\n <!-- Empty State -->\n @if (!loading() && processedData().length === 0) {\n <tr class=\"studio-table__row studio-table__row--empty\">\n <td [attr.colspan]=\"finalColumns().length + (selectionMode() === 'multiple' ? 1 : 0) + (expandable() ? 1 : 0) + (rowActions().length > 0 ? 1 : 0)\" class=\"studio-table__td\">\n <div class=\"studio-table__empty\">\n <studio-icon [name]=\"emptyState().icon || 'inbox'\" [size]=\"48\" class=\"studio-table__empty-icon\" />\n <h3 class=\"studio-table__empty-title\">{{ emptyState().title }}</h3>\n <p class=\"studio-table__empty-message\">{{ emptyState().message }}</p>\n @if (emptyState().action) {\n <studio-button\n size=\"sm\"\n (clicked)=\"emptyState().action!.handler()\">\n {{ emptyState().action!.label }}\n </studio-button>\n }\n </div>\n </td>\n </tr>\n }\n\n <!-- Data Rows -->\n @if (!loading()) {\n @for (row of processedData(); track getRowKey(row); let rowIndex = $index) {\n <!-- Main Row -->\n <tr\n class=\"studio-table__row\"\n [class.studio-table__row--selected]=\"isRowSelected(row)\"\n [class.studio-table__row--expanded]=\"isRowExpanded(row)\"\n [class.studio-table__row--clickable]=\"selectionMode() === 'single'\"\n (click)=\"selectionMode() === 'single' && selectRow(row); handleRowClick(row, $event)\"\n (dblclick)=\"handleRowDblClick(row)\">\n\n <!-- Selection Cell -->\n @if (selectionMode() === 'multiple') {\n <td class=\"studio-table__td studio-table__td--selection\">\n <studio-checkbox\n [value]=\"isRowSelected(row)\"\n (changed)=\"selectRow(row)\"\n (click)=\"$event.stopPropagation()\"\n />\n </td>\n }\n\n <!-- Expansion Cell -->\n @if (expandable()) {\n <td class=\"studio-table__td studio-table__td--expand\">\n <studio-button\n variant=\"ghost\"\n size=\"sm\"\n iconPosition=\"only\"\n [icon]=\"isRowExpanded(row) ? 'chevron-down' : 'chevron-right'\"\n (clicked)=\"toggleRowExpansion(row); $event.stopPropagation()\"\n />\n </td>\n }\n\n <!-- Data Cells -->\n @for (column of finalColumns(); track column.key) {\n <td\n [class]=\"getFullCellClass(row, column)\"\n [attr.data-label]=\"column.label\">\n\n @if (column.cellTemplate) {\n <ng-container *ngTemplateOutlet=\"column.cellTemplate; context: getCellContext(row, column, rowIndex)\" />\n } @else {\n <span>{{ column.formatter ? column.formatter(getCellValue(row, column), row) : getCellValue(row, column) }}</span>\n }\n </td>\n }\n\n <!-- Actions Cell -->\n @if (rowActions().length > 0) {\n <td class=\"studio-table__td studio-table__td--actions\">\n <div class=\"studio-table__actions\">\n @for (action of rowActions(); track action.label) {\n @if (isActionVisible(action, row)) {\n @if (action.divider) {\n <div class=\"studio-table__action-divider\"></div>\n }\n <studio-button\n variant=\"ghost\"\n size=\"sm\"\n [icon]=\"action.icon\"\n [disabled]=\"isActionDisabled(action, row)\"\n [color]=\"action.variant === 'danger' ? 'error' : 'primary'\"\n (clicked)=\"executeRowAction(action, row, $event)\">\n {{ action.label }}\n </studio-button>\n }\n }\n </div>\n </td>\n }\n </tr>\n\n <!-- Expanded Row -->\n @if (expandable() && isRowExpanded(row) && expandedRowTemplate()) {\n <tr class=\"studio-table__row studio-table__row--expansion\">\n <td [attr.colspan]=\"finalColumns().length + (selectionMode() === 'multiple' ? 1 : 0) + (expandable() ? 1 : 0) + (rowActions().length > 0 ? 1 : 0)\" class=\"studio-table__td\">\n <div class=\"studio-table__expansion-content\">\n <ng-container *ngTemplateOutlet=\"expandedRowTemplate(); context: { $implicit: row, index: rowIndex }\" />\n </div>\n </td>\n </tr>\n }\n }\n }\n </tbody>\n </table>\n </div>\n</div>\n", styles: [":host{display:block;font-family:var(--studio-font-family);position:relative}.studio-table__wrapper{position:relative;width:100%;overflow:hidden}.studio-table__container{width:100%;overflow-x:auto;overflow-y:visible;-webkit-overflow-scrolling:touch}.studio-table__container::-webkit-scrollbar{height:8px}.studio-table__container::-webkit-scrollbar-track{background:var(--studio-bg-secondary);border-radius:var(--studio-radius-sm)}.studio-table__container::-webkit-scrollbar-thumb{background:var(--studio-border-primary);border-radius:var(--studio-radius-sm)}.studio-table__container::-webkit-scrollbar-thumb:hover{background:var(--studio-text-tertiary)}.studio-table__table{width:100%;border-collapse:separate;border-spacing:0;background:var(--studio-bg-primary)}.studio-table__thead{background:var(--studio-bg-secondary)}.studio-table__header-row{border-bottom:1px solid var(--studio-border-primary)}.studio-table__th{padding:.75rem 1rem;text-align:left;font-weight:var(--studio-font-weight-semibold);font-size:var(--studio-font-size-sm);color:var(--studio-text-primary);white-space:nowrap;-webkit-user-select:none;user-select:none;position:relative}.studio-table__th--sortable{cursor:pointer;transition:background-color var(--studio-transition-fast)}.studio-table__th--sortable:hover{background:var(--studio-bg-tertiary)}.studio-table__th--sorted{color:var(--studio-primary)}.studio-table__th--selection,.studio-table__th--expand{width:48px;padding:.75rem .5rem}.studio-table__th--actions{width:auto;min-width:100px}.studio-table__th--align-center{text-align:center}.studio-table__th--align-right{text-align:right}.studio-table__th--fixed-left{position:sticky;left:0;z-index:2;background:var(--studio-bg-secondary);box-shadow:2px 0 4px #0000000d}.studio-table__th--fixed-right{position:sticky;right:0;z-index:2;background:var(--studio-bg-secondary);box-shadow:-2px 0 4px #0000000d}.studio-table__header-content{display:flex;align-items:center;gap:.5rem}.studio-table__sort-icon{flex-shrink:0;color:var(--studio-text-tertiary);transition:color var(--studio-transition-fast)}.studio-table__th--sorted .studio-table__sort-icon{color:var(--studio-primary)}.studio-table__row{border-bottom:1px solid var(--studio-border-primary);transition:background-color var(--studio-transition-fast)}.studio-table__row--clickable{cursor:pointer}.studio-table__row--selected{background:var(--studio-primary-bg)}.studio-table__row--expansion{background:var(--studio-bg-secondary)}.studio-table__row--loading{pointer-events:none}.studio-table__td{padding:.75rem 1rem;font-size:var(--studio-font-size-base);color:var(--studio-text-primary);vertical-align:middle}.studio-table__td--selection,.studio-table__td--expand{width:48px;padding:.75rem .5rem}.studio-table__td--actions{width:auto}.studio-table__td--align-center{text-align:center}.studio-table__td--align-right{text-align:right}.studio-table__td--fixed-left{position:sticky;left:0;z-index:1;background:var(--studio-bg-primary);box-shadow:2px 0 4px #0000000d}.studio-table__row--selected .studio-table__td--fixed-left{background:var(--studio-primary-bg)}.studio-table__td--fixed-right{position:sticky;right:0;z-index:1;background:var(--studio-bg-primary);box-shadow:-2px 0 4px #0000000d}.studio-table__row--selected .studio-table__td--fixed-right{background:var(--studio-primary-bg)}:host(.studio-table--compact) .studio-table__th,:host(.studio-table--compact) .studio-table__td{padding:.5rem .75rem}:host(.studio-table--compact) .studio-table__th{font-size:.813rem}:host(.studio-table--compact) .studio-table__td{font-size:.875rem}:host(.studio-table--spacious) .studio-table__th,:host(.studio-table--spacious) .studio-table__td{padding:1rem 1.5rem}:host(.studio-table--spacious) .studio-table__th{font-size:var(--studio-font-size-base)}:host(.studio-table--spacious) .studio-table__td{font-size:var(--studio-font-size-lg)}:host(.studio-table--striped) .studio-table__row:nth-child(2n){background:var(--studio-bg-secondary)}:host(.studio-table--bordered) .studio-table__table{border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md)}:host(.studio-table--bordered) .studio-table__th,:host(.studio-table--bordered) .studio-table__td{border-right:1px solid var(--studio-border-primary)}:host(.studio-table--bordered) .studio-table__th:last-child,:host(.studio-table--bordered) .studio-table__td:last-child{border-right:none}:host(.studio-table--minimal) .studio-table__thead{background:transparent}:host(.studio-table--minimal) .studio-table__header-row{border-bottom:2px solid var(--studio-border-primary)}:host(.studio-table--minimal) .studio-table__row{border-bottom-style:dashed}:host(.studio-table--hoverable) .studio-table__row:not(.studio-table__row--empty):not(.studio-table__row--loading):not(.studio-table__row--expansion):hover{background:var(--studio-bg-secondary)}:host(.studio-table--hoverable) .studio-table__row--selected:hover{background:var(--studio-primary-bg);filter:brightness(.98)}:host(.studio-table--sticky-header) .studio-table__thead{position:sticky;top:0;z-index:3;box-shadow:0 2px 4px #0000000d}.studio-table__actions{display:flex;align-items:center;gap:.25rem;flex-wrap:wrap}.studio-table__action-divider{width:1px;height:1.5rem;background:var(--studio-border-primary);margin:0 .25rem}.studio-table__expansion-content{padding:1rem;background:var(--studio-bg-tertiary);border-radius:var(--studio-radius-sm)}.studio-table__loading-overlay{position:absolute;inset:0;background:#fffc;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:10}.studio-table__spinner{animation:spin 1s linear infinite;color:var(--studio-primary)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-table__skeleton{height:1rem;background:linear-gradient(90deg,var(--studio-bg-secondary) 0%,var(--studio-bg-tertiary) 50%,var(--studio-bg-secondary) 100%);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:var(--studio-radius-sm)}.studio-table__skeleton--checkbox{width:1.25rem;height:1.25rem}.studio-table__skeleton--icon{width:2rem;height:1rem}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}.studio-table__empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem 1rem;text-align:center}.studio-table__empty-icon{color:var(--studio-text-tertiary);margin-bottom:1rem}.studio-table__empty-title{margin:0 0 .5rem;font-size:var(--studio-font-size-lg);font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-table__empty-message{margin:0 0 1.5rem;font-size:var(--studio-font-size-base);color:var(--studio-text-secondary)}@media (max-width: 768px){:host(.studio-table--responsive) .studio-table__container{overflow-x:visible}:host(.studio-table--responsive) .studio-table__table{display:block}:host(.studio-table--responsive) .studio-table__thead{display:none}:host(.studio-table--responsive) .studio-table__tbody{display:block}:host(.studio-table--responsive) .studio-table__row{display:block;margin-bottom:1rem;border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);box-shadow:var(--studio-shadow-sm);overflow:hidden}:host(.studio-table--responsive) .studio-table__row--empty,:host(.studio-table--responsive) .studio-table__row--loading{display:table-row}:host(.studio-table--responsive) .studio-table__row--expansion{margin-top:-1rem;border-top:none;border-top-left-radius:0;border-top-right-radius:0}:host(.studio-table--responsive) .studio-table__td{display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;border-bottom:1px solid var(--studio-border-primary)}:host(.studio-table--responsive) .studio-table__td:last-child{border-bottom:none}:host(.studio-table--responsive) .studio-table__td:before{content:attr(data-label);font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-secondary);min-width:100px;flex-shrink:0}:host(.studio-table--responsive) .studio-table__td--selection,:host(.studio-table--responsive) .studio-table__td--expand{display:flex;justify-content:center;padding:.5rem 1rem}:host(.studio-table--responsive) .studio-table__td--selection:before,:host(.studio-table--responsive) .studio-table__td--expand:before{display:none}:host(.studio-table--responsive) .studio-table__td--actions{display:block;padding:.75rem 1rem}:host(.studio-table--responsive) .studio-table__td--actions:before{display:block;margin-bottom:.5rem}:host(.studio-table--responsive) .studio-table__td--actions .studio-table__actions{justify-content:flex-start}:host(.studio-table--responsive) .studio-table__td--hide-mobile{display:none!important}:host(.studio-table--responsive) .studio-table__expansion-content{padding:.75rem 1rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth", "showFallback", "fallbackIcon"] }, { kind: "component", type: CheckboxComponent, selector: "studio-checkbox", inputs: ["size", "color", "variant", "radius", "label", "labelPosition", "description", "hint", "required", "error", "errorMessage", "disabled", "readonly", "indeterminate", "name", "tabIndex", "value"], outputs: ["changed"] }, { kind: "component", type: ButtonComponent, selector: "studio-button", inputs: ["variant", "size", "color", "radius", "shadow", "compact", "disabled", "loading", "loadingText", "fullWidth", "type", "icon", "iconPosition", "href", "target", "badge", "badgeColor", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5465
+ }
5466
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: TableComponent, decorators: [{
5467
+ type: Component,
5468
+ args: [{ selector: 'studio-table', standalone: true, imports: [CommonModule, IconComponent, CheckboxComponent, ButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
5469
+ '[class]': 'hostClasses()',
5470
+ }, template: "<div class=\"studio-table__wrapper\">\n <!-- Loading Overlay -->\n @if (loading()) {\n <div class=\"studio-table__loading-overlay\">\n <studio-icon name=\"loader-2\" [size]=\"32\" class=\"studio-table__spinner\" />\n </div>\n }\n\n <!-- Table Container -->\n <div class=\"studio-table__container\">\n <table class=\"studio-table__table\">\n <!-- Header -->\n @if (showHeader()) {\n <thead class=\"studio-table__thead\">\n <tr class=\"studio-table__header-row\">\n <!-- Selection Column -->\n @if (selectionMode() === 'multiple') {\n <th class=\"studio-table__th studio-table__th--selection\">\n <studio-checkbox\n [value]=\"allSelected()\"\n [indeterminate]=\"someSelected()\"\n (changed)=\"selectAll($event)\"\n />\n </th>\n }\n\n <!-- Expansion Column -->\n @if (expandable()) {\n <th class=\"studio-table__th studio-table__th--expand\"></th>\n }\n\n <!-- Data Columns -->\n @for (column of finalColumns(); track column.key) {\n <th\n [class]=\"getHeaderClass(column)\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth\"\n [style.max-width]=\"column.maxWidth\"\n (click)=\"column.sortable && sortBy(column)\">\n\n <div class=\"studio-table__header-content\">\n @if (column.headerTemplate) {\n <ng-container *ngTemplateOutlet=\"column.headerTemplate; context: getHeaderContext(column)\" />\n } @else {\n <span>{{ column.label }}</span>\n @if (column.sortable && sortable()) {\n <studio-icon\n [name]=\"getSortIcon(column)\"\n [size]=\"16\"\n class=\"studio-table__sort-icon\"\n />\n }\n }\n </div>\n </th>\n }\n\n <!-- Actions Column -->\n @if (rowActions().length > 0) {\n <th class=\"studio-table__th studio-table__th--actions\">Actions</th>\n }\n </tr>\n </thead>\n }\n\n <!-- Body -->\n <tbody class=\"studio-table__tbody\">\n <!-- Loading Skeleton -->\n @if (loading()) {\n @for (i of [].constructor(loadingRows()); track i) {\n <tr class=\"studio-table__row studio-table__row--loading\">\n @if (selectionMode() === 'multiple') {\n <td class=\"studio-table__td\">\n <div class=\"studio-table__skeleton studio-table__skeleton--checkbox\"></div>\n </td>\n }\n @if (expandable()) {\n <td class=\"studio-table__td\">\n <div class=\"studio-table__skeleton studio-table__skeleton--icon\"></div>\n </td>\n }\n @for (column of finalColumns(); track column.key) {\n <td class=\"studio-table__td\" [class.studio-table__th--hide-mobile]=\"column.hideOnMobile\">\n <div class=\"studio-table__skeleton\"></div>\n </td>\n }\n @if (rowActions().length > 0) {\n <td class=\"studio-table__td\">\n <div class=\"studio-table__skeleton studio-table__skeleton--icon\"></div>\n </td>\n }\n </tr>\n }\n }\n\n <!-- Empty State -->\n @if (!loading() && processedData().length === 0) {\n <tr class=\"studio-table__row studio-table__row--empty\">\n <td [attr.colspan]=\"finalColumns().length + (selectionMode() === 'multiple' ? 1 : 0) + (expandable() ? 1 : 0) + (rowActions().length > 0 ? 1 : 0)\" class=\"studio-table__td\">\n <div class=\"studio-table__empty\">\n <studio-icon [name]=\"emptyState().icon || 'inbox'\" [size]=\"48\" class=\"studio-table__empty-icon\" />\n <h3 class=\"studio-table__empty-title\">{{ emptyState().title }}</h3>\n <p class=\"studio-table__empty-message\">{{ emptyState().message }}</p>\n @if (emptyState().action) {\n <studio-button\n size=\"sm\"\n (clicked)=\"emptyState().action!.handler()\">\n {{ emptyState().action!.label }}\n </studio-button>\n }\n </div>\n </td>\n </tr>\n }\n\n <!-- Data Rows -->\n @if (!loading()) {\n @for (row of processedData(); track getRowKey(row); let rowIndex = $index) {\n <!-- Main Row -->\n <tr\n class=\"studio-table__row\"\n [class.studio-table__row--selected]=\"isRowSelected(row)\"\n [class.studio-table__row--expanded]=\"isRowExpanded(row)\"\n [class.studio-table__row--clickable]=\"selectionMode() === 'single'\"\n (click)=\"selectionMode() === 'single' && selectRow(row); handleRowClick(row, $event)\"\n (dblclick)=\"handleRowDblClick(row)\">\n\n <!-- Selection Cell -->\n @if (selectionMode() === 'multiple') {\n <td class=\"studio-table__td studio-table__td--selection\">\n <studio-checkbox\n [value]=\"isRowSelected(row)\"\n (changed)=\"selectRow(row)\"\n (click)=\"$event.stopPropagation()\"\n />\n </td>\n }\n\n <!-- Expansion Cell -->\n @if (expandable()) {\n <td class=\"studio-table__td studio-table__td--expand\">\n <studio-button\n variant=\"ghost\"\n size=\"sm\"\n iconPosition=\"only\"\n [icon]=\"isRowExpanded(row) ? 'chevron-down' : 'chevron-right'\"\n (clicked)=\"toggleRowExpansion(row); $event.stopPropagation()\"\n />\n </td>\n }\n\n <!-- Data Cells -->\n @for (column of finalColumns(); track column.key) {\n <td\n [class]=\"getFullCellClass(row, column)\"\n [attr.data-label]=\"column.label\">\n\n @if (column.cellTemplate) {\n <ng-container *ngTemplateOutlet=\"column.cellTemplate; context: getCellContext(row, column, rowIndex)\" />\n } @else {\n <span>{{ column.formatter ? column.formatter(getCellValue(row, column), row) : getCellValue(row, column) }}</span>\n }\n </td>\n }\n\n <!-- Actions Cell -->\n @if (rowActions().length > 0) {\n <td class=\"studio-table__td studio-table__td--actions\">\n <div class=\"studio-table__actions\">\n @for (action of rowActions(); track action.label) {\n @if (isActionVisible(action, row)) {\n @if (action.divider) {\n <div class=\"studio-table__action-divider\"></div>\n }\n <studio-button\n variant=\"ghost\"\n size=\"sm\"\n [icon]=\"action.icon\"\n [disabled]=\"isActionDisabled(action, row)\"\n [color]=\"action.variant === 'danger' ? 'error' : 'primary'\"\n (clicked)=\"executeRowAction(action, row, $event)\">\n {{ action.label }}\n </studio-button>\n }\n }\n </div>\n </td>\n }\n </tr>\n\n <!-- Expanded Row -->\n @if (expandable() && isRowExpanded(row) && expandedRowTemplate()) {\n <tr class=\"studio-table__row studio-table__row--expansion\">\n <td [attr.colspan]=\"finalColumns().length + (selectionMode() === 'multiple' ? 1 : 0) + (expandable() ? 1 : 0) + (rowActions().length > 0 ? 1 : 0)\" class=\"studio-table__td\">\n <div class=\"studio-table__expansion-content\">\n <ng-container *ngTemplateOutlet=\"expandedRowTemplate(); context: { $implicit: row, index: rowIndex }\" />\n </div>\n </td>\n </tr>\n }\n }\n }\n </tbody>\n </table>\n </div>\n</div>\n", styles: [":host{display:block;font-family:var(--studio-font-family);position:relative}.studio-table__wrapper{position:relative;width:100%;overflow:hidden}.studio-table__container{width:100%;overflow-x:auto;overflow-y:visible;-webkit-overflow-scrolling:touch}.studio-table__container::-webkit-scrollbar{height:8px}.studio-table__container::-webkit-scrollbar-track{background:var(--studio-bg-secondary);border-radius:var(--studio-radius-sm)}.studio-table__container::-webkit-scrollbar-thumb{background:var(--studio-border-primary);border-radius:var(--studio-radius-sm)}.studio-table__container::-webkit-scrollbar-thumb:hover{background:var(--studio-text-tertiary)}.studio-table__table{width:100%;border-collapse:separate;border-spacing:0;background:var(--studio-bg-primary)}.studio-table__thead{background:var(--studio-bg-secondary)}.studio-table__header-row{border-bottom:1px solid var(--studio-border-primary)}.studio-table__th{padding:.75rem 1rem;text-align:left;font-weight:var(--studio-font-weight-semibold);font-size:var(--studio-font-size-sm);color:var(--studio-text-primary);white-space:nowrap;-webkit-user-select:none;user-select:none;position:relative}.studio-table__th--sortable{cursor:pointer;transition:background-color var(--studio-transition-fast)}.studio-table__th--sortable:hover{background:var(--studio-bg-tertiary)}.studio-table__th--sorted{color:var(--studio-primary)}.studio-table__th--selection,.studio-table__th--expand{width:48px;padding:.75rem .5rem}.studio-table__th--actions{width:auto;min-width:100px}.studio-table__th--align-center{text-align:center}.studio-table__th--align-right{text-align:right}.studio-table__th--fixed-left{position:sticky;left:0;z-index:2;background:var(--studio-bg-secondary);box-shadow:2px 0 4px #0000000d}.studio-table__th--fixed-right{position:sticky;right:0;z-index:2;background:var(--studio-bg-secondary);box-shadow:-2px 0 4px #0000000d}.studio-table__header-content{display:flex;align-items:center;gap:.5rem}.studio-table__sort-icon{flex-shrink:0;color:var(--studio-text-tertiary);transition:color var(--studio-transition-fast)}.studio-table__th--sorted .studio-table__sort-icon{color:var(--studio-primary)}.studio-table__row{border-bottom:1px solid var(--studio-border-primary);transition:background-color var(--studio-transition-fast)}.studio-table__row--clickable{cursor:pointer}.studio-table__row--selected{background:var(--studio-primary-bg)}.studio-table__row--expansion{background:var(--studio-bg-secondary)}.studio-table__row--loading{pointer-events:none}.studio-table__td{padding:.75rem 1rem;font-size:var(--studio-font-size-base);color:var(--studio-text-primary);vertical-align:middle}.studio-table__td--selection,.studio-table__td--expand{width:48px;padding:.75rem .5rem}.studio-table__td--actions{width:auto}.studio-table__td--align-center{text-align:center}.studio-table__td--align-right{text-align:right}.studio-table__td--fixed-left{position:sticky;left:0;z-index:1;background:var(--studio-bg-primary);box-shadow:2px 0 4px #0000000d}.studio-table__row--selected .studio-table__td--fixed-left{background:var(--studio-primary-bg)}.studio-table__td--fixed-right{position:sticky;right:0;z-index:1;background:var(--studio-bg-primary);box-shadow:-2px 0 4px #0000000d}.studio-table__row--selected .studio-table__td--fixed-right{background:var(--studio-primary-bg)}:host(.studio-table--compact) .studio-table__th,:host(.studio-table--compact) .studio-table__td{padding:.5rem .75rem}:host(.studio-table--compact) .studio-table__th{font-size:.813rem}:host(.studio-table--compact) .studio-table__td{font-size:.875rem}:host(.studio-table--spacious) .studio-table__th,:host(.studio-table--spacious) .studio-table__td{padding:1rem 1.5rem}:host(.studio-table--spacious) .studio-table__th{font-size:var(--studio-font-size-base)}:host(.studio-table--spacious) .studio-table__td{font-size:var(--studio-font-size-lg)}:host(.studio-table--striped) .studio-table__row:nth-child(2n){background:var(--studio-bg-secondary)}:host(.studio-table--bordered) .studio-table__table{border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md)}:host(.studio-table--bordered) .studio-table__th,:host(.studio-table--bordered) .studio-table__td{border-right:1px solid var(--studio-border-primary)}:host(.studio-table--bordered) .studio-table__th:last-child,:host(.studio-table--bordered) .studio-table__td:last-child{border-right:none}:host(.studio-table--minimal) .studio-table__thead{background:transparent}:host(.studio-table--minimal) .studio-table__header-row{border-bottom:2px solid var(--studio-border-primary)}:host(.studio-table--minimal) .studio-table__row{border-bottom-style:dashed}:host(.studio-table--hoverable) .studio-table__row:not(.studio-table__row--empty):not(.studio-table__row--loading):not(.studio-table__row--expansion):hover{background:var(--studio-bg-secondary)}:host(.studio-table--hoverable) .studio-table__row--selected:hover{background:var(--studio-primary-bg);filter:brightness(.98)}:host(.studio-table--sticky-header) .studio-table__thead{position:sticky;top:0;z-index:3;box-shadow:0 2px 4px #0000000d}.studio-table__actions{display:flex;align-items:center;gap:.25rem;flex-wrap:wrap}.studio-table__action-divider{width:1px;height:1.5rem;background:var(--studio-border-primary);margin:0 .25rem}.studio-table__expansion-content{padding:1rem;background:var(--studio-bg-tertiary);border-radius:var(--studio-radius-sm)}.studio-table__loading-overlay{position:absolute;inset:0;background:#fffc;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:10}.studio-table__spinner{animation:spin 1s linear infinite;color:var(--studio-primary)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.studio-table__skeleton{height:1rem;background:linear-gradient(90deg,var(--studio-bg-secondary) 0%,var(--studio-bg-tertiary) 50%,var(--studio-bg-secondary) 100%);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:var(--studio-radius-sm)}.studio-table__skeleton--checkbox{width:1.25rem;height:1.25rem}.studio-table__skeleton--icon{width:2rem;height:1rem}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}.studio-table__empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem 1rem;text-align:center}.studio-table__empty-icon{color:var(--studio-text-tertiary);margin-bottom:1rem}.studio-table__empty-title{margin:0 0 .5rem;font-size:var(--studio-font-size-lg);font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-primary)}.studio-table__empty-message{margin:0 0 1.5rem;font-size:var(--studio-font-size-base);color:var(--studio-text-secondary)}@media (max-width: 768px){:host(.studio-table--responsive) .studio-table__container{overflow-x:visible}:host(.studio-table--responsive) .studio-table__table{display:block}:host(.studio-table--responsive) .studio-table__thead{display:none}:host(.studio-table--responsive) .studio-table__tbody{display:block}:host(.studio-table--responsive) .studio-table__row{display:block;margin-bottom:1rem;border:1px solid var(--studio-border-primary);border-radius:var(--studio-radius-md);box-shadow:var(--studio-shadow-sm);overflow:hidden}:host(.studio-table--responsive) .studio-table__row--empty,:host(.studio-table--responsive) .studio-table__row--loading{display:table-row}:host(.studio-table--responsive) .studio-table__row--expansion{margin-top:-1rem;border-top:none;border-top-left-radius:0;border-top-right-radius:0}:host(.studio-table--responsive) .studio-table__td{display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;border-bottom:1px solid var(--studio-border-primary)}:host(.studio-table--responsive) .studio-table__td:last-child{border-bottom:none}:host(.studio-table--responsive) .studio-table__td:before{content:attr(data-label);font-weight:var(--studio-font-weight-semibold);color:var(--studio-text-secondary);min-width:100px;flex-shrink:0}:host(.studio-table--responsive) .studio-table__td--selection,:host(.studio-table--responsive) .studio-table__td--expand{display:flex;justify-content:center;padding:.5rem 1rem}:host(.studio-table--responsive) .studio-table__td--selection:before,:host(.studio-table--responsive) .studio-table__td--expand:before{display:none}:host(.studio-table--responsive) .studio-table__td--actions{display:block;padding:.75rem 1rem}:host(.studio-table--responsive) .studio-table__td--actions:before{display:block;margin-bottom:.5rem}:host(.studio-table--responsive) .studio-table__td--actions .studio-table__actions{justify-content:flex-start}:host(.studio-table--responsive) .studio-table__td--hide-mobile{display:none!important}:host(.studio-table--responsive) .studio-table__expansion-content{padding:.75rem 1rem}}\n"] }]
5471
+ }], ctorParameters: () => [], propDecorators: { variantInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], densityInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "density", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rowKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowKey", required: false }] }], columnDirectives: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TableColumnDirective), { isSignal: true }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], sortable: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortable", required: false }] }], sortMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortMode", required: false }] }], hoverable: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverable", required: false }] }], stickyHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickyHeader", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], expandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandable", required: false }] }], expandedRowTemplate: [{ type: i0.ContentChild, args: ['expandedRow', { isSignal: true }] }], expandMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandMultiple", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingRows", required: false }] }], emptyState: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyState", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], mobileBreakpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileBreakpoint", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }], sort: [{ type: i0.Input, args: [{ isSignal: true, alias: "sort", required: false }] }, { type: i0.Output, args: ["sortChange"] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], rowDblClick: [{ type: i0.Output, args: ["rowDblClick"] }] } });
5472
+
5473
+ /**
5474
+ * Table component types and interfaces
5475
+ * Enterprise-grade type-safe table with full feature set
5476
+ */
5477
+
4382
5478
  class TabsComponent {
4383
5479
  tabs = input.required(...(ngDevMode ? [{ debugName: "tabs" }] : []));
4384
5480
  activeTab = signal('', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
@@ -5775,5 +6871,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
5775
6871
  * Generated bundle index. Do not edit.
5776
6872
  */
5777
6873
 
5778
- export { BadgeComponent, BadgeWrapperComponent, BottomNavigationComponent, ButtonComponent, ButtonGroupComponent, ButtonToggleGroupComponent, CheckboxComponent, ColorPickerCompactComponent, ColorPickerComponent, DEFAULT_COLOR_PRESETS, DrawerComponent, DrawerService, DropdownComponent, IconComponent, InputComponent, InspectorComponent, MASK_PRESETS, MaskDirective, MaskEngine, MenuComponent, ModalComponent, NavbarComponent, PopoverComponent, RadioButtonComponent, STUDIO_CONFIG, SelectComponent, SidebarComponent, StudioConfigService, SwitchComponent, TabsComponent, TextareaComponent, ThemeSwitchComponent, TooltipComponent, classNames, isSafeUrl, loadGoogleFont, loadGoogleFonts, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
6874
+ export { BadgeComponent, BadgeWrapperComponent, BottomNavigationComponent, ButtonComponent, ButtonGroupComponent, ButtonToggleGroupComponent, CardComponent, ChatComponent, ChatInputComponent, ChatMessageComponent, CheckboxComponent, ColorPickerCompactComponent, ColorPickerComponent, DEFAULT_COLOR_PRESETS, DrawerComponent, DrawerService, DropdownComponent, IconComponent, InputComponent, InspectorComponent, MASK_PRESETS, MaskDirective, MaskEngine, MenuComponent, ModalComponent, NavbarComponent, PopoverComponent, RadioButtonComponent, STUDIO_CONFIG, SelectComponent, SidebarComponent, StudioConfigService, SwitchComponent, TableColumnDirective, TableComponent, TabsComponent, TextareaComponent, ThemeSwitchComponent, TooltipComponent, classNames, isSafeUrl, loadGoogleFont, loadGoogleFonts, provideStudioConfig, provideStudioIcons, sanitizeUrl, withConfigDefault };
5779
6875
  //# sourceMappingURL=eduboxpro-studio.mjs.map