@lifecorner/angular-ui-kit 3.36.0 → 3.38.0
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.
- package/fesm2022/lifecorner-angular-ui-kit-card.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-card.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-description-list.mjs +4 -4
- package/fesm2022/lifecorner-angular-ui-kit-description-list.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-hero.mjs +24 -3
- package/fesm2022/lifecorner-angular-ui-kit-hero.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-internal-chart.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-internal-chart.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs +10 -5
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-select.mjs +15 -10
- package/fesm2022/lifecorner-angular-ui-kit-select.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-state-strip.mjs +27 -4
- package/fesm2022/lifecorner-angular-ui-kit-state-strip.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs.map +1 -1
- package/package.json +1 -1
- package/src/styles/_theme-light.scss +8 -1
- package/src/styles/theme-contrast.spec.ts +44 -0
- package/src/styles/theme-modes.spec.ts +20 -5
- package/types/lifecorner-angular-ui-kit-hero.d.ts +19 -1
- package/types/lifecorner-angular-ui-kit-internal-chart.d.ts +6 -0
- package/types/lifecorner-angular-ui-kit-list.d.ts +10 -0
- package/types/lifecorner-angular-ui-kit-select.d.ts +13 -1
- package/types/lifecorner-angular-ui-kit-state-strip.d.ts +20 -2
- package/types/lifecorner-angular-ui-kit-table.d.ts +9 -1
|
@@ -256,7 +256,7 @@ var CardComponent = class CardComponent {
|
|
|
256
256
|
}
|
|
257
257
|
},
|
|
258
258
|
ngImport: i0,
|
|
259
|
-
template: "<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- Enter/Space are handled by the host keydown listener (role=button, tabindex=0 when clickable) -->\n<div\n [class]=\"cardClasses()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"cardAriaLabel()\"\n [attr.tabindex]=\"isClickable() ? 0 : null\"\n (click)=\"handleClick($event)\"\n>\n @if (linkMode() && !title()) {\n <!-- Link card without a title (3.24): an empty anchor, named by ariaLabel, covers the card. -->\n <ng-container [ngTemplateOutlet]=\"cardLink\" [ngTemplateOutletContext]=\"{ bare: true }\" />\n }\n @if (title()) {\n <div class=\"card__header\">\n @if (icon()) {\n <div\n class=\"card__icon card__icon--{{ iconVariant() }} card__icon--size-{{ iconSize() }}\"\n aria-hidden=\"true\"\n >\n <lc-icon [name]=\"icon()!\" [size]=\"iconSize() === 'sm' ? 'xs' : 'sm'\" [decorative]=\"true\" />\n </div>\n }\n <div class=\"card__header-left\">\n <div class=\"card__title-row\">\n @if (isCollapsible()) {\n <!-- Collapsible card (3.36): the heading stays a heading and holds the toggle. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h3>\n }\n }
|
|
259
|
+
template: "<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- Enter/Space are handled by the host keydown listener (role=button, tabindex=0 when clickable) -->\n<div\n [class]=\"cardClasses()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"cardAriaLabel()\"\n [attr.tabindex]=\"isClickable() ? 0 : null\"\n (click)=\"handleClick($event)\"\n>\n @if (linkMode() && !title()) {\n <!-- Link card without a title (3.24): an empty anchor, named by ariaLabel, covers the card. -->\n <ng-container [ngTemplateOutlet]=\"cardLink\" [ngTemplateOutletContext]=\"{ bare: true }\" />\n }\n @if (title()) {\n <div class=\"card__header\">\n @if (icon()) {\n <div\n class=\"card__icon card__icon--{{ iconVariant() }} card__icon--size-{{ iconSize() }}\"\n aria-hidden=\"true\"\n >\n <lc-icon [name]=\"icon()!\" [size]=\"iconSize() === 'sm' ? 'xs' : 'sm'\" [decorative]=\"true\" />\n </div>\n }\n <div class=\"card__header-left\">\n <div class=\"card__title-row\">\n <!-- 3.38 (request 058, 057-s1): the &ngsp; spaces of this template put\n word breaks between the card's parts in its text (textContent,\n accessible name, copy), so title, badge, subtitle, body and footer\n don't run together. Each sits between flex items, where a\n whitespace-only run renders nothing; none is inside .card__title,\n the toggle, the link or the :empty badge slot. The one after the\n title ends each branch: right after an @if chain Angular drops a\n whitespace-only text while it looks for @else. -->\n @if (isCollapsible()) {\n <!-- Collapsible card (3.36): the heading stays a heading and holds the toggle. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h3>\n }\n }&ngsp;\n } @else if (linkMode()) {\n <!-- Link card (3.24): the heading stays a heading and holds the link. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h3>\n }\n }&ngsp;\n } @else {\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\">{{ title() }}</h2>\n }\n @case (4) {\n <h4 class=\"card__title\">{{ title() }}</h4>\n }\n @case (5) {\n <h5 class=\"card__title\">{{ title() }}</h5>\n }\n @case (6) {\n <h6 class=\"card__title\">{{ title() }}</h6>\n }\n @default {\n <h3 class=\"card__title\">{{ title() }}</h3>\n }\n }&ngsp;\n }\n <!-- Rich status badge: project an lc-badge here (takes visual\n precedence over the `badge` string). Wrapper hides when empty. -->\n <span class=\"card__badge-slot\"><ng-content select=\"[card-badge]\"></ng-content></span>&ngsp;\n @if (badge()) {\n <span class=\"card__badge card__badge--{{ badgeVariant() }}\">{{ badge() }}</span>&ngsp;\n }\n </div>\n @if (subtitle()) {\n <p class=\"card__subtitle\" [attr.id]=\"isCollapsible() ? subtitleId : null\">{{ subtitle() }}</p>\n }\n </div>&ngsp;\n <div class=\"card__header-action\">\n <ng-content select=\"[card-header-action]\"></ng-content>\n </div>\n @if (isCollapsible()) {\n <lc-icon name=\"chevron-down\" class=\"card__chevron\" size=\"sm\" [decorative]=\"true\" />\n }\n </div>&ngsp;\n }\n <ng-content select=\"[card-header]\"></ng-content>&ngsp;\n <div\n class=\"card__body\"\n [attr.id]=\"isCollapsible() ? bodyId : null\"\n [attr.hidden]=\"isCollapsible() && !expanded() ? '' : null\"\n >\n <ng-content></ng-content>\n </div>&ngsp;\n <ng-content select=\"[card-footer]\"></ng-content>\n</div>\n\n<!-- The toggle of a collapsible card (3.36): a button inside the heading,\n named by the title and described by the subtitle. Its ::after covers the\n head, so the icon tile, subtitle and chevron toggle too. -->\n<ng-template #cardToggle>\n <button\n type=\"button\"\n class=\"card__toggle\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"bodyId\"\n [attr.aria-describedby]=\"subtitle() ? subtitleId : null\"\n (click)=\"toggle()\"\n >{{ title() }}</button>\n</ng-template>\n\n<!-- The link of a link card (3.24): `href` (plain, no router) or `route`\n (RouterLink, created only here, so other cards never need a router).\n Its ::after covers the card. -->\n<ng-template #cardLink let-bare=\"bare\">\n @if (linkMode() === 'href') {\n <a class=\"card__link\" [class.card__link--bare]=\"bare\" [href]=\"href()\" [attr.aria-label]=\"ariaLabel()\">{{ bare ? '' : title() }}</a>\n } @else {\n <a\n class=\"card__link\"\n [class.card__link--bare]=\"bare\"\n [routerLink]=\"route()\"\n [queryParams]=\"queryParams()\"\n [attr.aria-label]=\"ariaLabel()\"\n >{{ bare ? '' : title() }}</a\n >\n }\n</ng-template>\n",
|
|
260
260
|
styles: [":host{display:block;height:100%}.card{position:relative;display:flex;flex-direction:column;height:100%;background-color:var(--color-surface);color:var(--color-text-primary);transition:box-shadow .15s ease-in-out,transform .15s ease-in-out,border-color .15s ease-in-out}.card__body{flex:1;display:flex;flex-direction:column}.card-elevated{position:relative;overflow:hidden;background-image:var(--gradient-surface);border:1px solid var(--color-border);box-shadow:var(--elevation-1)}.card-elevated:after{content:\"\";position:absolute;inset:0 0 auto;height:3px;background:var(--accent-line);opacity:.7;pointer-events:none}.card-elevated:hover{box-shadow:var(--elevation-2)}.card-outlined{background-image:none;border:1px solid var(--color-border)}.card-flat{background-image:none}.card-raised{background-image:none;border:1px solid var(--color-border);box-shadow:var(--shadow-auth-card, var(--elevation-3))}.card-dashed{background-color:var(--color-muted-tile, var(--color-surface-muted));background-image:none;border:1px dashed var(--color-muted-tile-border, var(--color-border));box-shadow:none;color:var(--color-text-secondary)}.card-padding-none{padding:0}.card-padding-xs{padding:var(--lc-density-padding-xs, var(--spacing-2))}.card-padding-sm{padding:var(--lc-density-padding-sm, var(--spacing-3))}.card-padding-md{padding:var(--lc-density-padding-md, var(--spacing-4))}.card-padding-lg{padding:var(--lc-density-padding-lg, var(--spacing-6))}.card-radius-none{border-radius:var(--border-radius-none)}.card-radius-sm{border-radius:var(--border-radius-sm)}.card-radius-md{border-radius:var(--border-radius-md)}.card-radius-lg{border-radius:var(--border-radius-lg)}.card-radius-xl{border-radius:var(--border-radius-xl, 1.5rem)}.card-radius-full{border-radius:var(--border-radius-full)}.card-clickable,.card-linked{cursor:pointer;-webkit-user-select:none;user-select:none}.card-clickable:hover,.card-linked:hover{background-color:var(--color-surface-hover);border-color:var(--color-border-strong)}.card-clickable:active,.card-linked:active{transform:scale(.98)}.card-clickable:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.card-linked{isolation:isolate}.card-linked:has(.card__link:focus-visible){outline:2px solid var(--color-primary-500);outline-offset:2px}@media(forced-colors:active){.card-linked:has(.card__link:focus-visible){outline-color:Highlight}}.card__link{color:inherit;text-decoration:none;outline:none}.card__link:after{content:\"\";position:absolute;inset:0;z-index:1}.card-selected{border:1px solid var(--color-primary);background-color:var(--color-surface-selected);box-shadow:var(--shadow-brand-glow)}.card-selected.card-elevated{box-shadow:var(--shadow-brand-glow),var(--elevation-2)}.card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--lc-density-gap-md, var(--spacing-4));margin-bottom:var(--lc-density-padding-md, var(--spacing-4));padding-bottom:var(--lc-density-padding-sm, var(--spacing-3));border-bottom:1px solid var(--color-border, #e5e7eb)}.card__icon{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:var(--border-radius-md)}.card__icon--size-sm{width:1.75rem;height:1.75rem;border-radius:var(--border-radius-sm)}.card__icon--brand{background-image:var(--gradient-brand-tile);color:var(--color-on-primary, #fff);box-shadow:var(--shadow-brand-glow)}.card__icon--subtle{background-color:#20849724;color:var(--color-primary-500);border:1px solid var(--color-border-strong)}.card__header-left{flex:1;min-width:0}.card__title-row{display:flex;align-items:center;gap:.5rem}.card__badge-slot{display:inline-flex;align-items:center}.card__badge-slot:empty{display:none}.card__title{margin:0;font-weight:600;font-size:var(--lc-card-title-size, var(--font-size-lg, 1.125rem));line-height:1.3;color:var(--color-text-primary);hyphens:auto;hyphenate-limit-chars:12 4 3}.card__badge{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .375rem;border-radius:9999px;font-size:.75rem;font-weight:600;line-height:1}.card__badge--default{background-color:var(--color-surface-hover);color:var(--color-text-secondary);border:1px solid var(--color-border)}.card__badge--primary{background-color:var(--color-primary-subtle);color:var(--color-on-primary-subtle);border:1px solid var(--color-primary-500)}.card__badge--success{background-color:var(--color-success-subtle);color:var(--color-on-success-subtle)}.card__badge--warning{background-color:var(--color-warning-subtle);color:var(--color-on-warning-subtle)}.card__badge--error{background-color:var(--color-error-subtle);color:var(--color-on-error-subtle)}.card__subtitle{margin:.25rem 0 0;font-size:.8125rem;color:var(--color-text-secondary);line-height:1.4}.card__header-action{flex-shrink:0;display:flex;align-items:center;gap:.5rem}:host ::ng-deep [card-header],:host ::ng-deep .card-header{display:flex;align-items:center;justify-content:space-between;gap:var(--lc-density-gap-sm, var(--spacing-2));margin-bottom:var(--lc-density-padding-md, var(--spacing-4));padding-bottom:var(--lc-density-padding-sm, var(--spacing-3));border-bottom:1px solid var(--color-divider, #e5e7eb);font-weight:600;font-size:1.125rem;color:var(--color-text-primary)}:host ::ng-deep .card-content{color:var(--color-text-primary)}:host ::ng-deep [card-footer],:host ::ng-deep .card-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--lc-density-gap-sm, var(--spacing-2));margin-top:var(--lc-density-padding-md, var(--spacing-4));padding-top:var(--lc-density-padding-sm, var(--spacing-3));border-top:1px solid var(--color-divider, #e5e7eb);color:var(--color-text-secondary)}:host(.lc-card--footer-equal){container:lc-card/inline-size;inline-size:100%}:host(.lc-card--footer-equal)>.card>::ng-deep :is([card-footer],.card-footer){display:grid;grid-template-columns:minmax(0,1fr);align-items:stretch}@container lc-card (width >= 30rem){:host(.lc-card--footer-equal)>.card>::ng-deep :is([card-footer],.card-footer){grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr)}}:host(.lc-card--footer-equal)>.card>::ng-deep :is([card-footer],.card-footer)>lc-button>.btn{block-size:100%}:host ::ng-deep :where(.card-linked :is(a[href],button,input,select,textarea,summary,[tabindex]):not(.card__link)){position:relative;z-index:2}:host ::ng-deep .card-dashed lc-icon{color:var(--color-muted-tile-icon, var(--color-text-tertiary))}.card-collapsible .card__header{position:relative;isolation:isolate;min-height:44px;align-items:center;cursor:pointer}.card-collapsible .card__header:has(.card__toggle:focus-visible){outline:2px solid var(--color-primary-500);outline-offset:2px}@media(forced-colors:active){.card-collapsible .card__header:has(.card__toggle:focus-visible){outline-color:Highlight}}.card-collapsible .card__header:hover .card__chevron{color:var(--color-text-primary)}.card__toggle{margin:0;padding:0;border:0;background:none;font:inherit;color:inherit;text-align:start;cursor:pointer;outline:none}.card__toggle:after{content:\"\";position:absolute;inset:0;z-index:1}.card-collapsible .card__header-action{position:relative;z-index:2}.card__chevron{flex-shrink:0;color:var(--color-text-secondary);transform:rotate(-180deg);transition:transform .2s ease}.card-collapsed .card__chevron{transform:none}@media(prefers-reduced-motion:reduce){.card__chevron{transition:none}}.card-collapsed .card__header{margin-bottom:0;padding-bottom:0;border-bottom:0}.card__body[hidden]{display:none}:host(.lc-card--collapsed)>.card>::ng-deep :is([card-footer],.card-footer){display:none}\n"],
|
|
261
261
|
dependencies: [
|
|
262
262
|
{
|
|
@@ -328,7 +328,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
328
328
|
"[class.lc-card--collapsed]": "isCollapsible() && !expanded()"
|
|
329
329
|
},
|
|
330
330
|
viewProviders: [ɵprovideKitIcons([ICON_CHEVRON_DOWN])],
|
|
331
|
-
template: "<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- Enter/Space are handled by the host keydown listener (role=button, tabindex=0 when clickable) -->\n<div\n [class]=\"cardClasses()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"cardAriaLabel()\"\n [attr.tabindex]=\"isClickable() ? 0 : null\"\n (click)=\"handleClick($event)\"\n>\n @if (linkMode() && !title()) {\n <!-- Link card without a title (3.24): an empty anchor, named by ariaLabel, covers the card. -->\n <ng-container [ngTemplateOutlet]=\"cardLink\" [ngTemplateOutletContext]=\"{ bare: true }\" />\n }\n @if (title()) {\n <div class=\"card__header\">\n @if (icon()) {\n <div\n class=\"card__icon card__icon--{{ iconVariant() }} card__icon--size-{{ iconSize() }}\"\n aria-hidden=\"true\"\n >\n <lc-icon [name]=\"icon()!\" [size]=\"iconSize() === 'sm' ? 'xs' : 'sm'\" [decorative]=\"true\" />\n </div>\n }\n <div class=\"card__header-left\">\n <div class=\"card__title-row\">\n @if (isCollapsible()) {\n <!-- Collapsible card (3.36): the heading stays a heading and holds the toggle. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h3>\n }\n }
|
|
331
|
+
template: "<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- Enter/Space are handled by the host keydown listener (role=button, tabindex=0 when clickable) -->\n<div\n [class]=\"cardClasses()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"cardAriaLabel()\"\n [attr.tabindex]=\"isClickable() ? 0 : null\"\n (click)=\"handleClick($event)\"\n>\n @if (linkMode() && !title()) {\n <!-- Link card without a title (3.24): an empty anchor, named by ariaLabel, covers the card. -->\n <ng-container [ngTemplateOutlet]=\"cardLink\" [ngTemplateOutletContext]=\"{ bare: true }\" />\n }\n @if (title()) {\n <div class=\"card__header\">\n @if (icon()) {\n <div\n class=\"card__icon card__icon--{{ iconVariant() }} card__icon--size-{{ iconSize() }}\"\n aria-hidden=\"true\"\n >\n <lc-icon [name]=\"icon()!\" [size]=\"iconSize() === 'sm' ? 'xs' : 'sm'\" [decorative]=\"true\" />\n </div>\n }\n <div class=\"card__header-left\">\n <div class=\"card__title-row\">\n <!-- 3.38 (request 058, 057-s1): the &ngsp; spaces of this template put\n word breaks between the card's parts in its text (textContent,\n accessible name, copy), so title, badge, subtitle, body and footer\n don't run together. Each sits between flex items, where a\n whitespace-only run renders nothing; none is inside .card__title,\n the toggle, the link or the :empty badge slot. The one after the\n title ends each branch: right after an @if chain Angular drops a\n whitespace-only text while it looks for @else. -->\n @if (isCollapsible()) {\n <!-- Collapsible card (3.36): the heading stays a heading and holds the toggle. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h3>\n }\n }&ngsp;\n } @else if (linkMode()) {\n <!-- Link card (3.24): the heading stays a heading and holds the link. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h3>\n }\n }&ngsp;\n } @else {\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\">{{ title() }}</h2>\n }\n @case (4) {\n <h4 class=\"card__title\">{{ title() }}</h4>\n }\n @case (5) {\n <h5 class=\"card__title\">{{ title() }}</h5>\n }\n @case (6) {\n <h6 class=\"card__title\">{{ title() }}</h6>\n }\n @default {\n <h3 class=\"card__title\">{{ title() }}</h3>\n }\n }&ngsp;\n }\n <!-- Rich status badge: project an lc-badge here (takes visual\n precedence over the `badge` string). Wrapper hides when empty. -->\n <span class=\"card__badge-slot\"><ng-content select=\"[card-badge]\"></ng-content></span>&ngsp;\n @if (badge()) {\n <span class=\"card__badge card__badge--{{ badgeVariant() }}\">{{ badge() }}</span>&ngsp;\n }\n </div>\n @if (subtitle()) {\n <p class=\"card__subtitle\" [attr.id]=\"isCollapsible() ? subtitleId : null\">{{ subtitle() }}</p>\n }\n </div>&ngsp;\n <div class=\"card__header-action\">\n <ng-content select=\"[card-header-action]\"></ng-content>\n </div>\n @if (isCollapsible()) {\n <lc-icon name=\"chevron-down\" class=\"card__chevron\" size=\"sm\" [decorative]=\"true\" />\n }\n </div>&ngsp;\n }\n <ng-content select=\"[card-header]\"></ng-content>&ngsp;\n <div\n class=\"card__body\"\n [attr.id]=\"isCollapsible() ? bodyId : null\"\n [attr.hidden]=\"isCollapsible() && !expanded() ? '' : null\"\n >\n <ng-content></ng-content>\n </div>&ngsp;\n <ng-content select=\"[card-footer]\"></ng-content>\n</div>\n\n<!-- The toggle of a collapsible card (3.36): a button inside the heading,\n named by the title and described by the subtitle. Its ::after covers the\n head, so the icon tile, subtitle and chevron toggle too. -->\n<ng-template #cardToggle>\n <button\n type=\"button\"\n class=\"card__toggle\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"bodyId\"\n [attr.aria-describedby]=\"subtitle() ? subtitleId : null\"\n (click)=\"toggle()\"\n >{{ title() }}</button>\n</ng-template>\n\n<!-- The link of a link card (3.24): `href` (plain, no router) or `route`\n (RouterLink, created only here, so other cards never need a router).\n Its ::after covers the card. -->\n<ng-template #cardLink let-bare=\"bare\">\n @if (linkMode() === 'href') {\n <a class=\"card__link\" [class.card__link--bare]=\"bare\" [href]=\"href()\" [attr.aria-label]=\"ariaLabel()\">{{ bare ? '' : title() }}</a>\n } @else {\n <a\n class=\"card__link\"\n [class.card__link--bare]=\"bare\"\n [routerLink]=\"route()\"\n [queryParams]=\"queryParams()\"\n [attr.aria-label]=\"ariaLabel()\"\n >{{ bare ? '' : title() }}</a\n >\n }\n</ng-template>\n",
|
|
332
332
|
styles: [":host{display:block;height:100%}.card{position:relative;display:flex;flex-direction:column;height:100%;background-color:var(--color-surface);color:var(--color-text-primary);transition:box-shadow .15s ease-in-out,transform .15s ease-in-out,border-color .15s ease-in-out}.card__body{flex:1;display:flex;flex-direction:column}.card-elevated{position:relative;overflow:hidden;background-image:var(--gradient-surface);border:1px solid var(--color-border);box-shadow:var(--elevation-1)}.card-elevated:after{content:\"\";position:absolute;inset:0 0 auto;height:3px;background:var(--accent-line);opacity:.7;pointer-events:none}.card-elevated:hover{box-shadow:var(--elevation-2)}.card-outlined{background-image:none;border:1px solid var(--color-border)}.card-flat{background-image:none}.card-raised{background-image:none;border:1px solid var(--color-border);box-shadow:var(--shadow-auth-card, var(--elevation-3))}.card-dashed{background-color:var(--color-muted-tile, var(--color-surface-muted));background-image:none;border:1px dashed var(--color-muted-tile-border, var(--color-border));box-shadow:none;color:var(--color-text-secondary)}.card-padding-none{padding:0}.card-padding-xs{padding:var(--lc-density-padding-xs, var(--spacing-2))}.card-padding-sm{padding:var(--lc-density-padding-sm, var(--spacing-3))}.card-padding-md{padding:var(--lc-density-padding-md, var(--spacing-4))}.card-padding-lg{padding:var(--lc-density-padding-lg, var(--spacing-6))}.card-radius-none{border-radius:var(--border-radius-none)}.card-radius-sm{border-radius:var(--border-radius-sm)}.card-radius-md{border-radius:var(--border-radius-md)}.card-radius-lg{border-radius:var(--border-radius-lg)}.card-radius-xl{border-radius:var(--border-radius-xl, 1.5rem)}.card-radius-full{border-radius:var(--border-radius-full)}.card-clickable,.card-linked{cursor:pointer;-webkit-user-select:none;user-select:none}.card-clickable:hover,.card-linked:hover{background-color:var(--color-surface-hover);border-color:var(--color-border-strong)}.card-clickable:active,.card-linked:active{transform:scale(.98)}.card-clickable:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.card-linked{isolation:isolate}.card-linked:has(.card__link:focus-visible){outline:2px solid var(--color-primary-500);outline-offset:2px}@media(forced-colors:active){.card-linked:has(.card__link:focus-visible){outline-color:Highlight}}.card__link{color:inherit;text-decoration:none;outline:none}.card__link:after{content:\"\";position:absolute;inset:0;z-index:1}.card-selected{border:1px solid var(--color-primary);background-color:var(--color-surface-selected);box-shadow:var(--shadow-brand-glow)}.card-selected.card-elevated{box-shadow:var(--shadow-brand-glow),var(--elevation-2)}.card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--lc-density-gap-md, var(--spacing-4));margin-bottom:var(--lc-density-padding-md, var(--spacing-4));padding-bottom:var(--lc-density-padding-sm, var(--spacing-3));border-bottom:1px solid var(--color-border, #e5e7eb)}.card__icon{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:var(--border-radius-md)}.card__icon--size-sm{width:1.75rem;height:1.75rem;border-radius:var(--border-radius-sm)}.card__icon--brand{background-image:var(--gradient-brand-tile);color:var(--color-on-primary, #fff);box-shadow:var(--shadow-brand-glow)}.card__icon--subtle{background-color:#20849724;color:var(--color-primary-500);border:1px solid var(--color-border-strong)}.card__header-left{flex:1;min-width:0}.card__title-row{display:flex;align-items:center;gap:.5rem}.card__badge-slot{display:inline-flex;align-items:center}.card__badge-slot:empty{display:none}.card__title{margin:0;font-weight:600;font-size:var(--lc-card-title-size, var(--font-size-lg, 1.125rem));line-height:1.3;color:var(--color-text-primary);hyphens:auto;hyphenate-limit-chars:12 4 3}.card__badge{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .375rem;border-radius:9999px;font-size:.75rem;font-weight:600;line-height:1}.card__badge--default{background-color:var(--color-surface-hover);color:var(--color-text-secondary);border:1px solid var(--color-border)}.card__badge--primary{background-color:var(--color-primary-subtle);color:var(--color-on-primary-subtle);border:1px solid var(--color-primary-500)}.card__badge--success{background-color:var(--color-success-subtle);color:var(--color-on-success-subtle)}.card__badge--warning{background-color:var(--color-warning-subtle);color:var(--color-on-warning-subtle)}.card__badge--error{background-color:var(--color-error-subtle);color:var(--color-on-error-subtle)}.card__subtitle{margin:.25rem 0 0;font-size:.8125rem;color:var(--color-text-secondary);line-height:1.4}.card__header-action{flex-shrink:0;display:flex;align-items:center;gap:.5rem}:host ::ng-deep [card-header],:host ::ng-deep .card-header{display:flex;align-items:center;justify-content:space-between;gap:var(--lc-density-gap-sm, var(--spacing-2));margin-bottom:var(--lc-density-padding-md, var(--spacing-4));padding-bottom:var(--lc-density-padding-sm, var(--spacing-3));border-bottom:1px solid var(--color-divider, #e5e7eb);font-weight:600;font-size:1.125rem;color:var(--color-text-primary)}:host ::ng-deep .card-content{color:var(--color-text-primary)}:host ::ng-deep [card-footer],:host ::ng-deep .card-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--lc-density-gap-sm, var(--spacing-2));margin-top:var(--lc-density-padding-md, var(--spacing-4));padding-top:var(--lc-density-padding-sm, var(--spacing-3));border-top:1px solid var(--color-divider, #e5e7eb);color:var(--color-text-secondary)}:host(.lc-card--footer-equal){container:lc-card/inline-size;inline-size:100%}:host(.lc-card--footer-equal)>.card>::ng-deep :is([card-footer],.card-footer){display:grid;grid-template-columns:minmax(0,1fr);align-items:stretch}@container lc-card (width >= 30rem){:host(.lc-card--footer-equal)>.card>::ng-deep :is([card-footer],.card-footer){grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr)}}:host(.lc-card--footer-equal)>.card>::ng-deep :is([card-footer],.card-footer)>lc-button>.btn{block-size:100%}:host ::ng-deep :where(.card-linked :is(a[href],button,input,select,textarea,summary,[tabindex]):not(.card__link)){position:relative;z-index:2}:host ::ng-deep .card-dashed lc-icon{color:var(--color-muted-tile-icon, var(--color-text-tertiary))}.card-collapsible .card__header{position:relative;isolation:isolate;min-height:44px;align-items:center;cursor:pointer}.card-collapsible .card__header:has(.card__toggle:focus-visible){outline:2px solid var(--color-primary-500);outline-offset:2px}@media(forced-colors:active){.card-collapsible .card__header:has(.card__toggle:focus-visible){outline-color:Highlight}}.card-collapsible .card__header:hover .card__chevron{color:var(--color-text-primary)}.card__toggle{margin:0;padding:0;border:0;background:none;font:inherit;color:inherit;text-align:start;cursor:pointer;outline:none}.card__toggle:after{content:\"\";position:absolute;inset:0;z-index:1}.card-collapsible .card__header-action{position:relative;z-index:2}.card__chevron{flex-shrink:0;color:var(--color-text-secondary);transform:rotate(-180deg);transition:transform .2s ease}.card-collapsed .card__chevron{transform:none}@media(prefers-reduced-motion:reduce){.card__chevron{transition:none}}.card-collapsed .card__header{margin-bottom:0;padding-bottom:0;border-bottom:0}.card__body[hidden]{display:none}:host(.lc-card--collapsed)>.card>::ng-deep :is([card-footer],.card-footer){display:none}\n"]
|
|
333
333
|
}]
|
|
334
334
|
}],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-card.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/card/card.component.ts","../../../../libs/angular-ui-kit/src/lib/card/card.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n model,\n output,\n HostListener,\n computed,\n effect,\n isDevMode,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { RouterLink, type Params } from '@angular/router';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_CHEVRON_DOWN } from '@lifecorner/angular-ui-kit/icons';\n\n/** Visual variant of `lc-card`. */\nexport type CardVariant = 'elevated' | 'outlined' | 'flat' | 'raised' | 'dashed';\n\n/** Heading level of `lc-card`'s built-in title. */\nexport type CardHeadingLevel = 2 | 3 | 4 | 5 | 6;\n\n/** Layout of `lc-card`'s `[card-footer]` slot: `default` (a flex row, end-aligned) or `equal` (children at equal width). */\nexport type CardFooterLayout = 'default' | 'equal';\n\n/** Counter for generated ids (3.36): creation order, so prerendered HTML is the same in every build. */\nlet nextCardId = 0;\n\n/** Whether a `route` value is a link: `''`, `null` and `undefined` are not. */\nfunction hasRoute(route: string | readonly unknown[] | null | undefined): boolean {\n return route !== '' && route !== null && route !== undefined;\n}\n\n/**\n * Card component for content grouping and visual hierarchy.\n *\n * Features:\n * - Variant styles (elevated, outlined, flat, raised, dashed)\n * - Configurable padding (none, xs, sm, md, lg)\n * - Border radius options (none, sm, md, lg, xl, full)\n * - Optional title display, with an optional leading icon tile\n * - Content projection for flexible body content\n * - Link mode (3.24): `href` or `route` make the whole card a real link,\n * the title stays a heading\n * - Equal footer (3.29): `footerLayout=\"equal\"` gives two answers of equal\n * weight in the `[card-footer]` slot the same width\n * - Collapsible (3.36): `collapsible` with `[(expanded)]` turns the head into\n * one toggle that opens and closes the body and footer\n *\n * @example\n * ```html\n * <lc-card title=\"Card Title\" variant=\"elevated\" padding=\"md\">\n * <p>Card body content</p>\n * </lc-card>\n *\n * <!-- With a leading brand-tile icon in the header -->\n * <lc-card title=\"Repository\" subtitle=\"Checkout & profile\" icon=\"git-branch\">\n * ...\n * </lc-card>\n *\n * <!-- An overview card that opens a page: heading h2 with a link inside -->\n * <lc-card title=\"SAP-Ist\" variant=\"outlined\" [headingLevel]=\"2\"\n * [route]=\"['/quellen', 'sap-ist']\" [queryParams]=\"{ ansicht: 'laeufe' }\">\n * ...\n * </lc-card>\n *\n * <!-- Two answers of equal weight (3.29): primary answer first -->\n * <lc-card title=\"Netflix\" variant=\"outlined\" footerLayout=\"equal\">\n * ...\n * <div card-footer>\n * <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"true\">Stimmt</lc-button>\n * <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"true\">Kein Vertrag</lc-button>\n * </div>\n * </lc-card>\n * ```\n */\n@Component({\n selector: 'lc-card',\n standalone: true,\n imports: [IconComponent, NgTemplateOutlet, RouterLink],\n templateUrl: './card.component.html',\n styleUrls: ['./card.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class.lc-card--footer-equal]': \"footerLayout() === 'equal'\",\n '[class.lc-card--collapsed]': 'isCollapsible() && !expanded()',\n },\n viewProviders: [ɵprovideKitIcons([ICON_CHEVRON_DOWN])],\n})\nexport class CardComponent {\n /**\n * Optional title rendered as a styled header.\n * For complex headers (e.g. title + action button), use content projection instead.\n */\n title = input<string | undefined>(undefined);\n\n /**\n * Optional subtitle rendered below the title.\n */\n subtitle = input<string | undefined>(undefined);\n\n /**\n * Optional leading icon (Tabler icon name) rendered as a teal brand tile to\n * the left of the title. Only shown when `title` is set.\n */\n icon = input<string | undefined>(undefined);\n\n /**\n * Visual treatment of the leading icon tile.\n * - brand: gradient teal tile with light ink (default)\n * - subtle: translucent surface tile with brand-teal ink\n * @default 'brand'\n */\n iconVariant = input<'brand' | 'subtle'>('brand');\n\n /**\n * Size of the leading icon tile.\n * - md: 2.25rem tile (default)\n * - sm: compact ~1.75rem chip for dense card headers\n * @default 'md'\n */\n iconSize = input<'sm' | 'md'>('md');\n\n /**\n * Optional badge text/count shown next to the title (e.g. item count).\n * For a richer status badge (e.g. a leading status dot), project an\n * `lc-badge` into the `card-badge` slot instead — the slot takes precedence.\n */\n badge = input<string | undefined>(undefined);\n\n /**\n * Badge color variant.\n * @default 'default'\n */\n badgeVariant = input<'default' | 'primary' | 'success' | 'warning' | 'error'>('default');\n\n /**\n * Visual variant of the card\n * - elevated: Box shadow (default)\n * - outlined: Border only (the hairline `--color-border`, no shadow) — the\n * content card on the \"Weite\" sky with `borderRadius=\"xl\"`\n * - flat: No shadow or border\n * - raised: plain surface, hairline border and the long, soft\n * `--shadow-auth-card`, no accent line — the sign-in card\n * - dashed: the muted \"coming soon\" tile — `--color-muted-tile` fill, 1 px\n * dashed `--color-muted-tile-border`, secondary ink, icons in\n * `--color-muted-tile-icon`. Never clickable: `clickable` is ignored;\n * `href` and `route` are ignored too\n * @default 'elevated'\n */\n variant = input<CardVariant>('elevated');\n\n /**\n * Padding inside the card\n * @default 'md'\n */\n padding = input<'none' | 'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the card is clickable (hover effects, cursor pointer). Has no\n * effect on a link card (`href`/`route`).\n * @default false\n */\n clickable = input<boolean>(false);\n\n /**\n * Whether the card is selected (if clickable)\n * @default false\n */\n selected = input<boolean>(false);\n\n /**\n * Border radius size: `none`, `sm`, `md`, `lg` (18 px), `xl` (24 px, the\n * \"Weite\" content card) or `full`.\n * @default 'md'\n */\n borderRadius = input<'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full'>('md');\n\n /**\n * Heading level of the built-in `title` (`h2`–`h6`), so the card fits the\n * page's outline. Semantics only, the look stays the same.\n * @default 3\n */\n headingLevel = input<CardHeadingLevel>(3);\n\n /**\n * Accessible name. On a link card (`href`/`route`) it names the link\n * instead of the card; it must contain the visible title (WCAG 2.5.3) and\n * the heading reads it too, so keep it short. Without it the link is named\n * by the title, and the card's content (badge, list) is read as normal\n * content. On other cards it labels the card.\n * @default undefined\n */\n ariaLabel = input<string | undefined>(undefined);\n\n /**\n * URL the card links to (3.24, quellen row 1). The card becomes a real\n * link: the built-in `title` is an `<a href>` inside its heading, and the\n * link covers the whole card (click, Enter, middle click, \"open in new\n * tab\", \"copy link\"). No router needed; works in prerendered HTML. Wins\n * over `route`. Ignored by `dashed`. On a link card `clickable` has no\n * effect and `cardClick` is not emitted.\n * @default undefined\n */\n href = input<string | undefined>(undefined);\n\n /**\n * In-app route the card links to through the Angular router (`RouterLink`\n * commands: `'/quellen/usm'` or `['/quellen', id]`), relative to the\n * consumer's route, rendered as a real `<a href>` like `href`. Needs the\n * app's router (`provideRouter`); without one, use `href`. `''` and `null`\n * mean no link.\n * @default undefined\n */\n route = input<string | readonly unknown[] | null | undefined>(undefined);\n\n /**\n * Query parameters of `route`, as `RouterLink`'s `queryParams`\n * (`{ ansicht: 'laeufe' }`). Ignored with `href` (write the query into the\n * URL).\n * @default undefined\n */\n queryParams = input<Params | null | undefined>(undefined);\n\n /**\n * Layout of the `[card-footer]` slot (3.29, CC-2). `equal`: its children\n * share the row at equal width once the card is at least 480 px (30rem)\n * wide, and stack full width, 8 px apart, below that (the card's own width,\n * at any viewport; long labels wrap inside the buttons, which get the\n * row's height). For two answers of equal weight, put\n * `<lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"true\">` in it,\n * primary answer first; the card adds layout only (gap, divider and\n * spacing as `default`) and never restyles the buttons. The card becomes a\n * size container and takes its parent's full width. Keep the default\n * `padding` (with `none` the buttons' focus ring is clipped). Works in link\n * cards (the buttons stay clickable above the link) and in prerendered\n * HTML (CSS only).\n * @default 'default'\n */\n footerLayout = input<CardFooterLayout>('default');\n\n /**\n * The card can close (3.36, regeln row 1): the head (icon, title, subtitle)\n * becomes one toggle, a button inside the title's heading with\n * `aria-expanded` and `aria-controls`, whose hit area is the whole head (at\n * least 44 px high); Enter, Space or a click open and close the body and the\n * `[card-footer]`. A chevron at the end of the head shows the state.\n * `[card-header-action]` stays a separate control beside it. Needs the\n * built-in `title` (otherwise ignored); wins over `clickable`, `href` and\n * `route`, which are then ignored; ignored on `dashed`. Bind `[(expanded)]`.\n * @default false\n */\n collapsible = input<boolean>(false);\n\n /**\n * Open state of a `collapsible` card (3.36), two-way: `[(expanded)]`. Open\n * by default, so a plain `collapsible` hides nothing; set `false` for a card\n * that starts closed (also in prerendered HTML). Closed, only the head\n * shows: the body is `hidden` and the footer is not displayed.\n * @default true\n */\n readonly expanded = model<boolean>(true);\n\n /**\n * Emitted when a `clickable` card is clicked or activated with Enter or\n * Space. Not emitted on a link card (`href`/`route`): the link navigates by\n * itself (one navigation); bind the native `(click)` for analytics.\n */\n readonly cardClick = output<MouseEvent>();\n\n /** Generated id prefix (3.36): creation order, so prerendered HTML is the same in every build. */\n private readonly uid = `lc-card-${nextCardId++}`;\n\n /** Id of the body a collapsible card's toggle controls. */\n protected readonly bodyId = `${this.uid}-body`;\n\n /** Id of the subtitle that describes a collapsible card's toggle. */\n protected readonly subtitleId = `${this.uid}-subtitle`;\n\n /**\n * Whether the card collapses (3.36): `collapsible` with a built-in title,\n * except for the dashed tile.\n */\n protected readonly isCollapsible = computed(\n () => this.collapsible() && !!this.title() && this.variant() !== 'dashed',\n );\n\n /**\n * How the card links (3.24): `href` wins over `route`; `''`/`null` routes\n * are no link, and the dashed \"coming soon\" tile never links. A\n * collapsible card (3.36) never links.\n */\n protected readonly linkMode = computed<'href' | 'route' | null>(() => {\n if (this.variant() === 'dashed' || this.isCollapsible()) return null;\n if (this.href()) return 'href';\n return hasRoute(this.route()) ? 'route' : null;\n });\n\n /**\n * Whether the card acts as a button: `clickable`, except for the dashed\n * \"coming soon\" tile, which is never interactive, a link card, whose\n * anchor is the only interactive element, and a collapsible card (3.36),\n * whose toggle is.\n */\n protected isClickable = computed(\n () => this.clickable() && this.variant() !== 'dashed' && !this.linkMode() && !this.isCollapsible(),\n );\n\n /** Opens or closes a collapsible card; `expandedChange` emits the new state. */\n protected toggle(): void {\n this.expanded.set(!this.expanded());\n }\n\n /** `ariaLabel` on the card; on a link card it names the anchor instead. */\n protected readonly cardAriaLabel = computed(() => (this.linkMode() ? undefined : this.ariaLabel()));\n\n constructor() {\n if (isDevMode()) {\n effect(() => {\n if (!this.collapsible() || this.variant() === 'dashed') return;\n if (!this.title()) {\n console.warn('[lc-card] collapsible needs the built-in title: ignored');\n } else if (this.clickable() || this.href() || hasRoute(this.route())) {\n console.warn('[lc-card] collapsible wins over clickable, href and route: they are ignored');\n }\n });\n effect(() => {\n if (!this.linkMode()) return;\n if (this.href() && hasRoute(this.route())) {\n console.warn('[lc-card] href and route are both set: href wins');\n }\n if (!this.title() && !this.ariaLabel()) {\n console.warn('[lc-card] a link card without title needs an ariaLabel to name its link');\n }\n });\n }\n }\n\n /**\n * Compute card CSS classes based on inputs\n */\n protected cardClasses = computed(() => {\n const classes = [\n 'card',\n `card-${this.variant()}`,\n `card-padding-${this.padding()}`,\n `card-radius-${this.borderRadius()}`,\n ];\n\n if (this.isClickable()) {\n classes.push('card-clickable');\n }\n\n // A link card looks and reacts like a clickable one (3.24).\n if (this.linkMode()) {\n classes.push('card-linked');\n }\n\n // The dashed tile is never interactive, so it is never selected either.\n if (this.selected() && this.variant() !== 'dashed') {\n classes.push('card-selected');\n }\n\n // A collapsible card (3.36), and its closed state.\n if (this.isCollapsible()) {\n classes.push('card-collapsible');\n if (!this.expanded()) classes.push('card-collapsed');\n }\n\n return classes.join(' ');\n });\n\n /**\n * Compute ARIA role based on clickable state\n */\n protected role = computed(() => (this.isClickable() ? 'button' : 'article'));\n\n /**\n * Handle card click events\n */\n protected handleClick(event: MouseEvent): void {\n if (this.isClickable()) {\n this.cardClick.emit(event);\n }\n }\n\n /**\n * Handle keyboard events for accessibility\n */\n @HostListener('keydown', ['$event'])\n protected handleKeydown(event: KeyboardEvent): void {\n if (this.isClickable() && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n const mouseEvent = new MouseEvent('click', {\n bubbles: true,\n cancelable: true,\n });\n this.cardClick.emit(mouseEvent);\n }\n }\n}\n","<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- Enter/Space are handled by the host keydown listener (role=button, tabindex=0 when clickable) -->\n<div\n [class]=\"cardClasses()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"cardAriaLabel()\"\n [attr.tabindex]=\"isClickable() ? 0 : null\"\n (click)=\"handleClick($event)\"\n>\n @if (linkMode() && !title()) {\n <!-- Link card without a title (3.24): an empty anchor, named by ariaLabel, covers the card. -->\n <ng-container [ngTemplateOutlet]=\"cardLink\" [ngTemplateOutletContext]=\"{ bare: true }\" />\n }\n @if (title()) {\n <div class=\"card__header\">\n @if (icon()) {\n <div\n class=\"card__icon card__icon--{{ iconVariant() }} card__icon--size-{{ iconSize() }}\"\n aria-hidden=\"true\"\n >\n <lc-icon [name]=\"icon()!\" [size]=\"iconSize() === 'sm' ? 'xs' : 'sm'\" [decorative]=\"true\" />\n </div>\n }\n <div class=\"card__header-left\">\n <div class=\"card__title-row\">\n @if (isCollapsible()) {\n <!-- Collapsible card (3.36): the heading stays a heading and holds the toggle. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h3>\n }\n }\n } @else if (linkMode()) {\n <!-- Link card (3.24): the heading stays a heading and holds the link. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h3>\n }\n }\n } @else {\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\">{{ title() }}</h2>\n }\n @case (4) {\n <h4 class=\"card__title\">{{ title() }}</h4>\n }\n @case (5) {\n <h5 class=\"card__title\">{{ title() }}</h5>\n }\n @case (6) {\n <h6 class=\"card__title\">{{ title() }}</h6>\n }\n @default {\n <h3 class=\"card__title\">{{ title() }}</h3>\n }\n }\n }\n <!-- Rich status badge: project an lc-badge here (takes visual\n precedence over the `badge` string). Wrapper hides when empty. -->\n <span class=\"card__badge-slot\"><ng-content select=\"[card-badge]\"></ng-content></span>\n @if (badge()) {\n <span class=\"card__badge card__badge--{{ badgeVariant() }}\">{{ badge() }}</span>\n }\n </div>\n @if (subtitle()) {\n <p class=\"card__subtitle\" [attr.id]=\"isCollapsible() ? subtitleId : null\">{{ subtitle() }}</p>\n }\n </div>\n <div class=\"card__header-action\">\n <ng-content select=\"[card-header-action]\"></ng-content>\n </div>\n @if (isCollapsible()) {\n <lc-icon name=\"chevron-down\" class=\"card__chevron\" size=\"sm\" [decorative]=\"true\" />\n }\n </div>\n }\n <ng-content select=\"[card-header]\"></ng-content>\n <div\n class=\"card__body\"\n [attr.id]=\"isCollapsible() ? bodyId : null\"\n [attr.hidden]=\"isCollapsible() && !expanded() ? '' : null\"\n >\n <ng-content></ng-content>\n </div>\n <ng-content select=\"[card-footer]\"></ng-content>\n</div>\n\n<!-- The toggle of a collapsible card (3.36): a button inside the heading,\n named by the title and described by the subtitle. Its ::after covers the\n head, so the icon tile, subtitle and chevron toggle too. -->\n<ng-template #cardToggle>\n <button\n type=\"button\"\n class=\"card__toggle\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"bodyId\"\n [attr.aria-describedby]=\"subtitle() ? subtitleId : null\"\n (click)=\"toggle()\"\n >{{ title() }}</button>\n</ng-template>\n\n<!-- The link of a link card (3.24): `href` (plain, no router) or `route`\n (RouterLink, created only here, so other cards never need a router).\n Its ::after covers the card. -->\n<ng-template #cardLink let-bare=\"bare\">\n @if (linkMode() === 'href') {\n <a class=\"card__link\" [class.card__link--bare]=\"bare\" [href]=\"href()\" [attr.aria-label]=\"ariaLabel()\">{{ bare ? '' : title() }}</a>\n } @else {\n <a\n class=\"card__link\"\n [class.card__link--bare]=\"bare\"\n [routerLink]=\"route()\"\n [queryParams]=\"queryParams()\"\n [attr.aria-label]=\"ariaLabel()\"\n >{{ bare ? '' : title() }}</a\n >\n }\n</ng-template>\n"],"mappings":";;;;;;AA0BA,IAAI,aAAa;AAGjB,SAAS,SAAS,OAAqD;CACrE,OAAO,UAAU,MAAM,UAAU,QAAQ,UAAU;AACrD;AA0DA,IAAa,gBAAb,MAAa,cAAa;CAKxB,QAAQ,MAA0B,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAK5C,WAAW,MAA0B,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAM/C,OAAO,MAA0B,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAQ3C,cAAc,MAA0B,SAAQ,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAQhD,WAAW,MAAmB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAOnC,QAAQ,MAA0B,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAM5C,eAAe,MAA+D,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAgBxF,UAAU,MAAmB,YAAW,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAMxC,UAAU,MAA0C,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAOzD,YAAY,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAMjC,WAAW,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAOhC,eAAe,MAAmD,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAOvE,eAAe,MAAwB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAUzC,YAAY,MAA0B,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAWhD,OAAO,MAA0B,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAU3C,QAAQ,MAAsD,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAQxE,cAAc,MAAiC,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAiBzD,eAAe,MAAwB,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAajD,cAAc,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAS1B,WAAW,MAAe,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAO/B,YAAY,OAAM;CAGV,MAAM,WAAW;CAGf,SAAS,GAAG,KAAK,IAAG;CAGpB,aAAa,GAAG,KAAK,IAAG;CAMxB,gBAAgB,eAC3B,KAAK,YAAW,KAAM,CAAC,CAAC,KAAK,MAAK,KAAM,KAAK,QAAO,MAAO,UAClE,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CAOkB,WAAW,eAAuC;EACnE,IAAI,KAAK,QAAO,MAAO,YAAY,KAAK,cAAa,GAAI,OAAO;EAChE,IAAI,KAAK,KAAI,GAAI,OAAO;EACxB,OAAO,SAAS,KAAK,MAAK,CAAE,IAAI,UAAU;CAC5C,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAQQ,cAAc,eAChB,KAAK,UAAS,KAAM,KAAK,QAAO,MAAO,YAAY,CAAC,KAAK,SAAQ,KAAM,CAAC,KAAK,cAAa,GACjG,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAGS,SAAM;EACd,KAAK,SAAS,IAAI,CAAC,KAAK,SAAQ,CAAE;CACpC;CAGmB,gBAAgB,eAAgB,KAAK,SAAQ,IAAK,SAAY,KAAK,UAAS,GAAI,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CAEnG,cAAA;EACE,IAAI,UAAS,GAAI;GACf,aAAY;IACV,IAAI,CAAC,KAAK,YAAW,KAAM,KAAK,QAAO,MAAO,UAAU;IACxD,IAAI,CAAC,KAAK,MAAK,GACb,QAAQ,KAAK,yDAAyD;SACjE,IAAI,KAAK,UAAS,KAAM,KAAK,KAAI,KAAM,SAAS,KAAK,MAAK,CAAE,GACjE,QAAQ,KAAK,6EAA6E;GAE9F,CAAC;GACD,aAAY;IACV,IAAI,CAAC,KAAK,SAAQ,GAAI;IACtB,IAAI,KAAK,KAAI,KAAM,SAAS,KAAK,MAAK,CAAE,GACtC,QAAQ,KAAK,kDAAkD;IAEjE,IAAI,CAAC,KAAK,MAAK,KAAM,CAAC,KAAK,UAAS,GAClC,QAAQ,KAAK,yEAAyE;GAE1F,CAAC;EACH;CACF;CAKU,cAAc,eAAc;EACpC,MAAM,UAAU;GACd;GACA,QAAQ,KAAK,QAAO;GACpB,gBAAgB,KAAK,QAAO;GAC5B,eAAe,KAAK,aAAY;EACjC;EAED,IAAI,KAAK,YAAW,GAClB,QAAQ,KAAK,gBAAgB;EAI/B,IAAI,KAAK,SAAQ,GACf,QAAQ,KAAK,aAAa;EAI5B,IAAI,KAAK,SAAQ,KAAM,KAAK,QAAO,MAAO,UACxC,QAAQ,KAAK,eAAe;EAI9B,IAAI,KAAK,cAAa,GAAI;GACxB,QAAQ,KAAK,kBAAkB;GAC/B,IAAI,CAAC,KAAK,SAAQ,GAAI,QAAQ,KAAK,gBAAgB;EACrD;EAEA,OAAO,QAAQ,KAAK,GAAG;CACzB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAKQ,OAAO,eAAgB,KAAK,YAAW,IAAK,WAAW,WAAW,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAKlE,YAAY,OAAiB;EACrC,IAAI,KAAK,YAAW,GAClB,KAAK,UAAU,KAAK,KAAK;CAE7B;CAMU,cAAc,OAAoB;EAC1C,IAAI,KAAK,YAAW,MAAO,MAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM;GACtE,MAAM,eAAc;GACpB,MAAM,aAAa,IAAI,WAAW,SAAS;IACzC,SAAS;IACT,YAAY;GACb,CAAA;GACD,KAAK,UAAU,KAAK,UAAU;EAChC;CACF;CAtTW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAa,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAb,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAa,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,cAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,cAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,cAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,cAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA;GAAA,UAAA;GAAA,WAAA;EAAA;EAAA,MAAA;GAAA,WAAA,EAAA,WAAA,wBAAA;GAAA,YAAA;IAAA,+BAAA;IAAA,4BAAA;GAAA;EAAA;EAAA,UAAA;EAAA,UCzF1B;EA8IA,QAAA,CAAA,m+OAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MD/DY;IAAa,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAgB,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAU,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;EAAA;EAAA,eAQtC,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;EAAC,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAE3C,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAa,YAAA,CAAA;EAbzB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAS,YACP;GAAI,SACP;IAAC;IAAe;IAAkB;GAAU;GAAC,iBAGrC,wBAAwB;GAAM,MACzC;IACJ,iCAAiC;IACjC,8BAA8B;GAC/B;GAAA,eACc,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;GAAC,UAAA;GAAA,QAAA,CAAA,m+OAAA;EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8SrD,MAAA;GAAa,MAAA,CAAA,WAAW,CAAC,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-card.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/card/card.component.ts","../../../../libs/angular-ui-kit/src/lib/card/card.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n model,\n output,\n HostListener,\n computed,\n effect,\n isDevMode,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { RouterLink, type Params } from '@angular/router';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_CHEVRON_DOWN } from '@lifecorner/angular-ui-kit/icons';\n\n/** Visual variant of `lc-card`. */\nexport type CardVariant = 'elevated' | 'outlined' | 'flat' | 'raised' | 'dashed';\n\n/** Heading level of `lc-card`'s built-in title. */\nexport type CardHeadingLevel = 2 | 3 | 4 | 5 | 6;\n\n/** Layout of `lc-card`'s `[card-footer]` slot: `default` (a flex row, end-aligned) or `equal` (children at equal width). */\nexport type CardFooterLayout = 'default' | 'equal';\n\n/** Counter for generated ids (3.36): creation order, so prerendered HTML is the same in every build. */\nlet nextCardId = 0;\n\n/** Whether a `route` value is a link: `''`, `null` and `undefined` are not. */\nfunction hasRoute(route: string | readonly unknown[] | null | undefined): boolean {\n return route !== '' && route !== null && route !== undefined;\n}\n\n/**\n * Card component for content grouping and visual hierarchy.\n *\n * Features:\n * - Variant styles (elevated, outlined, flat, raised, dashed)\n * - Configurable padding (none, xs, sm, md, lg)\n * - Border radius options (none, sm, md, lg, xl, full)\n * - Optional title display, with an optional leading icon tile\n * - Content projection for flexible body content\n * - Link mode (3.24): `href` or `route` make the whole card a real link,\n * the title stays a heading\n * - Equal footer (3.29): `footerLayout=\"equal\"` gives two answers of equal\n * weight in the `[card-footer]` slot the same width\n * - Collapsible (3.36): `collapsible` with `[(expanded)]` turns the head into\n * one toggle that opens and closes the body and footer\n *\n * @example\n * ```html\n * <lc-card title=\"Card Title\" variant=\"elevated\" padding=\"md\">\n * <p>Card body content</p>\n * </lc-card>\n *\n * <!-- With a leading brand-tile icon in the header -->\n * <lc-card title=\"Repository\" subtitle=\"Checkout & profile\" icon=\"git-branch\">\n * ...\n * </lc-card>\n *\n * <!-- An overview card that opens a page: heading h2 with a link inside -->\n * <lc-card title=\"SAP-Ist\" variant=\"outlined\" [headingLevel]=\"2\"\n * [route]=\"['/quellen', 'sap-ist']\" [queryParams]=\"{ ansicht: 'laeufe' }\">\n * ...\n * </lc-card>\n *\n * <!-- Two answers of equal weight (3.29): primary answer first -->\n * <lc-card title=\"Netflix\" variant=\"outlined\" footerLayout=\"equal\">\n * ...\n * <div card-footer>\n * <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"true\">Stimmt</lc-button>\n * <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"true\">Kein Vertrag</lc-button>\n * </div>\n * </lc-card>\n * ```\n */\n@Component({\n selector: 'lc-card',\n standalone: true,\n imports: [IconComponent, NgTemplateOutlet, RouterLink],\n templateUrl: './card.component.html',\n styleUrls: ['./card.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class.lc-card--footer-equal]': \"footerLayout() === 'equal'\",\n '[class.lc-card--collapsed]': 'isCollapsible() && !expanded()',\n },\n viewProviders: [ɵprovideKitIcons([ICON_CHEVRON_DOWN])],\n})\nexport class CardComponent {\n /**\n * Optional title rendered as a styled header.\n * For complex headers (e.g. title + action button), use content projection instead.\n */\n title = input<string | undefined>(undefined);\n\n /**\n * Optional subtitle rendered below the title.\n */\n subtitle = input<string | undefined>(undefined);\n\n /**\n * Optional leading icon (Tabler icon name) rendered as a teal brand tile to\n * the left of the title. Only shown when `title` is set.\n */\n icon = input<string | undefined>(undefined);\n\n /**\n * Visual treatment of the leading icon tile.\n * - brand: gradient teal tile with light ink (default)\n * - subtle: translucent surface tile with brand-teal ink\n * @default 'brand'\n */\n iconVariant = input<'brand' | 'subtle'>('brand');\n\n /**\n * Size of the leading icon tile.\n * - md: 2.25rem tile (default)\n * - sm: compact ~1.75rem chip for dense card headers\n * @default 'md'\n */\n iconSize = input<'sm' | 'md'>('md');\n\n /**\n * Optional badge text/count shown next to the title (e.g. item count).\n * For a richer status badge (e.g. a leading status dot), project an\n * `lc-badge` into the `card-badge` slot instead — the slot takes precedence.\n */\n badge = input<string | undefined>(undefined);\n\n /**\n * Badge color variant.\n * @default 'default'\n */\n badgeVariant = input<'default' | 'primary' | 'success' | 'warning' | 'error'>('default');\n\n /**\n * Visual variant of the card\n * - elevated: Box shadow (default)\n * - outlined: Border only (the hairline `--color-border`, no shadow) — the\n * content card on the \"Weite\" sky with `borderRadius=\"xl\"`\n * - flat: No shadow or border\n * - raised: plain surface, hairline border and the long, soft\n * `--shadow-auth-card`, no accent line — the sign-in card\n * - dashed: the muted \"coming soon\" tile — `--color-muted-tile` fill, 1 px\n * dashed `--color-muted-tile-border`, secondary ink, icons in\n * `--color-muted-tile-icon`. Never clickable: `clickable` is ignored;\n * `href` and `route` are ignored too\n * @default 'elevated'\n */\n variant = input<CardVariant>('elevated');\n\n /**\n * Padding inside the card\n * @default 'md'\n */\n padding = input<'none' | 'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the card is clickable (hover effects, cursor pointer). Has no\n * effect on a link card (`href`/`route`).\n * @default false\n */\n clickable = input<boolean>(false);\n\n /**\n * Whether the card is selected (if clickable)\n * @default false\n */\n selected = input<boolean>(false);\n\n /**\n * Border radius size: `none`, `sm`, `md`, `lg` (18 px), `xl` (24 px, the\n * \"Weite\" content card) or `full`.\n * @default 'md'\n */\n borderRadius = input<'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full'>('md');\n\n /**\n * Heading level of the built-in `title` (`h2`–`h6`), so the card fits the\n * page's outline. Semantics only, the look stays the same.\n * @default 3\n */\n headingLevel = input<CardHeadingLevel>(3);\n\n /**\n * Accessible name. On a link card (`href`/`route`) it names the link\n * instead of the card; it must contain the visible title (WCAG 2.5.3) and\n * the heading reads it too, so keep it short. Without it the link is named\n * by the title, and the card's content (badge, list) is read as normal\n * content. On other cards it labels the card.\n * @default undefined\n */\n ariaLabel = input<string | undefined>(undefined);\n\n /**\n * URL the card links to (3.24, quellen row 1). The card becomes a real\n * link: the built-in `title` is an `<a href>` inside its heading, and the\n * link covers the whole card (click, Enter, middle click, \"open in new\n * tab\", \"copy link\"). No router needed; works in prerendered HTML. Wins\n * over `route`. Ignored by `dashed`. On a link card `clickable` has no\n * effect and `cardClick` is not emitted.\n * @default undefined\n */\n href = input<string | undefined>(undefined);\n\n /**\n * In-app route the card links to through the Angular router (`RouterLink`\n * commands: `'/quellen/usm'` or `['/quellen', id]`), relative to the\n * consumer's route, rendered as a real `<a href>` like `href`. Needs the\n * app's router (`provideRouter`); without one, use `href`. `''` and `null`\n * mean no link.\n * @default undefined\n */\n route = input<string | readonly unknown[] | null | undefined>(undefined);\n\n /**\n * Query parameters of `route`, as `RouterLink`'s `queryParams`\n * (`{ ansicht: 'laeufe' }`). Ignored with `href` (write the query into the\n * URL).\n * @default undefined\n */\n queryParams = input<Params | null | undefined>(undefined);\n\n /**\n * Layout of the `[card-footer]` slot (3.29, CC-2). `equal`: its children\n * share the row at equal width once the card is at least 480 px (30rem)\n * wide, and stack full width, 8 px apart, below that (the card's own width,\n * at any viewport; long labels wrap inside the buttons, which get the\n * row's height). For two answers of equal weight, put\n * `<lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"true\">` in it,\n * primary answer first; the card adds layout only (gap, divider and\n * spacing as `default`) and never restyles the buttons. The card becomes a\n * size container and takes its parent's full width. Keep the default\n * `padding` (with `none` the buttons' focus ring is clipped). Works in link\n * cards (the buttons stay clickable above the link) and in prerendered\n * HTML (CSS only).\n * @default 'default'\n */\n footerLayout = input<CardFooterLayout>('default');\n\n /**\n * The card can close (3.36, regeln row 1): the head (icon, title, subtitle)\n * becomes one toggle, a button inside the title's heading with\n * `aria-expanded` and `aria-controls`, whose hit area is the whole head (at\n * least 44 px high); Enter, Space or a click open and close the body and the\n * `[card-footer]`. A chevron at the end of the head shows the state.\n * `[card-header-action]` stays a separate control beside it. Needs the\n * built-in `title` (otherwise ignored); wins over `clickable`, `href` and\n * `route`, which are then ignored; ignored on `dashed`. Bind `[(expanded)]`.\n * @default false\n */\n collapsible = input<boolean>(false);\n\n /**\n * Open state of a `collapsible` card (3.36), two-way: `[(expanded)]`. Open\n * by default, so a plain `collapsible` hides nothing; set `false` for a card\n * that starts closed (also in prerendered HTML). Closed, only the head\n * shows: the body is `hidden` and the footer is not displayed.\n * @default true\n */\n readonly expanded = model<boolean>(true);\n\n /**\n * Emitted when a `clickable` card is clicked or activated with Enter or\n * Space. Not emitted on a link card (`href`/`route`): the link navigates by\n * itself (one navigation); bind the native `(click)` for analytics.\n */\n readonly cardClick = output<MouseEvent>();\n\n /** Generated id prefix (3.36): creation order, so prerendered HTML is the same in every build. */\n private readonly uid = `lc-card-${nextCardId++}`;\n\n /** Id of the body a collapsible card's toggle controls. */\n protected readonly bodyId = `${this.uid}-body`;\n\n /** Id of the subtitle that describes a collapsible card's toggle. */\n protected readonly subtitleId = `${this.uid}-subtitle`;\n\n /**\n * Whether the card collapses (3.36): `collapsible` with a built-in title,\n * except for the dashed tile.\n */\n protected readonly isCollapsible = computed(\n () => this.collapsible() && !!this.title() && this.variant() !== 'dashed',\n );\n\n /**\n * How the card links (3.24): `href` wins over `route`; `''`/`null` routes\n * are no link, and the dashed \"coming soon\" tile never links. A\n * collapsible card (3.36) never links.\n */\n protected readonly linkMode = computed<'href' | 'route' | null>(() => {\n if (this.variant() === 'dashed' || this.isCollapsible()) return null;\n if (this.href()) return 'href';\n return hasRoute(this.route()) ? 'route' : null;\n });\n\n /**\n * Whether the card acts as a button: `clickable`, except for the dashed\n * \"coming soon\" tile, which is never interactive, a link card, whose\n * anchor is the only interactive element, and a collapsible card (3.36),\n * whose toggle is.\n */\n protected isClickable = computed(\n () => this.clickable() && this.variant() !== 'dashed' && !this.linkMode() && !this.isCollapsible(),\n );\n\n /** Opens or closes a collapsible card; `expandedChange` emits the new state. */\n protected toggle(): void {\n this.expanded.set(!this.expanded());\n }\n\n /** `ariaLabel` on the card; on a link card it names the anchor instead. */\n protected readonly cardAriaLabel = computed(() => (this.linkMode() ? undefined : this.ariaLabel()));\n\n constructor() {\n if (isDevMode()) {\n effect(() => {\n if (!this.collapsible() || this.variant() === 'dashed') return;\n if (!this.title()) {\n console.warn('[lc-card] collapsible needs the built-in title: ignored');\n } else if (this.clickable() || this.href() || hasRoute(this.route())) {\n console.warn('[lc-card] collapsible wins over clickable, href and route: they are ignored');\n }\n });\n effect(() => {\n if (!this.linkMode()) return;\n if (this.href() && hasRoute(this.route())) {\n console.warn('[lc-card] href and route are both set: href wins');\n }\n if (!this.title() && !this.ariaLabel()) {\n console.warn('[lc-card] a link card without title needs an ariaLabel to name its link');\n }\n });\n }\n }\n\n /**\n * Compute card CSS classes based on inputs\n */\n protected cardClasses = computed(() => {\n const classes = [\n 'card',\n `card-${this.variant()}`,\n `card-padding-${this.padding()}`,\n `card-radius-${this.borderRadius()}`,\n ];\n\n if (this.isClickable()) {\n classes.push('card-clickable');\n }\n\n // A link card looks and reacts like a clickable one (3.24).\n if (this.linkMode()) {\n classes.push('card-linked');\n }\n\n // The dashed tile is never interactive, so it is never selected either.\n if (this.selected() && this.variant() !== 'dashed') {\n classes.push('card-selected');\n }\n\n // A collapsible card (3.36), and its closed state.\n if (this.isCollapsible()) {\n classes.push('card-collapsible');\n if (!this.expanded()) classes.push('card-collapsed');\n }\n\n return classes.join(' ');\n });\n\n /**\n * Compute ARIA role based on clickable state\n */\n protected role = computed(() => (this.isClickable() ? 'button' : 'article'));\n\n /**\n * Handle card click events\n */\n protected handleClick(event: MouseEvent): void {\n if (this.isClickable()) {\n this.cardClick.emit(event);\n }\n }\n\n /**\n * Handle keyboard events for accessibility\n */\n @HostListener('keydown', ['$event'])\n protected handleKeydown(event: KeyboardEvent): void {\n if (this.isClickable() && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n const mouseEvent = new MouseEvent('click', {\n bubbles: true,\n cancelable: true,\n });\n this.cardClick.emit(mouseEvent);\n }\n }\n}\n","<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- Enter/Space are handled by the host keydown listener (role=button, tabindex=0 when clickable) -->\n<div\n [class]=\"cardClasses()\"\n [attr.role]=\"role()\"\n [attr.aria-label]=\"cardAriaLabel()\"\n [attr.tabindex]=\"isClickable() ? 0 : null\"\n (click)=\"handleClick($event)\"\n>\n @if (linkMode() && !title()) {\n <!-- Link card without a title (3.24): an empty anchor, named by ariaLabel, covers the card. -->\n <ng-container [ngTemplateOutlet]=\"cardLink\" [ngTemplateOutletContext]=\"{ bare: true }\" />\n }\n @if (title()) {\n <div class=\"card__header\">\n @if (icon()) {\n <div\n class=\"card__icon card__icon--{{ iconVariant() }} card__icon--size-{{ iconSize() }}\"\n aria-hidden=\"true\"\n >\n <lc-icon [name]=\"icon()!\" [size]=\"iconSize() === 'sm' ? 'xs' : 'sm'\" [decorative]=\"true\" />\n </div>\n }\n <div class=\"card__header-left\">\n <div class=\"card__title-row\">\n <!-- 3.38 (request 058, 057-s1): the &ngsp; spaces of this template put\n word breaks between the card's parts in its text (textContent,\n accessible name, copy), so title, badge, subtitle, body and footer\n don't run together. Each sits between flex items, where a\n whitespace-only run renders nothing; none is inside .card__title,\n the toggle, the link or the :empty badge slot. The one after the\n title ends each branch: right after an @if chain Angular drops a\n whitespace-only text while it looks for @else. -->\n @if (isCollapsible()) {\n <!-- Collapsible card (3.36): the heading stays a heading and holds the toggle. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardToggle\" /></h3>\n }\n }&ngsp;\n } @else if (linkMode()) {\n <!-- Link card (3.24): the heading stays a heading and holds the link. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h2>\n }\n @case (4) {\n <h4 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h4>\n }\n @case (5) {\n <h5 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h5>\n }\n @case (6) {\n <h6 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h6>\n }\n @default {\n <h3 class=\"card__title\"><ng-container [ngTemplateOutlet]=\"cardLink\" /></h3>\n }\n }&ngsp;\n } @else {\n @switch (headingLevel()) {\n @case (2) {\n <h2 class=\"card__title\">{{ title() }}</h2>\n }\n @case (4) {\n <h4 class=\"card__title\">{{ title() }}</h4>\n }\n @case (5) {\n <h5 class=\"card__title\">{{ title() }}</h5>\n }\n @case (6) {\n <h6 class=\"card__title\">{{ title() }}</h6>\n }\n @default {\n <h3 class=\"card__title\">{{ title() }}</h3>\n }\n }&ngsp;\n }\n <!-- Rich status badge: project an lc-badge here (takes visual\n precedence over the `badge` string). Wrapper hides when empty. -->\n <span class=\"card__badge-slot\"><ng-content select=\"[card-badge]\"></ng-content></span>&ngsp;\n @if (badge()) {\n <span class=\"card__badge card__badge--{{ badgeVariant() }}\">{{ badge() }}</span>&ngsp;\n }\n </div>\n @if (subtitle()) {\n <p class=\"card__subtitle\" [attr.id]=\"isCollapsible() ? subtitleId : null\">{{ subtitle() }}</p>\n }\n </div>&ngsp;\n <div class=\"card__header-action\">\n <ng-content select=\"[card-header-action]\"></ng-content>\n </div>\n @if (isCollapsible()) {\n <lc-icon name=\"chevron-down\" class=\"card__chevron\" size=\"sm\" [decorative]=\"true\" />\n }\n </div>&ngsp;\n }\n <ng-content select=\"[card-header]\"></ng-content>&ngsp;\n <div\n class=\"card__body\"\n [attr.id]=\"isCollapsible() ? bodyId : null\"\n [attr.hidden]=\"isCollapsible() && !expanded() ? '' : null\"\n >\n <ng-content></ng-content>\n </div>&ngsp;\n <ng-content select=\"[card-footer]\"></ng-content>\n</div>\n\n<!-- The toggle of a collapsible card (3.36): a button inside the heading,\n named by the title and described by the subtitle. Its ::after covers the\n head, so the icon tile, subtitle and chevron toggle too. -->\n<ng-template #cardToggle>\n <button\n type=\"button\"\n class=\"card__toggle\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-controls]=\"bodyId\"\n [attr.aria-describedby]=\"subtitle() ? subtitleId : null\"\n (click)=\"toggle()\"\n >{{ title() }}</button>\n</ng-template>\n\n<!-- The link of a link card (3.24): `href` (plain, no router) or `route`\n (RouterLink, created only here, so other cards never need a router).\n Its ::after covers the card. -->\n<ng-template #cardLink let-bare=\"bare\">\n @if (linkMode() === 'href') {\n <a class=\"card__link\" [class.card__link--bare]=\"bare\" [href]=\"href()\" [attr.aria-label]=\"ariaLabel()\">{{ bare ? '' : title() }}</a>\n } @else {\n <a\n class=\"card__link\"\n [class.card__link--bare]=\"bare\"\n [routerLink]=\"route()\"\n [queryParams]=\"queryParams()\"\n [attr.aria-label]=\"ariaLabel()\"\n >{{ bare ? '' : title() }}</a\n >\n }\n</ng-template>\n"],"mappings":"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"}
|
|
@@ -110,8 +110,8 @@ var DescriptionListComponent = class DescriptionListComponent {
|
|
|
110
110
|
},
|
|
111
111
|
outputs: { itemClick: "itemClick" },
|
|
112
112
|
ngImport: i0,
|
|
113
|
-
template: "<dl [class]=\"hostClasses()\">\n @for (item of items(); track item.term; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -- the row stays a dt/dd group (F-17): its button is the focusable control, and its click and keys bubble here -->\n <div\n class=\"lc-dl__row\"\n [class.lc-dl__row--clickable]=\"clickable()\"\n [class.lc-dl__row--total]=\"!!item.total\"\n (click)=\"itemClick.emit(item)\"\n (keydown)=\"onRowKeydown($event, item)\"\n >\n <dt class=\"lc-dl__term\" [attr.id]=\"clickable() ? termId(i) : null\">@if (item.total && totalPrefix()) {<span class=\"lc-dl__sr-only\">{{ totalPrefix() }}</span
|
|
114
|
-
styles: [":host{display:block}.lc-dl{margin:0}.lc-dl__row{display:flex;align-items:baseline;gap:var(--spacing-2)}.lc-dl__row--clickable{position:relative;cursor:pointer;border-radius:var(--border-radius-sm)}.lc-dl__row--clickable:hover{background:var(--color-surface-hover)}.lc-dl__action{position:absolute;inset:0;margin:0;padding:0;border:0;background:none;border-radius:var(--border-radius-sm);pointer-events:none}.lc-dl__action:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-dl__term{margin:0;flex-shrink:0;color:var(--color-text-secondary);font-weight:var(--font-weight-medium)}.lc-dl__leader{flex:1 1 auto;align-self:center;min-width:var(--spacing-4)}.lc-dl__value{margin:0;flex:0 1 auto;min-width:0;overflow-wrap:anywhere;text-align:right;color:var(--color-text-primary);font-weight:var(--font-weight-medium);font-variant-numeric:tabular-nums}.lc-dl__value--muted{color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__value--strong{color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__value--primary{color:var(--color-on-primary-subtle);font-weight:var(--font-weight-semibold)}.lc-dl__value--mono{font-family:var(--font-family-mono);font-variant-numeric:normal}.lc-dl__value-suffix{margin-left:.375rem;color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__link{color:var(--color-link);text-decoration:none}.lc-dl__link:hover{color:var(--color-link-hover);text-decoration:underline}.lc-dl__link:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-dl--rows .lc-dl__row{padding-block:var(--spacing-2)}.lc-dl--rows .lc-dl__term,.lc-dl--rows .lc-dl__value{flex:1000000 1 0%;max-width:max-content}.lc-dl--rows .lc-dl__term{min-width:0;overflow-wrap:break-word}.lc-dl--rows.lc-dl--sep-line .lc-dl__row,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom:1px solid var(--color-divider)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row:last-child,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row:last-child{border-bottom:0}.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom-style:dashed}.lc-dl--leaders .lc-dl__leader{border-bottom:1px dotted var(--color-border-strong);transform:translateY(-.15em)}@supports (margin-block-start: 1lh){.lc-dl--leaders .lc-dl__leader{align-self:flex-start;margin-block-start:calc(.5lh - .5px)}}.lc-dl--stacked .lc-dl__row{flex-direction:column;align-items:stretch;gap:var(--spacing-1);padding-block:var(--spacing-2)}.lc-dl--stacked .lc-dl__leader{display:none}.lc-dl--stacked .lc-dl__value{text-align:left}.lc-dl--sm{font-size:var(--font-size-xs)}.lc-dl--sm .lc-dl__row{padding-block:var(--spacing-1)}.lc-dl--md{font-size:var(--font-size-sm)}.lc-dl--rows .lc-dl__row.lc-dl__row--clickable{padding-block:max(var(--spacing-2),(var(--size-min-touch-height) - 1lh) / 2)}.lc-dl--rows.lc-dl--sm .lc-dl__row.lc-dl__row--clickable{padding-block:max(var(--spacing-1),(var(--size-min-touch-height) - 1lh) / 2)}@media(forced-colors:active){.lc-dl__action:focus-visible{outline-color:Highlight}}@media(forced-colors:active){.lc-dl__link:focus-visible{outline-color:Highlight}}lc-badge.lc-dl__badge{display:inline-flex;margin-block:calc((1lh - 1.5rem)/2)}.lc-dl--sm lc-badge.lc-dl__badge{margin-block:calc((1lh - 1.25rem)/2)}.lc-dl__badge--after-value{margin-inline-start:var(--spacing-1-5)}.lc-dl .lc-dl__row--total{border-top:1px solid var(--color-field-border);border-bottom:3px double var(--color-field-border)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row.lc-dl__row--total,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row.lc-dl__row--total{margin-top:-1px;border-bottom:3px double var(--color-field-border)}.lc-dl__row--total .lc-dl__term{position:relative;color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"],
|
|
113
|
+
template: "<dl [class]=\"hostClasses()\">\n @for (item of items(); track item.term; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -- the row stays a dt/dd group (F-17): its button is the focusable control, and its click and keys bubble here -->\n <div\n class=\"lc-dl__row\"\n [class.lc-dl__row--clickable]=\"clickable()\"\n [class.lc-dl__row--total]=\"!!item.total\"\n (click)=\"itemClick.emit(item)\"\n (keydown)=\"onRowKeydown($event, item)\"\n >\n <!-- 3.37 (request 057, regeln row 1, D-4): the &ngsp; spaces put word breaks into the text (textContent, names, copy); in the flex row they render nothing. -->\n <dt class=\"lc-dl__term\" [attr.id]=\"clickable() ? termId(i) : null\">@if (item.total && totalPrefix()) {<span class=\"lc-dl__sr-only\">{{ totalPrefix() }}</span>&ngsp;}{{ item.term }}</dt>&ngsp;<span class=\"lc-dl__leader\" aria-hidden=\"true\"></span>&ngsp;<dd [class]=\"valueClass(item)\" [attr.id]=\"clickable() ? valueId(i) : null\">\n @if (item.badge) {\n <!-- 3.36: the value as a badge; another value stays as text before it (D-2). -->\n @if (badgeShowsValue(item)) {\n @if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n <span class=\"lc-dl__badge-value\">{{ item.value }}</span>\n }\n }\n <lc-badge\n class=\"lc-dl__badge\"\n [class.lc-dl__badge--after-value]=\"badgeShowsValue(item)\"\n [size]=\"size() === 'sm' ? 'xs' : 'sm'\"\n [rounded]=\"true\"\n [variant]=\"item.badgeVariant ?? 'default'\"\n >&ngsp;{{ item.badge }}</lc-badge\n >\n } @else if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n {{ item.value }}\n }\n @if (item.valueSuffix) {\n @if (item.badge || item.href || item.datetime) {\n <!-- After a link, a time or a badge the suffix had no space before it; this one renders 0 px wide. -->\n <span class=\"lc-dl__sep\">&ngsp;</span>\n }\n <span class=\"lc-dl__value-suffix\">{{ item.valueSuffix }}</span>\n }\n @if (clickable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content -- named by aria-labelledby (the row's term and value); text inside would repeat the value -->\n <button\n type=\"button\"\n class=\"lc-dl__action\"\n [attr.aria-labelledby]=\"termId(i) + ' ' + valueId(i)\"\n ></button>\n }\n </dd>\n </div>&ngsp;\n }\n</dl>\n",
|
|
114
|
+
styles: [":host{display:block}.lc-dl{margin:0}.lc-dl__row{display:flex;align-items:baseline;gap:var(--spacing-2)}.lc-dl__row--clickable{position:relative;cursor:pointer;border-radius:var(--border-radius-sm)}.lc-dl__row--clickable:hover{background:var(--color-surface-hover)}.lc-dl__action{position:absolute;inset:0;margin:0;padding:0;border:0;background:none;border-radius:var(--border-radius-sm);pointer-events:none}.lc-dl__action:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-dl__term{margin:0;flex-shrink:0;color:var(--color-text-secondary);font-weight:var(--font-weight-medium)}.lc-dl__leader{flex:1 1 auto;align-self:center;min-width:var(--spacing-4)}.lc-dl__value{margin:0;flex:0 1 auto;min-width:0;overflow-wrap:anywhere;text-align:right;color:var(--color-text-primary);font-weight:var(--font-weight-medium);font-variant-numeric:tabular-nums}.lc-dl__value--muted{color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__value--strong{color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__value--primary{color:var(--color-on-primary-subtle);font-weight:var(--font-weight-semibold)}.lc-dl__value--mono{font-family:var(--font-family-mono);font-variant-numeric:normal}.lc-dl__value-suffix{margin-left:.375rem;color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__link{color:var(--color-link);text-decoration:none}.lc-dl__link:hover{color:var(--color-link-hover);text-decoration:underline}.lc-dl__link:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-dl--rows .lc-dl__row{padding-block:var(--spacing-2)}.lc-dl--rows .lc-dl__term,.lc-dl--rows .lc-dl__value{flex:1000000 1 0%;max-width:max-content}.lc-dl--rows .lc-dl__term{min-width:0;overflow-wrap:break-word}.lc-dl--rows.lc-dl--sep-line .lc-dl__row,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom:1px solid var(--color-divider)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row:last-child,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row:last-child{border-bottom:0}.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom-style:dashed}.lc-dl--leaders .lc-dl__leader{border-bottom:1px dotted var(--color-border-strong);transform:translateY(-.15em)}@supports (margin-block-start: 1lh){.lc-dl--leaders .lc-dl__leader{align-self:flex-start;margin-block-start:calc(.5lh - .5px)}}.lc-dl--stacked .lc-dl__row{flex-direction:column;align-items:stretch;gap:var(--spacing-1);padding-block:var(--spacing-2)}.lc-dl--stacked .lc-dl__leader{display:none}.lc-dl--stacked .lc-dl__value{text-align:left}.lc-dl--sm{font-size:var(--font-size-xs)}.lc-dl--sm .lc-dl__row{padding-block:var(--spacing-1)}.lc-dl--md{font-size:var(--font-size-sm)}.lc-dl--rows .lc-dl__row.lc-dl__row--clickable{padding-block:max(var(--spacing-2),(var(--size-min-touch-height) - 1lh) / 2)}.lc-dl--rows.lc-dl--sm .lc-dl__row.lc-dl__row--clickable{padding-block:max(var(--spacing-1),(var(--size-min-touch-height) - 1lh) / 2)}@media(forced-colors:active){.lc-dl__action:focus-visible{outline-color:Highlight}}@media(forced-colors:active){.lc-dl__link:focus-visible{outline-color:Highlight}}lc-badge.lc-dl__badge{display:inline-flex;margin-block:calc((1lh - 1.5rem)/2)}.lc-dl--sm lc-badge.lc-dl__badge{margin-block:calc((1lh - 1.25rem)/2)}.lc-dl__badge--after-value{margin-inline-start:var(--spacing-1-5)}.lc-dl .lc-dl__row--total{border-top:1px solid var(--color-field-border);border-bottom:3px double var(--color-field-border)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row.lc-dl__row--total,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row.lc-dl__row--total{margin-top:-1px;border-bottom:3px double var(--color-field-border)}.lc-dl__row--total .lc-dl__term{position:relative;color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.lc-dl__sep{font-size:0}\n"],
|
|
115
115
|
dependencies: [{
|
|
116
116
|
kind: "component",
|
|
117
117
|
type: BadgeComponent,
|
|
@@ -139,8 +139,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
139
139
|
standalone: true,
|
|
140
140
|
imports: [BadgeComponent],
|
|
141
141
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
142
|
-
template: "<dl [class]=\"hostClasses()\">\n @for (item of items(); track item.term; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -- the row stays a dt/dd group (F-17): its button is the focusable control, and its click and keys bubble here -->\n <div\n class=\"lc-dl__row\"\n [class.lc-dl__row--clickable]=\"clickable()\"\n [class.lc-dl__row--total]=\"!!item.total\"\n (click)=\"itemClick.emit(item)\"\n (keydown)=\"onRowKeydown($event, item)\"\n >\n <dt class=\"lc-dl__term\" [attr.id]=\"clickable() ? termId(i) : null\">@if (item.total && totalPrefix()) {<span class=\"lc-dl__sr-only\">{{ totalPrefix() }}</span
|
|
143
|
-
styles: [":host{display:block}.lc-dl{margin:0}.lc-dl__row{display:flex;align-items:baseline;gap:var(--spacing-2)}.lc-dl__row--clickable{position:relative;cursor:pointer;border-radius:var(--border-radius-sm)}.lc-dl__row--clickable:hover{background:var(--color-surface-hover)}.lc-dl__action{position:absolute;inset:0;margin:0;padding:0;border:0;background:none;border-radius:var(--border-radius-sm);pointer-events:none}.lc-dl__action:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-dl__term{margin:0;flex-shrink:0;color:var(--color-text-secondary);font-weight:var(--font-weight-medium)}.lc-dl__leader{flex:1 1 auto;align-self:center;min-width:var(--spacing-4)}.lc-dl__value{margin:0;flex:0 1 auto;min-width:0;overflow-wrap:anywhere;text-align:right;color:var(--color-text-primary);font-weight:var(--font-weight-medium);font-variant-numeric:tabular-nums}.lc-dl__value--muted{color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__value--strong{color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__value--primary{color:var(--color-on-primary-subtle);font-weight:var(--font-weight-semibold)}.lc-dl__value--mono{font-family:var(--font-family-mono);font-variant-numeric:normal}.lc-dl__value-suffix{margin-left:.375rem;color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__link{color:var(--color-link);text-decoration:none}.lc-dl__link:hover{color:var(--color-link-hover);text-decoration:underline}.lc-dl__link:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-dl--rows .lc-dl__row{padding-block:var(--spacing-2)}.lc-dl--rows .lc-dl__term,.lc-dl--rows .lc-dl__value{flex:1000000 1 0%;max-width:max-content}.lc-dl--rows .lc-dl__term{min-width:0;overflow-wrap:break-word}.lc-dl--rows.lc-dl--sep-line .lc-dl__row,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom:1px solid var(--color-divider)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row:last-child,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row:last-child{border-bottom:0}.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom-style:dashed}.lc-dl--leaders .lc-dl__leader{border-bottom:1px dotted var(--color-border-strong);transform:translateY(-.15em)}@supports (margin-block-start: 1lh){.lc-dl--leaders .lc-dl__leader{align-self:flex-start;margin-block-start:calc(.5lh - .5px)}}.lc-dl--stacked .lc-dl__row{flex-direction:column;align-items:stretch;gap:var(--spacing-1);padding-block:var(--spacing-2)}.lc-dl--stacked .lc-dl__leader{display:none}.lc-dl--stacked .lc-dl__value{text-align:left}.lc-dl--sm{font-size:var(--font-size-xs)}.lc-dl--sm .lc-dl__row{padding-block:var(--spacing-1)}.lc-dl--md{font-size:var(--font-size-sm)}.lc-dl--rows .lc-dl__row.lc-dl__row--clickable{padding-block:max(var(--spacing-2),(var(--size-min-touch-height) - 1lh) / 2)}.lc-dl--rows.lc-dl--sm .lc-dl__row.lc-dl__row--clickable{padding-block:max(var(--spacing-1),(var(--size-min-touch-height) - 1lh) / 2)}@media(forced-colors:active){.lc-dl__action:focus-visible{outline-color:Highlight}}@media(forced-colors:active){.lc-dl__link:focus-visible{outline-color:Highlight}}lc-badge.lc-dl__badge{display:inline-flex;margin-block:calc((1lh - 1.5rem)/2)}.lc-dl--sm lc-badge.lc-dl__badge{margin-block:calc((1lh - 1.25rem)/2)}.lc-dl__badge--after-value{margin-inline-start:var(--spacing-1-5)}.lc-dl .lc-dl__row--total{border-top:1px solid var(--color-field-border);border-bottom:3px double var(--color-field-border)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row.lc-dl__row--total,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row.lc-dl__row--total{margin-top:-1px;border-bottom:3px double var(--color-field-border)}.lc-dl__row--total .lc-dl__term{position:relative;color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n"]
|
|
142
|
+
template: "<dl [class]=\"hostClasses()\">\n @for (item of items(); track item.term; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -- the row stays a dt/dd group (F-17): its button is the focusable control, and its click and keys bubble here -->\n <div\n class=\"lc-dl__row\"\n [class.lc-dl__row--clickable]=\"clickable()\"\n [class.lc-dl__row--total]=\"!!item.total\"\n (click)=\"itemClick.emit(item)\"\n (keydown)=\"onRowKeydown($event, item)\"\n >\n <!-- 3.37 (request 057, regeln row 1, D-4): the &ngsp; spaces put word breaks into the text (textContent, names, copy); in the flex row they render nothing. -->\n <dt class=\"lc-dl__term\" [attr.id]=\"clickable() ? termId(i) : null\">@if (item.total && totalPrefix()) {<span class=\"lc-dl__sr-only\">{{ totalPrefix() }}</span>&ngsp;}{{ item.term }}</dt>&ngsp;<span class=\"lc-dl__leader\" aria-hidden=\"true\"></span>&ngsp;<dd [class]=\"valueClass(item)\" [attr.id]=\"clickable() ? valueId(i) : null\">\n @if (item.badge) {\n <!-- 3.36: the value as a badge; another value stays as text before it (D-2). -->\n @if (badgeShowsValue(item)) {\n @if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n <span class=\"lc-dl__badge-value\">{{ item.value }}</span>\n }\n }\n <lc-badge\n class=\"lc-dl__badge\"\n [class.lc-dl__badge--after-value]=\"badgeShowsValue(item)\"\n [size]=\"size() === 'sm' ? 'xs' : 'sm'\"\n [rounded]=\"true\"\n [variant]=\"item.badgeVariant ?? 'default'\"\n >&ngsp;{{ item.badge }}</lc-badge\n >\n } @else if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n {{ item.value }}\n }\n @if (item.valueSuffix) {\n @if (item.badge || item.href || item.datetime) {\n <!-- After a link, a time or a badge the suffix had no space before it; this one renders 0 px wide. -->\n <span class=\"lc-dl__sep\">&ngsp;</span>\n }\n <span class=\"lc-dl__value-suffix\">{{ item.valueSuffix }}</span>\n }\n @if (clickable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content -- named by aria-labelledby (the row's term and value); text inside would repeat the value -->\n <button\n type=\"button\"\n class=\"lc-dl__action\"\n [attr.aria-labelledby]=\"termId(i) + ' ' + valueId(i)\"\n ></button>\n }\n </dd>\n </div>&ngsp;\n }\n</dl>\n",
|
|
143
|
+
styles: [":host{display:block}.lc-dl{margin:0}.lc-dl__row{display:flex;align-items:baseline;gap:var(--spacing-2)}.lc-dl__row--clickable{position:relative;cursor:pointer;border-radius:var(--border-radius-sm)}.lc-dl__row--clickable:hover{background:var(--color-surface-hover)}.lc-dl__action{position:absolute;inset:0;margin:0;padding:0;border:0;background:none;border-radius:var(--border-radius-sm);pointer-events:none}.lc-dl__action:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-dl__term{margin:0;flex-shrink:0;color:var(--color-text-secondary);font-weight:var(--font-weight-medium)}.lc-dl__leader{flex:1 1 auto;align-self:center;min-width:var(--spacing-4)}.lc-dl__value{margin:0;flex:0 1 auto;min-width:0;overflow-wrap:anywhere;text-align:right;color:var(--color-text-primary);font-weight:var(--font-weight-medium);font-variant-numeric:tabular-nums}.lc-dl__value--muted{color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__value--strong{color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__value--primary{color:var(--color-on-primary-subtle);font-weight:var(--font-weight-semibold)}.lc-dl__value--mono{font-family:var(--font-family-mono);font-variant-numeric:normal}.lc-dl__value-suffix{margin-left:.375rem;color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__link{color:var(--color-link);text-decoration:none}.lc-dl__link:hover{color:var(--color-link-hover);text-decoration:underline}.lc-dl__link:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-dl--rows .lc-dl__row{padding-block:var(--spacing-2)}.lc-dl--rows .lc-dl__term,.lc-dl--rows .lc-dl__value{flex:1000000 1 0%;max-width:max-content}.lc-dl--rows .lc-dl__term{min-width:0;overflow-wrap:break-word}.lc-dl--rows.lc-dl--sep-line .lc-dl__row,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom:1px solid var(--color-divider)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row:last-child,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row:last-child{border-bottom:0}.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom-style:dashed}.lc-dl--leaders .lc-dl__leader{border-bottom:1px dotted var(--color-border-strong);transform:translateY(-.15em)}@supports (margin-block-start: 1lh){.lc-dl--leaders .lc-dl__leader{align-self:flex-start;margin-block-start:calc(.5lh - .5px)}}.lc-dl--stacked .lc-dl__row{flex-direction:column;align-items:stretch;gap:var(--spacing-1);padding-block:var(--spacing-2)}.lc-dl--stacked .lc-dl__leader{display:none}.lc-dl--stacked .lc-dl__value{text-align:left}.lc-dl--sm{font-size:var(--font-size-xs)}.lc-dl--sm .lc-dl__row{padding-block:var(--spacing-1)}.lc-dl--md{font-size:var(--font-size-sm)}.lc-dl--rows .lc-dl__row.lc-dl__row--clickable{padding-block:max(var(--spacing-2),(var(--size-min-touch-height) - 1lh) / 2)}.lc-dl--rows.lc-dl--sm .lc-dl__row.lc-dl__row--clickable{padding-block:max(var(--spacing-1),(var(--size-min-touch-height) - 1lh) / 2)}@media(forced-colors:active){.lc-dl__action:focus-visible{outline-color:Highlight}}@media(forced-colors:active){.lc-dl__link:focus-visible{outline-color:Highlight}}lc-badge.lc-dl__badge{display:inline-flex;margin-block:calc((1lh - 1.5rem)/2)}.lc-dl--sm lc-badge.lc-dl__badge{margin-block:calc((1lh - 1.25rem)/2)}.lc-dl__badge--after-value{margin-inline-start:var(--spacing-1-5)}.lc-dl .lc-dl__row--total{border-top:1px solid var(--color-field-border);border-bottom:3px double var(--color-field-border)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row.lc-dl__row--total,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row.lc-dl__row--total{margin-top:-1px;border-bottom:3px double var(--color-field-border)}.lc-dl__row--total .lc-dl__term{position:relative;color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.lc-dl__sep{font-size:0}\n"]
|
|
144
144
|
}]
|
|
145
145
|
}],
|
|
146
146
|
propDecorators: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-description-list.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/description-list/description-list.component.ts","../../../../libs/angular-ui-kit/src/lib/description-list/description-list.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n output,\n computed,\n} from '@angular/core';\nimport { BadgeComponent, type BadgeVariant } from '@lifecorner/angular-ui-kit/badge';\n\n/**\n * Emphasis treatment applied to a row's value.\n * - `mono` renders the value in the monospace font (paths, URLs, hashes).\n */\nexport type DescriptionListEmphasis =\n | 'default'\n | 'strong'\n | 'muted'\n | 'primary'\n | 'mono';\n\nexport interface DescriptionListItem {\n /** Label shown on the term side of the row. */\n term: string;\n /** Value shown on the description side of the row. */\n value: string;\n /**\n * Optional qualifying suffix appended after the value on the same line and\n * rendered muted (e.g. a rating grade or \"last checked\" hint). Wraps if the\n * combined value + suffix exceed the available width.\n */\n valueSuffix?: string;\n /** Optional link — renders the value as an anchor. */\n href?: string;\n /**\n * Machine-readable date or time of the value (ISO 8601, e.g.\n * `2026-10-12T18:05:00+02:00`): renders the value inside\n * `<time datetime>`, so assistive tech and parsers get the exact moment\n * behind „heute 18:05“. Ignored together with `href`.\n */\n datetime?: string;\n /** Optional visual emphasis for the value. @default 'default' */\n emphasis?: DescriptionListEmphasis;\n /**\n * Shows the value as an `lc-badge` (3.36, quellen row 2): rounded, `sm` in\n * an md list, `xs` in an sm list. A `value` that is empty or the same word\n * (trimmed, any case) is not shown; another value stays as text before the\n * badge („1“ [Freigegeben]), and `href` or `datetime` wrap that text only.\n * Term and value stay one `dt`/`dd` pair, read as „term, badge“.\n */\n badge?: string;\n /** Variant of the `badge`, as `lc-badge`. @default 'default' */\n badgeVariant?: BadgeVariant;\n /**\n * The sum item (3.36, app-shell row 2): a rule above and a double rule\n * below (`--color-field-border`), term and value semibold with tabular\n * figures; its `emphasis` is ignored. `totalAriaLabel` is read before its\n * term. Usually the last item.\n * @default false\n */\n total?: boolean;\n /** Optional opaque payload echoed back in `itemClick`. */\n id?: string;\n}\n\nexport type DescriptionListLayout = 'rows' | 'stacked';\nexport type DescriptionListSize = 'sm' | 'md';\n\n/**\n * Per-row separator style (applies to the `rows` layout).\n * - `line` solid hairline under each row (default — unchanged look)\n * - `divider` subtle dashed line, for the dense card look\n * - `none` no row separator\n *\n * Orthogonal to `leaders`, which draws dotted leaders *between* term and value.\n */\nexport type DescriptionListSeparator = 'line' | 'divider' | 'none';\n\n/** Counter for generated ids: they follow creation order, so prerendered HTML is the same in every build. */\nlet nextUniqueId = 0;\n\n/**\n * Description list for key/value metadata (a styled `<dl>`).\n *\n * Features:\n * - `rows` layout: term on the left, value on the right, with an optional\n * dotted leader line connecting them (the DS2.0 \"spec sheet\" look).\n * - `rows`: a row that is too narrow is shared — term and value each keep\n * their width up to half of the free width (row − 32 px); the longer one\n * wraps in the rest: the term at spaces, the value at spaces or inside an\n * unbroken string (3.26).\n * - `stacked` layout: term above value, for narrow columns.\n * - Per-row value emphasis and optional links.\n * - Semantic markup (`<dl>`/`<dt>`/`<dd>`) for accessibility; `clickable`\n * rows hold a native button (named by term and value) that the keyboard\n * reaches, and the `dl` keeps its term and value pairs.\n * - 3.36: an item's value as a badge (`badge`, `badgeVariant`), and a sum\n * item (`total`) with ledger rules, announced with `totalAriaLabel`.\n *\n * @example\n * ```html\n * <lc-description-list\n * [items]=\"[\n * { term: 'Repository', value: 'example/project', href: '#', emphasis: 'primary' },\n * { term: 'Access', value: 'Token stored · read only' },\n * { term: 'Status', value: 'Maintained', emphasis: 'strong' }\n * ]\"\n * [leaders]=\"true\" />\n * ```\n */\n@Component({\n selector: 'lc-description-list',\n standalone: true,\n imports: [BadgeComponent],\n templateUrl: './description-list.component.html',\n styleUrls: ['./description-list.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DescriptionListComponent {\n /** Rows to render. */\n readonly items = input.required<readonly DescriptionListItem[]>();\n\n /**\n * Row layout.\n * - rows: term left / value right (default)\n * - stacked: term above value\n * @default 'rows'\n */\n readonly layout = input<DescriptionListLayout>('rows');\n\n /**\n * Draw a dotted leader line between term and value. Only applies to the\n * `rows` layout.\n * @default false\n */\n readonly leaders = input<boolean>(false);\n\n /** Density of the rows. @default 'md' */\n readonly size = input<DescriptionListSize>('md');\n\n /**\n * Per-row separator style for the `rows` layout. Defaults to `line`, which is\n * identical to the previous behavior. Orthogonal to `leaders`.\n * @default 'line'\n */\n readonly separator = input<DescriptionListSeparator>('line');\n\n /**\n * Whether rows are interactive. When set, each row holds a native button,\n * named by its term and value, that Tab reaches; Enter, Space and a click\n * anywhere on the row emit `itemClick`. The `dl` keeps its term and value\n * pairs. Set this whenever you handle `itemClick`.\n * @default false\n */\n readonly clickable = input<boolean>(false);\n\n /**\n * Read before the term of a `total` item and not shown (3.36, app-shell\n * row 2): „Summe“ makes a screen reader read „Summe, Gesamtkosten Ist,\n * 522.530,00 €“. Empty adds nothing.\n * @default ''\n */\n readonly totalAriaLabel = input<string>('');\n\n /** Emitted when a row is clicked (or activated via keyboard when `clickable`). */\n readonly itemClick = output<DescriptionListItem>();\n\n /** The visually hidden start of a total's term: „Summe, “ (3.36). */\n protected readonly totalPrefix = computed(() => {\n const label = this.totalAriaLabel().trim();\n return label ? `${label}, ` : '';\n });\n\n /**\n * Whether a badge item also shows its `value` as text (3.36, D-2): not when\n * it is empty or the badge's word.\n */\n protected badgeShowsValue(item: DescriptionListItem): boolean {\n const value = (item.value ?? '').trim();\n return value !== '' && value.toLowerCase() !== (item.badge ?? '').trim().toLowerCase();\n }\n\n /** Generated id prefix, taken once per instance, so later ids don't shift. */\n private readonly uid = `lc-dl-${nextUniqueId++}`;\n\n /** Id of row `index`'s term (only rendered when `clickable`). */\n protected termId(index: number): string {\n return `${this.uid}-t${index}`;\n }\n\n /** Id of row `index`'s value (only rendered when `clickable`). */\n protected valueId(index: number): string {\n return `${this.uid}-v${index}`;\n }\n\n protected readonly hostClasses = computed(() =>\n [\n 'lc-dl',\n `lc-dl--${this.layout()}`,\n `lc-dl--${this.size()}`,\n `lc-dl--sep-${this.separator()}`,\n this.leaders() && this.layout() === 'rows' ? 'lc-dl--leaders' : '',\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n protected valueClass(item: DescriptionListItem): string {\n // A total is always strong (3.36): its `emphasis` is ignored.\n return `lc-dl__value lc-dl__value--${item.total ? 'strong' : (item.emphasis ?? 'default')}`;\n }\n\n /**\n * Keydown dispatched on the row itself (a consumer's test, a script). Keys\n * from the row's button or a nested link are theirs: the button's native\n * activation clicks it, and the click bubbles to the row.\n */\n protected onRowKeydown(event: KeyboardEvent, item: DescriptionListItem): void {\n if (event.target !== event.currentTarget) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.itemClick.emit(item);\n }\n }\n}\n","<dl [class]=\"hostClasses()\">\n @for (item of items(); track item.term; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -- the row stays a dt/dd group (F-17): its button is the focusable control, and its click and keys bubble here -->\n <div\n class=\"lc-dl__row\"\n [class.lc-dl__row--clickable]=\"clickable()\"\n [class.lc-dl__row--total]=\"!!item.total\"\n (click)=\"itemClick.emit(item)\"\n (keydown)=\"onRowKeydown($event, item)\"\n >\n <dt class=\"lc-dl__term\" [attr.id]=\"clickable() ? termId(i) : null\">@if (item.total && totalPrefix()) {<span class=\"lc-dl__sr-only\">{{ totalPrefix() }}</span>}{{ item.term }}</dt>\n <span class=\"lc-dl__leader\" aria-hidden=\"true\"></span>\n <dd [class]=\"valueClass(item)\" [attr.id]=\"clickable() ? valueId(i) : null\">\n @if (item.badge) {\n <!-- 3.36: the value as a badge; another value stays as text before it (D-2). -->\n @if (badgeShowsValue(item)) {\n @if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n <span class=\"lc-dl__badge-value\">{{ item.value }}</span>\n }\n }\n <lc-badge\n class=\"lc-dl__badge\"\n [class.lc-dl__badge--after-value]=\"badgeShowsValue(item)\"\n [size]=\"size() === 'sm' ? 'xs' : 'sm'\"\n [rounded]=\"true\"\n [variant]=\"item.badgeVariant ?? 'default'\"\n >{{ item.badge }}</lc-badge\n >\n } @else if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n {{ item.value }}\n }\n @if (item.valueSuffix) {\n <span class=\"lc-dl__value-suffix\">{{ item.valueSuffix }}</span>\n }\n @if (clickable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content -- named by aria-labelledby (the row's term and value); text inside would repeat the value -->\n <button\n type=\"button\"\n class=\"lc-dl__action\"\n [attr.aria-labelledby]=\"termId(i) + ' ' + valueId(i)\"\n ></button>\n }\n </dd>\n </div>\n }\n</dl>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-description-list.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/description-list/description-list.component.ts","../../../../libs/angular-ui-kit/src/lib/description-list/description-list.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n output,\n computed,\n} from '@angular/core';\nimport { BadgeComponent, type BadgeVariant } from '@lifecorner/angular-ui-kit/badge';\n\n/**\n * Emphasis treatment applied to a row's value.\n * - `mono` renders the value in the monospace font (paths, URLs, hashes).\n */\nexport type DescriptionListEmphasis =\n | 'default'\n | 'strong'\n | 'muted'\n | 'primary'\n | 'mono';\n\nexport interface DescriptionListItem {\n /** Label shown on the term side of the row. */\n term: string;\n /** Value shown on the description side of the row. */\n value: string;\n /**\n * Optional qualifying suffix appended after the value on the same line and\n * rendered muted (e.g. a rating grade or \"last checked\" hint). Wraps if the\n * combined value + suffix exceed the available width.\n */\n valueSuffix?: string;\n /** Optional link — renders the value as an anchor. */\n href?: string;\n /**\n * Machine-readable date or time of the value (ISO 8601, e.g.\n * `2026-10-12T18:05:00+02:00`): renders the value inside\n * `<time datetime>`, so assistive tech and parsers get the exact moment\n * behind „heute 18:05“. Ignored together with `href`.\n */\n datetime?: string;\n /** Optional visual emphasis for the value. @default 'default' */\n emphasis?: DescriptionListEmphasis;\n /**\n * Shows the value as an `lc-badge` (3.36, quellen row 2): rounded, `sm` in\n * an md list, `xs` in an sm list. A `value` that is empty or the same word\n * (trimmed, any case) is not shown; another value stays as text before the\n * badge („1“ [Freigegeben]), and `href` or `datetime` wrap that text only.\n * Term and value stay one `dt`/`dd` pair, read as „term, badge“.\n */\n badge?: string;\n /** Variant of the `badge`, as `lc-badge`. @default 'default' */\n badgeVariant?: BadgeVariant;\n /**\n * The sum item (3.36, app-shell row 2): a rule above and a double rule\n * below (`--color-field-border`), term and value semibold with tabular\n * figures; its `emphasis` is ignored. `totalAriaLabel` is read before its\n * term. Usually the last item.\n * @default false\n */\n total?: boolean;\n /** Optional opaque payload echoed back in `itemClick`. */\n id?: string;\n}\n\nexport type DescriptionListLayout = 'rows' | 'stacked';\nexport type DescriptionListSize = 'sm' | 'md';\n\n/**\n * Per-row separator style (applies to the `rows` layout).\n * - `line` solid hairline under each row (default — unchanged look)\n * - `divider` subtle dashed line, for the dense card look\n * - `none` no row separator\n *\n * Orthogonal to `leaders`, which draws dotted leaders *between* term and value.\n */\nexport type DescriptionListSeparator = 'line' | 'divider' | 'none';\n\n/** Counter for generated ids: they follow creation order, so prerendered HTML is the same in every build. */\nlet nextUniqueId = 0;\n\n/**\n * Description list for key/value metadata (a styled `<dl>`).\n *\n * Features:\n * - `rows` layout: term on the left, value on the right, with an optional\n * dotted leader line connecting them (the DS2.0 \"spec sheet\" look).\n * - `rows`: a row that is too narrow is shared — term and value each keep\n * their width up to half of the free width (row − 32 px); the longer one\n * wraps in the rest: the term at spaces, the value at spaces or inside an\n * unbroken string (3.26).\n * - `stacked` layout: term above value, for narrow columns.\n * - Per-row value emphasis and optional links.\n * - Semantic markup (`<dl>`/`<dt>`/`<dd>`) for accessibility; `clickable`\n * rows hold a native button (named by term and value) that the keyboard\n * reaches, and the `dl` keeps its term and value pairs.\n * - 3.36: an item's value as a badge (`badge`, `badgeVariant`), and a sum\n * item (`total`) with ledger rules, announced with `totalAriaLabel`.\n *\n * @example\n * ```html\n * <lc-description-list\n * [items]=\"[\n * { term: 'Repository', value: 'example/project', href: '#', emphasis: 'primary' },\n * { term: 'Access', value: 'Token stored · read only' },\n * { term: 'Status', value: 'Maintained', emphasis: 'strong' }\n * ]\"\n * [leaders]=\"true\" />\n * ```\n */\n@Component({\n selector: 'lc-description-list',\n standalone: true,\n imports: [BadgeComponent],\n templateUrl: './description-list.component.html',\n styleUrls: ['./description-list.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DescriptionListComponent {\n /** Rows to render. */\n readonly items = input.required<readonly DescriptionListItem[]>();\n\n /**\n * Row layout.\n * - rows: term left / value right (default)\n * - stacked: term above value\n * @default 'rows'\n */\n readonly layout = input<DescriptionListLayout>('rows');\n\n /**\n * Draw a dotted leader line between term and value. Only applies to the\n * `rows` layout.\n * @default false\n */\n readonly leaders = input<boolean>(false);\n\n /** Density of the rows. @default 'md' */\n readonly size = input<DescriptionListSize>('md');\n\n /**\n * Per-row separator style for the `rows` layout. Defaults to `line`, which is\n * identical to the previous behavior. Orthogonal to `leaders`.\n * @default 'line'\n */\n readonly separator = input<DescriptionListSeparator>('line');\n\n /**\n * Whether rows are interactive. When set, each row holds a native button,\n * named by its term and value, that Tab reaches; Enter, Space and a click\n * anywhere on the row emit `itemClick`. The `dl` keeps its term and value\n * pairs. Set this whenever you handle `itemClick`.\n * @default false\n */\n readonly clickable = input<boolean>(false);\n\n /**\n * Read before the term of a `total` item and not shown (3.36, app-shell\n * row 2): „Summe“ makes a screen reader read „Summe, Gesamtkosten Ist,\n * 522.530,00 €“. Empty adds nothing.\n * @default ''\n */\n readonly totalAriaLabel = input<string>('');\n\n /** Emitted when a row is clicked (or activated via keyboard when `clickable`). */\n readonly itemClick = output<DescriptionListItem>();\n\n /** The visually hidden start of a total's term: „Summe, “ (3.36). */\n protected readonly totalPrefix = computed(() => {\n const label = this.totalAriaLabel().trim();\n return label ? `${label}, ` : '';\n });\n\n /**\n * Whether a badge item also shows its `value` as text (3.36, D-2): not when\n * it is empty or the badge's word.\n */\n protected badgeShowsValue(item: DescriptionListItem): boolean {\n const value = (item.value ?? '').trim();\n return value !== '' && value.toLowerCase() !== (item.badge ?? '').trim().toLowerCase();\n }\n\n /** Generated id prefix, taken once per instance, so later ids don't shift. */\n private readonly uid = `lc-dl-${nextUniqueId++}`;\n\n /** Id of row `index`'s term (only rendered when `clickable`). */\n protected termId(index: number): string {\n return `${this.uid}-t${index}`;\n }\n\n /** Id of row `index`'s value (only rendered when `clickable`). */\n protected valueId(index: number): string {\n return `${this.uid}-v${index}`;\n }\n\n protected readonly hostClasses = computed(() =>\n [\n 'lc-dl',\n `lc-dl--${this.layout()}`,\n `lc-dl--${this.size()}`,\n `lc-dl--sep-${this.separator()}`,\n this.leaders() && this.layout() === 'rows' ? 'lc-dl--leaders' : '',\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n protected valueClass(item: DescriptionListItem): string {\n // A total is always strong (3.36): its `emphasis` is ignored.\n return `lc-dl__value lc-dl__value--${item.total ? 'strong' : (item.emphasis ?? 'default')}`;\n }\n\n /**\n * Keydown dispatched on the row itself (a consumer's test, a script). Keys\n * from the row's button or a nested link are theirs: the button's native\n * activation clicks it, and the click bubbles to the row.\n */\n protected onRowKeydown(event: KeyboardEvent, item: DescriptionListItem): void {\n if (event.target !== event.currentTarget) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.itemClick.emit(item);\n }\n }\n}\n","<dl [class]=\"hostClasses()\">\n @for (item of items(); track item.term; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -- the row stays a dt/dd group (F-17): its button is the focusable control, and its click and keys bubble here -->\n <div\n class=\"lc-dl__row\"\n [class.lc-dl__row--clickable]=\"clickable()\"\n [class.lc-dl__row--total]=\"!!item.total\"\n (click)=\"itemClick.emit(item)\"\n (keydown)=\"onRowKeydown($event, item)\"\n >\n <!-- 3.37 (request 057, regeln row 1, D-4): the &ngsp; spaces put word breaks into the text (textContent, names, copy); in the flex row they render nothing. -->\n <dt class=\"lc-dl__term\" [attr.id]=\"clickable() ? termId(i) : null\">@if (item.total && totalPrefix()) {<span class=\"lc-dl__sr-only\">{{ totalPrefix() }}</span>&ngsp;}{{ item.term }}</dt>&ngsp;<span class=\"lc-dl__leader\" aria-hidden=\"true\"></span>&ngsp;<dd [class]=\"valueClass(item)\" [attr.id]=\"clickable() ? valueId(i) : null\">\n @if (item.badge) {\n <!-- 3.36: the value as a badge; another value stays as text before it (D-2). -->\n @if (badgeShowsValue(item)) {\n @if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n <span class=\"lc-dl__badge-value\">{{ item.value }}</span>\n }\n }\n <lc-badge\n class=\"lc-dl__badge\"\n [class.lc-dl__badge--after-value]=\"badgeShowsValue(item)\"\n [size]=\"size() === 'sm' ? 'xs' : 'sm'\"\n [rounded]=\"true\"\n [variant]=\"item.badgeVariant ?? 'default'\"\n >&ngsp;{{ item.badge }}</lc-badge\n >\n } @else if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n {{ item.value }}\n }\n @if (item.valueSuffix) {\n @if (item.badge || item.href || item.datetime) {\n <!-- After a link, a time or a badge the suffix had no space before it; this one renders 0 px wide. -->\n <span class=\"lc-dl__sep\">&ngsp;</span>\n }\n <span class=\"lc-dl__value-suffix\">{{ item.valueSuffix }}</span>\n }\n @if (clickable()) {\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content -- named by aria-labelledby (the row's term and value); text inside would repeat the value -->\n <button\n type=\"button\"\n class=\"lc-dl__action\"\n [attr.aria-labelledby]=\"termId(i) + ' ' + valueId(i)\"\n ></button>\n }\n </dd>\n </div>&ngsp;\n }\n</dl>\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
-
import { ChangeDetectionStrategy, Component, computed, input, viewChild } from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, booleanAttribute, computed, input, viewChild } from "@angular/core";
|
|
3
3
|
let nextHeroId = 0;
|
|
4
4
|
var HeroComponent = class HeroComponent {
|
|
5
5
|
label = input(void 0, ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
@@ -10,6 +10,10 @@ var HeroComponent = class HeroComponent {
|
|
|
10
10
|
variant = input("default", ...ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []);
|
|
11
11
|
contentWidth = input("full", ...ngDevMode ? [{ debugName: "contentWidth" }] : /* istanbul ignore next */ []);
|
|
12
12
|
headingLevel = input(1, ...ngDevMode ? [{ debugName: "headingLevel" }] : /* istanbul ignore next */ []);
|
|
13
|
+
fill = input(false, {
|
|
14
|
+
...ngDevMode ? { debugName: "fill" } : /* istanbul ignore next */ {},
|
|
15
|
+
transform: booleanAttribute
|
|
16
|
+
});
|
|
13
17
|
titleEl = viewChild("titleEl", ...ngDevMode ? [{ debugName: "titleEl" }] : /* istanbul ignore next */ []);
|
|
14
18
|
labelEl = viewChild("labelEl", ...ngDevMode ? [{ debugName: "labelEl" }] : /* istanbul ignore next */ []);
|
|
15
19
|
focusTitle() {
|
|
@@ -104,8 +108,16 @@ var HeroComponent = class HeroComponent {
|
|
|
104
108
|
isSignal: true,
|
|
105
109
|
isRequired: false,
|
|
106
110
|
transformFunction: null
|
|
111
|
+
},
|
|
112
|
+
fill: {
|
|
113
|
+
classPropertyName: "fill",
|
|
114
|
+
publicName: "fill",
|
|
115
|
+
isSignal: true,
|
|
116
|
+
isRequired: false,
|
|
117
|
+
transformFunction: null
|
|
107
118
|
}
|
|
108
119
|
},
|
|
120
|
+
host: { properties: { "class.lc-hero--fill": "fill()" } },
|
|
109
121
|
viewQueries: [{
|
|
110
122
|
propertyName: "titleEl",
|
|
111
123
|
first: true,
|
|
@@ -121,7 +133,7 @@ var HeroComponent = class HeroComponent {
|
|
|
121
133
|
}],
|
|
122
134
|
ngImport: i0,
|
|
123
135
|
template: "<div [class]=\"heroClasses()\">\n <div class=\"hero__inner\">\n <div class=\"hero__content\">\n @if (label()) {\n <span #labelEl class=\"hero__label\">{{ label() }}</span>\n }\n <!-- 3.36: the element follows `headingLevel`; the look is the same at every level. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 #titleEl class=\"hero__title\">{{ title() }}</h2>\n }\n @case (3) {\n <h3 #titleEl class=\"hero__title\">{{ title() }}</h3>\n }\n @case (4) {\n <h4 #titleEl class=\"hero__title\">{{ title() }}</h4>\n }\n @case (5) {\n <h5 #titleEl class=\"hero__title\">{{ title() }}</h5>\n }\n @case (6) {\n <h6 #titleEl class=\"hero__title\">{{ title() }}</h6>\n }\n @default {\n <h1 #titleEl class=\"hero__title\">{{ title() }}</h1>\n }\n }\n <div class=\"hero__body\">\n <ng-content></ng-content>\n </div>\n </div>\n <div class=\"hero__media\">\n <ng-content select=\"[hero-media]\"></ng-content>\n </div>\n </div>\n <ng-content select=\"[hero-footer]\"></ng-content>\n</div>\n",
|
|
124
|
-
styles: [":host{display:block;width:100%}.hero{position:relative;display:flex;flex-direction:column;justify-content:space-between;color:#fff;overflow:hidden}.hero--primary{background:linear-gradient(135deg,#0d353d,#
|
|
136
|
+
styles: [":host{display:block;width:100%}:host(.lc-hero--fill){display:flex;flex-direction:column}:host(.lc-hero--fill)>.hero{flex:1 1 auto}:host(.lc-hero--fill) .hero__inner{align-content:start}.hero{position:relative;display:flex;flex-direction:column;justify-content:space-between;color:#fff;overflow:hidden}.hero--primary{background:linear-gradient(135deg,#0d353d,#1f8092)}.hero--secondary{background:linear-gradient(135deg,#2d3c46,#5a798c)}.hero--neutral{background:linear-gradient(135deg,#111827,#4b5563)}.hero--success{background:linear-gradient(135deg,#46543b,#697957)}.hero--info{background:linear-gradient(135deg,#27445c,#3b6588)}.hero--warning{background:linear-gradient(135deg,#68481d,#9b6b2b)}.hero--accent-orange{background:linear-gradient(135deg,#7a3a10,#b06024)}.hero--accent-purple{background:linear-gradient(135deg,#3a2a52,#866aa0)}.hero--accent-violet{background:linear-gradient(135deg,#221a42,#4e3f84)}.hero--sm{padding:1.5rem 1.25rem}@media(min-width:640px){.hero--sm{padding:2rem}}@media(min-width:1024px){.hero--sm{padding:2.5rem 3rem}}.hero--md{padding:2rem 1.25rem}@media(min-width:640px){.hero--md{padding:2.5rem 2rem}}@media(min-width:1024px){.hero--md{padding:3rem 3.5rem}}.hero--lg{padding:2.5rem 1.25rem}@media(min-width:640px){.hero--lg{padding:3rem 2.5rem}}@media(min-width:1024px){.hero--lg{padding:4rem}}.hero--radius-none{border-radius:var(--border-radius-none)}.hero--radius-sm{border-radius:var(--border-radius-sm)}.hero--radius-md{border-radius:var(--border-radius-md)}.hero--radius-lg{border-radius:var(--border-radius-lg)}.hero--slim{padding:1rem 1.25rem!important}@media(min-width:640px){.hero--slim{padding:1.25rem 2rem!important}}@media(min-width:1024px){.hero--slim{padding:1.5rem 3rem!important}}.hero--slim .hero__title{font-size:1.125rem!important;font-weight:700;line-height:1.3}@media(min-width:640px){.hero--slim .hero__title{font-size:1.25rem!important}}@media(min-width:1024px){.hero--slim .hero__title{font-size:1.5rem!important}}.hero--slim .hero__label{font-size:.5625rem;margin-bottom:.375rem;letter-spacing:.12em}@media(min-width:640px){.hero--slim .hero__label{font-size:.625rem;margin-bottom:.5rem}}.hero--slim .hero__body{margin-top:.5rem;font-size:.8125rem}@media(min-width:640px){.hero--slim .hero__body{font-size:.875rem;margin-top:.625rem}}.hero--slim ::ng-deep [hero-footer]{margin-top:1rem;padding-top:.75rem}@media(min-width:640px){.hero--slim ::ng-deep [hero-footer]{margin-top:1.25rem}}.hero--light{color:#1f2937}.hero--light .hero__label{opacity:.7}.hero--light .hero__body{color:#1f2937bf}.hero--light ::ng-deep [hero-footer]{border-top-color:#0000001f}.hero--light.hero--primary{background:linear-gradient(135deg,#dbeafe,#eff6ff)}.hero--light.hero--secondary{background:linear-gradient(135deg,#e0e7ff,#eef2ff)}.hero--light.hero--neutral{background:linear-gradient(135deg,#e5e7eb,#f9fafb)}.hero--light.hero--success{background:linear-gradient(135deg,#d1fae5,#ecfdf5)}.hero--light.hero--info{background:linear-gradient(135deg,#dbeafe,#eff6ff)}.hero--light.hero--warning{background:linear-gradient(135deg,#fef3c7,#fffbeb)}.hero--light.hero--accent-orange{background:linear-gradient(135deg,#ffedd5,#fff7ed)}.hero--light.hero--accent-purple{background:linear-gradient(135deg,#e9d5ff,#f5f3ff)}.hero--light.hero--accent-violet{background:linear-gradient(135deg,#ddd6fe,#ede9fe)}@media(min-width:1024px){.hero--content-lg.hero--sm{padding-inline:max(3rem,(100% - 1024px) / 2 + 3rem)}.hero--content-lg.hero--md{padding-inline:max(3.5rem,(100% - 1024px) / 2 + 3rem)}.hero--content-lg.hero--lg{padding-inline:max(4rem,(100% - 1024px) / 2 + 3rem)}.hero--content-lg.hero--slim{padding-inline:max(3rem,(100% - 1024px) / 2 + 3rem)!important}}.hero__inner{flex:1}.hero__content{min-width:0}.hero__label{display:inline-block;font-size:.6875rem;font-weight:600;letter-spacing:.15em;text-transform:uppercase;margin-bottom:.75rem}@media(min-width:640px){.hero__label{font-size:.75rem;margin-bottom:1rem}}.hero__title{margin:0;font-weight:800;line-height:1.1;color:inherit}.hero--sm .hero__title{font-size:1.5rem}@media(min-width:640px){.hero--sm .hero__title{font-size:1.75rem}}@media(min-width:1024px){.hero--sm .hero__title{font-size:2rem}}.hero--md .hero__title{font-size:1.75rem}@media(min-width:640px){.hero--md .hero__title{font-size:2.25rem}}@media(min-width:1024px){.hero--md .hero__title{font-size:2.75rem}}.hero--lg .hero__title{font-size:2rem}@media(min-width:640px){.hero--lg .hero__title{font-size:2.75rem}}@media(min-width:1024px){.hero--lg .hero__title{font-size:3.5rem}}.hero__title:focus-visible{outline:2px solid currentColor;outline-offset:2px;box-shadow:0 0 0 2px #111827;border-radius:var(--border-radius-sm)}.hero--light .hero__title:focus-visible{box-shadow:0 0 0 2px #fff}@media(forced-colors:active){.hero__title:focus-visible{outline-color:Highlight;box-shadow:none}}.hero__body{margin-top:1rem;font-size:.875rem;line-height:1.6;max-width:48rem}@media(min-width:640px){.hero__body{font-size:1rem;margin-top:1.25rem}}@media(min-width:1024px){.hero__body{font-size:1.125rem;margin-top:1.5rem}}.hero__body:empty{display:none}.hero__media{max-width:var(--lc-hero-media-width, 23rem);margin-top:2rem;padding-top:1.5rem;border-top:1px solid rgba(255,255,255,.2)}@media(min-width:640px){.hero__media{margin-top:2.5rem}}.hero__media:empty{display:none}.hero--slim .hero__media{margin-top:1rem;padding-top:.75rem}@media(min-width:640px){.hero--slim .hero__media{margin-top:1.25rem}}.hero--light .hero__media{border-top-color:#0000001f}@media(min-width:1024px){.hero__inner:has(>.hero__media:not(:empty)){display:grid;grid-template-columns:minmax(0,1fr) var(--lc-hero-media-width, 23rem);column-gap:3.5rem;align-items:center}.hero__inner:has(>.hero__media:not(:empty))>.hero__media{max-width:none;margin-top:0;padding-top:0;border-top:0}}:host ::ng-deep [hero-footer]{display:grid;grid-template-columns:1fr;gap:1rem;margin-top:2rem;padding-top:1.5rem;border-top:1px solid rgba(255,255,255,.2)}@media(min-width:640px){:host ::ng-deep [hero-footer]{grid-template-columns:repeat(2,1fr);margin-top:2.5rem}}@media(min-width:1024px){:host ::ng-deep [hero-footer]{grid-template-columns:repeat(auto-fit,minmax(10rem,1fr));margin-top:3rem}}\n"],
|
|
125
137
|
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
126
138
|
});
|
|
127
139
|
};
|
|
@@ -136,8 +148,9 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
136
148
|
selector: "lc-hero",
|
|
137
149
|
standalone: true,
|
|
138
150
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
151
|
+
host: { "[class.lc-hero--fill]": "fill()" },
|
|
139
152
|
template: "<div [class]=\"heroClasses()\">\n <div class=\"hero__inner\">\n <div class=\"hero__content\">\n @if (label()) {\n <span #labelEl class=\"hero__label\">{{ label() }}</span>\n }\n <!-- 3.36: the element follows `headingLevel`; the look is the same at every level. -->\n @switch (headingLevel()) {\n @case (2) {\n <h2 #titleEl class=\"hero__title\">{{ title() }}</h2>\n }\n @case (3) {\n <h3 #titleEl class=\"hero__title\">{{ title() }}</h3>\n }\n @case (4) {\n <h4 #titleEl class=\"hero__title\">{{ title() }}</h4>\n }\n @case (5) {\n <h5 #titleEl class=\"hero__title\">{{ title() }}</h5>\n }\n @case (6) {\n <h6 #titleEl class=\"hero__title\">{{ title() }}</h6>\n }\n @default {\n <h1 #titleEl class=\"hero__title\">{{ title() }}</h1>\n }\n }\n <div class=\"hero__body\">\n <ng-content></ng-content>\n </div>\n </div>\n <div class=\"hero__media\">\n <ng-content select=\"[hero-media]\"></ng-content>\n </div>\n </div>\n <ng-content select=\"[hero-footer]\"></ng-content>\n</div>\n",
|
|
140
|
-
styles: [":host{display:block;width:100%}.hero{position:relative;display:flex;flex-direction:column;justify-content:space-between;color:#fff;overflow:hidden}.hero--primary{background:linear-gradient(135deg,#0d353d,#
|
|
153
|
+
styles: [":host{display:block;width:100%}:host(.lc-hero--fill){display:flex;flex-direction:column}:host(.lc-hero--fill)>.hero{flex:1 1 auto}:host(.lc-hero--fill) .hero__inner{align-content:start}.hero{position:relative;display:flex;flex-direction:column;justify-content:space-between;color:#fff;overflow:hidden}.hero--primary{background:linear-gradient(135deg,#0d353d,#1f8092)}.hero--secondary{background:linear-gradient(135deg,#2d3c46,#5a798c)}.hero--neutral{background:linear-gradient(135deg,#111827,#4b5563)}.hero--success{background:linear-gradient(135deg,#46543b,#697957)}.hero--info{background:linear-gradient(135deg,#27445c,#3b6588)}.hero--warning{background:linear-gradient(135deg,#68481d,#9b6b2b)}.hero--accent-orange{background:linear-gradient(135deg,#7a3a10,#b06024)}.hero--accent-purple{background:linear-gradient(135deg,#3a2a52,#866aa0)}.hero--accent-violet{background:linear-gradient(135deg,#221a42,#4e3f84)}.hero--sm{padding:1.5rem 1.25rem}@media(min-width:640px){.hero--sm{padding:2rem}}@media(min-width:1024px){.hero--sm{padding:2.5rem 3rem}}.hero--md{padding:2rem 1.25rem}@media(min-width:640px){.hero--md{padding:2.5rem 2rem}}@media(min-width:1024px){.hero--md{padding:3rem 3.5rem}}.hero--lg{padding:2.5rem 1.25rem}@media(min-width:640px){.hero--lg{padding:3rem 2.5rem}}@media(min-width:1024px){.hero--lg{padding:4rem}}.hero--radius-none{border-radius:var(--border-radius-none)}.hero--radius-sm{border-radius:var(--border-radius-sm)}.hero--radius-md{border-radius:var(--border-radius-md)}.hero--radius-lg{border-radius:var(--border-radius-lg)}.hero--slim{padding:1rem 1.25rem!important}@media(min-width:640px){.hero--slim{padding:1.25rem 2rem!important}}@media(min-width:1024px){.hero--slim{padding:1.5rem 3rem!important}}.hero--slim .hero__title{font-size:1.125rem!important;font-weight:700;line-height:1.3}@media(min-width:640px){.hero--slim .hero__title{font-size:1.25rem!important}}@media(min-width:1024px){.hero--slim .hero__title{font-size:1.5rem!important}}.hero--slim .hero__label{font-size:.5625rem;margin-bottom:.375rem;letter-spacing:.12em}@media(min-width:640px){.hero--slim .hero__label{font-size:.625rem;margin-bottom:.5rem}}.hero--slim .hero__body{margin-top:.5rem;font-size:.8125rem}@media(min-width:640px){.hero--slim .hero__body{font-size:.875rem;margin-top:.625rem}}.hero--slim ::ng-deep [hero-footer]{margin-top:1rem;padding-top:.75rem}@media(min-width:640px){.hero--slim ::ng-deep [hero-footer]{margin-top:1.25rem}}.hero--light{color:#1f2937}.hero--light .hero__label{opacity:.7}.hero--light .hero__body{color:#1f2937bf}.hero--light ::ng-deep [hero-footer]{border-top-color:#0000001f}.hero--light.hero--primary{background:linear-gradient(135deg,#dbeafe,#eff6ff)}.hero--light.hero--secondary{background:linear-gradient(135deg,#e0e7ff,#eef2ff)}.hero--light.hero--neutral{background:linear-gradient(135deg,#e5e7eb,#f9fafb)}.hero--light.hero--success{background:linear-gradient(135deg,#d1fae5,#ecfdf5)}.hero--light.hero--info{background:linear-gradient(135deg,#dbeafe,#eff6ff)}.hero--light.hero--warning{background:linear-gradient(135deg,#fef3c7,#fffbeb)}.hero--light.hero--accent-orange{background:linear-gradient(135deg,#ffedd5,#fff7ed)}.hero--light.hero--accent-purple{background:linear-gradient(135deg,#e9d5ff,#f5f3ff)}.hero--light.hero--accent-violet{background:linear-gradient(135deg,#ddd6fe,#ede9fe)}@media(min-width:1024px){.hero--content-lg.hero--sm{padding-inline:max(3rem,(100% - 1024px) / 2 + 3rem)}.hero--content-lg.hero--md{padding-inline:max(3.5rem,(100% - 1024px) / 2 + 3rem)}.hero--content-lg.hero--lg{padding-inline:max(4rem,(100% - 1024px) / 2 + 3rem)}.hero--content-lg.hero--slim{padding-inline:max(3rem,(100% - 1024px) / 2 + 3rem)!important}}.hero__inner{flex:1}.hero__content{min-width:0}.hero__label{display:inline-block;font-size:.6875rem;font-weight:600;letter-spacing:.15em;text-transform:uppercase;margin-bottom:.75rem}@media(min-width:640px){.hero__label{font-size:.75rem;margin-bottom:1rem}}.hero__title{margin:0;font-weight:800;line-height:1.1;color:inherit}.hero--sm .hero__title{font-size:1.5rem}@media(min-width:640px){.hero--sm .hero__title{font-size:1.75rem}}@media(min-width:1024px){.hero--sm .hero__title{font-size:2rem}}.hero--md .hero__title{font-size:1.75rem}@media(min-width:640px){.hero--md .hero__title{font-size:2.25rem}}@media(min-width:1024px){.hero--md .hero__title{font-size:2.75rem}}.hero--lg .hero__title{font-size:2rem}@media(min-width:640px){.hero--lg .hero__title{font-size:2.75rem}}@media(min-width:1024px){.hero--lg .hero__title{font-size:3.5rem}}.hero__title:focus-visible{outline:2px solid currentColor;outline-offset:2px;box-shadow:0 0 0 2px #111827;border-radius:var(--border-radius-sm)}.hero--light .hero__title:focus-visible{box-shadow:0 0 0 2px #fff}@media(forced-colors:active){.hero__title:focus-visible{outline-color:Highlight;box-shadow:none}}.hero__body{margin-top:1rem;font-size:.875rem;line-height:1.6;max-width:48rem}@media(min-width:640px){.hero__body{font-size:1rem;margin-top:1.25rem}}@media(min-width:1024px){.hero__body{font-size:1.125rem;margin-top:1.5rem}}.hero__body:empty{display:none}.hero__media{max-width:var(--lc-hero-media-width, 23rem);margin-top:2rem;padding-top:1.5rem;border-top:1px solid rgba(255,255,255,.2)}@media(min-width:640px){.hero__media{margin-top:2.5rem}}.hero__media:empty{display:none}.hero--slim .hero__media{margin-top:1rem;padding-top:.75rem}@media(min-width:640px){.hero--slim .hero__media{margin-top:1.25rem}}.hero--light .hero__media{border-top-color:#0000001f}@media(min-width:1024px){.hero__inner:has(>.hero__media:not(:empty)){display:grid;grid-template-columns:minmax(0,1fr) var(--lc-hero-media-width, 23rem);column-gap:3.5rem;align-items:center}.hero__inner:has(>.hero__media:not(:empty))>.hero__media{max-width:none;margin-top:0;padding-top:0;border-top:0}}:host ::ng-deep [hero-footer]{display:grid;grid-template-columns:1fr;gap:1rem;margin-top:2rem;padding-top:1.5rem;border-top:1px solid rgba(255,255,255,.2)}@media(min-width:640px){:host ::ng-deep [hero-footer]{grid-template-columns:repeat(2,1fr);margin-top:2.5rem}}@media(min-width:1024px){:host ::ng-deep [hero-footer]{grid-template-columns:repeat(auto-fit,minmax(10rem,1fr));margin-top:3rem}}\n"]
|
|
141
154
|
}]
|
|
142
155
|
}],
|
|
143
156
|
propDecorators: {
|
|
@@ -205,6 +218,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
205
218
|
required: false
|
|
206
219
|
}]
|
|
207
220
|
}],
|
|
221
|
+
fill: [{
|
|
222
|
+
type: i0.Input,
|
|
223
|
+
args: [{
|
|
224
|
+
isSignal: true,
|
|
225
|
+
alias: "fill",
|
|
226
|
+
required: false
|
|
227
|
+
}]
|
|
228
|
+
}],
|
|
208
229
|
titleEl: [{
|
|
209
230
|
type: i0.ViewChild,
|
|
210
231
|
args: ["titleEl", { isSignal: true }]
|