@compsych-ui-components/angular 8.0.2 → 8.0.3
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.
|
@@ -206,7 +206,7 @@ export class CardComponent {
|
|
|
206
206
|
return this.sanitizer.bypassSecurityTrustHtml(svg);
|
|
207
207
|
}
|
|
208
208
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
209
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CardComponent, isStandalone: true, selector: "compsych-card", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, imageSrc: { classPropertyName: "imageSrc", publicName: "imageSrc", isSignal: true, isRequired: false, transformFunction: null }, hideImage: { classPropertyName: "hideImage", publicName: "hideImage", isSignal: true, isRequired: false, transformFunction: null }, imagePosition: { classPropertyName: "imagePosition", publicName: "imagePosition", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, category: { classPropertyName: "category", publicName: "category", isSignal: true, isRequired: false, transformFunction: null }, categoryStyle: { classPropertyName: "categoryStyle", publicName: "categoryStyle", isSignal: true, isRequired: false, transformFunction: null }, iconStyle: { classPropertyName: "iconStyle", publicName: "iconStyle", 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 }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, headline: { classPropertyName: "headline", publicName: "headline", isSignal: true, isRequired: false, transformFunction: null }, headlineDescription: { classPropertyName: "headlineDescription", publicName: "headlineDescription", isSignal: true, isRequired: false, transformFunction: null }, metrics: { classPropertyName: "metrics", publicName: "metrics", isSignal: true, isRequired: false, transformFunction: null }, actionLabel: { classPropertyName: "actionLabel", publicName: "actionLabel", isSignal: true, isRequired: false, transformFunction: null }, actionLeadingIcon: { classPropertyName: "actionLeadingIcon", publicName: "actionLeadingIcon", isSignal: true, isRequired: false, transformFunction: null }, actionTrailingIcon: { classPropertyName: "actionTrailingIcon", publicName: "actionTrailingIcon", isSignal: true, isRequired: false, transformFunction: null }, actionDisabled: { classPropertyName: "actionDisabled", publicName: "actionDisabled", isSignal: true, isRequired: false, transformFunction: null }, inlineIcon: { classPropertyName: "inlineIcon", publicName: "inlineIcon", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, showGradient: { classPropertyName: "showGradient", publicName: "showGradient", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, darkBackground: { classPropertyName: "darkBackground", publicName: "darkBackground", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, trailingIcon: { classPropertyName: "trailingIcon", publicName: "trailingIcon", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, metricSize: { classPropertyName: "metricSize", publicName: "metricSize", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: false, transformFunction: null }, headingLevel: { classPropertyName: "headingLevel", publicName: "headingLevel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cardClick: "cardClick", actionClick: "actionClick" }, host: { listeners: { "click": "onActivate()", "keydown": "onKeyDown($event)" }, properties: { "class.cmp-card--outlined": "appearance() === 'outlined'", "class.cmp-card--filled": "appearance() === 'filled'", "class.cmp-card--gradient": "appearance() === 'gradient'", "class.cmp-card--banner": "appearance() === 'banner'", "class.cmp-card--content": "variant() === 'content'", "class.cmp-card--basic": "variant() === 'basic'", "attr.data-card-size": "variant() === 'basic' ? size() : null", "class.cmp-card--metric": "variant() === 'metric'", "class.cmp-card--current": "variant() === 'metric' && current()", "class.cmp-card--radius-md": "radius() === 'md'", "class.cmp-card--radius-lg": "radius() === 'lg'", "class.cmp-card--radius-xl": "radius() === 'xl'", "class.cmp-card--pad-none": "effectivePadding() === 'none'", "class.cmp-card--pad-sm": "effectivePadding() === 'sm'", "class.cmp-card--pad-md": "effectivePadding() === 'md'", "class.cmp-card--pad-lg": "effectivePadding() === 'lg'", "class.cmp-card--pad-xl": "effectivePadding() === 'xl'", "style.width": "fullWidth() ? '100%' : null", "class.cmp-card--interactive": "interactive()", "class.cmp-card--disabled": "disabled()", "class.cmp-card--selected": "selected()", "class.cmp-card--no-gradient": "!showGradient()", "class.cmp-card--compact": "compact()", "class.cmp-card--metric-sm": "variant() === 'metric' && metricSize() === 'small'", "class.cmp-card--dark-bg": "darkBackground()", "class.cmp-card--hide-image": "hideImage()", "attr.role": "interactive() ? 'button' : null", "attr.tabindex": "interactive() && !disabled() ? 0 : null", "attr.aria-label": "ariaLabel() ?? null", "attr.aria-disabled": "disabled() || null", "attr.aria-pressed": "interactive() && variant() === 'metric' ? current() : null", "style.border-color": "variant() === 'metric' && current() ? 'var(--accent-primary-sys-primary)' : null", "style.border-width": "variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null" }, classAttribute: "cmp-card" }, hostDirectives: [{ directive: i1.RippleDirective }], ngImport: i0, template: "@if (isBanner() && mediaUrl() && !hideImage()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (isBanner()) {\r\n <div class=\"cc cc--banner\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n }\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row \u2014 icon \u00B7 title \u00B7 arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--banner]=\"isBanner()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragment: renders <h2>\u2013<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n", styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden;border-radius:var(--border-radius-sys-radius-lg);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);isolation:isolate;container-type:inline-size;text-wrap:pretty}:host.cmp-card--radius-md{border-radius:var(--border-radius-sys-radius-md)}:host.cmp-card--radius-lg{border-radius:var(--border-radius-sys-radius-lg)}:host.cmp-card--radius-xl{border-radius:var(--border-radius-sys-radius-xl)}.cmp-card__body{position:relative;z-index:1;display:flex;flex-direction:column;flex:1 1 auto;min-height:0}:host.cmp-card--pad-none .cmp-card__body{padding:0}:host.cmp-card--pad-sm .cmp-card__body{padding:var(--spacing-padding-sys-padding-16)}:host.cmp-card--pad-md .cmp-card__body{padding:var(--spacing-padding-sys-padding-20)}:host.cmp-card--pad-lg .cmp-card__body{padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--pad-xl .cmp-card__body{padding:var(--spacing-padding-sys-padding-32)}:host.cmp-card--outlined{background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant)}:host.cmp-card--filled{background-color:var(--accent-primary-sys-primary-container);color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--gradient{background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%);background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant)}:host.cmp-card--gradient.cmp-card--content{background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--content .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--content .cc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-16);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}:host.cmp-card--gradient.cmp-card--content.cmp-card--no-gradient .cc{background-image:none}:host.cmp-card--compact .cc:not(.cc--banner){min-height:0}:host.cmp-card--gradient.cmp-card--content .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--gradient.cmp-card--content .cc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);font-weight:var(--body-small-sys-font-weight)}:host.cmp-card--banner{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}:host.cmp-card--banner.cmp-card--hide-image{background-color:var(--accent-primary-sys-primary-container)}.cmp-card__media{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center}.cmp-card__scrim{position:absolute;inset:0;z-index:0;background-image:linear-gradient(180deg,var(--transparent-neutral-sys-black-40) 0%,var(--transparent-neutral-sys-black-10) 32%,var(--transparent-neutral-sys-black-10) 64%,var(--transparent-neutral-sys-black-50) 100%);mix-blend-mode:multiply}:host.cmp-card--interactive{cursor:pointer;transition:box-shadow .14s ease-out,border-color .14s ease-out,border-width .14s ease-out}:host.cmp-card--interactive:after{content:\"\";position:absolute;inset:0;z-index:0;pointer-events:none;border-radius:inherit;background-color:var(--surface-surface-sys-on-surface);opacity:0;transition:opacity .14s ease-out}:host.cmp-card--interactive.cmp-card--filled:after,:host.cmp-card--interactive.cmp-card--banner:after{background-color:var(--accent-primary-sys-on-primary)}:host.cmp-card--interactive:hover{border-color:var(--outline-sys-outline-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 4px 16px #0000001a,0 2px 4px #00000014}:host.cmp-card--interactive:hover:after{opacity:.08}:host.cmp-card--interactive:active:after{opacity:.1}:host.cmp-card--selected,:host.cmp-card--interactive:focus-visible{outline:none;border-color:var(--add-on-primary-fixed-sys-on-primary-fixed-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}:host.cmp-card--disabled{pointer-events:none;opacity:.38}:host.cmp-card--dark-bg{background-color:var(--transparent-neutral-sys-white-20);background-image:none;border-color:transparent;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--dark-bg .mc__value,:host.cmp-card--dark-bg .mc__label{color:var(--accent-primary-sys-on-primary)}@media(prefers-reduced-motion:reduce){:host.cmp-card--interactive{transition:none}}@media(forced-colors:active){:host{border:1px solid CanvasText;forced-color-adjust:none}:host.cmp-card--interactive:focus-visible{outline:2px solid Highlight;outline-offset:2px}}.cc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-12);font-family:var(--body-medium-sys-font-family)}.cc:not(.cc--banner){min-height:18.125rem}.cc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.cc__top--label{justify-content:flex-start;align-items:center;gap:var(--spacing-padding-sys-padding-16)}.cc__category-label{background:transparent;padding:0;color:var(--accent-primary-sys-primary);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}.cc__icon{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary);line-height:0}.cc__icon--neutral{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cc__banner{display:flex;align-items:center;justify-content:center;width:100%;height:120px;flex-shrink:0;overflow:hidden;border-radius:var(--border-radius-sys-radius-sm);background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cc__banner-icon{display:inline-flex;line-height:0}.cc__container{display:flex;flex-direction:column;justify-content:space-between;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-8);padding:var(--spacing-padding-sys-padding-8)}.cc__title-group{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cc__category-eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc--with-icon .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized);color:var(--surface-surface-sys-on-surface)}.cc--inline-icon .cc__container{flex:0 0 auto;margin-top:auto}.cc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.cc__arrow{display:inline-flex;color:var(--surface-surface-sys-on-surface-variant);flex-shrink:0;line-height:0}.cc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.cc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.cc__title{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}.cc__subtitle{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}.cc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-2) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc__chip--glass{background-color:var(--transparent-neutral-sys-white-20);color:var(--accent-primary-sys-on-primary);-webkit-backdrop-filter:blur(.375rem);backdrop-filter:blur(.375rem)}.cc--filled .cc__icon{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--accent-primary-sys-primary)}.cc--filled .cc__category-label,.cc--filled .cc__title{color:var(--accent-primary-sys-on-primary-container)}.cc--filled .cc__category-eyebrow,.cc--filled .cc__subtitle,.cc--filled .cc__desc,.cc--filled .cc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}.cc--banner{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:12.5rem;justify-content:space-between;gap:var(--spacing-padding-sys-padding-24);padding:var(--spacing-padding-sys-padding-24)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.cc__img-top{display:flex;flex-direction:column;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12)}.cc__img-foot{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--spacing-padding-sys-padding-16)}.cc__banner-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__headline{margin:0;font-family:var(--headline-large-sys-font-family);font-size:var(--headline-large-sys-font-size);line-height:var(--headline-large-sys-line-height);font-weight:var(--headline-large-sys-font-weight);letter-spacing:var(--headline-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}:host.cmp-card--outlined .cc__headline{color:var(--surface-surface-sys-on-surface)}.cc__img-foot compsych-button{align-self:flex-end;flex-shrink:0}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__img-foot compsych-button{align-self:flex-start}}.cc--banner .cc__title,.cc--banner .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--banner .cc__subtitle{color:var(--transparent-neutral-sys-white-80)}.cc--banner .cc__desc{color:var(--accent-primary-sys-on-primary-container-variant)}.cc__metrics{display:flex;flex-wrap:wrap;gap:var(--spacing-padding-sys-padding-8)}.cc__metrics compsych-card{flex:0 0 auto;width:8rem}.cc__headline-desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--transparent-neutral-sys-white-80)}.ac{display:flex;flex:1 1 auto;align-items:center;gap:var(--spacing-padding-sys-padding-16);font-family:var(--body-medium-sys-font-family)}.ac__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.ac__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4);flex:1 1 auto;min-width:0}.ac__label{margin:0;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.ac__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.ac__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.ac--no-desc .ac__label{line-height:1}.ac--vertical{flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:var(--spacing-padding-sys-padding-16)}.ac__badge{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--surface-surface-container-sys-surface-container);color:var(--surface-surface-sys-on-surface);transition:background-color .14s ease-out;line-height:0}:host(:hover) .ac__badge{background-color:var(--surface-surface-container-sys-surface-container-lowest)}.ac--vertical .ac__label{white-space:pre-line;overflow:visible;font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight)}@media(prefers-reduced-motion:reduce){.ac__badge{transition:none}}.mc{display:flex;flex:1 1 auto;flex-direction:column;align-items:center;justify-content:center;gap:var(--spacing-padding-sys-padding-8);text-align:center;font-family:var(--body-medium-sys-font-family)}.mc__value{font-family:var(--headline-medium-sys-font-family);font-size:var(--headline-medium-sys-font-size);line-height:var(--headline-medium-sys-line-height);font-weight:var(--headline-medium-sys-font-weight);letter-spacing:var(--headline-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc__label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc--current .mc__value,.mc--current .mc__label{color:var(--accent-primary-sys-primary)}.mc--current .mc__value{font-weight:var(--headline-medium-sys-font-weight-emphasized)}.mc--current .mc__label{font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--metric{box-shadow:0 2px 2px #0000000f,0 2px 4px #0000000a}:host.cmp-card--metric-sm .mc{gap:var(--spacing-padding-sys-padding-4)}:host.cmp-card--metric-sm .mc__value{font-size:var(--headline-small-sys-font-size);line-height:var(--headline-small-sys-line-height);letter-spacing:var(--headline-small-sys-tracking);font-weight:var(--headline-small-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__value{font-weight:var(--headline-small-sys-font-weight-emphasized)}:host.cmp-card--metric-sm .mc__label{font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);font-weight:var(--label-medium-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__label{font-weight:var(--label-medium-sys-font-weight-emphasized)}:host.cmp-card--metric.cmp-card--current{box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}.bc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-48);padding:var(--spacing-padding-sys-padding-32);font-family:var(--body-medium-sys-font-family)}.bc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.bc__icon{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.bc__icon--badge{align-items:center;justify-content:center;width:60px;height:60px;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.bc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.bc__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.bc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.bc__body{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-24)}.bc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.bc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.bc__eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__title{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface)}.bc__subtitle{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface-variant)}.bc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]){background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .bc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-24);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}.bc--banner{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--banner .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--banner .bc--row .bc__title,:host.cmp-card--banner .bc--row .bc__icon,:host.cmp-card--banner .bc--row .bc__arrow{color:var(--accent-primary-sys-on-primary)}:host[data-card-size=sm] .bc{gap:var(--spacing-padding-sys-padding-40);padding:var(--spacing-padding-sys-padding-24)}:host[data-card-size=sm] .bc__title,:host[data-card-size=sm] .bc__subtitle{font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);letter-spacing:var(--title-small-sys-tracking);font-weight:var(--title-small-sys-font-weight)}:host[data-card-size=sm] .bc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking)}:host[data-card-size=xs]{border-radius:var(--border-radius-sys-radius-md)}.bc--row{flex-direction:row;align-items:center;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-16)}.bc--row .bc__icon{color:var(--surface-surface-sys-on-surface)}.bc--row .bc__row-text{flex:1 1 auto;min-width:0}.bc--row .bc__title{font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);font-weight:var(--body-medium-sys-font-weight)}.bc--promo{justify-content:space-between;gap:var(--spacing-padding-sys-padding-24)}.bc--promo .bc__chip{align-self:flex-start}.bc--promo compsych-button{align-self:flex-end}.bc--promo.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}:host.cmp-card--filled .bc__title,:host.cmp-card--filled .bc__icon{color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--filled .bc__eyebrow,:host.cmp-card--filled .bc__subtitle,:host.cmp-card--filled .bc__desc,:host.cmp-card--filled .bc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}\n"], dependencies: [{ kind: "component", type: CardComponent, selector: "compsych-card", inputs: ["variant", "appearance", "radius", "padding", "size", "interactive", "disabled", "selected", "imageSrc", "hideImage", "imagePosition", "icon", "category", "categoryStyle", "iconStyle", "title", "subtitle", "description", "headline", "headlineDescription", "metrics", "actionLabel", "actionLeadingIcon", "actionTrailingIcon", "actionDisabled", "inlineIcon", "showArrow", "showGradient", "compact", "darkBackground", "label", "trailingIcon", "orientation", "fullWidth", "metricSize", "value", "current", "headingLevel", "aria-label"], outputs: ["cardClick", "actionClick"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ButtonComponent, selector: "compsych-button", inputs: ["label", "variant", "size", "leadingIcon", "trailingIcon", "type", "ariaLabel", "iconOnly", "disabled", "loading", "fullWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
209
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CardComponent, isStandalone: true, selector: "compsych-card", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, imageSrc: { classPropertyName: "imageSrc", publicName: "imageSrc", isSignal: true, isRequired: false, transformFunction: null }, hideImage: { classPropertyName: "hideImage", publicName: "hideImage", isSignal: true, isRequired: false, transformFunction: null }, imagePosition: { classPropertyName: "imagePosition", publicName: "imagePosition", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, category: { classPropertyName: "category", publicName: "category", isSignal: true, isRequired: false, transformFunction: null }, categoryStyle: { classPropertyName: "categoryStyle", publicName: "categoryStyle", isSignal: true, isRequired: false, transformFunction: null }, iconStyle: { classPropertyName: "iconStyle", publicName: "iconStyle", 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 }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, headline: { classPropertyName: "headline", publicName: "headline", isSignal: true, isRequired: false, transformFunction: null }, headlineDescription: { classPropertyName: "headlineDescription", publicName: "headlineDescription", isSignal: true, isRequired: false, transformFunction: null }, metrics: { classPropertyName: "metrics", publicName: "metrics", isSignal: true, isRequired: false, transformFunction: null }, actionLabel: { classPropertyName: "actionLabel", publicName: "actionLabel", isSignal: true, isRequired: false, transformFunction: null }, actionLeadingIcon: { classPropertyName: "actionLeadingIcon", publicName: "actionLeadingIcon", isSignal: true, isRequired: false, transformFunction: null }, actionTrailingIcon: { classPropertyName: "actionTrailingIcon", publicName: "actionTrailingIcon", isSignal: true, isRequired: false, transformFunction: null }, actionDisabled: { classPropertyName: "actionDisabled", publicName: "actionDisabled", isSignal: true, isRequired: false, transformFunction: null }, inlineIcon: { classPropertyName: "inlineIcon", publicName: "inlineIcon", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, showGradient: { classPropertyName: "showGradient", publicName: "showGradient", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, darkBackground: { classPropertyName: "darkBackground", publicName: "darkBackground", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, trailingIcon: { classPropertyName: "trailingIcon", publicName: "trailingIcon", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, metricSize: { classPropertyName: "metricSize", publicName: "metricSize", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: false, transformFunction: null }, headingLevel: { classPropertyName: "headingLevel", publicName: "headingLevel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cardClick: "cardClick", actionClick: "actionClick" }, host: { listeners: { "click": "onActivate()", "keydown": "onKeyDown($event)" }, properties: { "class.cmp-card--outlined": "appearance() === 'outlined'", "class.cmp-card--filled": "appearance() === 'filled'", "class.cmp-card--gradient": "appearance() === 'gradient'", "class.cmp-card--banner": "appearance() === 'banner'", "class.cmp-card--content": "variant() === 'content'", "class.cmp-card--basic": "variant() === 'basic'", "attr.data-card-size": "variant() === 'basic' ? size() : null", "class.cmp-card--metric": "variant() === 'metric'", "class.cmp-card--current": "variant() === 'metric' && current()", "class.cmp-card--radius-md": "radius() === 'md'", "class.cmp-card--radius-lg": "radius() === 'lg'", "class.cmp-card--radius-xl": "radius() === 'xl'", "class.cmp-card--pad-none": "effectivePadding() === 'none'", "class.cmp-card--pad-sm": "effectivePadding() === 'sm'", "class.cmp-card--pad-md": "effectivePadding() === 'md'", "class.cmp-card--pad-lg": "effectivePadding() === 'lg'", "class.cmp-card--pad-xl": "effectivePadding() === 'xl'", "style.width": "fullWidth() ? '100%' : null", "class.cmp-card--interactive": "interactive()", "class.cmp-card--disabled": "disabled()", "class.cmp-card--selected": "selected()", "class.cmp-card--no-gradient": "!showGradient()", "class.cmp-card--compact": "compact()", "class.cmp-card--metric-sm": "variant() === 'metric' && metricSize() === 'small'", "class.cmp-card--dark-bg": "darkBackground()", "class.cmp-card--hide-image": "hideImage()", "attr.role": "interactive() ? 'button' : null", "attr.tabindex": "interactive() && !disabled() ? 0 : null", "attr.aria-label": "ariaLabel() ?? null", "attr.aria-disabled": "disabled() || null", "attr.aria-pressed": "interactive() && variant() === 'metric' ? current() : null", "style.border-color": "variant() === 'metric' && current() ? 'var(--accent-primary-sys-primary)' : null", "style.border-width": "variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null" }, classAttribute: "cmp-card" }, hostDirectives: [{ directive: i1.RippleDirective }], ngImport: i0, template: "@if (isBanner() && mediaUrl() && !hideImage()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (isBanner()) {\r\n <div class=\"cc cc--banner\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n }\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row \u2014 icon \u00B7 title \u00B7 arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--banner]=\"isBanner()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragment: renders <h2>\u2013<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n", styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden;border-radius:var(--border-radius-sys-radius-lg);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);isolation:isolate;container-type:inline-size;text-wrap:pretty}:host.cmp-card--radius-md{border-radius:var(--border-radius-sys-radius-md)}:host.cmp-card--radius-lg{border-radius:var(--border-radius-sys-radius-lg)}:host.cmp-card--radius-xl{border-radius:var(--border-radius-sys-radius-xl)}.cmp-card__body{position:relative;z-index:1;display:flex;flex-direction:column;flex:1 1 auto;min-height:0}:host.cmp-card--pad-none .cmp-card__body{padding:0}:host.cmp-card--pad-sm .cmp-card__body{padding:var(--spacing-padding-sys-padding-16)}:host.cmp-card--pad-md .cmp-card__body{padding:var(--spacing-padding-sys-padding-20)}:host.cmp-card--pad-lg .cmp-card__body{padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--pad-xl .cmp-card__body{padding:var(--spacing-padding-sys-padding-32)}:host.cmp-card--outlined{background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant)}:host.cmp-card--filled{background-color:var(--accent-primary-sys-primary-container);color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--gradient{background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%);background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant)}:host.cmp-card--gradient.cmp-card--content{background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--content .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--content .cc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-16);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}:host.cmp-card--gradient.cmp-card--content.cmp-card--no-gradient .cc{background-image:none}:host.cmp-card--compact .cc:not(.cc--banner){min-height:0}:host.cmp-card--gradient.cmp-card--content .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--gradient.cmp-card--content .cc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);font-weight:var(--body-small-sys-font-weight)}:host.cmp-card--banner{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}:host.cmp-card--banner.cmp-card--hide-image{background-color:var(--accent-primary-sys-primary-container)}.cmp-card__media{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center}.cmp-card__scrim{position:absolute;inset:0;z-index:0;background-image:linear-gradient(180deg,var(--transparent-neutral-sys-black-40) 0%,var(--transparent-neutral-sys-black-10) 32%,var(--transparent-neutral-sys-black-10) 64%,var(--transparent-neutral-sys-black-50) 100%);mix-blend-mode:multiply}:host.cmp-card--interactive{cursor:pointer;transition:box-shadow .3s cubic-bezier(.4,0,.2,1),border-color .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1)}:host.cmp-card--interactive:after{content:\"\";position:absolute;inset:0;z-index:0;pointer-events:none;border-radius:inherit;background-color:var(--surface-surface-sys-on-surface);opacity:0;transition:opacity .12s ease-out}:host.cmp-card--interactive.cmp-card--filled:after,:host.cmp-card--interactive.cmp-card--banner:after{background-color:var(--accent-primary-sys-on-primary)}:host.cmp-card--interactive:hover{border-color:var(--outline-sys-outline-variant);transform:translateY(-2px);box-shadow:0 4px 16px #0000001a,0 2px 4px #00000014}:host.cmp-card--interactive:hover:after{opacity:.08}:host.cmp-card--interactive:active:after{opacity:.1}:host.cmp-card--selected,:host.cmp-card--interactive:focus-visible{outline:none;border-color:var(--add-on-primary-fixed-sys-on-primary-fixed-variant);box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}.cc__arrow,.bc__arrow{transition:transform .3s cubic-bezier(.4,0,.2,1)}:host.cmp-card--interactive:hover .cc__arrow,:host.cmp-card--interactive:hover .bc__arrow{transform:translate(2px,-2px)}:host.cmp-card--disabled{pointer-events:none;opacity:.38}:host.cmp-card--dark-bg{background-color:var(--transparent-neutral-sys-white-20);background-image:none;border-color:transparent;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--dark-bg .mc__value,:host.cmp-card--dark-bg .mc__label{color:var(--accent-primary-sys-on-primary)}@media(prefers-reduced-motion:reduce){:host.cmp-card--interactive{transition:box-shadow .3s cubic-bezier(.4,0,.2,1),border-color .3s cubic-bezier(.4,0,.2,1)}:host.cmp-card--interactive:hover{transform:none}:host.cmp-card--interactive:hover .cc__arrow,:host.cmp-card--interactive:hover .bc__arrow{transform:none}}@media(forced-colors:active){:host{border:1px solid CanvasText;forced-color-adjust:none}:host.cmp-card--interactive:focus-visible{outline:2px solid Highlight;outline-offset:2px}}.cc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-12);font-family:var(--body-medium-sys-font-family)}.cc:not(.cc--banner){min-height:18.125rem}.cc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.cc__top--label{justify-content:flex-start;align-items:center;gap:var(--spacing-padding-sys-padding-16)}.cc__category-label{background:transparent;padding:0;color:var(--accent-primary-sys-primary);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}.cc__icon{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary);line-height:0}.cc__icon--neutral{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cc__banner{display:flex;align-items:center;justify-content:center;width:100%;height:120px;flex-shrink:0;overflow:hidden;border-radius:var(--border-radius-sys-radius-sm);background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cc__banner-icon{display:inline-flex;line-height:0}.cc__container{display:flex;flex-direction:column;justify-content:space-between;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-8);padding:var(--spacing-padding-sys-padding-8)}.cc__title-group{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cc__category-eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc--with-icon .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized);color:var(--surface-surface-sys-on-surface)}.cc--inline-icon .cc__container{flex:0 0 auto;margin-top:auto}.cc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.cc__arrow{display:inline-flex;color:var(--surface-surface-sys-on-surface-variant);flex-shrink:0;line-height:0}.cc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.cc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.cc__title{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}.cc__subtitle{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}.cc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-2) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc__chip--glass{background-color:var(--transparent-neutral-sys-white-20);color:var(--accent-primary-sys-on-primary);-webkit-backdrop-filter:blur(.375rem);backdrop-filter:blur(.375rem)}.cc--filled .cc__icon{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--accent-primary-sys-primary)}.cc--filled .cc__category-label,.cc--filled .cc__title{color:var(--accent-primary-sys-on-primary-container)}.cc--filled .cc__category-eyebrow,.cc--filled .cc__subtitle,.cc--filled .cc__desc,.cc--filled .cc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}.cc--banner{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:12.5rem;justify-content:space-between;gap:var(--spacing-padding-sys-padding-24);padding:var(--spacing-padding-sys-padding-24)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.cc__img-top{display:flex;flex-direction:column;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12)}.cc__img-foot{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--spacing-padding-sys-padding-16)}.cc__banner-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__headline{margin:0;font-family:var(--headline-large-sys-font-family);font-size:var(--headline-large-sys-font-size);line-height:var(--headline-large-sys-line-height);font-weight:var(--headline-large-sys-font-weight);letter-spacing:var(--headline-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}:host.cmp-card--outlined .cc__headline{color:var(--surface-surface-sys-on-surface)}.cc__img-foot compsych-button{align-self:flex-end;flex-shrink:0}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__img-foot compsych-button{align-self:flex-start}}.cc--banner .cc__title,.cc--banner .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--banner .cc__subtitle{color:var(--transparent-neutral-sys-white-80)}.cc--banner .cc__desc{color:var(--accent-primary-sys-on-primary-container-variant)}.cc__metrics{display:flex;flex-wrap:wrap;gap:var(--spacing-padding-sys-padding-8)}.cc__metrics compsych-card{flex:0 0 auto;width:8rem}.cc__headline-desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--transparent-neutral-sys-white-80)}.ac{display:flex;flex:1 1 auto;align-items:center;gap:var(--spacing-padding-sys-padding-16);font-family:var(--body-medium-sys-font-family)}.ac__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.ac__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4);flex:1 1 auto;min-width:0}.ac__label{margin:0;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.ac__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.ac__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.ac--no-desc .ac__label{line-height:1}.ac--vertical{flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:var(--spacing-padding-sys-padding-16)}.ac__badge{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--surface-surface-container-sys-surface-container);color:var(--surface-surface-sys-on-surface);transition:background-color .14s ease-out;line-height:0}:host(:hover) .ac__badge{background-color:var(--surface-surface-container-sys-surface-container-lowest)}.ac--vertical .ac__label{white-space:pre-line;overflow:visible;font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight)}@media(prefers-reduced-motion:reduce){.ac__badge{transition:none}}.mc{display:flex;flex:1 1 auto;flex-direction:column;align-items:center;justify-content:center;gap:var(--spacing-padding-sys-padding-8);text-align:center;font-family:var(--body-medium-sys-font-family)}.mc__value{font-family:var(--headline-medium-sys-font-family);font-size:var(--headline-medium-sys-font-size);line-height:var(--headline-medium-sys-line-height);font-weight:var(--headline-medium-sys-font-weight);letter-spacing:var(--headline-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc__label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc--current .mc__value,.mc--current .mc__label{color:var(--accent-primary-sys-primary)}.mc--current .mc__value{font-weight:var(--headline-medium-sys-font-weight-emphasized)}.mc--current .mc__label{font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--metric{box-shadow:0 2px 2px #0000000f,0 2px 4px #0000000a}:host.cmp-card--metric-sm .mc{gap:var(--spacing-padding-sys-padding-4)}:host.cmp-card--metric-sm .mc__value{font-size:var(--headline-small-sys-font-size);line-height:var(--headline-small-sys-line-height);letter-spacing:var(--headline-small-sys-tracking);font-weight:var(--headline-small-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__value{font-weight:var(--headline-small-sys-font-weight-emphasized)}:host.cmp-card--metric-sm .mc__label{font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);font-weight:var(--label-medium-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__label{font-weight:var(--label-medium-sys-font-weight-emphasized)}:host.cmp-card--metric.cmp-card--current{box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}.bc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-48);padding:var(--spacing-padding-sys-padding-32);font-family:var(--body-medium-sys-font-family)}.bc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.bc__icon{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.bc__icon--badge{align-items:center;justify-content:center;width:60px;height:60px;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.bc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.bc__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.bc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.bc__body{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-24)}.bc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.bc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.bc__eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__title{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface)}.bc__subtitle{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface-variant)}.bc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]){background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .bc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-24);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}.bc--banner{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--banner .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--banner .bc--row .bc__title,:host.cmp-card--banner .bc--row .bc__icon,:host.cmp-card--banner .bc--row .bc__arrow{color:var(--accent-primary-sys-on-primary)}:host[data-card-size=sm] .bc{gap:var(--spacing-padding-sys-padding-40);padding:var(--spacing-padding-sys-padding-24)}:host[data-card-size=sm] .bc__title,:host[data-card-size=sm] .bc__subtitle{font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);letter-spacing:var(--title-small-sys-tracking);font-weight:var(--title-small-sys-font-weight)}:host[data-card-size=sm] .bc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking)}:host[data-card-size=xs]{border-radius:var(--border-radius-sys-radius-md)}.bc--row{flex-direction:row;align-items:center;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-16)}.bc--row .bc__icon{color:var(--surface-surface-sys-on-surface)}.bc--row .bc__row-text{flex:1 1 auto;min-width:0}.bc--row .bc__title{font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);font-weight:var(--body-medium-sys-font-weight)}.bc--promo{justify-content:space-between;gap:var(--spacing-padding-sys-padding-24)}.bc--promo .bc__chip{align-self:flex-start}.bc--promo compsych-button{align-self:flex-end}.bc--promo.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}:host.cmp-card--filled .bc__title,:host.cmp-card--filled .bc__icon{color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--filled .bc__eyebrow,:host.cmp-card--filled .bc__subtitle,:host.cmp-card--filled .bc__desc,:host.cmp-card--filled .bc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}\n"], dependencies: [{ kind: "component", type: CardComponent, selector: "compsych-card", inputs: ["variant", "appearance", "radius", "padding", "size", "interactive", "disabled", "selected", "imageSrc", "hideImage", "imagePosition", "icon", "category", "categoryStyle", "iconStyle", "title", "subtitle", "description", "headline", "headlineDescription", "metrics", "actionLabel", "actionLeadingIcon", "actionTrailingIcon", "actionDisabled", "inlineIcon", "showArrow", "showGradient", "compact", "darkBackground", "label", "trailingIcon", "orientation", "fullWidth", "metricSize", "value", "current", "headingLevel", "aria-label"], outputs: ["cardClick", "actionClick"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ButtonComponent, selector: "compsych-button", inputs: ["label", "variant", "size", "leadingIcon", "trailingIcon", "type", "ariaLabel", "iconOnly", "disabled", "loading", "fullWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
210
210
|
}
|
|
211
211
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CardComponent, decorators: [{
|
|
212
212
|
type: Component,
|
|
@@ -247,6 +247,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
247
247
|
'[style.border-width]': "variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null",
|
|
248
248
|
'(click)': 'onActivate()',
|
|
249
249
|
'(keydown)': 'onKeyDown($event)',
|
|
250
|
-
}, template: "@if (isBanner() && mediaUrl() && !hideImage()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (isBanner()) {\r\n <div class=\"cc cc--banner\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n }\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row \u2014 icon \u00B7 title \u00B7 arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--banner]=\"isBanner()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragment: renders <h2>\u2013<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n", styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden;border-radius:var(--border-radius-sys-radius-lg);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);isolation:isolate;container-type:inline-size;text-wrap:pretty}:host.cmp-card--radius-md{border-radius:var(--border-radius-sys-radius-md)}:host.cmp-card--radius-lg{border-radius:var(--border-radius-sys-radius-lg)}:host.cmp-card--radius-xl{border-radius:var(--border-radius-sys-radius-xl)}.cmp-card__body{position:relative;z-index:1;display:flex;flex-direction:column;flex:1 1 auto;min-height:0}:host.cmp-card--pad-none .cmp-card__body{padding:0}:host.cmp-card--pad-sm .cmp-card__body{padding:var(--spacing-padding-sys-padding-16)}:host.cmp-card--pad-md .cmp-card__body{padding:var(--spacing-padding-sys-padding-20)}:host.cmp-card--pad-lg .cmp-card__body{padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--pad-xl .cmp-card__body{padding:var(--spacing-padding-sys-padding-32)}:host.cmp-card--outlined{background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant)}:host.cmp-card--filled{background-color:var(--accent-primary-sys-primary-container);color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--gradient{background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%);background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant)}:host.cmp-card--gradient.cmp-card--content{background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--content .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--content .cc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-16);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}:host.cmp-card--gradient.cmp-card--content.cmp-card--no-gradient .cc{background-image:none}:host.cmp-card--compact .cc:not(.cc--banner){min-height:0}:host.cmp-card--gradient.cmp-card--content .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--gradient.cmp-card--content .cc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);font-weight:var(--body-small-sys-font-weight)}:host.cmp-card--banner{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}:host.cmp-card--banner.cmp-card--hide-image{background-color:var(--accent-primary-sys-primary-container)}.cmp-card__media{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center}.cmp-card__scrim{position:absolute;inset:0;z-index:0;background-image:linear-gradient(180deg,var(--transparent-neutral-sys-black-40) 0%,var(--transparent-neutral-sys-black-10) 32%,var(--transparent-neutral-sys-black-10) 64%,var(--transparent-neutral-sys-black-50) 100%);mix-blend-mode:multiply}:host.cmp-card--interactive{cursor:pointer;transition:box-shadow .14s ease-out,border-color .14s ease-out,border-width .14s ease-out}:host.cmp-card--interactive:after{content:\"\";position:absolute;inset:0;z-index:0;pointer-events:none;border-radius:inherit;background-color:var(--surface-surface-sys-on-surface);opacity:0;transition:opacity .14s ease-out}:host.cmp-card--interactive.cmp-card--filled:after,:host.cmp-card--interactive.cmp-card--banner:after{background-color:var(--accent-primary-sys-on-primary)}:host.cmp-card--interactive:hover{border-color:var(--outline-sys-outline-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 4px 16px #0000001a,0 2px 4px #00000014}:host.cmp-card--interactive:hover:after{opacity:.08}:host.cmp-card--interactive:active:after{opacity:.1}:host.cmp-card--selected,:host.cmp-card--interactive:focus-visible{outline:none;border-color:var(--add-on-primary-fixed-sys-on-primary-fixed-variant);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}:host.cmp-card--disabled{pointer-events:none;opacity:.38}:host.cmp-card--dark-bg{background-color:var(--transparent-neutral-sys-white-20);background-image:none;border-color:transparent;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--dark-bg .mc__value,:host.cmp-card--dark-bg .mc__label{color:var(--accent-primary-sys-on-primary)}@media(prefers-reduced-motion:reduce){:host.cmp-card--interactive{transition:none}}@media(forced-colors:active){:host{border:1px solid CanvasText;forced-color-adjust:none}:host.cmp-card--interactive:focus-visible{outline:2px solid Highlight;outline-offset:2px}}.cc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-12);font-family:var(--body-medium-sys-font-family)}.cc:not(.cc--banner){min-height:18.125rem}.cc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.cc__top--label{justify-content:flex-start;align-items:center;gap:var(--spacing-padding-sys-padding-16)}.cc__category-label{background:transparent;padding:0;color:var(--accent-primary-sys-primary);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}.cc__icon{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary);line-height:0}.cc__icon--neutral{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cc__banner{display:flex;align-items:center;justify-content:center;width:100%;height:120px;flex-shrink:0;overflow:hidden;border-radius:var(--border-radius-sys-radius-sm);background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cc__banner-icon{display:inline-flex;line-height:0}.cc__container{display:flex;flex-direction:column;justify-content:space-between;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-8);padding:var(--spacing-padding-sys-padding-8)}.cc__title-group{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cc__category-eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc--with-icon .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized);color:var(--surface-surface-sys-on-surface)}.cc--inline-icon .cc__container{flex:0 0 auto;margin-top:auto}.cc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.cc__arrow{display:inline-flex;color:var(--surface-surface-sys-on-surface-variant);flex-shrink:0;line-height:0}.cc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.cc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.cc__title{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}.cc__subtitle{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}.cc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-2) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc__chip--glass{background-color:var(--transparent-neutral-sys-white-20);color:var(--accent-primary-sys-on-primary);-webkit-backdrop-filter:blur(.375rem);backdrop-filter:blur(.375rem)}.cc--filled .cc__icon{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--accent-primary-sys-primary)}.cc--filled .cc__category-label,.cc--filled .cc__title{color:var(--accent-primary-sys-on-primary-container)}.cc--filled .cc__category-eyebrow,.cc--filled .cc__subtitle,.cc--filled .cc__desc,.cc--filled .cc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}.cc--banner{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:12.5rem;justify-content:space-between;gap:var(--spacing-padding-sys-padding-24);padding:var(--spacing-padding-sys-padding-24)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.cc__img-top{display:flex;flex-direction:column;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12)}.cc__img-foot{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--spacing-padding-sys-padding-16)}.cc__banner-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__headline{margin:0;font-family:var(--headline-large-sys-font-family);font-size:var(--headline-large-sys-font-size);line-height:var(--headline-large-sys-line-height);font-weight:var(--headline-large-sys-font-weight);letter-spacing:var(--headline-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}:host.cmp-card--outlined .cc__headline{color:var(--surface-surface-sys-on-surface)}.cc__img-foot compsych-button{align-self:flex-end;flex-shrink:0}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__img-foot compsych-button{align-self:flex-start}}.cc--banner .cc__title,.cc--banner .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--banner .cc__subtitle{color:var(--transparent-neutral-sys-white-80)}.cc--banner .cc__desc{color:var(--accent-primary-sys-on-primary-container-variant)}.cc__metrics{display:flex;flex-wrap:wrap;gap:var(--spacing-padding-sys-padding-8)}.cc__metrics compsych-card{flex:0 0 auto;width:8rem}.cc__headline-desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--transparent-neutral-sys-white-80)}.ac{display:flex;flex:1 1 auto;align-items:center;gap:var(--spacing-padding-sys-padding-16);font-family:var(--body-medium-sys-font-family)}.ac__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.ac__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4);flex:1 1 auto;min-width:0}.ac__label{margin:0;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.ac__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.ac__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.ac--no-desc .ac__label{line-height:1}.ac--vertical{flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:var(--spacing-padding-sys-padding-16)}.ac__badge{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--surface-surface-container-sys-surface-container);color:var(--surface-surface-sys-on-surface);transition:background-color .14s ease-out;line-height:0}:host(:hover) .ac__badge{background-color:var(--surface-surface-container-sys-surface-container-lowest)}.ac--vertical .ac__label{white-space:pre-line;overflow:visible;font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight)}@media(prefers-reduced-motion:reduce){.ac__badge{transition:none}}.mc{display:flex;flex:1 1 auto;flex-direction:column;align-items:center;justify-content:center;gap:var(--spacing-padding-sys-padding-8);text-align:center;font-family:var(--body-medium-sys-font-family)}.mc__value{font-family:var(--headline-medium-sys-font-family);font-size:var(--headline-medium-sys-font-size);line-height:var(--headline-medium-sys-line-height);font-weight:var(--headline-medium-sys-font-weight);letter-spacing:var(--headline-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc__label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc--current .mc__value,.mc--current .mc__label{color:var(--accent-primary-sys-primary)}.mc--current .mc__value{font-weight:var(--headline-medium-sys-font-weight-emphasized)}.mc--current .mc__label{font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--metric{box-shadow:0 2px 2px #0000000f,0 2px 4px #0000000a}:host.cmp-card--metric-sm .mc{gap:var(--spacing-padding-sys-padding-4)}:host.cmp-card--metric-sm .mc__value{font-size:var(--headline-small-sys-font-size);line-height:var(--headline-small-sys-line-height);letter-spacing:var(--headline-small-sys-tracking);font-weight:var(--headline-small-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__value{font-weight:var(--headline-small-sys-font-weight-emphasized)}:host.cmp-card--metric-sm .mc__label{font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);font-weight:var(--label-medium-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__label{font-weight:var(--label-medium-sys-font-weight-emphasized)}:host.cmp-card--metric.cmp-card--current{box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}.bc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-48);padding:var(--spacing-padding-sys-padding-32);font-family:var(--body-medium-sys-font-family)}.bc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.bc__icon{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.bc__icon--badge{align-items:center;justify-content:center;width:60px;height:60px;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.bc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.bc__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.bc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.bc__body{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-24)}.bc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.bc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.bc__eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__title{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface)}.bc__subtitle{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface-variant)}.bc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]){background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .bc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-24);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}.bc--banner{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--banner .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--banner .bc--row .bc__title,:host.cmp-card--banner .bc--row .bc__icon,:host.cmp-card--banner .bc--row .bc__arrow{color:var(--accent-primary-sys-on-primary)}:host[data-card-size=sm] .bc{gap:var(--spacing-padding-sys-padding-40);padding:var(--spacing-padding-sys-padding-24)}:host[data-card-size=sm] .bc__title,:host[data-card-size=sm] .bc__subtitle{font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);letter-spacing:var(--title-small-sys-tracking);font-weight:var(--title-small-sys-font-weight)}:host[data-card-size=sm] .bc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking)}:host[data-card-size=xs]{border-radius:var(--border-radius-sys-radius-md)}.bc--row{flex-direction:row;align-items:center;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-16)}.bc--row .bc__icon{color:var(--surface-surface-sys-on-surface)}.bc--row .bc__row-text{flex:1 1 auto;min-width:0}.bc--row .bc__title{font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);font-weight:var(--body-medium-sys-font-weight)}.bc--promo{justify-content:space-between;gap:var(--spacing-padding-sys-padding-24)}.bc--promo .bc__chip{align-self:flex-start}.bc--promo compsych-button{align-self:flex-end}.bc--promo.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}:host.cmp-card--filled .bc__title,:host.cmp-card--filled .bc__icon{color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--filled .bc__eyebrow,:host.cmp-card--filled .bc__subtitle,:host.cmp-card--filled .bc__desc,:host.cmp-card--filled .bc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}\n"] }]
|
|
250
|
+
}, template: "@if (isBanner() && mediaUrl() && !hideImage()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (isBanner()) {\r\n <div class=\"cc cc--banner\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n }\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row \u2014 icon \u00B7 title \u00B7 arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--banner]=\"isBanner()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragment: renders <h2>\u2013<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n", styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden;border-radius:var(--border-radius-sys-radius-lg);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);isolation:isolate;container-type:inline-size;text-wrap:pretty}:host.cmp-card--radius-md{border-radius:var(--border-radius-sys-radius-md)}:host.cmp-card--radius-lg{border-radius:var(--border-radius-sys-radius-lg)}:host.cmp-card--radius-xl{border-radius:var(--border-radius-sys-radius-xl)}.cmp-card__body{position:relative;z-index:1;display:flex;flex-direction:column;flex:1 1 auto;min-height:0}:host.cmp-card--pad-none .cmp-card__body{padding:0}:host.cmp-card--pad-sm .cmp-card__body{padding:var(--spacing-padding-sys-padding-16)}:host.cmp-card--pad-md .cmp-card__body{padding:var(--spacing-padding-sys-padding-20)}:host.cmp-card--pad-lg .cmp-card__body{padding:var(--spacing-padding-sys-padding-24)}:host.cmp-card--pad-xl .cmp-card__body{padding:var(--spacing-padding-sys-padding-32)}:host.cmp-card--outlined{background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant)}:host.cmp-card--filled{background-color:var(--accent-primary-sys-primary-container);color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--gradient{background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%);background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant)}:host.cmp-card--gradient.cmp-card--content{background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--content .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--content .cc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-16);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}:host.cmp-card--gradient.cmp-card--content.cmp-card--no-gradient .cc{background-image:none}:host.cmp-card--compact .cc:not(.cc--banner){min-height:0}:host.cmp-card--gradient.cmp-card--content .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--gradient.cmp-card--content .cc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);font-weight:var(--body-small-sys-font-weight)}:host.cmp-card--banner{color:var(--accent-primary-sys-on-primary-container);background-color:var(--surface-surface-container-sys-surface-container-high)}:host.cmp-card--banner.cmp-card--hide-image{background-color:var(--accent-primary-sys-primary-container)}.cmp-card__media{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center}.cmp-card__scrim{position:absolute;inset:0;z-index:0;background-image:linear-gradient(180deg,var(--transparent-neutral-sys-black-40) 0%,var(--transparent-neutral-sys-black-10) 32%,var(--transparent-neutral-sys-black-10) 64%,var(--transparent-neutral-sys-black-50) 100%);mix-blend-mode:multiply}:host.cmp-card--interactive{cursor:pointer;transition:box-shadow .3s cubic-bezier(.4,0,.2,1),border-color .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1)}:host.cmp-card--interactive:after{content:\"\";position:absolute;inset:0;z-index:0;pointer-events:none;border-radius:inherit;background-color:var(--surface-surface-sys-on-surface);opacity:0;transition:opacity .12s ease-out}:host.cmp-card--interactive.cmp-card--filled:after,:host.cmp-card--interactive.cmp-card--banner:after{background-color:var(--accent-primary-sys-on-primary)}:host.cmp-card--interactive:hover{border-color:var(--outline-sys-outline-variant);transform:translateY(-2px);box-shadow:0 4px 16px #0000001a,0 2px 4px #00000014}:host.cmp-card--interactive:hover:after{opacity:.08}:host.cmp-card--interactive:active:after{opacity:.1}:host.cmp-card--selected,:host.cmp-card--interactive:focus-visible{outline:none;border-color:var(--add-on-primary-fixed-sys-on-primary-fixed-variant);box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}.cc__arrow,.bc__arrow{transition:transform .3s cubic-bezier(.4,0,.2,1)}:host.cmp-card--interactive:hover .cc__arrow,:host.cmp-card--interactive:hover .bc__arrow{transform:translate(2px,-2px)}:host.cmp-card--disabled{pointer-events:none;opacity:.38}:host.cmp-card--dark-bg{background-color:var(--transparent-neutral-sys-white-20);background-image:none;border-color:transparent;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--dark-bg .mc__value,:host.cmp-card--dark-bg .mc__label{color:var(--accent-primary-sys-on-primary)}@media(prefers-reduced-motion:reduce){:host.cmp-card--interactive{transition:box-shadow .3s cubic-bezier(.4,0,.2,1),border-color .3s cubic-bezier(.4,0,.2,1)}:host.cmp-card--interactive:hover{transform:none}:host.cmp-card--interactive:hover .cc__arrow,:host.cmp-card--interactive:hover .bc__arrow{transform:none}}@media(forced-colors:active){:host{border:1px solid CanvasText;forced-color-adjust:none}:host.cmp-card--interactive:focus-visible{outline:2px solid Highlight;outline-offset:2px}}.cc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-12);font-family:var(--body-medium-sys-font-family)}.cc:not(.cc--banner){min-height:18.125rem}.cc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.cc__top--label{justify-content:flex-start;align-items:center;gap:var(--spacing-padding-sys-padding-16)}.cc__category-label{background:transparent;padding:0;color:var(--accent-primary-sys-primary);font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized)}.cc__icon{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary);line-height:0}.cc__icon--neutral{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline)}.cc__banner{display:flex;align-items:center;justify-content:center;width:100%;height:120px;flex-shrink:0;overflow:hidden;border-radius:var(--border-radius-sys-radius-sm);background-color:var(--add-on-primary-fixed-sys-primary-fixed-dim);color:var(--add-on-primary-fixed-sys-on-primary-fixed)}.cc__banner-icon{display:inline-flex;line-height:0}.cc__container{display:flex;flex-direction:column;justify-content:space-between;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-8);padding:var(--spacing-padding-sys-padding-8)}.cc__title-group{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cc__category-eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc--with-icon .cc__title{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking);font-weight:var(--label-large-sys-font-weight-emphasized);color:var(--surface-surface-sys-on-surface)}.cc--inline-icon .cc__container{flex:0 0 auto;margin-top:auto}.cc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.cc__arrow{display:inline-flex;color:var(--surface-surface-sys-on-surface-variant);flex-shrink:0;line-height:0}.cc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.cc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.cc__title{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}.cc__subtitle{margin:0;font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight-emphasized);letter-spacing:var(--title-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.cc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}.cc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-2) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.cc__chip--glass{background-color:var(--transparent-neutral-sys-white-20);color:var(--accent-primary-sys-on-primary);-webkit-backdrop-filter:blur(.375rem);backdrop-filter:blur(.375rem)}.cc--filled .cc__icon{background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--accent-primary-sys-primary)}.cc--filled .cc__category-label,.cc--filled .cc__title{color:var(--accent-primary-sys-on-primary-container)}.cc--filled .cc__category-eyebrow,.cc--filled .cc__subtitle,.cc--filled .cc__desc,.cc--filled .cc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}.cc--banner{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:12.5rem;justify-content:space-between;gap:var(--spacing-padding-sys-padding-24);padding:var(--spacing-padding-sys-padding-24)}.cc__media-icon{display:inline-flex;flex-shrink:0;color:var(--accent-primary-sys-on-primary);line-height:0}.cc__img-top{display:flex;flex-direction:column;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12)}.cc__img-foot{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--spacing-padding-sys-padding-16)}.cc__banner-text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8);min-width:0}.cc__headline{margin:0;font-family:var(--headline-large-sys-font-family);font-size:var(--headline-large-sys-font-size);line-height:var(--headline-large-sys-line-height);font-weight:var(--headline-large-sys-font-weight);letter-spacing:var(--headline-large-sys-tracking);color:var(--accent-primary-sys-on-primary)}:host.cmp-card--outlined .cc__headline{color:var(--surface-surface-sys-on-surface)}.cc__img-foot compsych-button{align-self:flex-end;flex-shrink:0}@container (max-width: 36rem){.cc__img-foot{flex-direction:column;align-items:flex-start}.cc__img-foot compsych-button{align-self:flex-start}}.cc--banner .cc__title,.cc--banner .cc__arrow{color:var(--accent-primary-sys-on-primary)}.cc--banner .cc__subtitle{color:var(--transparent-neutral-sys-white-80)}.cc--banner .cc__desc{color:var(--accent-primary-sys-on-primary-container-variant)}.cc__metrics{display:flex;flex-wrap:wrap;gap:var(--spacing-padding-sys-padding-8)}.cc__metrics compsych-card{flex:0 0 auto;width:8rem}.cc__headline-desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--transparent-neutral-sys-white-80)}.ac{display:flex;flex:1 1 auto;align-items:center;gap:var(--spacing-padding-sys-padding-16);font-family:var(--body-medium-sys-font-family)}.ac__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.ac__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4);flex:1 1 auto;min-width:0}.ac__label{margin:0;font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight-emphasized);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.ac__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.ac__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.ac--no-desc .ac__label{line-height:1}.ac--vertical{flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:var(--spacing-padding-sys-padding-16)}.ac__badge{display:inline-flex;align-items:center;justify-content:center;width:var(--sys-size-xl);height:var(--sys-size-xl);flex-shrink:0;border-radius:var(--border-radius-sys-radius-full);background-color:var(--surface-surface-container-sys-surface-container);color:var(--surface-surface-sys-on-surface);transition:background-color .14s ease-out;line-height:0}:host(:hover) .ac__badge{background-color:var(--surface-surface-container-sys-surface-container-lowest)}.ac--vertical .ac__label{white-space:pre-line;overflow:visible;font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);font-weight:var(--title-small-sys-font-weight)}@media(prefers-reduced-motion:reduce){.ac__badge{transition:none}}.mc{display:flex;flex:1 1 auto;flex-direction:column;align-items:center;justify-content:center;gap:var(--spacing-padding-sys-padding-8);text-align:center;font-family:var(--body-medium-sys-font-family)}.mc__value{font-family:var(--headline-medium-sys-font-family);font-size:var(--headline-medium-sys-font-size);line-height:var(--headline-medium-sys-line-height);font-weight:var(--headline-medium-sys-font-weight);letter-spacing:var(--headline-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc__label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);line-height:var(--label-large-sys-line-height);font-weight:var(--label-large-sys-font-weight);letter-spacing:var(--label-large-sys-tracking);color:var(--surface-surface-sys-on-surface)}.mc--current .mc__value,.mc--current .mc__label{color:var(--accent-primary-sys-primary)}.mc--current .mc__value{font-weight:var(--headline-medium-sys-font-weight-emphasized)}.mc--current .mc__label{font-weight:var(--label-large-sys-font-weight-emphasized)}:host.cmp-card--metric{box-shadow:0 2px 2px #0000000f,0 2px 4px #0000000a}:host.cmp-card--metric-sm .mc{gap:var(--spacing-padding-sys-padding-4)}:host.cmp-card--metric-sm .mc__value{font-size:var(--headline-small-sys-font-size);line-height:var(--headline-small-sys-line-height);letter-spacing:var(--headline-small-sys-tracking);font-weight:var(--headline-small-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__value{font-weight:var(--headline-small-sys-font-weight-emphasized)}:host.cmp-card--metric-sm .mc__label{font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);font-weight:var(--label-medium-sys-font-weight)}:host.cmp-card--metric-sm .mc--current .mc__label{font-weight:var(--label-medium-sys-font-weight-emphasized)}:host.cmp-card--metric.cmp-card--current{box-shadow:0 0 0 var(--spacing-padding-sys-padding-4) var(--transparent-primary-sys-primary-08)}.bc{display:flex;flex-direction:column;flex:1 1 auto;gap:var(--spacing-padding-sys-padding-48);padding:var(--spacing-padding-sys-padding-32);font-family:var(--body-medium-sys-font-family)}.bc__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-padding-sys-padding-8)}.bc__icon{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface);line-height:0}.bc__icon--badge{align-items:center;justify-content:center;width:60px;height:60px;border-radius:var(--border-radius-sys-radius-full);background-color:var(--accent-primary-sys-primary);color:var(--accent-primary-sys-on-primary)}.bc__top-end{display:inline-flex;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.bc__arrow{display:inline-flex;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);line-height:0}.bc__chip{display:inline-flex;align-items:center;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-12);border-radius:var(--border-radius-sys-radius-full);background-color:var(--custom-info-sys-info-container);color:var(--custom-info-sys-on-info-container);font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);white-space:nowrap}.bc__body{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-24)}.bc__text{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-12)}.bc__heading{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-4)}.bc__eyebrow{margin:0;font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}.bc__title{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface)}.bc__subtitle{margin:0;font-family:var(--title-medium-sys-font-family);font-size:var(--title-medium-sys-font-size);line-height:var(--title-medium-sys-line-height);letter-spacing:var(--title-medium-sys-tracking);font-weight:var(--title-medium-sys-font-weight);color:var(--surface-surface-sys-on-surface-variant)}.bc__desc{margin:0;font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);color:var(--surface-surface-sys-on-surface-variant)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]){background-image:none;border-radius:var(--border-radius-sys-radius-xl)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .cmp-card__body{padding:var(--spacing-padding-sys-padding-8)}:host.cmp-card--gradient.cmp-card--basic:not([data-card-size=xs]):not([data-card-size=lg]) .bc{gap:var(--spacing-padding-sys-padding-32);padding:var(--spacing-padding-sys-padding-24);border-radius:var(--border-radius-sys-radius-lg);background-image:linear-gradient(180deg,var(--transparent-primary-sys-primary-08) 0%,var(--transparent-neutral-sys-white-10) 100%)}.bc--banner{justify-content:space-between;gap:var(--spacing-padding-sys-padding-12);min-height:15.25rem}.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}.bc--banner .bc__arrow{align-self:flex-end;color:var(--accent-primary-sys-on-primary)}:host.cmp-card--banner .bc--row .bc__title,:host.cmp-card--banner .bc--row .bc__icon,:host.cmp-card--banner .bc--row .bc__arrow{color:var(--accent-primary-sys-on-primary)}:host[data-card-size=sm] .bc{gap:var(--spacing-padding-sys-padding-40);padding:var(--spacing-padding-sys-padding-24)}:host[data-card-size=sm] .bc__title,:host[data-card-size=sm] .bc__subtitle{font-family:var(--title-small-sys-font-family);font-size:var(--title-small-sys-font-size);line-height:var(--title-small-sys-line-height);letter-spacing:var(--title-small-sys-tracking);font-weight:var(--title-small-sys-font-weight)}:host[data-card-size=sm] .bc__desc{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height);letter-spacing:var(--body-small-sys-tracking)}:host[data-card-size=xs]{border-radius:var(--border-radius-sys-radius-md)}.bc--row{flex-direction:row;align-items:center;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-16)}.bc--row .bc__icon{color:var(--surface-surface-sys-on-surface)}.bc--row .bc__row-text{flex:1 1 auto;min-width:0}.bc--row .bc__title{font-family:var(--body-medium-sys-font-family);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);letter-spacing:var(--body-medium-sys-tracking);font-weight:var(--body-medium-sys-font-weight)}.bc--promo{justify-content:space-between;gap:var(--spacing-padding-sys-padding-24)}.bc--promo .bc__chip{align-self:flex-start}.bc--promo compsych-button{align-self:flex-end}.bc--promo.bc--banner .bc__title{color:var(--accent-primary-sys-on-primary)}.bc--promo.bc--banner .bc__subtitle{color:var(--transparent-neutral-sys-white-80)}.bc--promo.bc--banner .bc__desc{color:var(--transparent-neutral-sys-white-50)}:host.cmp-card--filled .bc__title,:host.cmp-card--filled .bc__icon{color:var(--accent-primary-sys-on-primary-container)}:host.cmp-card--filled .bc__eyebrow,:host.cmp-card--filled .bc__subtitle,:host.cmp-card--filled .bc__desc,:host.cmp-card--filled .bc__arrow{color:var(--accent-primary-sys-on-primary-container-variant)}\n"] }]
|
|
251
251
|
}], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], imageSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageSrc", required: false }] }], hideImage: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideImage", required: false }] }], imagePosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "imagePosition", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], category: [{ type: i0.Input, args: [{ isSignal: true, alias: "category", required: false }] }], categoryStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "categoryStyle", required: false }] }], iconStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconStyle", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], headline: [{ type: i0.Input, args: [{ isSignal: true, alias: "headline", required: false }] }], headlineDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "headlineDescription", required: false }] }], metrics: [{ type: i0.Input, args: [{ isSignal: true, alias: "metrics", required: false }] }], actionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionLabel", required: false }] }], actionLeadingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionLeadingIcon", required: false }] }], actionTrailingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionTrailingIcon", required: false }] }], actionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionDisabled", required: false }] }], inlineIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "inlineIcon", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], showGradient: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGradient", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], darkBackground: [{ type: i0.Input, args: [{ isSignal: true, alias: "darkBackground", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], trailingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "trailingIcon", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], metricSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricSize", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: false }] }], headingLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingLevel", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], cardClick: [{ type: i0.Output, args: ["cardClick"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }] } });
|
|
252
252
|
//# sourceMappingURL=card.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/card-base/card.ts","../../../../../../packages/angular/src/lib/card-base/card.html"],"names":[],"mappings":"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","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { NgTemplateOutlet } from '@angular/common';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\nimport { RippleDirective } from './ripple.directive';\r\nimport { ButtonComponent } from '../button/button';\r\n\r\n/** A single metric item for the banner card's metric row. */\r\nexport interface BannerMetric {\r\n value: string | number;\r\n label?: string;\r\n /** Renders the metric in its primary-color \"current\" state. */\r\n current?: boolean;\r\n}\r\n\r\n/**\r\n * Card type — selects the projected/laid-out content. Mirrors the library's `variant` pattern.\r\n * `basic` is the Figma \"cards\" section (the \"Card Item\" family: icon + arrow +\r\n * title/subtitle, sized, across the outlined/filled/gradient/banner surfaces) —\r\n * distinct from the `content` category tiles.\r\n */\r\nexport type CardVariant = 'basic' | 'content' | 'action' | 'metric';\r\n/** Visual surface treatment. Mirrors the Figma \"Card Item\" Style property. */\r\nexport type CardAppearance = 'outlined' | 'filled' | 'gradient' | 'banner';\r\n/** Corner radius token: `md` (12px), `lg` (16px), `xl` (24px). */\r\nexport type CardRadius = 'md' | 'lg' | 'xl';\r\n/** Inner padding token (used by `variant=\"basic\"`; typed variants size themselves). */\r\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'xl';\r\n/** Action-card layout. */\r\nexport type CardOrientation = 'horizontal' | 'vertical';\r\n/** Metric-card size. `medium` is the default (24px padding, headline-medium value); `small` is compact (16px padding, headline-small value). */\r\nexport type CardMetricSize = 'medium' | 'small';\r\n/** Base Card Item size (Figma \"Size\" property). Drives layout + type scale. */\r\nexport type CardSize = 'xl' | 'lg' | 'md' | 'sm' | 'xs';\r\n/** Heading level for the title / headline / action label (screen-reader heading semantics). */\r\nexport type CardHeadingLevel = 2 | 3 | 4 | 5 | 6;\r\n/** How the content-variant category renders: trailing pill (`chip`) or leading plain-text `label`. */\r\nexport type CardCategoryStyle = 'chip' | 'label';\r\n/**\r\n * Content-variant icon badge treatment:\r\n * - `primary` — white icon on a filled primary (blue) circle (default).\r\n * - `neutral` — dark (on-surface) icon on a white circle with a thin outline.\r\n */\r\nexport type CardIconStyle = 'primary' | 'neutral';\r\n\r\n/**\r\n * Card — the single Cards component for the ComPsych Design System.\r\n *\r\n * Figma: Core Components — \"Cards\" (file VFBn7KCDy3FSIlvhNo3ylq, 1117:9829).\r\n *\r\n * One component, switched by `variant` (like Accordion's `variant`):\r\n * - `basic` — a bare surface; project your own content.\r\n * - `content` — icon badge / image, category chip, title, subtitle, description,\r\n * action pill, arrow; headline layout.\r\n * - `action` — compact interactive row (icon · label/description · arrow); horizontal/vertical.\r\n * - `metric` — centered value + label; `current` (selected) state.\r\n *\r\n * `appearance` is the orthogonal surface skin (outlined / filled / gradient / banner).\r\n * When `interactive`, the whole card is a button (role/tabindex/keyboard) with the\r\n * hover / focus / pressed ripple. All values are sys design tokens.\r\n *\r\n * <compsych-card variant=\"content\" appearance=\"gradient\" icon=\"circle-play\"\r\n * category=\"Video\" title=\"Mindful breathing\" actionLabel=\"Watch\" [interactive]=\"true\" />\r\n * <compsych-card variant=\"metric\" value=\"24\" label=\"Sessions\" [current]=\"true\" [interactive]=\"true\" />\r\n * <compsych-card>Projected content</compsych-card>\r\n */\r\n@Component({\r\n selector: 'compsych-card',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [NgTemplateOutlet, ButtonComponent, CardComponent],\r\n hostDirectives: [RippleDirective],\r\n templateUrl: './card.html',\r\n styleUrl: './card.css',\r\n host: {\r\n class: 'cmp-card',\r\n '[class.cmp-card--outlined]': \"appearance() === 'outlined'\",\r\n '[class.cmp-card--filled]': \"appearance() === 'filled'\",\r\n '[class.cmp-card--gradient]': \"appearance() === 'gradient'\",\r\n '[class.cmp-card--banner]': \"appearance() === 'banner'\",\r\n '[class.cmp-card--content]': \"variant() === 'content'\",\r\n '[class.cmp-card--basic]': \"variant() === 'basic'\",\r\n '[attr.data-card-size]': \"variant() === 'basic' ? size() : null\",\r\n '[class.cmp-card--metric]': \"variant() === 'metric'\",\r\n '[class.cmp-card--current]': \"variant() === 'metric' && current()\",\r\n '[class.cmp-card--radius-md]': \"radius() === 'md'\",\r\n '[class.cmp-card--radius-lg]': \"radius() === 'lg'\",\r\n '[class.cmp-card--radius-xl]': \"radius() === 'xl'\",\r\n '[class.cmp-card--pad-none]': \"effectivePadding() === 'none'\",\r\n '[class.cmp-card--pad-sm]': \"effectivePadding() === 'sm'\",\r\n '[class.cmp-card--pad-md]': \"effectivePadding() === 'md'\",\r\n '[class.cmp-card--pad-lg]': \"effectivePadding() === 'lg'\",\r\n '[class.cmp-card--pad-xl]': \"effectivePadding() === 'xl'\",\r\n '[style.width]': \"fullWidth() ? '100%' : null\",\r\n '[class.cmp-card--interactive]': 'interactive()',\r\n '[class.cmp-card--disabled]': 'disabled()',\r\n '[class.cmp-card--selected]': 'selected()',\r\n '[class.cmp-card--no-gradient]': '!showGradient()',\r\n '[class.cmp-card--compact]': 'compact()',\r\n '[class.cmp-card--metric-sm]': \"variant() === 'metric' && metricSize() === 'small'\",\r\n '[class.cmp-card--dark-bg]': 'darkBackground()',\r\n '[class.cmp-card--hide-image]': 'hideImage()',\r\n '[attr.role]': \"interactive() ? 'button' : null\",\r\n '[attr.tabindex]': 'interactive() && !disabled() ? 0 : null',\r\n '[attr.aria-label]': 'ariaLabel() ?? null',\r\n '[attr.aria-disabled]': 'disabled() || null',\r\n '[attr.aria-pressed]': \"interactive() && variant() === 'metric' ? current() : null\",\r\n '[style.border-color]': \"variant() === 'metric' && current() ? 'var(--accent-primary-sys-primary)' : null\",\r\n '[style.border-width]': \"variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null\",\r\n '(click)': 'onActivate()',\r\n '(keydown)': 'onKeyDown($event)',\r\n },\r\n})\r\nexport class CardComponent {\r\n // ── Surface (all variants) ──────────────────────────────\r\n /** Card type. Defaults to `basic` (projected content). */\r\n readonly variant = input<CardVariant>('basic');\r\n /** Surface treatment. Defaults to `outlined`. */\r\n readonly appearance = input<CardAppearance>('outlined');\r\n /** Corner radius token. Defaults to `lg` (16px). */\r\n readonly radius = input<CardRadius>('lg');\r\n /** Inner padding for `variant=\"basic\"`. Typed variants size themselves. */\r\n readonly padding = input<CardPadding>('lg');\r\n /** Card Item size (`variant=\"basic\"`): xl/lg/md/sm/xs. Defaults to `md`. */\r\n readonly size = input<CardSize>('md');\r\n /** Whole-card click target: adds role/tabindex, hover/press states and ripple. */\r\n readonly interactive = input<boolean>(false);\r\n /** Disabled visual + non-interactive. */\r\n readonly disabled = input<boolean>(false);\r\n /** Applies the focused (blue outline) appearance. Useful for action cards to indicate selection. */\r\n readonly selected = input<boolean>(false);\r\n /** Background image URL for `appearance=\"banner\"`. */\r\n readonly imageSrc = input<string>('');\r\n /**\r\n * Hides the background image on an `appearance=\"banner\"` card and replaces it\r\n * with a `--accent-primary-sys-primary-container` solid background.\r\n */\r\n readonly hideImage = input<boolean>(false);\r\n /**\r\n * `background-position` for the `banner` appearance media (e.g. `'85% 0'` for an\r\n * off-center image). Defaults to `'center'`.\r\n */\r\n readonly imagePosition = input<string>('center');\r\n\r\n // ── Content variant ─────────────────────────────────────\r\n /** Lucide icon name (content badge / action leading icon). */\r\n readonly icon = input<string>('');\r\n /** Content: category chip text. */\r\n readonly category = input<string>('');\r\n /**\r\n * Content: how the category renders — `'chip'` (default) as the trailing pill,\r\n * or `'label'` as a leading plain-text label beside the icon.\r\n */\r\n readonly categoryStyle = input<CardCategoryStyle>('chip');\r\n /**\r\n * Content: icon badge treatment — `'primary'` (default) is a white icon on a\r\n * filled primary (blue) circle; `'neutral'` is a dark icon on a white circle\r\n * with a thin outline.\r\n */\r\n readonly iconStyle = input<CardIconStyle>('primary');\r\n /** Content: title. */\r\n readonly title = input<string>('');\r\n /** Content: subtitle. */\r\n readonly subtitle = input<string>('');\r\n /** Content/action: supporting description. */\r\n readonly description = input<string>('');\r\n /** Content: large display text for the headline layout. */\r\n readonly headline = input<string>('');\r\n /** Content (`appearance=\"banner\"`): supporting text rendered below the headline, in white-80. */\r\n readonly headlineDescription = input<string>('');\r\n /** Content (`appearance=\"banner\"`): metric cards rendered in a dark row below the headline description. */\r\n readonly metrics = input<BannerMetric[]>([]);\r\n /** Content: presentational action pill label. */\r\n readonly actionLabel = input<string>('');\r\n /** Content: leading Lucide icon name rendered inside the action pill. */\r\n readonly actionLeadingIcon = input<string>('');\r\n /** Content: trailing Lucide icon name rendered inside the action pill. */\r\n readonly actionTrailingIcon = input<string>('');\r\n /** Content: disables the action button. */\r\n readonly actionDisabled = input<boolean>(false);\r\n /** Content (outlined/filled): when true, replaces the full-width banner with a plain icon in the top-left corner. */\r\n readonly inlineIcon = input<boolean>(false);\r\n /** Content: show the trailing arrow-up-right affordance. */\r\n readonly showArrow = input<boolean>(true);\r\n /** Content (gradient): show the inner gradient panel background. Set to `false` to render a flat surface. */\r\n readonly showGradient = input<boolean>(true);\r\n /** Content: remove the fixed min-height so the card sizes to its content. */\r\n readonly compact = input<boolean>(false);\r\n /**\r\n * Renders the card on a dark surface: background becomes\r\n * `--transparent-neutral-sys-white-20` (closest token to rgba(255,255,255,0.16))\r\n * and text color becomes white.\r\n */\r\n readonly darkBackground = input<boolean>(false);\r\n\r\n // ── Action variant ──────────────────────────────────────\r\n /** Action/metric: primary label. */\r\n readonly label = input<string>('');\r\n /** Action: trailing Lucide icon (horizontal layout). */\r\n readonly trailingIcon = input<string>('arrow-up-right');\r\n /** Action: layout orientation. */\r\n readonly orientation = input<CardOrientation>('horizontal');\r\n /** Action: stretch the card to 100% of its container width. */\r\n readonly fullWidth = input<boolean>(false);\r\n\r\n // ── Metric variant ──────────────────────────────────────\r\n /** Metric: size variant. Defaults to `medium`. */\r\n readonly metricSize = input<CardMetricSize>('medium');\r\n /** Metric: the prominent value. */\r\n readonly value = input<string | number>('');\r\n /** Metric: selected/current state (primary border + text). */\r\n readonly current = input<boolean>(false);\r\n\r\n // ── Accessibility ───────────────────────────────────────\r\n /**\r\n * Opts the title / headline / action label into a heading in the\r\n * accessibility tree via `role=\"heading\"` + `aria-level`, so consumers that\r\n * replace real headings keep heading semantics and screen-reader heading\r\n * navigation (WCAG 1.3.1). Omit (default) to render as plain text — no visual\r\n * or behavioral change for existing usages.\r\n */\r\n readonly headingLevel = input<CardHeadingLevel | undefined>(undefined);\r\n /**\r\n * Accessible name for an `interactive` card (which is a `role=\"button\"`).\r\n * Required for image-only / icon-only interactive cards that have no text, and\r\n * useful to give text-heavy cards a concise name instead of their full content.\r\n * Bind as `aria-label`.\r\n */\r\n readonly ariaLabel = input<string | undefined>(undefined, { alias: 'aria-label' });\r\n\r\n /** Emits on click / Enter / Space when interactive and not disabled. */\r\n readonly cardClick = output<void>();\r\n /** Emits when the banner card's action button is clicked. */\r\n readonly actionClick = output<void>();\r\n\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private readonly ripple = inject(RippleDirective);\r\n\r\n readonly isBanner = computed(() => this.appearance() === 'banner');\r\n\r\n /**\r\n * Heading level actually applied. Suppressed when the whole card is interactive\r\n * (`role=\"button\"`), since a heading nested in a button isn't exposed as a\r\n * heading — the two would conflict.\r\n */\r\n readonly effectiveHeadingLevel = computed(() =>\r\n this.interactive() ? undefined : this.headingLevel(),\r\n );\r\n\r\n /** Base Card Item plain-icon glyph size by `size` (48 md, 32 sm, 24 xs). */\r\n readonly basicIconSize = computed(() => (this.size() === 'sm' ? 32 : this.size() === 'xs' ? 24 : 48));\r\n /** Base Card Item arrow glyph size by `size` (24 md, 20 sm/xs). */\r\n readonly basicArrowSize = computed(() => (this.size() === 'md' ? 24 : 20));\r\n\r\n /** CSS `url(...)` for the media layer, or null when no image is set. */\r\n readonly mediaUrl = computed(() => {\r\n const src = this.imageSrc();\r\n return src ? `url(\"${src}\")` : null;\r\n });\r\n\r\n /** Padding resolved per variant; `basic` honors the `padding` input. */\r\n readonly effectivePadding = computed<CardPadding>(() => {\r\n switch (this.variant()) {\r\n case 'content':\r\n return this.isBanner() ? 'none' : 'sm';\r\n case 'action':\r\n return 'lg'; // 24px — Figma action card (60017:8036)\r\n case 'basic':\r\n return 'none'; // .bc controls its own padding per style (Figma Base Card Item)\r\n case 'metric':\r\n return this.metricSize() === 'small' ? 'sm' : 'lg'; // sm=16px, lg=24px\r\n default:\r\n return this.padding();\r\n }\r\n });\r\n\r\n constructor() {\r\n effect(() => {\r\n this.ripple.suppressed = !this.interactive() || this.disabled();\r\n });\r\n }\r\n\r\n onActivate(): void {\r\n if (!this.interactive() || this.disabled()) return;\r\n this.cardClick.emit();\r\n }\r\n\r\n onKeyDown(event: KeyboardEvent): void {\r\n if (!this.interactive() || this.disabled()) return;\r\n if (event.repeat) return;\r\n if (event.key !== 'Enter' && event.key !== ' ') return;\r\n event.preventDefault();\r\n this.cardClick.emit();\r\n }\r\n\r\n /** Renders a sized/weighted Lucide SVG for template use. */\r\n iconSvg(name: string, size: number, strokeWidth = 1.75): SafeHtml {\r\n let svg = LUCIDE_ICONS[name] ?? '';\r\n svg = svg.replace('<svg ', `<svg width=\"${size}\" height=\"${size}\" `);\r\n if (strokeWidth !== 1.5) {\r\n svg = svg.replace('stroke-width=\"1.5\"', `stroke-width=\"${strokeWidth}\"`);\r\n }\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n}\r\n","@if (isBanner() && mediaUrl() && !hideImage()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (isBanner()) {\r\n <div class=\"cc cc--banner\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n }\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row — icon · title · arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--banner]=\"isBanner()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragment: renders <h2>–<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n"]}
|
|
1
|
+
{"version":3,"file":"card.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/card-base/card.ts","../../../../../../packages/angular/src/lib/card-base/card.html"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,QAAQ,EACR,MAAM,EACN,MAAM,EACN,KAAK,EACL,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAY,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;;;AAwCnD;;;;;;;;;;;;;;;;;;;;GAoBG;AAgDH,MAAM,OAAO,aAAa;IACxB,2DAA2D;IAC3D,0DAA0D;IACjD,OAAO,GAAG,KAAK,CAAc,OAAO,8EAAC,CAAC;IAC/C,iDAAiD;IACxC,UAAU,GAAG,KAAK,CAAiB,UAAU,iFAAC,CAAC;IACxD,oDAAoD;IAC3C,MAAM,GAAG,KAAK,CAAa,IAAI,6EAAC,CAAC;IAC1C,2EAA2E;IAClE,OAAO,GAAG,KAAK,CAAc,IAAI,8EAAC,CAAC;IAC5C,4EAA4E;IACnE,IAAI,GAAG,KAAK,CAAW,IAAI,2EAAC,CAAC;IACtC,kFAAkF;IACzE,WAAW,GAAG,KAAK,CAAU,KAAK,kFAAC,CAAC;IAC7C,yCAAyC;IAChC,QAAQ,GAAG,KAAK,CAAU,KAAK,+EAAC,CAAC;IAC1C,oGAAoG;IAC3F,QAAQ,GAAG,KAAK,CAAU,KAAK,+EAAC,CAAC;IAC1C,sDAAsD;IAC7C,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC;;;OAGG;IACM,SAAS,GAAG,KAAK,CAAU,KAAK,gFAAC,CAAC;IAC3C;;;OAGG;IACM,aAAa,GAAG,KAAK,CAAS,QAAQ,oFAAC,CAAC;IAEjD,2DAA2D;IAC3D,8DAA8D;IACrD,IAAI,GAAG,KAAK,CAAS,EAAE,2EAAC,CAAC;IAClC,mCAAmC;IAC1B,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC;;;OAGG;IACM,aAAa,GAAG,KAAK,CAAoB,MAAM,oFAAC,CAAC;IAC1D;;;;OAIG;IACM,SAAS,GAAG,KAAK,CAAgB,SAAS,gFAAC,CAAC;IACrD,sBAAsB;IACb,KAAK,GAAG,KAAK,CAAS,EAAE,4EAAC,CAAC;IACnC,yBAAyB;IAChB,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC,8CAA8C;IACrC,WAAW,GAAG,KAAK,CAAS,EAAE,kFAAC,CAAC;IACzC,2DAA2D;IAClD,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC,CAAC;IACtC,iGAAiG;IACxF,mBAAmB,GAAG,KAAK,CAAS,EAAE,0FAAC,CAAC;IACjD,2GAA2G;IAClG,OAAO,GAAG,KAAK,CAAiB,EAAE,8EAAC,CAAC;IAC7C,iDAAiD;IACxC,WAAW,GAAG,KAAK,CAAS,EAAE,kFAAC,CAAC;IACzC,yEAAyE;IAChE,iBAAiB,GAAG,KAAK,CAAS,EAAE,wFAAC,CAAC;IAC/C,0EAA0E;IACjE,kBAAkB,GAAG,KAAK,CAAS,EAAE,yFAAC,CAAC;IAChD,2CAA2C;IAClC,cAAc,GAAG,KAAK,CAAU,KAAK,qFAAC,CAAC;IAChD,qHAAqH;IAC5G,UAAU,GAAG,KAAK,CAAU,KAAK,iFAAC,CAAC;IAC5C,4DAA4D;IACnD,SAAS,GAAG,KAAK,CAAU,IAAI,gFAAC,CAAC;IAC1C,6GAA6G;IACpG,YAAY,GAAG,KAAK,CAAU,IAAI,mFAAC,CAAC;IAC7C,6EAA6E;IACpE,OAAO,GAAG,KAAK,CAAU,KAAK,8EAAC,CAAC;IACzC;;;;OAIG;IACM,cAAc,GAAG,KAAK,CAAU,KAAK,qFAAC,CAAC;IAEhD,2DAA2D;IAC3D,oCAAoC;IAC3B,KAAK,GAAG,KAAK,CAAS,EAAE,4EAAC,CAAC;IACnC,wDAAwD;IAC/C,YAAY,GAAG,KAAK,CAAS,gBAAgB,mFAAC,CAAC;IACxD,kCAAkC;IACzB,WAAW,GAAG,KAAK,CAAkB,YAAY,kFAAC,CAAC;IAC5D,+DAA+D;IACtD,SAAS,GAAG,KAAK,CAAU,KAAK,gFAAC,CAAC;IAE3C,2DAA2D;IAC3D,kDAAkD;IACzC,UAAU,GAAG,KAAK,CAAiB,QAAQ,iFAAC,CAAC;IACtD,mCAAmC;IAC1B,KAAK,GAAG,KAAK,CAAkB,EAAE,4EAAC,CAAC;IAC5C,8DAA8D;IACrD,OAAO,GAAG,KAAK,CAAU,KAAK,8EAAC,CAAC;IAEzC,2DAA2D;IAC3D;;;;;;OAMG;IACM,YAAY,GAAG,KAAK,CAA+B,SAAS,mFAAC,CAAC;IACvE;;;;;OAKG;IACM,SAAS,GAAG,KAAK,CAAqB,SAAS,iFAAI,KAAK,EAAE,YAAY,GAAG,CAAC;IAEnF,wEAAwE;IAC/D,SAAS,GAAG,MAAM,EAAQ,CAAC;IACpC,6DAA6D;IACpD,WAAW,GAAG,MAAM,EAAQ,CAAC;IAErB,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;IAEzC,QAAQ,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,QAAQ,+EAAC,CAAC;IAEnE;;;;OAIG;IACM,qBAAqB,GAAG,QAAQ,CAAC,GAAG,EAAE,CAC7C,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,4FACrD,CAAC;IAEF,4EAA4E;IACnE,aAAa,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,oFAAC,CAAC;IACtG,mEAAmE;IAC1D,cAAc,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,qFAAC,CAAC;IAE3E,wEAAwE;IAC/D,QAAQ,GAAG,QAAQ,CAAC,GAAG,EAAE;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC,+EAAC,CAAC;IAEH,wEAAwE;IAC/D,gBAAgB,GAAG,QAAQ,CAAc,GAAG,EAAE;QACrD,QAAQ,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACvB,KAAK,SAAS;gBACZ,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YACzC,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,CAAC,wCAAwC;YACvD,KAAK,OAAO;gBACV,OAAO,MAAM,CAAC,CAAC,gEAAgE;YACjF,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,UAAU,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,mBAAmB;YACzE;gBACE,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC,uFAAC,CAAC;IAEH;QACE,MAAM,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE,OAAO;QACnD,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,SAAS,CAAC,KAAoB;QAC5B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE,OAAO;QACnD,IAAI,KAAK,CAAC,MAAM;YAAE,OAAO;QACzB,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG;YAAE,OAAO;QACvD,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,4DAA4D;IAC5D,OAAO,CAAC,IAAY,EAAE,IAAY,EAAE,WAAW,GAAG,IAAI;QACpD,IAAI,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACnC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,eAAe,IAAI,aAAa,IAAI,IAAI,CAAC,CAAC;QACrE,IAAI,WAAW,KAAK,GAAG,EAAE,CAAC;YACxB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE,iBAAiB,WAAW,GAAG,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC;wGA9LU,aAAa;4FAAb,aAAa,8wOCzH1B,ogZAgPA,o7rBDvHa,aAAa,+nBA3Cd,gBAAgB,oJAAE,eAAe;;4FA2ChC,aAAa;kBA/CzB,SAAS;+BACE,eAAe,cACb,IAAI,mBACC,uBAAuB,CAAC,MAAM,WACtC,CAAC,gBAAgB,EAAE,eAAe,gBAAgB,kBAC3C,CAAC,eAAe,CAAC,QAG3B;wBACJ,KAAK,EAAE,UAAU;wBACjB,4BAA4B,EAAE,6BAA6B;wBAC3D,0BAA0B,EAAE,2BAA2B;wBACvD,4BAA4B,EAAE,6BAA6B;wBAC3D,0BAA0B,EAAE,2BAA2B;wBACvD,2BAA2B,EAAE,yBAAyB;wBACtD,yBAAyB,EAAE,uBAAuB;wBAClD,uBAAuB,EAAE,uCAAuC;wBAChE,0BAA0B,EAAE,wBAAwB;wBACpD,2BAA2B,EAAE,qCAAqC;wBAClE,6BAA6B,EAAE,mBAAmB;wBAClD,6BAA6B,EAAE,mBAAmB;wBAClD,6BAA6B,EAAE,mBAAmB;wBAClD,4BAA4B,EAAE,+BAA+B;wBAC7D,0BAA0B,EAAE,6BAA6B;wBACzD,0BAA0B,EAAE,6BAA6B;wBACzD,0BAA0B,EAAE,6BAA6B;wBACzD,0BAA0B,EAAE,6BAA6B;wBACzD,eAAe,EAAE,6BAA6B;wBAC9C,+BAA+B,EAAE,eAAe;wBAChD,4BAA4B,EAAE,YAAY;wBAC1C,4BAA4B,EAAE,YAAY;wBAC1C,+BAA+B,EAAE,iBAAiB;wBAClD,2BAA2B,EAAE,WAAW;wBACxC,6BAA6B,EAAE,oDAAoD;wBACnF,2BAA2B,EAAE,kBAAkB;wBAC/C,8BAA8B,EAAE,aAAa;wBAC7C,aAAa,EAAE,iCAAiC;wBAChD,iBAAiB,EAAE,yCAAyC;wBAC5D,mBAAmB,EAAE,qBAAqB;wBAC1C,sBAAsB,EAAE,oBAAoB;wBAC5C,qBAAqB,EAAE,4DAA4D;wBACnF,sBAAsB,EAAE,kFAAkF;wBAC1G,sBAAsB,EAAE,qFAAqF;wBAC7G,SAAS,EAAE,cAAc;wBACzB,WAAW,EAAE,mBAAmB;qBACjC","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n} from '@angular/core';\r\nimport { NgTemplateOutlet } from '@angular/common';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\nimport { RippleDirective } from './ripple.directive';\r\nimport { ButtonComponent } from '../button/button';\r\n\r\n/** A single metric item for the banner card's metric row. */\r\nexport interface BannerMetric {\r\n value: string | number;\r\n label?: string;\r\n /** Renders the metric in its primary-color \"current\" state. */\r\n current?: boolean;\r\n}\r\n\r\n/**\r\n * Card type — selects the projected/laid-out content. Mirrors the library's `variant` pattern.\r\n * `basic` is the Figma \"cards\" section (the \"Card Item\" family: icon + arrow +\r\n * title/subtitle, sized, across the outlined/filled/gradient/banner surfaces) —\r\n * distinct from the `content` category tiles.\r\n */\r\nexport type CardVariant = 'basic' | 'content' | 'action' | 'metric';\r\n/** Visual surface treatment. Mirrors the Figma \"Card Item\" Style property. */\r\nexport type CardAppearance = 'outlined' | 'filled' | 'gradient' | 'banner';\r\n/** Corner radius token: `md` (12px), `lg` (16px), `xl` (24px). */\r\nexport type CardRadius = 'md' | 'lg' | 'xl';\r\n/** Inner padding token (used by `variant=\"basic\"`; typed variants size themselves). */\r\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'xl';\r\n/** Action-card layout. */\r\nexport type CardOrientation = 'horizontal' | 'vertical';\r\n/** Metric-card size. `medium` is the default (24px padding, headline-medium value); `small` is compact (16px padding, headline-small value). */\r\nexport type CardMetricSize = 'medium' | 'small';\r\n/** Base Card Item size (Figma \"Size\" property). Drives layout + type scale. */\r\nexport type CardSize = 'xl' | 'lg' | 'md' | 'sm' | 'xs';\r\n/** Heading level for the title / headline / action label (screen-reader heading semantics). */\r\nexport type CardHeadingLevel = 2 | 3 | 4 | 5 | 6;\r\n/** How the content-variant category renders: trailing pill (`chip`) or leading plain-text `label`. */\r\nexport type CardCategoryStyle = 'chip' | 'label';\r\n/**\r\n * Content-variant icon badge treatment:\r\n * - `primary` — white icon on a filled primary (blue) circle (default).\r\n * - `neutral` — dark (on-surface) icon on a white circle with a thin outline.\r\n */\r\nexport type CardIconStyle = 'primary' | 'neutral';\r\n\r\n/**\r\n * Card — the single Cards component for the ComPsych Design System.\r\n *\r\n * Figma: Core Components — \"Cards\" (file VFBn7KCDy3FSIlvhNo3ylq, 1117:9829).\r\n *\r\n * One component, switched by `variant` (like Accordion's `variant`):\r\n * - `basic` — a bare surface; project your own content.\r\n * - `content` — icon badge / image, category chip, title, subtitle, description,\r\n * action pill, arrow; headline layout.\r\n * - `action` — compact interactive row (icon · label/description · arrow); horizontal/vertical.\r\n * - `metric` — centered value + label; `current` (selected) state.\r\n *\r\n * `appearance` is the orthogonal surface skin (outlined / filled / gradient / banner).\r\n * When `interactive`, the whole card is a button (role/tabindex/keyboard) with the\r\n * hover / focus / pressed ripple. All values are sys design tokens.\r\n *\r\n * <compsych-card variant=\"content\" appearance=\"gradient\" icon=\"circle-play\"\r\n * category=\"Video\" title=\"Mindful breathing\" actionLabel=\"Watch\" [interactive]=\"true\" />\r\n * <compsych-card variant=\"metric\" value=\"24\" label=\"Sessions\" [current]=\"true\" [interactive]=\"true\" />\r\n * <compsych-card>Projected content</compsych-card>\r\n */\r\n@Component({\r\n selector: 'compsych-card',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [NgTemplateOutlet, ButtonComponent, CardComponent],\r\n hostDirectives: [RippleDirective],\r\n templateUrl: './card.html',\r\n styleUrl: './card.css',\r\n host: {\r\n class: 'cmp-card',\r\n '[class.cmp-card--outlined]': \"appearance() === 'outlined'\",\r\n '[class.cmp-card--filled]': \"appearance() === 'filled'\",\r\n '[class.cmp-card--gradient]': \"appearance() === 'gradient'\",\r\n '[class.cmp-card--banner]': \"appearance() === 'banner'\",\r\n '[class.cmp-card--content]': \"variant() === 'content'\",\r\n '[class.cmp-card--basic]': \"variant() === 'basic'\",\r\n '[attr.data-card-size]': \"variant() === 'basic' ? size() : null\",\r\n '[class.cmp-card--metric]': \"variant() === 'metric'\",\r\n '[class.cmp-card--current]': \"variant() === 'metric' && current()\",\r\n '[class.cmp-card--radius-md]': \"radius() === 'md'\",\r\n '[class.cmp-card--radius-lg]': \"radius() === 'lg'\",\r\n '[class.cmp-card--radius-xl]': \"radius() === 'xl'\",\r\n '[class.cmp-card--pad-none]': \"effectivePadding() === 'none'\",\r\n '[class.cmp-card--pad-sm]': \"effectivePadding() === 'sm'\",\r\n '[class.cmp-card--pad-md]': \"effectivePadding() === 'md'\",\r\n '[class.cmp-card--pad-lg]': \"effectivePadding() === 'lg'\",\r\n '[class.cmp-card--pad-xl]': \"effectivePadding() === 'xl'\",\r\n '[style.width]': \"fullWidth() ? '100%' : null\",\r\n '[class.cmp-card--interactive]': 'interactive()',\r\n '[class.cmp-card--disabled]': 'disabled()',\r\n '[class.cmp-card--selected]': 'selected()',\r\n '[class.cmp-card--no-gradient]': '!showGradient()',\r\n '[class.cmp-card--compact]': 'compact()',\r\n '[class.cmp-card--metric-sm]': \"variant() === 'metric' && metricSize() === 'small'\",\r\n '[class.cmp-card--dark-bg]': 'darkBackground()',\r\n '[class.cmp-card--hide-image]': 'hideImage()',\r\n '[attr.role]': \"interactive() ? 'button' : null\",\r\n '[attr.tabindex]': 'interactive() && !disabled() ? 0 : null',\r\n '[attr.aria-label]': 'ariaLabel() ?? null',\r\n '[attr.aria-disabled]': 'disabled() || null',\r\n '[attr.aria-pressed]': \"interactive() && variant() === 'metric' ? current() : null\",\r\n '[style.border-color]': \"variant() === 'metric' && current() ? 'var(--accent-primary-sys-primary)' : null\",\r\n '[style.border-width]': \"variant() === 'metric' && current() ? 'var(--border-width-sys-stroke-thick)' : null\",\r\n '(click)': 'onActivate()',\r\n '(keydown)': 'onKeyDown($event)',\r\n },\r\n})\r\nexport class CardComponent {\r\n // ── Surface (all variants) ──────────────────────────────\r\n /** Card type. Defaults to `basic` (projected content). */\r\n readonly variant = input<CardVariant>('basic');\r\n /** Surface treatment. Defaults to `outlined`. */\r\n readonly appearance = input<CardAppearance>('outlined');\r\n /** Corner radius token. Defaults to `lg` (16px). */\r\n readonly radius = input<CardRadius>('lg');\r\n /** Inner padding for `variant=\"basic\"`. Typed variants size themselves. */\r\n readonly padding = input<CardPadding>('lg');\r\n /** Card Item size (`variant=\"basic\"`): xl/lg/md/sm/xs. Defaults to `md`. */\r\n readonly size = input<CardSize>('md');\r\n /** Whole-card click target: adds role/tabindex, hover/press states and ripple. */\r\n readonly interactive = input<boolean>(false);\r\n /** Disabled visual + non-interactive. */\r\n readonly disabled = input<boolean>(false);\r\n /** Applies the focused (blue outline) appearance. Useful for action cards to indicate selection. */\r\n readonly selected = input<boolean>(false);\r\n /** Background image URL for `appearance=\"banner\"`. */\r\n readonly imageSrc = input<string>('');\r\n /**\r\n * Hides the background image on an `appearance=\"banner\"` card and replaces it\r\n * with a `--accent-primary-sys-primary-container` solid background.\r\n */\r\n readonly hideImage = input<boolean>(false);\r\n /**\r\n * `background-position` for the `banner` appearance media (e.g. `'85% 0'` for an\r\n * off-center image). Defaults to `'center'`.\r\n */\r\n readonly imagePosition = input<string>('center');\r\n\r\n // ── Content variant ─────────────────────────────────────\r\n /** Lucide icon name (content badge / action leading icon). */\r\n readonly icon = input<string>('');\r\n /** Content: category chip text. */\r\n readonly category = input<string>('');\r\n /**\r\n * Content: how the category renders — `'chip'` (default) as the trailing pill,\r\n * or `'label'` as a leading plain-text label beside the icon.\r\n */\r\n readonly categoryStyle = input<CardCategoryStyle>('chip');\r\n /**\r\n * Content: icon badge treatment — `'primary'` (default) is a white icon on a\r\n * filled primary (blue) circle; `'neutral'` is a dark icon on a white circle\r\n * with a thin outline.\r\n */\r\n readonly iconStyle = input<CardIconStyle>('primary');\r\n /** Content: title. */\r\n readonly title = input<string>('');\r\n /** Content: subtitle. */\r\n readonly subtitle = input<string>('');\r\n /** Content/action: supporting description. */\r\n readonly description = input<string>('');\r\n /** Content: large display text for the headline layout. */\r\n readonly headline = input<string>('');\r\n /** Content (`appearance=\"banner\"`): supporting text rendered below the headline, in white-80. */\r\n readonly headlineDescription = input<string>('');\r\n /** Content (`appearance=\"banner\"`): metric cards rendered in a dark row below the headline description. */\r\n readonly metrics = input<BannerMetric[]>([]);\r\n /** Content: presentational action pill label. */\r\n readonly actionLabel = input<string>('');\r\n /** Content: leading Lucide icon name rendered inside the action pill. */\r\n readonly actionLeadingIcon = input<string>('');\r\n /** Content: trailing Lucide icon name rendered inside the action pill. */\r\n readonly actionTrailingIcon = input<string>('');\r\n /** Content: disables the action button. */\r\n readonly actionDisabled = input<boolean>(false);\r\n /** Content (outlined/filled): when true, replaces the full-width banner with a plain icon in the top-left corner. */\r\n readonly inlineIcon = input<boolean>(false);\r\n /** Content: show the trailing arrow-up-right affordance. */\r\n readonly showArrow = input<boolean>(true);\r\n /** Content (gradient): show the inner gradient panel background. Set to `false` to render a flat surface. */\r\n readonly showGradient = input<boolean>(true);\r\n /** Content: remove the fixed min-height so the card sizes to its content. */\r\n readonly compact = input<boolean>(false);\r\n /**\r\n * Renders the card on a dark surface: background becomes\r\n * `--transparent-neutral-sys-white-20` (closest token to rgba(255,255,255,0.16))\r\n * and text color becomes white.\r\n */\r\n readonly darkBackground = input<boolean>(false);\r\n\r\n // ── Action variant ──────────────────────────────────────\r\n /** Action/metric: primary label. */\r\n readonly label = input<string>('');\r\n /** Action: trailing Lucide icon (horizontal layout). */\r\n readonly trailingIcon = input<string>('arrow-up-right');\r\n /** Action: layout orientation. */\r\n readonly orientation = input<CardOrientation>('horizontal');\r\n /** Action: stretch the card to 100% of its container width. */\r\n readonly fullWidth = input<boolean>(false);\r\n\r\n // ── Metric variant ──────────────────────────────────────\r\n /** Metric: size variant. Defaults to `medium`. */\r\n readonly metricSize = input<CardMetricSize>('medium');\r\n /** Metric: the prominent value. */\r\n readonly value = input<string | number>('');\r\n /** Metric: selected/current state (primary border + text). */\r\n readonly current = input<boolean>(false);\r\n\r\n // ── Accessibility ───────────────────────────────────────\r\n /**\r\n * Opts the title / headline / action label into a heading in the\r\n * accessibility tree via `role=\"heading\"` + `aria-level`, so consumers that\r\n * replace real headings keep heading semantics and screen-reader heading\r\n * navigation (WCAG 1.3.1). Omit (default) to render as plain text — no visual\r\n * or behavioral change for existing usages.\r\n */\r\n readonly headingLevel = input<CardHeadingLevel | undefined>(undefined);\r\n /**\r\n * Accessible name for an `interactive` card (which is a `role=\"button\"`).\r\n * Required for image-only / icon-only interactive cards that have no text, and\r\n * useful to give text-heavy cards a concise name instead of their full content.\r\n * Bind as `aria-label`.\r\n */\r\n readonly ariaLabel = input<string | undefined>(undefined, { alias: 'aria-label' });\r\n\r\n /** Emits on click / Enter / Space when interactive and not disabled. */\r\n readonly cardClick = output<void>();\r\n /** Emits when the banner card's action button is clicked. */\r\n readonly actionClick = output<void>();\r\n\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private readonly ripple = inject(RippleDirective);\r\n\r\n readonly isBanner = computed(() => this.appearance() === 'banner');\r\n\r\n /**\r\n * Heading level actually applied. Suppressed when the whole card is interactive\r\n * (`role=\"button\"`), since a heading nested in a button isn't exposed as a\r\n * heading — the two would conflict.\r\n */\r\n readonly effectiveHeadingLevel = computed(() =>\r\n this.interactive() ? undefined : this.headingLevel(),\r\n );\r\n\r\n /** Base Card Item plain-icon glyph size by `size` (48 md, 32 sm, 24 xs). */\r\n readonly basicIconSize = computed(() => (this.size() === 'sm' ? 32 : this.size() === 'xs' ? 24 : 48));\r\n /** Base Card Item arrow glyph size by `size` (24 md, 20 sm/xs). */\r\n readonly basicArrowSize = computed(() => (this.size() === 'md' ? 24 : 20));\r\n\r\n /** CSS `url(...)` for the media layer, or null when no image is set. */\r\n readonly mediaUrl = computed(() => {\r\n const src = this.imageSrc();\r\n return src ? `url(\"${src}\")` : null;\r\n });\r\n\r\n /** Padding resolved per variant; `basic` honors the `padding` input. */\r\n readonly effectivePadding = computed<CardPadding>(() => {\r\n switch (this.variant()) {\r\n case 'content':\r\n return this.isBanner() ? 'none' : 'sm';\r\n case 'action':\r\n return 'lg'; // 24px — Figma action card (60017:8036)\r\n case 'basic':\r\n return 'none'; // .bc controls its own padding per style (Figma Base Card Item)\r\n case 'metric':\r\n return this.metricSize() === 'small' ? 'sm' : 'lg'; // sm=16px, lg=24px\r\n default:\r\n return this.padding();\r\n }\r\n });\r\n\r\n constructor() {\r\n effect(() => {\r\n this.ripple.suppressed = !this.interactive() || this.disabled();\r\n });\r\n }\r\n\r\n onActivate(): void {\r\n if (!this.interactive() || this.disabled()) return;\r\n this.cardClick.emit();\r\n }\r\n\r\n onKeyDown(event: KeyboardEvent): void {\r\n if (!this.interactive() || this.disabled()) return;\r\n if (event.repeat) return;\r\n if (event.key !== 'Enter' && event.key !== ' ') return;\r\n event.preventDefault();\r\n this.cardClick.emit();\r\n }\r\n\r\n /** Renders a sized/weighted Lucide SVG for template use. */\r\n iconSvg(name: string, size: number, strokeWidth = 1.75): SafeHtml {\r\n let svg = LUCIDE_ICONS[name] ?? '';\r\n svg = svg.replace('<svg ', `<svg width=\"${size}\" height=\"${size}\" `);\r\n if (strokeWidth !== 1.5) {\r\n svg = svg.replace('stroke-width=\"1.5\"', `stroke-width=\"${strokeWidth}\"`);\r\n }\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n}\r\n","@if (isBanner() && mediaUrl() && !hideImage()) {\r\n <div class=\"cmp-card__media\" [style.background-image]=\"mediaUrl()\" [style.background-position]=\"imagePosition()\"></div>\r\n <div class=\"cmp-card__scrim\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<div class=\"cmp-card__body\">\r\n @switch (variant()) {\r\n @case ('content') {\r\n @if (isBanner()) {\r\n <div class=\"cc cc--banner\">\r\n <div class=\"cc__img-top\">\r\n @if (icon()) {\r\n <div class=\"cc__media-icon\" [innerHTML]=\"iconSvg(icon(), 48)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (category()) { <span class=\"cc__chip cc__chip--glass\">{{ category() }}</span> }\r\n </div>\r\n <div class=\"cc__img-foot\">\r\n @if (title() || subtitle() || headline() || description() || headlineDescription() || metrics().length) {\r\n <div class=\"cc__banner-text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n @if (headlineDescription()) { <p class=\"cc__headline-desc\" [innerHTML]=\"headlineDescription()\"></p> }\r\n @if (metrics().length) {\r\n <div class=\"cc__metrics\">\r\n @for (m of metrics(); track $index) {\r\n <compsych-card variant=\"metric\" [value]=\"m.value\" [label]=\"m.label ?? ''\" [current]=\"m.current ?? false\" [darkBackground]=\"true\" metricSize=\"small\" />\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"elevated\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" (click)=\"actionClick.emit(); $event.stopPropagation()\" />\r\n }\r\n </div>\r\n </div>\r\n } @else if (appearance() === 'gradient') {\r\n <div class=\"cc\">\r\n <div class=\"cc__top\" [class.cc__top--label]=\"categoryStyle() === 'label'\">\r\n @if (icon()) {\r\n <div class=\"cc__icon\" [class.cc__icon--neutral]=\"iconStyle() === 'neutral'\" [innerHTML]=\"iconSvg(icon(), 24)\" aria-hidden=\"true\"></div>\r\n }\r\n @if (categoryStyle() === 'label' && category()) {\r\n <span class=\"cc__category-label\">{{ category() }}</span>\r\n }\r\n <div class=\"cc__top-end\">\r\n @if (categoryStyle() === 'chip' && category()) { <span class=\"cc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"cc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 24)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"cc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"cc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"cc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) {\r\n <compsych-button variant=\"outlined\" [label]=\"actionLabel()\" [leadingIcon]=\"actionLeadingIcon()\" [trailingIcon]=\"actionTrailingIcon()\" [disabled]=\"actionDisabled()\" />\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"cc cc--with-icon\" [class.cc--filled]=\"appearance() === 'filled'\" [class.cc--inline-icon]=\"inlineIcon()\">\r\n @if (inlineIcon()) {\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 32, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n } @else {\r\n <div class=\"cc__banner\">\r\n @if (icon()) {\r\n <span class=\"cc__banner-icon\" [innerHTML]=\"iconSvg(icon(), 48, 1.5)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n }\r\n <div class=\"cc__container\">\r\n <div class=\"cc__title-group\">\r\n @if (category()) { <p class=\"cc__category-eyebrow\">{{ category() }}</p> }\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__title', text: title() }\" /> }\r\n </div>\r\n @if (description()) { <p class=\"cc__desc\">{{ description() }}</p> }\r\n @if (headline()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'cc__headline', text: headline() }\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('action') {\r\n @if (orientation() === 'vertical') {\r\n <div class=\"ac ac--vertical\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__badge\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"ac\" [class.ac--no-desc]=\"!description()\">\r\n @if (icon()) {\r\n <div class=\"ac__icon\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"ac__text\">\r\n <ng-container [ngTemplateOutlet]=\"labelTpl\" />\r\n @if (description()) { <span class=\"ac__desc\">{{ description() }}</span> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @case ('metric') {\r\n <div class=\"mc\" [class.mc--current]=\"current()\">\r\n <span class=\"mc__value\">{{ value() }}</span>\r\n @if (label()) { <span class=\"mc__label\">{{ label() }}</span> }\r\n </div>\r\n }\r\n\r\n @case ('basic') {\r\n @if (size() === 'xs') {\r\n <!-- xs base card (Figma 243:3264): compact horizontal row — icon · title · arrow. -->\r\n <div class=\"bc bc--row\">\r\n @if (icon()) {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), 24, 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n <div class=\"bc__row-text\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', 20)\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else if (size() === 'lg') {\r\n <!-- lg base card (Figma 243:3205): text + optional chip, button bottom-right. -->\r\n <div class=\"bc bc--promo\" [class.bc--banner]=\"isBanner()\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n } @else if (isBanner()) {\r\n <!-- md banner base card (Figma 59442:12042): text over the image, arrow bottom-right. -->\r\n <div class=\"bc bc--banner\">\r\n <div class=\"bc__text\">\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n } @else {\r\n <!-- md / sm base card (Figma 243:3174, 243:3179, 947:8067):\r\n icon + arrow row, then eyebrow / title / subtitle / description / button. -->\r\n <div class=\"bc\">\r\n <div class=\"bc__top\">\r\n @if (icon()) {\r\n @if (appearance() === 'gradient') {\r\n <div class=\"bc__icon bc__icon--badge\" [innerHTML]=\"iconSvg(icon(), 32)\" aria-hidden=\"true\"></div>\r\n } @else {\r\n <div class=\"bc__icon\" [innerHTML]=\"iconSvg(icon(), basicIconSize(), 1.5)\" aria-hidden=\"true\"></div>\r\n }\r\n }\r\n <div class=\"bc__top-end\">\r\n @if (category()) { <span class=\"bc__chip\">{{ category() }}</span> }\r\n @if (showArrow()) {\r\n <span class=\"bc__arrow\" [innerHTML]=\"iconSvg('arrow-up-right', basicArrowSize())\" aria-hidden=\"true\"></span>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"bc__body\">\r\n <div class=\"bc__text\">\r\n @if (label()) { <p class=\"bc__eyebrow\">{{ label() }}</p> }\r\n @if (title() || subtitle()) {\r\n <div class=\"bc__heading\">\r\n @if (title()) { <ng-container [ngTemplateOutlet]=\"headingTpl\" [ngTemplateOutletContext]=\"{ $implicit: 'bc__title', text: title() }\" /> }\r\n @if (subtitle()) { <p class=\"bc__subtitle\">{{ subtitle() }}</p> }\r\n </div>\r\n }\r\n @if (description()) { <p class=\"bc__desc\">{{ description() }}</p> }\r\n </div>\r\n @if (actionLabel()) { <compsych-button [variant]=\"appearance() === 'filled' ? 'elevated' : 'outlined'\" [label]=\"actionLabel()\" [disabled]=\"actionDisabled()\" /> }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @default {\r\n <ng-content />\r\n }\r\n }\r\n</div>\r\n\r\n<!-- Heading fragment: renders <h2>–<h6> when headingLevel is set, else <p>.\r\n Pass $implicit = CSS class string, text = display text.\r\n Used by all title/headline slots across content and basic variants. -->\r\n<ng-template #headingTpl let-cls let-text=\"text\">\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 [class]=\"cls\">{{ text }}</h2> }\r\n @case (3) { <h3 [class]=\"cls\">{{ text }}</h3> }\r\n @case (4) { <h4 [class]=\"cls\">{{ text }}</h4> }\r\n @case (5) { <h5 [class]=\"cls\">{{ text }}</h5> }\r\n @case (6) { <h6 [class]=\"cls\">{{ text }}</h6> }\r\n @default { <p [class]=\"cls\">{{ text }}</p> }\r\n }\r\n</ng-template>\r\n\r\n<!-- Action-card label: same heading-level logic but defaults to <span> (inline) not <p>. -->\r\n<ng-template #labelTpl>\r\n @switch (effectiveHeadingLevel()) {\r\n @case (2) { <h2 class=\"ac__label\">{{ label() }}</h2> }\r\n @case (3) { <h3 class=\"ac__label\">{{ label() }}</h3> }\r\n @case (4) { <h4 class=\"ac__label\">{{ label() }}</h4> }\r\n @case (5) { <h5 class=\"ac__label\">{{ label() }}</h5> }\r\n @case (6) { <h6 class=\"ac__label\">{{ label() }}</h6> }\r\n @default { <span class=\"ac__label\">{{ label() }}</span> }\r\n }\r\n</ng-template>\r\n"]}
|
|
@@ -179,7 +179,9 @@ export class DropdownComponent {
|
|
|
179
179
|
}
|
|
180
180
|
/** Value array bound to the CDK listbox (single-select, so 0 or 1 entry). */
|
|
181
181
|
get listboxValue() {
|
|
182
|
-
|
|
182
|
+
if (!this.value || !this.options.some((o) => o.value === this.value))
|
|
183
|
+
return [];
|
|
184
|
+
return [this.value];
|
|
183
185
|
}
|
|
184
186
|
/** True when the bound FormControl is invalid and touched, or when `error` is explicitly set. */
|
|
185
187
|
get hasError() {
|
|
@@ -297,185 +299,11 @@ export class DropdownComponent {
|
|
|
297
299
|
this.cdr.markForCheck();
|
|
298
300
|
}
|
|
299
301
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
300
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DropdownComponent, isStandalone: true, selector: "compsych-dropdown", inputs: { label: "label", placeholder: "placeholder", value: "value", options: "options", size: "size", id: "id", ariaDescribedBy: "ariaDescribedBy", supportingText: "supportingText", errorMessage: "errorMessage", errorMessages: "errorMessages", required: ["required", "required", booleanAttribute], error: ["error", "error", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], hideLabel: ["hideLabel", "hideLabel", booleanAttribute], labelPosition: "labelPosition", inlineLabel: ["inlineLabel", "inlineLabel", booleanAttribute], leadingIcon: "leadingIcon", optionsLeadingIcon: "optionsLeadingIcon" }, outputs: { valueChange: "valueChange", opened: "opened", closed: "closed" }, viewQueries: [{ propertyName: "triggerBtn", first: true, predicate: ["triggerBtn"], descendants: true }, { propertyName: "listboxEl", first: true, predicate: ["listboxEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
301
|
-
<div [class]="wrapperClasses">
|
|
302
|
-
<div class="label-row" [class.sr-only]="hideLabel || inlineLabel">
|
|
303
|
-
<label class="label" [id]="labelId" [for]="triggerId">
|
|
304
|
-
{{ label }}
|
|
305
|
-
@if (isRequired) {
|
|
306
|
-
<span class="required-marker" aria-hidden="true"> *</span>
|
|
307
|
-
}
|
|
308
|
-
</label>
|
|
309
|
-
</div>
|
|
310
|
-
|
|
311
|
-
<button
|
|
312
|
-
#triggerBtn
|
|
313
|
-
cdkOverlayOrigin
|
|
314
|
-
#origin="cdkOverlayOrigin"
|
|
315
|
-
type="button"
|
|
316
|
-
class="trigger"
|
|
317
|
-
[id]="triggerId"
|
|
318
|
-
[class.placeholder]="!selectedOption && !inlineLabel"
|
|
319
|
-
[class.error]="hasError"
|
|
320
|
-
[class.open]="isOpen"
|
|
321
|
-
[disabled]="disabled"
|
|
322
|
-
role="combobox"
|
|
323
|
-
aria-haspopup="listbox"
|
|
324
|
-
[attr.aria-expanded]="isOpen"
|
|
325
|
-
[attr.aria-controls]="listboxId"
|
|
326
|
-
[attr.aria-labelledby]="labelId + ' ' + triggerId"
|
|
327
|
-
[attr.aria-invalid]="hasError ? 'true' : null"
|
|
328
|
-
[attr.aria-required]="isRequired ? 'true' : null"
|
|
329
|
-
[attr.aria-describedby]="describedBy"
|
|
330
|
-
(click)="toggle()"
|
|
331
|
-
(keydown)="onTriggerKeydown($event)"
|
|
332
|
-
>
|
|
333
|
-
@if (triggerIconSvg) {
|
|
334
|
-
<span class="trigger-icon" aria-hidden="true" [innerHTML]="triggerIconSvg"></span>
|
|
335
|
-
}
|
|
336
|
-
<span class="trigger-text">{{ triggerText }}</span>
|
|
337
|
-
<span class="trigger-chevron" aria-hidden="true" [innerHTML]="chevronSvg"></span>
|
|
338
|
-
</button>
|
|
339
|
-
|
|
340
|
-
@if (displayedSupportingText) {
|
|
341
|
-
<span class="supporting-text" [class.supporting-text--error]="hasError" [id]="triggerId + '-supporting'">
|
|
342
|
-
{{ displayedSupportingText }}
|
|
343
|
-
</span>
|
|
344
|
-
}
|
|
345
|
-
</div>
|
|
346
|
-
|
|
347
|
-
<ng-template
|
|
348
|
-
cdkConnectedOverlay
|
|
349
|
-
[cdkConnectedOverlayOrigin]="origin"
|
|
350
|
-
[cdkConnectedOverlayOpen]="isOpen"
|
|
351
|
-
[cdkConnectedOverlayWidth]="overlayWidth"
|
|
352
|
-
[cdkConnectedOverlayPositions]="overlayPositions"
|
|
353
|
-
[cdkConnectedOverlayViewportMargin]="8"
|
|
354
|
-
(overlayOutsideClick)="close()"
|
|
355
|
-
(attach)="onPanelAttach()"
|
|
356
|
-
(detach)="close()"
|
|
357
|
-
>
|
|
358
|
-
<ul
|
|
359
|
-
#listboxEl
|
|
360
|
-
cdkListbox
|
|
361
|
-
class="panel"
|
|
362
|
-
[class.sm]="size === 'sm'"
|
|
363
|
-
[style.width.px]="overlayWidth"
|
|
364
|
-
[id]="listboxId"
|
|
365
|
-
[attr.aria-labelledby]="labelId"
|
|
366
|
-
[cdkListboxValue]="listboxValue"
|
|
367
|
-
(cdkListboxValueChange)="onListboxValueChange($event)"
|
|
368
|
-
(keydown)="onListboxKeydown($event)"
|
|
369
|
-
>
|
|
370
|
-
@for (opt of options; track opt.value) {
|
|
371
|
-
<li class="option" [class.error]="opt.error" [cdkOption]="opt.value" [cdkOptionDisabled]="!!opt.disabled">
|
|
372
|
-
<span class="option-inner">
|
|
373
|
-
@if (opt.iconSvg || opt.icon || optionsLeadingIcon) {
|
|
374
|
-
<span class="option-icon" aria-hidden="true" [innerHTML]="optionIcon(opt)"></span>
|
|
375
|
-
}
|
|
376
|
-
<span class="option-text">
|
|
377
|
-
<span class="option-label">{{ opt.label }}</span>
|
|
378
|
-
@if (opt.supportingText) {
|
|
379
|
-
<span class="option-support">{{ opt.supportingText }}</span>
|
|
380
|
-
}
|
|
381
|
-
</span>
|
|
382
|
-
</span>
|
|
383
|
-
</li>
|
|
384
|
-
}
|
|
385
|
-
</ul>
|
|
386
|
-
</ng-template>
|
|
387
|
-
`, isInline: true, styles: [":host{display:block}.cmp-dropdown{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cmp-dropdown.label-left{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:\"label field\" \". support\";align-items:center;column-gap:var(--spacing-padding-sys-padding-12);row-gap:var(--spacing-padding-sys-padding-4)}.cmp-dropdown.label-left .label-row{grid-area:label}.cmp-dropdown.label-left .trigger{grid-area:field}.cmp-dropdown.label-left .supporting-text{grid-area:support}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label-row{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.label{font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.cmp-dropdown.lg .label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.required-marker{color:var(--custom-info-sys-info)}.cmp-dropdown.disabled .label{opacity:.64}.trigger{box-sizing:border-box;width:100%;display:flex;align-items:center;gap:var(--spacing-padding-sys-padding-8);margin:0;border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-sm);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--body-medium-sys-font-family);font-weight:var(--body-medium-sys-font-weight);text-align:start;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease}.trigger-icon{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant)}.trigger-text{flex:1 0 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trigger.placeholder .trigger-text{color:var(--surface-surface-sys-on-surface-variant)}.trigger-chevron{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);transition:color .15s ease,transform .16s ease}.trigger:focus-visible .trigger-chevron,.trigger.open .trigger-chevron{color:var(--accent-primary-sys-primary)}.trigger.open .trigger-chevron{transform:rotate(180deg)}.trigger.error:not(:disabled) .trigger-chevron{color:var(--error-sys-error)}@media(prefers-reduced-motion:reduce){.trigger-chevron{transition:color .15s ease}}.trigger:hover:not(:disabled):not(.open){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.trigger:focus-visible,.trigger.open{border-color:var(--accent-primary-sys-primary);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger.error:not(:disabled):not(.open){border-color:var(--error-sys-error)}.trigger.error:focus-visible,.trigger.error.open{border-color:var(--error-sys-error);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger:disabled{background-color:var(--surface-surface-container-sys-surface-container-low);color:var(--surface-surface-sys-on-surface-variant);border-color:var(--outline-sys-outline-variant);cursor:not-allowed}.trigger:disabled .trigger-text,.trigger:disabled .trigger-icon,.trigger:disabled .trigger-chevron{opacity:.64}.supporting-text{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);font-weight:var(--body-small-sys-font-weight);line-height:var(--body-small-sys-line-height);color:var(--surface-surface-sys-on-surface-variant)}.supporting-text--error{color:var(--error-sys-error)}.cmp-dropdown.disabled .supporting-text{opacity:.64}.cmp-dropdown.sm .trigger{height:40px;gap:var(--spacing-padding-sys-padding-4);padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-12);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.cmp-dropdown.md .trigger{height:48px;padding:var(--spacing-padding-sys-padding-12) var(--spacing-padding-sys-padding-16);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.cmp-dropdown.lg .trigger{height:56px;padding:var(--spacing-padding-sys-padding-16) var(--spacing-padding-sys-padding-20);border-radius:var(--border-radius-sys-radius-md);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.panel{box-sizing:border-box;list-style:none;margin:0;padding:var(--spacing-padding-sys-padding-4) 0;max-height:340px;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-md);box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014;outline:none;font-family:var(--body-medium-sys-font-family)}.option{box-sizing:border-box;display:block;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-8);cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.option-inner{display:flex;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-8);border-radius:var(--border-radius-sys-radius-sm);color:var(--surface-surface-sys-on-surface);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);transition:background-color .12s ease-out}.panel.sm .option-inner{font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;color:var(--surface-surface-sys-on-surface);margin-top:var(--spacing-padding-sys-padding-2)}.option-text{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--spacing-padding-sys-padding-8);row-gap:var(--spacing-padding-sys-padding-2)}.option-label{min-width:0}.option-support{color:var(--surface-surface-sys-on-surface-variant);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option.error .option-icon,.option.error .option-label{color:var(--error-sys-error)}.option:hover:not([aria-disabled=true]) .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent)}.option:focus-visible{outline:none}.option:focus-visible .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent);outline:var(--border-width-sys-stroke-medium) solid var(--accent-primary-sys-primary);outline-offset:-2px}.option[aria-disabled=true]{cursor:not-allowed}.option[aria-disabled=true] .option-inner{color:var(--surface-surface-sys-on-surface-variant);opacity:.64}@media(forced-colors:active){.trigger{border:1px solid ButtonText;forced-color-adjust:none}.trigger:focus-visible,.trigger.open{outline:2px solid Highlight;outline-offset:2px}.trigger:disabled{color:GrayText;border-color:GrayText;background:ButtonFace;opacity:1}.cmp-dropdown.disabled .label{color:GrayText;opacity:1}.supporting-text--error{color:LinkText}.panel{border:1px solid ButtonText}.option:focus-visible .option-inner{outline:2px solid Highlight;outline-offset:-2px}}\n"], dependencies: [{ kind: "directive", type: CdkListbox, selector: "[cdkListbox]", inputs: ["id", "tabindex", "cdkListboxValue", "cdkListboxMultiple", "cdkListboxDisabled", "cdkListboxUseActiveDescendant", "cdkListboxOrientation", "cdkListboxCompareWith", "cdkListboxNavigationWrapDisabled", "cdkListboxNavigatesDisabledOptions"], outputs: ["cdkListboxValueChange"], exportAs: ["cdkListbox"] }, { kind: "directive", type: CdkOption, selector: "[cdkOption]", inputs: ["id", "cdkOption", "cdkOptionTypeaheadLabel", "cdkOptionDisabled", "tabindex"], exportAs: ["cdkOption"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
302
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DropdownComponent, isStandalone: true, selector: "compsych-dropdown", inputs: { label: "label", placeholder: "placeholder", value: "value", options: "options", size: "size", id: "id", ariaDescribedBy: "ariaDescribedBy", supportingText: "supportingText", errorMessage: "errorMessage", errorMessages: "errorMessages", required: ["required", "required", booleanAttribute], error: ["error", "error", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], hideLabel: ["hideLabel", "hideLabel", booleanAttribute], labelPosition: "labelPosition", inlineLabel: ["inlineLabel", "inlineLabel", booleanAttribute], leadingIcon: "leadingIcon", optionsLeadingIcon: "optionsLeadingIcon" }, outputs: { valueChange: "valueChange", opened: "opened", closed: "closed" }, viewQueries: [{ propertyName: "triggerBtn", first: true, predicate: ["triggerBtn"], descendants: true }, { propertyName: "listboxEl", first: true, predicate: ["listboxEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div [class]=\"wrapperClasses\">\n <div class=\"label-row\" [class.sr-only]=\"hideLabel || inlineLabel\">\n <label class=\"label\" [id]=\"labelId\" [for]=\"triggerId\">\n {{ label }}\n @if (isRequired) {\n <span class=\"required-marker\" aria-hidden=\"true\"> *</span>\n }\n </label>\n </div>\n\n <button\n #triggerBtn\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"trigger\"\n [id]=\"triggerId\"\n [class.placeholder]=\"!selectedOption && !inlineLabel\"\n [class.error]=\"hasError\"\n [class.open]=\"isOpen\"\n [disabled]=\"disabled\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-labelledby]=\"labelId + ' ' + triggerId\"\n [attr.aria-invalid]=\"hasError ? 'true' : null\"\n [attr.aria-required]=\"isRequired ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy\"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n @if (triggerIconSvg) {\n <span class=\"trigger-icon\" aria-hidden=\"true\" [innerHTML]=\"triggerIconSvg\"></span>\n }\n <span class=\"trigger-text\">{{ triggerText }}</span>\n <span class=\"trigger-chevron\" aria-hidden=\"true\" [innerHTML]=\"chevronSvg\"></span>\n </button>\n\n @if (displayedSupportingText) {\n <span class=\"supporting-text\" [class.supporting-text--error]=\"hasError\" [id]=\"triggerId + '-supporting'\">\n {{ displayedSupportingText }}\n </span>\n }\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayViewportMargin]=\"8\"\n (overlayOutsideClick)=\"close()\"\n (attach)=\"onPanelAttach()\"\n (detach)=\"close()\"\n>\n @if (isOpen) {\n <ul\n #listboxEl\n cdkListbox\n class=\"panel\"\n [class.sm]=\"size === 'sm'\"\n [style.width.px]=\"overlayWidth\"\n [id]=\"listboxId\"\n [attr.aria-labelledby]=\"labelId\"\n [cdkListboxValue]=\"listboxValue\"\n (cdkListboxValueChange)=\"onListboxValueChange($event)\"\n (keydown)=\"onListboxKeydown($event)\"\n >\n @for (opt of options; track opt.value) {\n <li class=\"option\" [class.error]=\"opt.error\" [cdkOption]=\"opt.value\" [cdkOptionDisabled]=\"!!opt.disabled\">\n <span class=\"option-inner\">\n @if (opt.iconSvg || opt.icon || optionsLeadingIcon) {\n <span class=\"option-icon\" aria-hidden=\"true\" [innerHTML]=\"optionIcon(opt)\"></span>\n }\n <span class=\"option-text\">\n <span class=\"option-label\">{{ opt.label }}</span>\n @if (opt.supportingText) {\n <span class=\"option-support\">{{ opt.supportingText }}</span>\n }\n </span>\n </span>\n </li>\n }\n </ul>\n }\n</ng-template>\n", styles: [":host{display:block}.cmp-dropdown{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cmp-dropdown.label-left{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:\"label field\" \". support\";align-items:center;column-gap:var(--spacing-padding-sys-padding-12);row-gap:var(--spacing-padding-sys-padding-4)}.cmp-dropdown.label-left .label-row{grid-area:label}.cmp-dropdown.label-left .trigger{grid-area:field}.cmp-dropdown.label-left .supporting-text{grid-area:support}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label-row{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.label{font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.cmp-dropdown.lg .label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.required-marker{color:var(--custom-info-sys-info)}.cmp-dropdown.disabled .label{opacity:.64}.trigger{box-sizing:border-box;width:100%;display:flex;align-items:center;gap:var(--spacing-padding-sys-padding-8);margin:0;border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-sm);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--body-medium-sys-font-family);font-weight:var(--body-medium-sys-font-weight);text-align:start;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease}.trigger-icon{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant)}.trigger-text{flex:1 0 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trigger.placeholder .trigger-text{color:var(--surface-surface-sys-on-surface-variant)}.trigger-chevron{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);transition:color .15s ease,transform .16s ease}.trigger:focus-visible .trigger-chevron,.trigger.open .trigger-chevron{color:var(--accent-primary-sys-primary)}.trigger.open .trigger-chevron{transform:rotate(180deg)}.trigger.error:not(:disabled) .trigger-chevron{color:var(--error-sys-error)}@media(prefers-reduced-motion:reduce){.trigger-chevron{transition:color .15s ease}}.trigger:hover:not(:disabled):not(.open){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.trigger:focus-visible,.trigger.open{border-color:var(--accent-primary-sys-primary);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger.error:not(:disabled):not(.open){border-color:var(--error-sys-error)}.trigger.error:focus-visible,.trigger.error.open{border-color:var(--error-sys-error);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger:disabled{background-color:var(--surface-surface-container-sys-surface-container-low);color:var(--surface-surface-sys-on-surface-variant);border-color:var(--outline-sys-outline-variant);cursor:not-allowed}.trigger:disabled .trigger-text,.trigger:disabled .trigger-icon,.trigger:disabled .trigger-chevron{opacity:.64}.supporting-text{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);font-weight:var(--body-small-sys-font-weight);line-height:var(--body-small-sys-line-height);color:var(--surface-surface-sys-on-surface-variant)}.supporting-text--error{color:var(--error-sys-error)}.cmp-dropdown.disabled .supporting-text{opacity:.64}.cmp-dropdown.sm .trigger{height:40px;gap:var(--spacing-padding-sys-padding-4);padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-12);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.cmp-dropdown.md .trigger{height:48px;padding:var(--spacing-padding-sys-padding-12) var(--spacing-padding-sys-padding-16);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.cmp-dropdown.lg .trigger{height:56px;padding:var(--spacing-padding-sys-padding-16) var(--spacing-padding-sys-padding-20);border-radius:var(--border-radius-sys-radius-md);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.panel{box-sizing:border-box;list-style:none;margin:0;padding:var(--spacing-padding-sys-padding-4) 0;max-height:340px;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-md);box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014;outline:none;font-family:var(--body-medium-sys-font-family)}.option{box-sizing:border-box;display:block;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-8);cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.option-inner{display:flex;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-8);border-radius:var(--border-radius-sys-radius-sm);color:var(--surface-surface-sys-on-surface);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);transition:background-color .12s ease-out}.panel.sm .option-inner{font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;color:var(--surface-surface-sys-on-surface);margin-top:var(--spacing-padding-sys-padding-2)}.option-text{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--spacing-padding-sys-padding-8);row-gap:var(--spacing-padding-sys-padding-2)}.option-label{min-width:0}.option-support{color:var(--surface-surface-sys-on-surface-variant);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option.error .option-icon,.option.error .option-label{color:var(--error-sys-error)}.option:hover:not([aria-disabled=true]) .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent)}.option:focus-visible{outline:none}.option:focus-visible .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent);outline:var(--border-width-sys-stroke-medium) solid var(--accent-primary-sys-primary);outline-offset:-2px}.option[aria-disabled=true]{cursor:not-allowed}.option[aria-disabled=true] .option-inner{color:var(--surface-surface-sys-on-surface-variant);opacity:.64}@media(forced-colors:active){.trigger{border:1px solid ButtonText;forced-color-adjust:none}.trigger:focus-visible,.trigger.open{outline:2px solid Highlight;outline-offset:2px}.trigger:disabled{color:GrayText;border-color:GrayText;background:ButtonFace;opacity:1}.cmp-dropdown.disabled .label{color:GrayText;opacity:1}.supporting-text--error{color:LinkText}.panel{border:1px solid ButtonText}.option:focus-visible .option-inner{outline:2px solid Highlight;outline-offset:-2px}}\n"], dependencies: [{ kind: "directive", type: CdkListbox, selector: "[cdkListbox]", inputs: ["id", "tabindex", "cdkListboxValue", "cdkListboxMultiple", "cdkListboxDisabled", "cdkListboxUseActiveDescendant", "cdkListboxOrientation", "cdkListboxCompareWith", "cdkListboxNavigationWrapDisabled", "cdkListboxNavigatesDisabledOptions"], outputs: ["cdkListboxValueChange"], exportAs: ["cdkListbox"] }, { kind: "directive", type: CdkOption, selector: "[cdkOption]", inputs: ["id", "cdkOption", "cdkOptionTypeaheadLabel", "cdkOptionDisabled", "tabindex"], exportAs: ["cdkOption"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
388
303
|
}
|
|
389
304
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DropdownComponent, decorators: [{
|
|
390
305
|
type: Component,
|
|
391
|
-
args: [{ selector: 'compsych-dropdown', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CdkListbox, CdkOption, CdkConnectedOverlay, CdkOverlayOrigin], template: `
|
|
392
|
-
<div [class]="wrapperClasses">
|
|
393
|
-
<div class="label-row" [class.sr-only]="hideLabel || inlineLabel">
|
|
394
|
-
<label class="label" [id]="labelId" [for]="triggerId">
|
|
395
|
-
{{ label }}
|
|
396
|
-
@if (isRequired) {
|
|
397
|
-
<span class="required-marker" aria-hidden="true"> *</span>
|
|
398
|
-
}
|
|
399
|
-
</label>
|
|
400
|
-
</div>
|
|
401
|
-
|
|
402
|
-
<button
|
|
403
|
-
#triggerBtn
|
|
404
|
-
cdkOverlayOrigin
|
|
405
|
-
#origin="cdkOverlayOrigin"
|
|
406
|
-
type="button"
|
|
407
|
-
class="trigger"
|
|
408
|
-
[id]="triggerId"
|
|
409
|
-
[class.placeholder]="!selectedOption && !inlineLabel"
|
|
410
|
-
[class.error]="hasError"
|
|
411
|
-
[class.open]="isOpen"
|
|
412
|
-
[disabled]="disabled"
|
|
413
|
-
role="combobox"
|
|
414
|
-
aria-haspopup="listbox"
|
|
415
|
-
[attr.aria-expanded]="isOpen"
|
|
416
|
-
[attr.aria-controls]="listboxId"
|
|
417
|
-
[attr.aria-labelledby]="labelId + ' ' + triggerId"
|
|
418
|
-
[attr.aria-invalid]="hasError ? 'true' : null"
|
|
419
|
-
[attr.aria-required]="isRequired ? 'true' : null"
|
|
420
|
-
[attr.aria-describedby]="describedBy"
|
|
421
|
-
(click)="toggle()"
|
|
422
|
-
(keydown)="onTriggerKeydown($event)"
|
|
423
|
-
>
|
|
424
|
-
@if (triggerIconSvg) {
|
|
425
|
-
<span class="trigger-icon" aria-hidden="true" [innerHTML]="triggerIconSvg"></span>
|
|
426
|
-
}
|
|
427
|
-
<span class="trigger-text">{{ triggerText }}</span>
|
|
428
|
-
<span class="trigger-chevron" aria-hidden="true" [innerHTML]="chevronSvg"></span>
|
|
429
|
-
</button>
|
|
430
|
-
|
|
431
|
-
@if (displayedSupportingText) {
|
|
432
|
-
<span class="supporting-text" [class.supporting-text--error]="hasError" [id]="triggerId + '-supporting'">
|
|
433
|
-
{{ displayedSupportingText }}
|
|
434
|
-
</span>
|
|
435
|
-
}
|
|
436
|
-
</div>
|
|
437
|
-
|
|
438
|
-
<ng-template
|
|
439
|
-
cdkConnectedOverlay
|
|
440
|
-
[cdkConnectedOverlayOrigin]="origin"
|
|
441
|
-
[cdkConnectedOverlayOpen]="isOpen"
|
|
442
|
-
[cdkConnectedOverlayWidth]="overlayWidth"
|
|
443
|
-
[cdkConnectedOverlayPositions]="overlayPositions"
|
|
444
|
-
[cdkConnectedOverlayViewportMargin]="8"
|
|
445
|
-
(overlayOutsideClick)="close()"
|
|
446
|
-
(attach)="onPanelAttach()"
|
|
447
|
-
(detach)="close()"
|
|
448
|
-
>
|
|
449
|
-
<ul
|
|
450
|
-
#listboxEl
|
|
451
|
-
cdkListbox
|
|
452
|
-
class="panel"
|
|
453
|
-
[class.sm]="size === 'sm'"
|
|
454
|
-
[style.width.px]="overlayWidth"
|
|
455
|
-
[id]="listboxId"
|
|
456
|
-
[attr.aria-labelledby]="labelId"
|
|
457
|
-
[cdkListboxValue]="listboxValue"
|
|
458
|
-
(cdkListboxValueChange)="onListboxValueChange($event)"
|
|
459
|
-
(keydown)="onListboxKeydown($event)"
|
|
460
|
-
>
|
|
461
|
-
@for (opt of options; track opt.value) {
|
|
462
|
-
<li class="option" [class.error]="opt.error" [cdkOption]="opt.value" [cdkOptionDisabled]="!!opt.disabled">
|
|
463
|
-
<span class="option-inner">
|
|
464
|
-
@if (opt.iconSvg || opt.icon || optionsLeadingIcon) {
|
|
465
|
-
<span class="option-icon" aria-hidden="true" [innerHTML]="optionIcon(opt)"></span>
|
|
466
|
-
}
|
|
467
|
-
<span class="option-text">
|
|
468
|
-
<span class="option-label">{{ opt.label }}</span>
|
|
469
|
-
@if (opt.supportingText) {
|
|
470
|
-
<span class="option-support">{{ opt.supportingText }}</span>
|
|
471
|
-
}
|
|
472
|
-
</span>
|
|
473
|
-
</span>
|
|
474
|
-
</li>
|
|
475
|
-
}
|
|
476
|
-
</ul>
|
|
477
|
-
</ng-template>
|
|
478
|
-
`, styles: [":host{display:block}.cmp-dropdown{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cmp-dropdown.label-left{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:\"label field\" \". support\";align-items:center;column-gap:var(--spacing-padding-sys-padding-12);row-gap:var(--spacing-padding-sys-padding-4)}.cmp-dropdown.label-left .label-row{grid-area:label}.cmp-dropdown.label-left .trigger{grid-area:field}.cmp-dropdown.label-left .supporting-text{grid-area:support}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label-row{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.label{font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.cmp-dropdown.lg .label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.required-marker{color:var(--custom-info-sys-info)}.cmp-dropdown.disabled .label{opacity:.64}.trigger{box-sizing:border-box;width:100%;display:flex;align-items:center;gap:var(--spacing-padding-sys-padding-8);margin:0;border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-sm);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--body-medium-sys-font-family);font-weight:var(--body-medium-sys-font-weight);text-align:start;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease}.trigger-icon{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant)}.trigger-text{flex:1 0 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trigger.placeholder .trigger-text{color:var(--surface-surface-sys-on-surface-variant)}.trigger-chevron{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);transition:color .15s ease,transform .16s ease}.trigger:focus-visible .trigger-chevron,.trigger.open .trigger-chevron{color:var(--accent-primary-sys-primary)}.trigger.open .trigger-chevron{transform:rotate(180deg)}.trigger.error:not(:disabled) .trigger-chevron{color:var(--error-sys-error)}@media(prefers-reduced-motion:reduce){.trigger-chevron{transition:color .15s ease}}.trigger:hover:not(:disabled):not(.open){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.trigger:focus-visible,.trigger.open{border-color:var(--accent-primary-sys-primary);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger.error:not(:disabled):not(.open){border-color:var(--error-sys-error)}.trigger.error:focus-visible,.trigger.error.open{border-color:var(--error-sys-error);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger:disabled{background-color:var(--surface-surface-container-sys-surface-container-low);color:var(--surface-surface-sys-on-surface-variant);border-color:var(--outline-sys-outline-variant);cursor:not-allowed}.trigger:disabled .trigger-text,.trigger:disabled .trigger-icon,.trigger:disabled .trigger-chevron{opacity:.64}.supporting-text{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);font-weight:var(--body-small-sys-font-weight);line-height:var(--body-small-sys-line-height);color:var(--surface-surface-sys-on-surface-variant)}.supporting-text--error{color:var(--error-sys-error)}.cmp-dropdown.disabled .supporting-text{opacity:.64}.cmp-dropdown.sm .trigger{height:40px;gap:var(--spacing-padding-sys-padding-4);padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-12);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.cmp-dropdown.md .trigger{height:48px;padding:var(--spacing-padding-sys-padding-12) var(--spacing-padding-sys-padding-16);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.cmp-dropdown.lg .trigger{height:56px;padding:var(--spacing-padding-sys-padding-16) var(--spacing-padding-sys-padding-20);border-radius:var(--border-radius-sys-radius-md);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.panel{box-sizing:border-box;list-style:none;margin:0;padding:var(--spacing-padding-sys-padding-4) 0;max-height:340px;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-md);box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014;outline:none;font-family:var(--body-medium-sys-font-family)}.option{box-sizing:border-box;display:block;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-8);cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.option-inner{display:flex;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-8);border-radius:var(--border-radius-sys-radius-sm);color:var(--surface-surface-sys-on-surface);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);transition:background-color .12s ease-out}.panel.sm .option-inner{font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;color:var(--surface-surface-sys-on-surface);margin-top:var(--spacing-padding-sys-padding-2)}.option-text{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--spacing-padding-sys-padding-8);row-gap:var(--spacing-padding-sys-padding-2)}.option-label{min-width:0}.option-support{color:var(--surface-surface-sys-on-surface-variant);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option.error .option-icon,.option.error .option-label{color:var(--error-sys-error)}.option:hover:not([aria-disabled=true]) .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent)}.option:focus-visible{outline:none}.option:focus-visible .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent);outline:var(--border-width-sys-stroke-medium) solid var(--accent-primary-sys-primary);outline-offset:-2px}.option[aria-disabled=true]{cursor:not-allowed}.option[aria-disabled=true] .option-inner{color:var(--surface-surface-sys-on-surface-variant);opacity:.64}@media(forced-colors:active){.trigger{border:1px solid ButtonText;forced-color-adjust:none}.trigger:focus-visible,.trigger.open{outline:2px solid Highlight;outline-offset:2px}.trigger:disabled{color:GrayText;border-color:GrayText;background:ButtonFace;opacity:1}.cmp-dropdown.disabled .label{color:GrayText;opacity:1}.supporting-text--error{color:LinkText}.panel{border:1px solid ButtonText}.option:focus-visible .option-inner{outline:2px solid Highlight;outline-offset:-2px}}\n"] }]
|
|
306
|
+
args: [{ selector: 'compsych-dropdown', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CdkListbox, CdkOption, CdkConnectedOverlay, CdkOverlayOrigin], template: "<div [class]=\"wrapperClasses\">\n <div class=\"label-row\" [class.sr-only]=\"hideLabel || inlineLabel\">\n <label class=\"label\" [id]=\"labelId\" [for]=\"triggerId\">\n {{ label }}\n @if (isRequired) {\n <span class=\"required-marker\" aria-hidden=\"true\"> *</span>\n }\n </label>\n </div>\n\n <button\n #triggerBtn\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"trigger\"\n [id]=\"triggerId\"\n [class.placeholder]=\"!selectedOption && !inlineLabel\"\n [class.error]=\"hasError\"\n [class.open]=\"isOpen\"\n [disabled]=\"disabled\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-labelledby]=\"labelId + ' ' + triggerId\"\n [attr.aria-invalid]=\"hasError ? 'true' : null\"\n [attr.aria-required]=\"isRequired ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy\"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n @if (triggerIconSvg) {\n <span class=\"trigger-icon\" aria-hidden=\"true\" [innerHTML]=\"triggerIconSvg\"></span>\n }\n <span class=\"trigger-text\">{{ triggerText }}</span>\n <span class=\"trigger-chevron\" aria-hidden=\"true\" [innerHTML]=\"chevronSvg\"></span>\n </button>\n\n @if (displayedSupportingText) {\n <span class=\"supporting-text\" [class.supporting-text--error]=\"hasError\" [id]=\"triggerId + '-supporting'\">\n {{ displayedSupportingText }}\n </span>\n }\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayViewportMargin]=\"8\"\n (overlayOutsideClick)=\"close()\"\n (attach)=\"onPanelAttach()\"\n (detach)=\"close()\"\n>\n @if (isOpen) {\n <ul\n #listboxEl\n cdkListbox\n class=\"panel\"\n [class.sm]=\"size === 'sm'\"\n [style.width.px]=\"overlayWidth\"\n [id]=\"listboxId\"\n [attr.aria-labelledby]=\"labelId\"\n [cdkListboxValue]=\"listboxValue\"\n (cdkListboxValueChange)=\"onListboxValueChange($event)\"\n (keydown)=\"onListboxKeydown($event)\"\n >\n @for (opt of options; track opt.value) {\n <li class=\"option\" [class.error]=\"opt.error\" [cdkOption]=\"opt.value\" [cdkOptionDisabled]=\"!!opt.disabled\">\n <span class=\"option-inner\">\n @if (opt.iconSvg || opt.icon || optionsLeadingIcon) {\n <span class=\"option-icon\" aria-hidden=\"true\" [innerHTML]=\"optionIcon(opt)\"></span>\n }\n <span class=\"option-text\">\n <span class=\"option-label\">{{ opt.label }}</span>\n @if (opt.supportingText) {\n <span class=\"option-support\">{{ opt.supportingText }}</span>\n }\n </span>\n </span>\n </li>\n }\n </ul>\n }\n</ng-template>\n", styles: [":host{display:block}.cmp-dropdown{display:flex;flex-direction:column;gap:var(--spacing-padding-sys-padding-8)}.cmp-dropdown.label-left{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:\"label field\" \". support\";align-items:center;column-gap:var(--spacing-padding-sys-padding-12);row-gap:var(--spacing-padding-sys-padding-4)}.cmp-dropdown.label-left .label-row{grid-area:label}.cmp-dropdown.label-left .trigger{grid-area:field}.cmp-dropdown.label-left .supporting-text{grid-area:support}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.label-row{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-padding-sys-padding-8)}.label{font-family:var(--label-medium-sys-font-family);font-size:var(--label-medium-sys-font-size);font-weight:var(--label-medium-sys-font-weight-emphasized);line-height:var(--label-medium-sys-line-height);letter-spacing:var(--label-medium-sys-tracking);color:var(--surface-surface-sys-on-surface)}.cmp-dropdown.lg .label{font-family:var(--label-large-sys-font-family);font-size:var(--label-large-sys-font-size);font-weight:var(--label-large-sys-font-weight-emphasized);line-height:var(--label-large-sys-line-height);letter-spacing:var(--label-large-sys-tracking)}.required-marker{color:var(--custom-info-sys-info)}.cmp-dropdown.disabled .label{opacity:.64}.trigger{box-sizing:border-box;width:100%;display:flex;align-items:center;gap:var(--spacing-padding-sys-padding-8);margin:0;border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-sm);background-color:var(--surface-surface-container-sys-surface-container-lowest);color:var(--surface-surface-sys-on-surface);font-family:var(--body-medium-sys-font-family);font-weight:var(--body-medium-sys-font-weight);text-align:start;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease}.trigger-icon{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant)}.trigger-text{flex:1 0 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trigger.placeholder .trigger-text{color:var(--surface-surface-sys-on-surface-variant)}.trigger-chevron{display:flex;align-items:center;flex-shrink:0;color:var(--surface-surface-sys-on-surface-variant);transition:color .15s ease,transform .16s ease}.trigger:focus-visible .trigger-chevron,.trigger.open .trigger-chevron{color:var(--accent-primary-sys-primary)}.trigger.open .trigger-chevron{transform:rotate(180deg)}.trigger.error:not(:disabled) .trigger-chevron{color:var(--error-sys-error)}@media(prefers-reduced-motion:reduce){.trigger-chevron{transition:color .15s ease}}.trigger:hover:not(:disabled):not(.open){box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014}.trigger:focus-visible,.trigger.open{border-color:var(--accent-primary-sys-primary);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger.error:not(:disabled):not(.open){border-color:var(--error-sys-error)}.trigger.error:focus-visible,.trigger.error.open{border-color:var(--error-sys-error);border-width:var(--border-width-sys-stroke-medium);box-shadow:0 0 0 4px var(--transparent-primary-sys-primary-08)}.trigger:disabled{background-color:var(--surface-surface-container-sys-surface-container-low);color:var(--surface-surface-sys-on-surface-variant);border-color:var(--outline-sys-outline-variant);cursor:not-allowed}.trigger:disabled .trigger-text,.trigger:disabled .trigger-icon,.trigger:disabled .trigger-chevron{opacity:.64}.supporting-text{font-family:var(--body-small-sys-font-family);font-size:var(--body-small-sys-font-size);font-weight:var(--body-small-sys-font-weight);line-height:var(--body-small-sys-line-height);color:var(--surface-surface-sys-on-surface-variant)}.supporting-text--error{color:var(--error-sys-error)}.cmp-dropdown.disabled .supporting-text{opacity:.64}.cmp-dropdown.sm .trigger{height:40px;gap:var(--spacing-padding-sys-padding-4);padding:var(--spacing-padding-sys-padding-8) var(--spacing-padding-sys-padding-12);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.cmp-dropdown.md .trigger{height:48px;padding:var(--spacing-padding-sys-padding-12) var(--spacing-padding-sys-padding-16);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.cmp-dropdown.lg .trigger{height:56px;padding:var(--spacing-padding-sys-padding-16) var(--spacing-padding-sys-padding-20);border-radius:var(--border-radius-sys-radius-md);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height)}.panel{box-sizing:border-box;list-style:none;margin:0;padding:var(--spacing-padding-sys-padding-4) 0;max-height:340px;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-surface-container-sys-surface-container-lowest);border:var(--border-width-sys-stroke-thin) solid var(--outline-sys-outline-variant);border-radius:var(--border-radius-sys-radius-md);box-shadow:0 4px 16px var(--transparent-neutral-sys-black-10),0 2px 4px #00000014;outline:none;font-family:var(--body-medium-sys-font-family)}.option{box-sizing:border-box;display:block;padding:var(--spacing-padding-sys-padding-4) var(--spacing-padding-sys-padding-8);cursor:pointer;outline:none;-webkit-user-select:none;user-select:none}.option-inner{display:flex;align-items:flex-start;gap:var(--spacing-padding-sys-padding-12);padding:var(--spacing-padding-sys-padding-8);border-radius:var(--border-radius-sys-radius-sm);color:var(--surface-surface-sys-on-surface);font-size:var(--body-medium-sys-font-size);line-height:var(--body-medium-sys-line-height);transition:background-color .12s ease-out}.panel.sm .option-inner{font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;color:var(--surface-surface-sys-on-surface);margin-top:var(--spacing-padding-sys-padding-2)}.option-text{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--spacing-padding-sys-padding-8);row-gap:var(--spacing-padding-sys-padding-2)}.option-label{min-width:0}.option-support{color:var(--surface-surface-sys-on-surface-variant);font-size:var(--body-small-sys-font-size);line-height:var(--body-small-sys-line-height)}.option.error .option-icon,.option.error .option-label{color:var(--error-sys-error)}.option:hover:not([aria-disabled=true]) .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent)}.option:focus-visible{outline:none}.option:focus-visible .option-inner{background-color:color-mix(in srgb,var(--surface-surface-sys-on-surface-variant) 8%,transparent);outline:var(--border-width-sys-stroke-medium) solid var(--accent-primary-sys-primary);outline-offset:-2px}.option[aria-disabled=true]{cursor:not-allowed}.option[aria-disabled=true] .option-inner{color:var(--surface-surface-sys-on-surface-variant);opacity:.64}@media(forced-colors:active){.trigger{border:1px solid ButtonText;forced-color-adjust:none}.trigger:focus-visible,.trigger.open{outline:2px solid Highlight;outline-offset:2px}.trigger:disabled{color:GrayText;border-color:GrayText;background:ButtonFace;opacity:1}.cmp-dropdown.disabled .label{color:GrayText;opacity:1}.supporting-text--error{color:LinkText}.panel{border:1px solid ButtonText}.option:focus-visible .option-inner{outline:2px solid Highlight;outline-offset:-2px}}\n"] }]
|
|
479
307
|
}], ctorParameters: () => [], propDecorators: { triggerBtn: [{
|
|
480
308
|
type: ViewChild,
|
|
481
309
|
args: ['triggerBtn']
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/dropdown/dropdown.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n Input,\r\n OnChanges,\r\n Output,\r\n ViewChild,\r\n booleanAttribute,\r\n inject,\r\n} from '@angular/core';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { ControlValueAccessor, NgControl, Validators } from '@angular/forms';\r\nimport { CdkListbox, CdkOption, ListboxValueChangeEvent } from '@angular/cdk/listbox';\r\nimport { CdkConnectedOverlay, CdkOverlayOrigin, ConnectedPosition } from '@angular/cdk/overlay';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\nimport { DropdownLabelPosition, DropdownOption, DropdownSize } from './dropdown-types';\r\n\r\nlet nextId = 0;\r\n\r\n/**\r\n * A labelled single-select dropdown built on the CDK Listbox (`@angular/cdk/listbox`)\r\n * and CDK Overlay. The trigger renders the closed field (label, placeholder/selected\r\n * value and chevron); the options open in an overlay panel with full keyboard support\r\n * (arrow keys, Home/End, typeahead) provided by the CDK listbox.\r\n *\r\n * Implements `ControlValueAccessor` so it works with both reactive forms\r\n * (`formControlName`, `[formControl]`) and template-driven forms (`ngModel`). The error\r\n * visual state is driven automatically by the bound `FormControl`'s validity once the\r\n * field has been touched, and can also be set explicitly via the `error` input.\r\n */\r\n@Component({\r\n selector: 'compsych-dropdown',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [CdkListbox, CdkOption, CdkConnectedOverlay, CdkOverlayOrigin],\r\n template: `\r\n <div [class]=\"wrapperClasses\">\r\n <div class=\"label-row\" [class.sr-only]=\"hideLabel || inlineLabel\">\r\n <label class=\"label\" [id]=\"labelId\" [for]=\"triggerId\">\r\n {{ label }}\r\n @if (isRequired) {\r\n <span class=\"required-marker\" aria-hidden=\"true\"> *</span>\r\n }\r\n </label>\r\n </div>\r\n\r\n <button\r\n #triggerBtn\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n type=\"button\"\r\n class=\"trigger\"\r\n [id]=\"triggerId\"\r\n [class.placeholder]=\"!selectedOption && !inlineLabel\"\r\n [class.error]=\"hasError\"\r\n [class.open]=\"isOpen\"\r\n [disabled]=\"disabled\"\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"isOpen\"\r\n [attr.aria-controls]=\"listboxId\"\r\n [attr.aria-labelledby]=\"labelId + ' ' + triggerId\"\r\n [attr.aria-invalid]=\"hasError ? 'true' : null\"\r\n [attr.aria-required]=\"isRequired ? 'true' : null\"\r\n [attr.aria-describedby]=\"describedBy\"\r\n (click)=\"toggle()\"\r\n (keydown)=\"onTriggerKeydown($event)\"\r\n >\r\n @if (triggerIconSvg) {\r\n <span class=\"trigger-icon\" aria-hidden=\"true\" [innerHTML]=\"triggerIconSvg\"></span>\r\n }\r\n <span class=\"trigger-text\">{{ triggerText }}</span>\r\n <span class=\"trigger-chevron\" aria-hidden=\"true\" [innerHTML]=\"chevronSvg\"></span>\r\n </button>\r\n\r\n @if (displayedSupportingText) {\r\n <span class=\"supporting-text\" [class.supporting-text--error]=\"hasError\" [id]=\"triggerId + '-supporting'\">\r\n {{ displayedSupportingText }}\r\n </span>\r\n }\r\n </div>\r\n\r\n <ng-template\r\n cdkConnectedOverlay\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen\"\r\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\r\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\r\n [cdkConnectedOverlayViewportMargin]=\"8\"\r\n (overlayOutsideClick)=\"close()\"\r\n (attach)=\"onPanelAttach()\"\r\n (detach)=\"close()\"\r\n >\r\n <ul\r\n #listboxEl\r\n cdkListbox\r\n class=\"panel\"\r\n [class.sm]=\"size === 'sm'\"\r\n [style.width.px]=\"overlayWidth\"\r\n [id]=\"listboxId\"\r\n [attr.aria-labelledby]=\"labelId\"\r\n [cdkListboxValue]=\"listboxValue\"\r\n (cdkListboxValueChange)=\"onListboxValueChange($event)\"\r\n (keydown)=\"onListboxKeydown($event)\"\r\n >\r\n @for (opt of options; track opt.value) {\r\n <li class=\"option\" [class.error]=\"opt.error\" [cdkOption]=\"opt.value\" [cdkOptionDisabled]=\"!!opt.disabled\">\r\n <span class=\"option-inner\">\r\n @if (opt.iconSvg || opt.icon || optionsLeadingIcon) {\r\n <span class=\"option-icon\" aria-hidden=\"true\" [innerHTML]=\"optionIcon(opt)\"></span>\r\n }\r\n <span class=\"option-text\">\r\n <span class=\"option-label\">{{ opt.label }}</span>\r\n @if (opt.supportingText) {\r\n <span class=\"option-support\">{{ opt.supportingText }}</span>\r\n }\r\n </span>\r\n </span>\r\n </li>\r\n }\r\n </ul>\r\n </ng-template>\r\n `,\r\n styleUrl: './dropdown.css',\r\n})\r\nexport class DropdownComponent implements ControlValueAccessor, OnChanges {\r\n private readonly _autoId = `cmp-dropdown-${++nextId}`;\r\n private readonly cdr = inject(ChangeDetectorRef);\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private _onChange: (value: string) => void = () => {};\r\n private _onTouched: () => void = () => {};\r\n\r\n /** Injected when the component is used inside a reactive or template-driven form. */\r\n protected readonly ngControl: NgControl | null;\r\n\r\n constructor() {\r\n const ctrl = inject(NgControl, { optional: true, self: true });\r\n if (ctrl) ctrl.valueAccessor = this;\r\n this.ngControl = ctrl;\r\n this.chevronSvg = this.buildIconSvg('chevron-down');\r\n }\r\n\r\n @ViewChild('triggerBtn') private triggerBtn?: ElementRef<HTMLButtonElement>;\r\n @ViewChild('listboxEl') private listboxEl?: ElementRef<HTMLUListElement>;\r\n\r\n /** Label displayed above the trigger. */\r\n @Input() label = '';\r\n /** Text shown in the trigger when no option is selected. */\r\n @Input() placeholder = '';\r\n /** Currently selected value. When used in a form, the form controls the value. */\r\n @Input() value = '';\r\n /** Selectable options rendered in the overlay panel. */\r\n @Input() options: DropdownOption[] = [];\r\n /** Size variant — controls height, padding, and font size. Defaults to `'md'`. */\r\n @Input() size: DropdownSize = 'md';\r\n /** Native `id` attribute for the trigger. Auto-generated if omitted. */\r\n @Input() id?: string;\r\n /**\r\n * Id(s) of external elements that describe the field, space-separated.\r\n * Forwarded to `aria-describedby` on the trigger.\r\n */\r\n @Input() ariaDescribedBy?: string;\r\n /** Text displayed below the trigger. Shown in red when in error state. */\r\n @Input() supportingText = '';\r\n /**\r\n * Static error text shown in red when in error state. Used when the dropdown is\r\n * outside a form (with `[error]=\"true\"`). When inside a form, prefer `errorMessages`.\r\n */\r\n @Input() errorMessage = '';\r\n /**\r\n * Map of Angular validator error keys to display strings. The component reads\r\n * `ngControl.errors` to determine which validator failed and shows the matching\r\n * message in red below the trigger. Example: `{ required: 'Please choose an option' }`\r\n */\r\n @Input() errorMessages: Record<string, string> = {};\r\n /**\r\n * Adds a blue asterisk after the label. When used in a form, this is set\r\n * automatically if the bound `FormControl` has `Validators.required`.\r\n * Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) required = false;\r\n /**\r\n * Applies the error visual state (red border) explicitly. When used in a form,\r\n * the error state is driven automatically from the `FormControl`'s validity once\r\n * the field is touched — this input is only needed outside of forms. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) error = false;\r\n /** Disables the dropdown. When used in a form, also responds to `FormControl.disable()`. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) disabled = false;\r\n /** Visually hides the label while keeping it accessible to screen readers. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) hideLabel = false;\r\n /** Places the label above the trigger (`'top'`, default) or beside it (`'left'`). */\r\n @Input() labelPosition: DropdownLabelPosition = 'top';\r\n /**\r\n * Renders the label as the trigger's own resting text instead of a separate\r\n * label above/beside it — e.g. the trigger reads \"I want to\" until an option\r\n * is chosen. No visible external label is shown, but the `label` is still\r\n * exposed to assistive tech (a screen-reader-only `<label>` + `aria-labelledby`),\r\n * so the field is announced as a properly labelled combobox. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) inlineLabel = false;\r\n /** Lucide icon name rendered inside the trigger, before the displayed value/placeholder (e.g. `'globe'`). */\r\n @Input() leadingIcon?: string;\r\n /** Default Lucide icon shown before every option's label; each option's own `icon` (from the Icon Mapping) overrides it. */\r\n @Input() optionsLeadingIcon?: string;\r\n\r\n /** Emits the newly selected value whenever the user picks an option. */\r\n @Output() readonly valueChange = new EventEmitter<string>();\r\n /** Emitted when the overlay panel opens. */\r\n @Output() readonly opened = new EventEmitter<void>();\r\n /** Emitted when the overlay panel closes. */\r\n @Output() readonly closed = new EventEmitter<void>();\r\n\r\n protected readonly chevronSvg: SafeHtml;\r\n protected leadingIconSvg: SafeHtml | null = null;\r\n private readonly optionIconCache = new Map<string, SafeHtml>();\r\n\r\n protected isOpen = false;\r\n protected overlayWidth = 0;\r\n protected readonly overlayPositions: ConnectedPosition[] = [\r\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },\r\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },\r\n ];\r\n\r\n ngOnChanges(): void {\r\n this.leadingIconSvg = this.leadingIcon ? this.buildIconSvg(this.leadingIcon) : null;\r\n }\r\n\r\n private buildIconSvg(name: string): SafeHtml {\r\n const svg = (LUCIDE_ICONS[name] ?? '').replace('<svg ', '<svg width=\"20\" height=\"20\" ');\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n\r\n /**\r\n * Scales trusted raw SVG (e.g. a flag) to 20px wide, preserving aspect ratio via its\r\n * viewBox. Only the root `<svg>` tag's width/height are normalized — inner elements\r\n * (rects/paths that draw the icon) keep their own dimensions.\r\n */\r\n private buildRawIconSvg(svg: string): SafeHtml {\r\n const sized = svg.replace(/<svg\\b[^>]*>/, (openTag) =>\r\n openTag.replace(/\\s(?:width|height)=\"[^\"]*\"/g, '').replace('<svg', '<svg width=\"20\"')\r\n );\r\n return this.sanitizer.bypassSecurityTrustHtml(sized);\r\n }\r\n\r\n /**\r\n * Resolves an icon to cached SafeHtml: a trusted raw `iconSvg` wins, else a Lucide\r\n * `iconName`. Returns null when neither is set. Cached so rows keep a stable reference.\r\n */\r\n private resolveIcon(iconSvg: string | undefined, iconName: string | undefined): SafeHtml | null {\r\n if (iconSvg) {\r\n const key = 'raw:' + iconSvg;\r\n let svg = this.optionIconCache.get(key);\r\n if (!svg) {\r\n svg = this.buildRawIconSvg(iconSvg);\r\n this.optionIconCache.set(key, svg);\r\n }\r\n return svg;\r\n }\r\n if (iconName) {\r\n let svg = this.optionIconCache.get(iconName);\r\n if (!svg) {\r\n svg = this.buildIconSvg(iconName);\r\n this.optionIconCache.set(iconName, svg);\r\n }\r\n return svg;\r\n }\r\n return null;\r\n }\r\n\r\n /** Icon for an option row: its own `iconSvg`/`icon`, else the shared `optionsLeadingIcon`. */\r\n protected optionIcon(option: DropdownOption): SafeHtml | null {\r\n return this.resolveIcon(option.iconSvg, option.icon ?? this.optionsLeadingIcon);\r\n }\r\n\r\n /** Icon in the trigger: the selected option's own icon (flag/glyph), else the fixed `leadingIcon`. */\r\n get triggerIconSvg(): SafeHtml | null {\r\n return this.resolveIcon(this.selectedOption?.iconSvg, this.selectedOption?.icon) ?? this.leadingIconSvg;\r\n }\r\n\r\n get triggerId(): string {\r\n return this.id ?? this._autoId;\r\n }\r\n\r\n get labelId(): string {\r\n return this.triggerId + '-label';\r\n }\r\n\r\n get listboxId(): string {\r\n return this.triggerId + '-listbox';\r\n }\r\n\r\n get selectedOption(): DropdownOption | undefined {\r\n return this.options.find((o) => o.value === this.value);\r\n }\r\n\r\n /**\r\n * Resting text shown in the trigger: the selected option's label, else the\r\n * `label` in inline-label mode (so the label reads as the field's own text),\r\n * else the placeholder.\r\n */\r\n get triggerText(): string {\r\n return this.selectedOption?.label || (this.inlineLabel ? this.label : this.placeholder);\r\n }\r\n\r\n /** Value array bound to the CDK listbox (single-select, so 0 or 1 entry). */\r\n get listboxValue(): readonly string[] {\r\n return this.value ? [this.value] : [];\r\n }\r\n\r\n /** True when the bound FormControl is invalid and touched, or when `error` is explicitly set. */\r\n get hasError(): boolean {\r\n return this.error || !!(this.ngControl?.invalid && this.ngControl.touched);\r\n }\r\n\r\n /** True when `required` is set explicitly, or when the bound FormControl has Validators.required. */\r\n get isRequired(): boolean {\r\n return this.required || !!this.ngControl?.control?.hasValidator(Validators.required);\r\n }\r\n\r\n private get activeErrorMessage(): string {\r\n const errors = this.ngControl?.errors;\r\n if (!errors) return '';\r\n for (const key of Object.keys(errors)) {\r\n if (this.errorMessages[key]) return this.errorMessages[key];\r\n }\r\n return '';\r\n }\r\n\r\n get displayedSupportingText(): string {\r\n if (this.hasError) {\r\n return this.activeErrorMessage || this.errorMessage || this.supportingText;\r\n }\r\n return this.supportingText;\r\n }\r\n\r\n get describedBy(): string | null {\r\n const parts: string[] = [];\r\n if (this.ariaDescribedBy) parts.push(this.ariaDescribedBy);\r\n if (this.supportingText || this.errorMessage || Object.keys(this.errorMessages).length) {\r\n parts.push(this.triggerId + '-supporting');\r\n }\r\n return parts.length ? parts.join(' ') : null;\r\n }\r\n\r\n get wrapperClasses(): string {\r\n return ['cmp-dropdown', this.size, this.disabled ? 'disabled' : '', this.labelPosition === 'left' ? 'label-left' : '']\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n // ── Open / close ──────────────────────────────────────────────────────────\r\n\r\n protected toggle(): void {\r\n if (this.isOpen) {\r\n this.close(true);\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n protected open(): void {\r\n if (this.disabled || this.isOpen) return;\r\n this.overlayWidth = this.triggerBtn?.nativeElement.offsetWidth ?? 0;\r\n this.isOpen = true;\r\n this.opened.emit();\r\n this.cdr.markForCheck();\r\n }\r\n\r\n protected close(refocus = false): void {\r\n if (!this.isOpen) return;\r\n this.isOpen = false;\r\n this._onTouched();\r\n this.closed.emit();\r\n if (refocus) {\r\n setTimeout(() => this.triggerBtn?.nativeElement.focus());\r\n }\r\n this.cdr.markForCheck();\r\n }\r\n\r\n protected onPanelAttach(): void {\r\n setTimeout(() => this.listboxEl?.nativeElement.focus());\r\n }\r\n\r\n // ── Keyboard ──────────────────────────────────────────────────────────────\r\n\r\n protected onTriggerKeydown(event: KeyboardEvent): void {\r\n if (this.disabled) return;\r\n if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && !this.isOpen) {\r\n event.preventDefault();\r\n this.open();\r\n } else if (event.key === 'Escape' && this.isOpen) {\r\n event.preventDefault();\r\n this.close(true);\r\n }\r\n }\r\n\r\n protected onListboxKeydown(event: KeyboardEvent): void {\r\n if (event.key === 'Escape') {\r\n event.preventDefault();\r\n this.close(true);\r\n } else if (event.key === 'Tab') {\r\n event.preventDefault();\r\n this.close(true);\r\n }\r\n }\r\n\r\n protected onListboxValueChange(event: ListboxValueChangeEvent<string>): void {\r\n const next = event.value[0] ?? '';\r\n this.value = next;\r\n this._onChange(next);\r\n this.valueChange.emit(next);\r\n this.close(true);\r\n }\r\n\r\n // ── ControlValueAccessor ────────────────────────────────────────────────────\r\n\r\n writeValue(value: string | null): void {\r\n this.value = value ?? '';\r\n this.cdr.markForCheck();\r\n }\r\n\r\n registerOnChange(fn: (value: string) => void): void {\r\n this._onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: () => void): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n /** Called by Angular when the bound FormControl is programmatically disabled or enabled. */\r\n setDisabledState(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n this.cdr.markForCheck();\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"dropdown.js","sourceRoot":"","sources":["../../../../../../packages/angular/src/lib/dropdown/dropdown.ts","../../../../../../packages/angular/src/lib/dropdown/dropdown.html"],"names":[],"mappings":"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","sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n Input,\r\n OnChanges,\r\n Output,\r\n ViewChild,\r\n booleanAttribute,\r\n inject,\r\n} from '@angular/core';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { ControlValueAccessor, NgControl, Validators } from '@angular/forms';\r\nimport { CdkListbox, CdkOption, ListboxValueChangeEvent } from '@angular/cdk/listbox';\r\nimport { CdkConnectedOverlay, CdkOverlayOrigin, ConnectedPosition } from '@angular/cdk/overlay';\r\nimport { LUCIDE_ICONS } from '@compsych-ui-components/shared/assets/lucide-icons.generated';\r\nimport { DropdownLabelPosition, DropdownOption, DropdownSize } from './dropdown-types';\r\n\r\nlet nextId = 0;\r\n\r\n/**\r\n * A labelled single-select dropdown built on the CDK Listbox (`@angular/cdk/listbox`)\r\n * and CDK Overlay. The trigger renders the closed field (label, placeholder/selected\r\n * value and chevron); the options open in an overlay panel with full keyboard support\r\n * (arrow keys, Home/End, typeahead) provided by the CDK listbox.\r\n *\r\n * Implements `ControlValueAccessor` so it works with both reactive forms\r\n * (`formControlName`, `[formControl]`) and template-driven forms (`ngModel`). The error\r\n * visual state is driven automatically by the bound `FormControl`'s validity once the\r\n * field has been touched, and can also be set explicitly via the `error` input.\r\n */\r\n@Component({\r\n selector: 'compsych-dropdown',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [CdkListbox, CdkOption, CdkConnectedOverlay, CdkOverlayOrigin],\r\n templateUrl: './dropdown.html',\r\n styleUrl: './dropdown.css',\r\n})\r\nexport class DropdownComponent implements ControlValueAccessor, OnChanges {\r\n private readonly _autoId = `cmp-dropdown-${++nextId}`;\r\n private readonly cdr = inject(ChangeDetectorRef);\r\n private readonly sanitizer = inject(DomSanitizer);\r\n private _onChange: (value: string) => void = () => {};\r\n private _onTouched: () => void = () => {};\r\n\r\n /** Injected when the component is used inside a reactive or template-driven form. */\r\n protected readonly ngControl: NgControl | null;\r\n\r\n constructor() {\r\n const ctrl = inject(NgControl, { optional: true, self: true });\r\n if (ctrl) ctrl.valueAccessor = this;\r\n this.ngControl = ctrl;\r\n this.chevronSvg = this.buildIconSvg('chevron-down');\r\n }\r\n\r\n @ViewChild('triggerBtn') private triggerBtn?: ElementRef<HTMLButtonElement>;\r\n @ViewChild('listboxEl') private listboxEl?: ElementRef<HTMLUListElement>;\r\n\r\n /** Label displayed above the trigger. */\r\n @Input() label = '';\r\n /** Text shown in the trigger when no option is selected. */\r\n @Input() placeholder = '';\r\n /** Currently selected value. When used in a form, the form controls the value. */\r\n @Input() value = '';\r\n /** Selectable options rendered in the overlay panel. */\r\n @Input() options: DropdownOption[] = [];\r\n /** Size variant — controls height, padding, and font size. Defaults to `'md'`. */\r\n @Input() size: DropdownSize = 'md';\r\n /** Native `id` attribute for the trigger. Auto-generated if omitted. */\r\n @Input() id?: string;\r\n /**\r\n * Id(s) of external elements that describe the field, space-separated.\r\n * Forwarded to `aria-describedby` on the trigger.\r\n */\r\n @Input() ariaDescribedBy?: string;\r\n /** Text displayed below the trigger. Shown in red when in error state. */\r\n @Input() supportingText = '';\r\n /**\r\n * Static error text shown in red when in error state. Used when the dropdown is\r\n * outside a form (with `[error]=\"true\"`). When inside a form, prefer `errorMessages`.\r\n */\r\n @Input() errorMessage = '';\r\n /**\r\n * Map of Angular validator error keys to display strings. The component reads\r\n * `ngControl.errors` to determine which validator failed and shows the matching\r\n * message in red below the trigger. Example: `{ required: 'Please choose an option' }`\r\n */\r\n @Input() errorMessages: Record<string, string> = {};\r\n /**\r\n * Adds a blue asterisk after the label. When used in a form, this is set\r\n * automatically if the bound `FormControl` has `Validators.required`.\r\n * Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) required = false;\r\n /**\r\n * Applies the error visual state (red border) explicitly. When used in a form,\r\n * the error state is driven automatically from the `FormControl`'s validity once\r\n * the field is touched — this input is only needed outside of forms. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) error = false;\r\n /** Disables the dropdown. When used in a form, also responds to `FormControl.disable()`. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) disabled = false;\r\n /** Visually hides the label while keeping it accessible to screen readers. Supports boolean coercion. */\r\n @Input({ transform: booleanAttribute }) hideLabel = false;\r\n /** Places the label above the trigger (`'top'`, default) or beside it (`'left'`). */\r\n @Input() labelPosition: DropdownLabelPosition = 'top';\r\n /**\r\n * Renders the label as the trigger's own resting text instead of a separate\r\n * label above/beside it — e.g. the trigger reads \"I want to\" until an option\r\n * is chosen. No visible external label is shown, but the `label` is still\r\n * exposed to assistive tech (a screen-reader-only `<label>` + `aria-labelledby`),\r\n * so the field is announced as a properly labelled combobox. Supports boolean coercion.\r\n */\r\n @Input({ transform: booleanAttribute }) inlineLabel = false;\r\n /** Lucide icon name rendered inside the trigger, before the displayed value/placeholder (e.g. `'globe'`). */\r\n @Input() leadingIcon?: string;\r\n /** Default Lucide icon shown before every option's label; each option's own `icon` (from the Icon Mapping) overrides it. */\r\n @Input() optionsLeadingIcon?: string;\r\n\r\n /** Emits the newly selected value whenever the user picks an option. */\r\n @Output() readonly valueChange = new EventEmitter<string>();\r\n /** Emitted when the overlay panel opens. */\r\n @Output() readonly opened = new EventEmitter<void>();\r\n /** Emitted when the overlay panel closes. */\r\n @Output() readonly closed = new EventEmitter<void>();\r\n\r\n protected readonly chevronSvg: SafeHtml;\r\n protected leadingIconSvg: SafeHtml | null = null;\r\n private readonly optionIconCache = new Map<string, SafeHtml>();\r\n\r\n protected isOpen = false;\r\n protected overlayWidth = 0;\r\n protected readonly overlayPositions: ConnectedPosition[] = [\r\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },\r\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },\r\n ];\r\n\r\n ngOnChanges(): void {\r\n this.leadingIconSvg = this.leadingIcon ? this.buildIconSvg(this.leadingIcon) : null;\r\n }\r\n\r\n private buildIconSvg(name: string): SafeHtml {\r\n const svg = (LUCIDE_ICONS[name] ?? '').replace('<svg ', '<svg width=\"20\" height=\"20\" ');\r\n return this.sanitizer.bypassSecurityTrustHtml(svg);\r\n }\r\n\r\n /**\r\n * Scales trusted raw SVG (e.g. a flag) to 20px wide, preserving aspect ratio via its\r\n * viewBox. Only the root `<svg>` tag's width/height are normalized — inner elements\r\n * (rects/paths that draw the icon) keep their own dimensions.\r\n */\r\n private buildRawIconSvg(svg: string): SafeHtml {\r\n const sized = svg.replace(/<svg\\b[^>]*>/, (openTag) =>\r\n openTag.replace(/\\s(?:width|height)=\"[^\"]*\"/g, '').replace('<svg', '<svg width=\"20\"')\r\n );\r\n return this.sanitizer.bypassSecurityTrustHtml(sized);\r\n }\r\n\r\n /**\r\n * Resolves an icon to cached SafeHtml: a trusted raw `iconSvg` wins, else a Lucide\r\n * `iconName`. Returns null when neither is set. Cached so rows keep a stable reference.\r\n */\r\n private resolveIcon(iconSvg: string | undefined, iconName: string | undefined): SafeHtml | null {\r\n if (iconSvg) {\r\n const key = 'raw:' + iconSvg;\r\n let svg = this.optionIconCache.get(key);\r\n if (!svg) {\r\n svg = this.buildRawIconSvg(iconSvg);\r\n this.optionIconCache.set(key, svg);\r\n }\r\n return svg;\r\n }\r\n if (iconName) {\r\n let svg = this.optionIconCache.get(iconName);\r\n if (!svg) {\r\n svg = this.buildIconSvg(iconName);\r\n this.optionIconCache.set(iconName, svg);\r\n }\r\n return svg;\r\n }\r\n return null;\r\n }\r\n\r\n /** Icon for an option row: its own `iconSvg`/`icon`, else the shared `optionsLeadingIcon`. */\r\n protected optionIcon(option: DropdownOption): SafeHtml | null {\r\n return this.resolveIcon(option.iconSvg, option.icon ?? this.optionsLeadingIcon);\r\n }\r\n\r\n /** Icon in the trigger: the selected option's own icon (flag/glyph), else the fixed `leadingIcon`. */\r\n get triggerIconSvg(): SafeHtml | null {\r\n return this.resolveIcon(this.selectedOption?.iconSvg, this.selectedOption?.icon) ?? this.leadingIconSvg;\r\n }\r\n\r\n get triggerId(): string {\r\n return this.id ?? this._autoId;\r\n }\r\n\r\n get labelId(): string {\r\n return this.triggerId + '-label';\r\n }\r\n\r\n get listboxId(): string {\r\n return this.triggerId + '-listbox';\r\n }\r\n\r\n get selectedOption(): DropdownOption | undefined {\r\n return this.options.find((o) => o.value === this.value);\r\n }\r\n\r\n /**\r\n * Resting text shown in the trigger: the selected option's label, else the\r\n * `label` in inline-label mode (so the label reads as the field's own text),\r\n * else the placeholder.\r\n */\r\n get triggerText(): string {\r\n return this.selectedOption?.label || (this.inlineLabel ? this.label : this.placeholder);\r\n }\r\n\r\n /** Value array bound to the CDK listbox (single-select, so 0 or 1 entry). */\r\n get listboxValue(): readonly string[] {\r\n if (!this.value || !this.options.some((o) => o.value === this.value)) return [];\r\n return [this.value];\r\n }\r\n\r\n /** True when the bound FormControl is invalid and touched, or when `error` is explicitly set. */\r\n get hasError(): boolean {\r\n return this.error || !!(this.ngControl?.invalid && this.ngControl.touched);\r\n }\r\n\r\n /** True when `required` is set explicitly, or when the bound FormControl has Validators.required. */\r\n get isRequired(): boolean {\r\n return this.required || !!this.ngControl?.control?.hasValidator(Validators.required);\r\n }\r\n\r\n private get activeErrorMessage(): string {\r\n const errors = this.ngControl?.errors;\r\n if (!errors) return '';\r\n for (const key of Object.keys(errors)) {\r\n if (this.errorMessages[key]) return this.errorMessages[key];\r\n }\r\n return '';\r\n }\r\n\r\n get displayedSupportingText(): string {\r\n if (this.hasError) {\r\n return this.activeErrorMessage || this.errorMessage || this.supportingText;\r\n }\r\n return this.supportingText;\r\n }\r\n\r\n get describedBy(): string | null {\r\n const parts: string[] = [];\r\n if (this.ariaDescribedBy) parts.push(this.ariaDescribedBy);\r\n if (this.supportingText || this.errorMessage || Object.keys(this.errorMessages).length) {\r\n parts.push(this.triggerId + '-supporting');\r\n }\r\n return parts.length ? parts.join(' ') : null;\r\n }\r\n\r\n get wrapperClasses(): string {\r\n return ['cmp-dropdown', this.size, this.disabled ? 'disabled' : '', this.labelPosition === 'left' ? 'label-left' : '']\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n // ── Open / close ──────────────────────────────────────────────────────────\r\n\r\n protected toggle(): void {\r\n if (this.isOpen) {\r\n this.close(true);\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n protected open(): void {\r\n if (this.disabled || this.isOpen) return;\r\n this.overlayWidth = this.triggerBtn?.nativeElement.offsetWidth ?? 0;\r\n this.isOpen = true;\r\n this.opened.emit();\r\n this.cdr.markForCheck();\r\n }\r\n\r\n protected close(refocus = false): void {\r\n if (!this.isOpen) return;\r\n this.isOpen = false;\r\n this._onTouched();\r\n this.closed.emit();\r\n if (refocus) {\r\n setTimeout(() => this.triggerBtn?.nativeElement.focus());\r\n }\r\n this.cdr.markForCheck();\r\n }\r\n\r\n protected onPanelAttach(): void {\r\n setTimeout(() => this.listboxEl?.nativeElement.focus());\r\n }\r\n\r\n // ── Keyboard ──────────────────────────────────────────────────────────────\r\n\r\n protected onTriggerKeydown(event: KeyboardEvent): void {\r\n if (this.disabled) return;\r\n if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && !this.isOpen) {\r\n event.preventDefault();\r\n this.open();\r\n } else if (event.key === 'Escape' && this.isOpen) {\r\n event.preventDefault();\r\n this.close(true);\r\n }\r\n }\r\n\r\n protected onListboxKeydown(event: KeyboardEvent): void {\r\n if (event.key === 'Escape') {\r\n event.preventDefault();\r\n this.close(true);\r\n } else if (event.key === 'Tab') {\r\n event.preventDefault();\r\n this.close(true);\r\n }\r\n }\r\n\r\n protected onListboxValueChange(event: ListboxValueChangeEvent<string>): void {\r\n const next = event.value[0] ?? '';\r\n this.value = next;\r\n this._onChange(next);\r\n this.valueChange.emit(next);\r\n this.close(true);\r\n }\r\n\r\n // ── ControlValueAccessor ────────────────────────────────────────────────────\r\n\r\n writeValue(value: string | null): void {\r\n this.value = value ?? '';\r\n this.cdr.markForCheck();\r\n }\r\n\r\n registerOnChange(fn: (value: string) => void): void {\r\n this._onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: () => void): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n /** Called by Angular when the bound FormControl is programmatically disabled or enabled. */\r\n setDisabledState(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n this.cdr.markForCheck();\r\n }\r\n\r\n}\r\n","<div [class]=\"wrapperClasses\">\n <div class=\"label-row\" [class.sr-only]=\"hideLabel || inlineLabel\">\n <label class=\"label\" [id]=\"labelId\" [for]=\"triggerId\">\n {{ label }}\n @if (isRequired) {\n <span class=\"required-marker\" aria-hidden=\"true\"> *</span>\n }\n </label>\n </div>\n\n <button\n #triggerBtn\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n type=\"button\"\n class=\"trigger\"\n [id]=\"triggerId\"\n [class.placeholder]=\"!selectedOption && !inlineLabel\"\n [class.error]=\"hasError\"\n [class.open]=\"isOpen\"\n [disabled]=\"disabled\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-labelledby]=\"labelId + ' ' + triggerId\"\n [attr.aria-invalid]=\"hasError ? 'true' : null\"\n [attr.aria-required]=\"isRequired ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy\"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n @if (triggerIconSvg) {\n <span class=\"trigger-icon\" aria-hidden=\"true\" [innerHTML]=\"triggerIconSvg\"></span>\n }\n <span class=\"trigger-text\">{{ triggerText }}</span>\n <span class=\"trigger-chevron\" aria-hidden=\"true\" [innerHTML]=\"chevronSvg\"></span>\n </button>\n\n @if (displayedSupportingText) {\n <span class=\"supporting-text\" [class.supporting-text--error]=\"hasError\" [id]=\"triggerId + '-supporting'\">\n {{ displayedSupportingText }}\n </span>\n }\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayViewportMargin]=\"8\"\n (overlayOutsideClick)=\"close()\"\n (attach)=\"onPanelAttach()\"\n (detach)=\"close()\"\n>\n @if (isOpen) {\n <ul\n #listboxEl\n cdkListbox\n class=\"panel\"\n [class.sm]=\"size === 'sm'\"\n [style.width.px]=\"overlayWidth\"\n [id]=\"listboxId\"\n [attr.aria-labelledby]=\"labelId\"\n [cdkListboxValue]=\"listboxValue\"\n (cdkListboxValueChange)=\"onListboxValueChange($event)\"\n (keydown)=\"onListboxKeydown($event)\"\n >\n @for (opt of options; track opt.value) {\n <li class=\"option\" [class.error]=\"opt.error\" [cdkOption]=\"opt.value\" [cdkOptionDisabled]=\"!!opt.disabled\">\n <span class=\"option-inner\">\n @if (opt.iconSvg || opt.icon || optionsLeadingIcon) {\n <span class=\"option-icon\" aria-hidden=\"true\" [innerHTML]=\"optionIcon(opt)\"></span>\n }\n <span class=\"option-text\">\n <span class=\"option-label\">{{ opt.label }}</span>\n @if (opt.supportingText) {\n <span class=\"option-support\">{{ opt.supportingText }}</span>\n }\n </span>\n </span>\n </li>\n }\n </ul>\n }\n</ng-template>\n"]}
|