@lifecorner/angular-ui-kit 3.36.0 → 3.37.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-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 +18 -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
|
@@ -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,#208497)}.hero--secondary{background:linear-gradient(135deg,#2d3c46,#7097af)}.hero--neutral{background:linear-gradient(135deg,#111827,#4b5563)}.hero--success{background:linear-gradient(135deg,#5f7150,#8ea475)}.hero--info{background:linear-gradient(135deg,#27445c,#3b6588)}.hero--warning{background:linear-gradient(135deg,#9b6b2b,#e1a040)}.hero--accent-orange{background:linear-gradient(135deg,#7a3a10,#df792e)}.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{
|
|
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,#208497)}.hero--secondary{background:linear-gradient(135deg,#2d3c46,#7097af)}.hero--neutral{background:linear-gradient(135deg,#111827,#4b5563)}.hero--success{background:linear-gradient(135deg,#5f7150,#8ea475)}.hero--info{background:linear-gradient(135deg,#27445c,#3b6588)}.hero--warning{background:linear-gradient(135deg,#9b6b2b,#e1a040)}.hero--accent-orange{background:linear-gradient(135deg,#7a3a10,#df792e)}.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;opacity:.8;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;color:#ffffffd9;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,#208497)}.hero--secondary{background:linear-gradient(135deg,#2d3c46,#7097af)}.hero--neutral{background:linear-gradient(135deg,#111827,#4b5563)}.hero--success{background:linear-gradient(135deg,#5f7150,#8ea475)}.hero--info{background:linear-gradient(135deg,#27445c,#3b6588)}.hero--warning{background:linear-gradient(135deg,#9b6b2b,#e1a040)}.hero--accent-orange{background:linear-gradient(135deg,#7a3a10,#df792e)}.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{
|
|
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,#208497)}.hero--secondary{background:linear-gradient(135deg,#2d3c46,#7097af)}.hero--neutral{background:linear-gradient(135deg,#111827,#4b5563)}.hero--success{background:linear-gradient(135deg,#5f7150,#8ea475)}.hero--info{background:linear-gradient(135deg,#27445c,#3b6588)}.hero--warning{background:linear-gradient(135deg,#9b6b2b,#e1a040)}.hero--accent-orange{background:linear-gradient(135deg,#7a3a10,#df792e)}.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;opacity:.8;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;color:#ffffffd9;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 }]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-hero.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/hero/hero.component.ts","../../../../libs/angular-ui-kit/src/lib/hero/hero.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n input,\n computed,\n viewChild,\n} from '@angular/core';\n\nexport type HeroColor =\n | 'primary'\n | 'secondary'\n | 'neutral'\n | 'success'\n | 'info'\n | 'warning'\n | 'accent-orange'\n | 'accent-purple'\n | 'accent-violet';\n\nexport type HeroSize = 'sm' | 'md' | 'lg';\nexport type HeroVariant = 'default' | 'slim' | 'light';\n\n/**\n * Width of the hero's content box.\n * - `full`: the content runs to the hero's own padding (default, as before 3.4)\n * - `lg`: from 1024 px the content sits on the `lc-container` `lg` page column\n * (1024 px minus its 48 px sides, so at most 928 px), centred, while the\n * background stays full-bleed\n */\nexport type HeroContentWidth = 'full' | 'lg';\n\n/** Heading level of `lc-hero`'s title (3.36): `h1`–`h6`, the same look at every level. */\nexport type HeroHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;\n\n/** Ids of the title and label, set by `focusTitle()` (module counter, only at the call). */\nlet nextHeroId = 0;\n\n/**\n * Hero component for prominent page headers with gradient backgrounds.\n *\n * Features:\n * - Color gradient variants (primary, secondary, success, warning, info, neutral, accent-orange, accent-purple, accent-violet)\n * - 3 visual variants: default (dark gradient), slim (compact banner), light (pastel gradient with dark text)\n * - Size options (sm, md, lg)\n * - Optional label text above the title\n * - Configurable border radius\n * - Content projection for body and footer sections\n * - Footer slot for metadata, stats, or CTAs\n * - Media slot (`[hero-media]`) for a visual: below the text on small screens,\n * beside it from 1024 px, never under the body's 85 % opacity\n * - Content width `lg`: a full-bleed band whose text lines up with the page column\n * - `headingLevel` (3.36): the title as `h1`–`h6`, the same look at every level\n * - `focusTitle()` (3.36): moves focus to the title (`tabindex=\"-1\"`, out of the\n * Tab order) after an action replaced the stage (WCAG 2.4.3)\n *\n * @example\n * ```html\n * <lc-hero label=\"MY APP\" title=\"Welcome\" color=\"primary\" variant=\"slim\">\n * <p>Description text</p>\n * <div hero-footer>Status: Active</div>\n * </lc-hero>\n *\n * <lc-hero title=\"Everything in view\" borderRadius=\"none\" contentWidth=\"lg\">\n * <p>Description text</p>\n * <lc-card hero-media variant=\"elevated\">…</lc-card>\n * </lc-hero>\n * ```\n */\n@Component({\n selector: 'lc-hero',\n standalone: true,\n templateUrl: './hero.component.html',\n styleUrls: ['./hero.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class HeroComponent {\n /**\n * Small uppercase label displayed above the title.\n */\n label = input<string | undefined>(undefined);\n\n /**\n * Main headline text.\n */\n title = input.required<string>();\n\n /**\n * Color theme for the gradient background.\n * @default 'primary'\n */\n color = input<HeroColor>('primary');\n\n /**\n * Size variant controlling padding and font sizes.\n * @default 'md'\n */\n size = input<HeroSize>('md');\n\n /**\n * Border radius of the hero container.\n * @default 'lg'\n */\n borderRadius = input<'none' | 'sm' | 'md' | 'lg'>('lg');\n\n /**\n * Visual variant.\n * - `default`: dark gradient with white text\n * - `slim`: compact single-line banner\n * - `light`: softer pastel gradient with dark text\n * @default 'default'\n */\n variant = input<HeroVariant>('default');\n\n /**\n * Width of the content box. `lg` keeps the background full-bleed and, from\n * 1024 px, puts the label, title, body, media and footer on the 1024 px page\n * column (the `lc-container` `lg` content box), never closer to the edge than\n * the size padding. Use it for a full-width band (`borderRadius=\"none\"`) whose\n * text should line up with the page content below.\n * @default 'full'\n */\n contentWidth = input<HeroContentWidth>('full');\n\n /**\n * Element of the title (`h1`–`h6`), so the hero fits the page's outline\n * (3.36, cockpit row 1). Only the element changes: size, weight, line height\n * and spacing are the same at every level, `size`, `variant` and breakpoint.\n * Use 2 under an `lc-page-header`, which holds the page's `h1`.\n * @default 1\n */\n headingLevel = input<HeroHeadingLevel>(1);\n\n private readonly titleEl = viewChild<ElementRef<HTMLElement>>('titleEl');\n private readonly labelEl = viewChild<ElementRef<HTMLElement>>('labelEl');\n\n /**\n * Moves the focus to the title (3.36, monatsstand row 1), e.g. after an\n * action replaced the stage and the button that was used is gone, so focus\n * doesn't fall back to the page (WCAG 2.4.3). Gives the title\n * `tabindex=\"-1\"` first: it stays out of the Tab order. With a `label`, the\n * title is named \"label title\" (`aria-labelledby` on both, ids set at the\n * call), so the label is read before it. Call it after the new state has\n * rendered, e.g. `afterNextRender(() => this.hero().focusTitle(), { injector })`\n * with `hero = viewChild.required(HeroComponent)`, as\n * `lc-next-step-card.focusTitle()`. Without a call nothing changes.\n */\n focusTitle(): void {\n const title = this.titleEl()?.nativeElement;\n if (!title) return;\n const label = this.labelEl()?.nativeElement;\n if (label) {\n title.id ||= `lc-hero-title-${++nextHeroId}`;\n label.id ||= `lc-hero-label-${++nextHeroId}`;\n title.setAttribute('aria-labelledby', `${label.id} ${title.id}`);\n } else {\n title.removeAttribute('aria-labelledby');\n }\n title.setAttribute('tabindex', '-1');\n title.focus();\n }\n\n protected heroClasses = computed(() => {\n return [\n 'hero',\n `hero--${this.color()}`,\n `hero--${this.size()}`,\n `hero--radius-${this.borderRadius()}`,\n `hero--${this.variant()}`,\n `hero--content-${this.contentWidth()}`,\n ].join(' ');\n });\n}\n","<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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-hero.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/hero/hero.component.ts","../../../../libs/angular-ui-kit/src/lib/hero/hero.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n booleanAttribute,\n input,\n computed,\n viewChild,\n} from '@angular/core';\n\nexport type HeroColor =\n | 'primary'\n | 'secondary'\n | 'neutral'\n | 'success'\n | 'info'\n | 'warning'\n | 'accent-orange'\n | 'accent-purple'\n | 'accent-violet';\n\nexport type HeroSize = 'sm' | 'md' | 'lg';\nexport type HeroVariant = 'default' | 'slim' | 'light';\n\n/**\n * Width of the hero's content box.\n * - `full`: the content runs to the hero's own padding (default, as before 3.4)\n * - `lg`: from 1024 px the content sits on the `lc-container` `lg` page column\n * (1024 px minus its 48 px sides, so at most 928 px), centred, while the\n * background stays full-bleed\n */\nexport type HeroContentWidth = 'full' | 'lg';\n\n/** Heading level of `lc-hero`'s title (3.36): `h1`–`h6`, the same look at every level. */\nexport type HeroHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;\n\n/** Ids of the title and label, set by `focusTitle()` (module counter, only at the call). */\nlet nextHeroId = 0;\n\n/**\n * Hero component for prominent page headers with gradient backgrounds.\n *\n * Features:\n * - Color gradient variants (primary, secondary, success, warning, info, neutral, accent-orange, accent-purple, accent-violet)\n * - 3 visual variants: default (dark gradient), slim (compact banner), light (pastel gradient with dark text)\n * - Size options (sm, md, lg)\n * - Optional label text above the title\n * - Configurable border radius\n * - Content projection for body and footer sections\n * - Footer slot for metadata, stats, or CTAs\n * - Media slot (`[hero-media]`) for a visual: below the text on small screens,\n * beside it from 1024 px\n * - 3.37: components in the default slot keep full opacity (only the body\n * text is softened, through its colour), and badges in a hero take the light\n * palette in both themes; `fill` takes the height of a stretching grid or\n * flex row\n * - Content width `lg`: a full-bleed band whose text lines up with the page column\n * - `headingLevel` (3.36): the title as `h1`–`h6`, the same look at every level\n * - `focusTitle()` (3.36): moves focus to the title (`tabindex=\"-1\"`, out of the\n * Tab order) after an action replaced the stage (WCAG 2.4.3)\n *\n * @example\n * ```html\n * <lc-hero label=\"MY APP\" title=\"Welcome\" color=\"primary\" variant=\"slim\">\n * <p>Description text</p>\n * <div hero-footer>Status: Active</div>\n * </lc-hero>\n *\n * <lc-hero title=\"Everything in view\" borderRadius=\"none\" contentWidth=\"lg\">\n * <p>Description text</p>\n * <lc-card hero-media variant=\"elevated\">…</lc-card>\n * </lc-hero>\n * ```\n */\n@Component({\n selector: 'lc-hero',\n standalone: true,\n templateUrl: './hero.component.html',\n styleUrls: ['./hero.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class.lc-hero--fill]': 'fill()',\n },\n})\nexport class HeroComponent {\n /**\n * Small uppercase label displayed above the title.\n */\n label = input<string | undefined>(undefined);\n\n /**\n * Main headline text.\n */\n title = input.required<string>();\n\n /**\n * Color theme for the gradient background.\n * @default 'primary'\n */\n color = input<HeroColor>('primary');\n\n /**\n * Size variant controlling padding and font sizes.\n * @default 'md'\n */\n size = input<HeroSize>('md');\n\n /**\n * Border radius of the hero container.\n * @default 'lg'\n */\n borderRadius = input<'none' | 'sm' | 'md' | 'lg'>('lg');\n\n /**\n * Visual variant.\n * - `default`: dark gradient with white text\n * - `slim`: compact single-line banner\n * - `light`: softer pastel gradient with dark text\n * @default 'default'\n */\n variant = input<HeroVariant>('default');\n\n /**\n * Width of the content box. `lg` keeps the background full-bleed and, from\n * 1024 px, puts the label, title, body, media and footer on the 1024 px page\n * column (the `lc-container` `lg` content box), never closer to the edge than\n * the size padding. Use it for a full-width band (`borderRadius=\"none\"`) whose\n * text should line up with the page content below.\n * @default 'full'\n */\n contentWidth = input<HeroContentWidth>('full');\n\n /**\n * Element of the title (`h1`–`h6`), so the hero fits the page's outline\n * (3.36, cockpit row 1). Only the element changes: size, weight, line height\n * and spacing are the same at every level, `size`, `variant` and breakpoint.\n * Use 2 under an `lc-page-header`, which holds the page's `h1`.\n * @default 1\n */\n headingLevel = input<HeroHeadingLevel>(1);\n\n /**\n * Fill the height the container gives the hero (3.37, cockpit row 1): in a\n * grid or flex row that stretches its items, the band ends at the row's\n * bottom edge; the content stays at the top and `[hero-footer]` sits at the\n * bottom. Without it the hero is as tall as its content.\n * @default false\n */\n fill = input(false, { transform: booleanAttribute });\n\n private readonly titleEl = viewChild<ElementRef<HTMLElement>>('titleEl');\n private readonly labelEl = viewChild<ElementRef<HTMLElement>>('labelEl');\n\n /**\n * Moves the focus to the title (3.36, monatsstand row 1), e.g. after an\n * action replaced the stage and the button that was used is gone, so focus\n * doesn't fall back to the page (WCAG 2.4.3). Gives the title\n * `tabindex=\"-1\"` first: it stays out of the Tab order. With a `label`, the\n * title is named \"label title\" (`aria-labelledby` on both, ids set at the\n * call), so the label is read before it. Call it after the new state has\n * rendered, e.g. `afterNextRender(() => this.hero().focusTitle(), { injector })`\n * with `hero = viewChild.required(HeroComponent)`, as\n * `lc-next-step-card.focusTitle()`. Without a call nothing changes.\n */\n focusTitle(): void {\n const title = this.titleEl()?.nativeElement;\n if (!title) return;\n const label = this.labelEl()?.nativeElement;\n if (label) {\n title.id ||= `lc-hero-title-${++nextHeroId}`;\n label.id ||= `lc-hero-label-${++nextHeroId}`;\n title.setAttribute('aria-labelledby', `${label.id} ${title.id}`);\n } else {\n title.removeAttribute('aria-labelledby');\n }\n title.setAttribute('tabindex', '-1');\n title.focus();\n }\n\n protected heroClasses = computed(() => {\n return [\n 'hero',\n `hero--${this.color()}`,\n `hero--${this.size()}`,\n `hero--radius-${this.borderRadius()}`,\n `hero--${this.variant()}`,\n `hero--content-${this.contentWidth()}`,\n ].join(' ');\n });\n}\n","<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"],"mappings":"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"}
|
|
@@ -32,8 +32,8 @@ function readableInk(fill) {
|
|
|
32
32
|
const CHART_PALETTE = [
|
|
33
33
|
"var(--color-primary-500)",
|
|
34
34
|
"var(--color-secondary-500)",
|
|
35
|
-
"var(--color-success
|
|
36
|
-
"var(--color-warning
|
|
35
|
+
"var(--color-text-success)",
|
|
36
|
+
"var(--color-text-warning)",
|
|
37
37
|
"var(--color-error-default)",
|
|
38
38
|
"var(--color-info-default)",
|
|
39
39
|
"var(--color-primary-700)",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-internal-chart.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/internal/chart/chart-color.ts","../../../../libs/angular-ui-kit/src/lib/internal/chart/chart-palette.ts","../../../../libs/angular-ui-kit/src/lib/internal/chart/chart-path.ts","../../../../libs/angular-ui-kit/src/lib/internal/chart/chart-scale.ts"],"sourcesContent":["/**\n * Colour helpers for text drawn on top of chart fills.\n */\n\n/** Parses `#rgb`, `#rrggbb`, `rgb()` and `rgba()`. Anything else → null. */\nexport function parseRgb(color: string): [number, number, number] | null {\n const hex = color.trim().match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);\n if (hex) {\n const h = hex[1];\n const full = h.length === 3 ? h.split('').map(c => c + c).join('') : h;\n return [0, 2, 4].map(i => parseInt(full.slice(i, i + 2), 16)) as [number, number, number];\n }\n const rgb = color.match(/^rgba?\\(([^)]+)\\)/i);\n if (rgb) {\n const p = rgb[1].split(',').map(s => parseFloat(s));\n if (p.length >= 3 && p.every(n => !Number.isNaN(n))) return [p[0], p[1], p[2]];\n }\n return null;\n}\n\n/**\n * Ink that stays readable on `fill`, or `null` when that cannot be decided.\n *\n * A literal colour (`#…`, `rgb()`) is measured by its relative luminance and\n * gets a dark or light ink. A `var(--…)` token can't be resolved without the\n * DOM — and its resolution flips with the theme — so `null` is returned and\n * the caller should draw the label in `--color-text-primary` with a\n * `--color-surface` halo (`paint-order: stroke`), which reads on any fill in\n * both themes.\n */\nexport function readableInk(fill: string): string | null {\n const rgb = parseRgb(fill);\n if (!rgb) return null;\n const [r, g, b] = rgb.map(c => {\n const s = c / 255;\n return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);\n });\n const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;\n return luminance > 0.4 ? '#111827' : '#f9fafb';\n}\n","/**\n * Default categorical palette for the chart family.\n *\n * Every entry is a theme token whose light *and* dark resolutions sit clearly\n * against `--color-surface`: the 500 brand shades and the status defaults flip\n * to their pastel tints in the dark theme, the 700 shades to their light tints,\n * so consecutive hues stay distinguishable on both themes. (The 300 shades and\n * `-light` status tints some charts used before resolve to dark, low-contrast\n * colours on the dark theme, which is why they are not in this list.)\n *\n * Charts fall back to this list when a series/segment brings no `color` of its\n * own; per-item colours always win.\n */\nexport const CHART_PALETTE: readonly string[] = [\n 'var(--color-primary-500)',\n 'var(--color-secondary-500)',\n 'var(--color-success-default)',\n 'var(--color-warning-default)',\n 'var(--color-error-default)',\n 'var(--color-info-default)',\n 'var(--color-primary-700)',\n 'var(--color-secondary-700)',\n];\n\n/** Palette colour for the series/segment at `index`, wrapping around. */\nexport function chartColor(index: number): string {\n return CHART_PALETTE[index % CHART_PALETTE.length];\n}\n","/**\n * SVG path builders shared by the line-shaped charts (line, area, sparkline).\n */\n\nexport interface ChartPoint {\n x: number;\n y: number;\n}\n\n/** `M x,y L x,y …` polyline through the points; '' for fewer than two points. */\nexport function linearPath(points: readonly ChartPoint[]): string {\n if (points.length < 2) return '';\n return points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' ');\n}\n\n/**\n * Smooth cubic path through the points (Catmull-Rom → Bézier approximation);\n * '' for fewer than two points.\n */\nexport function smoothPath(points: readonly ChartPoint[]): string {\n if (points.length < 2) return '';\n let d = `M${points[0].x},${points[0].y}`;\n for (let i = 0; i < points.length - 1; i++) {\n const p0 = points[Math.max(i - 1, 0)];\n const p1 = points[i];\n const p2 = points[i + 1];\n const p3 = points[Math.min(i + 2, points.length - 1)];\n const cp1x = p1.x + (p2.x - p0.x) / 6;\n const cp1y = p1.y + (p2.y - p0.y) / 6;\n const cp2x = p2.x - (p3.x - p1.x) / 6;\n const cp2y = p2.y - (p3.y - p1.y) / 6;\n d += ` C${cp1x},${cp1y} ${cp2x},${cp2y} ${p2.x},${p2.y}`;\n }\n return d;\n}\n","/**\n * Numeric helpers shared by the chart family: a \"nice\" linear scale for axes\n * and grids, float-safe value formatting, and a NaN guard for caller data.\n *\n * Every chart used to place its grid on its own ad-hoc rounding\n * (`Math.ceil(max / 4)`, `Math.round(v * 10) / 10`, `toFixed`), which let the\n * top tick disagree with the value at the plot edge and leaked binary float\n * noise (`0.30000000000000004`) into tick labels. This module is the one\n * routine they all go through instead.\n */\n\n/** Signature of a chart's `formatValue` input. */\nexport type ChartValueFormatter = (value: number) => string;\n\n/** `value` if it is a finite number, otherwise `fallback` (NaN, ±Infinity, undefined, null…). */\nexport function toFinite(value: unknown, fallback = 0): number {\n return typeof value === 'number' && Number.isFinite(value) ? value : fallback;\n}\n\n/** Strips binary float noise (0.1 + 0.2 → 0.3) and normalises -0 to 0. */\nexport function cleanNumber(value: number): number {\n if (!Number.isFinite(value)) return 0;\n const v = Number(value.toPrecision(12));\n return v === 0 ? 0 : v;\n}\n\n/** Default tick/value formatter: float-clean `String(value)`, no locale, no unit. */\nexport function formatChartValue(value: number): string {\n return String(cleanNumber(value));\n}\n\nexport interface NiceScale {\n /** Lower bound — a multiple of `step`, ≤ the requested min. */\n min: number;\n /** Upper bound — a multiple of `step`, ≥ the requested max. */\n max: number;\n /** Tick interval: 1, 2, 2.5 or 5 × 10ⁿ. */\n step: number;\n /** All tick values from `min` to `max` inclusive. */\n ticks: number[];\n}\n\n/** Rounds a raw interval up to the nearest 1, 2, 2.5 or 5 × 10ⁿ. */\nexport function niceStep(raw: number): number {\n if (!Number.isFinite(raw) || raw <= 0) return 1;\n const magnitude = Math.pow(10, Math.floor(Math.log10(raw)));\n const fraction = raw / magnitude;\n const nice = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 2.5 ? 2.5 : fraction <= 5 ? 5 : 10;\n return cleanNumber(nice * magnitude);\n}\n\n/**\n * Linear scale whose bounds are multiples of a nice step, so every tick label\n * is a round number and the outermost ticks equal the values at the plot\n * edges. Bounds are only ever extended outward, never shrunk. A degenerate\n * range (`min === max`) is widened towards zero, or to [0, 1] when both are 0.\n *\n * `intervals` is the *target* number of steps; the result may have one more\n * or fewer because the bounds snap to the step.\n */\nexport function niceScale(min: number, max: number, intervals = 4): NiceScale {\n let lo = Math.min(toFinite(min), toFinite(max));\n let hi = Math.max(toFinite(min), toFinite(max));\n if (lo === hi) {\n if (lo > 0) lo = 0;\n else if (lo < 0) hi = 0;\n else hi = 1;\n }\n const step = niceStep((hi - lo) / Math.max(1, intervals));\n // cleanNumber before floor/ceil: 0.3 / 0.1 is 2.9999999999999996, which would\n // otherwise floor to 2 and pull the bound one step too far out.\n const niceMin = cleanNumber(Math.floor(cleanNumber(lo / step)) * step);\n const niceMax = cleanNumber(Math.ceil(cleanNumber(hi / step)) * step);\n const count = Math.round((niceMax - niceMin) / step);\n const ticks: number[] = [];\n for (let i = 0; i <= count; i++) ticks.push(cleanNumber(niceMin + i * step));\n return { min: niceMin, max: niceMax, step, ticks };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-internal-chart.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/internal/chart/chart-color.ts","../../../../libs/angular-ui-kit/src/lib/internal/chart/chart-palette.ts","../../../../libs/angular-ui-kit/src/lib/internal/chart/chart-path.ts","../../../../libs/angular-ui-kit/src/lib/internal/chart/chart-scale.ts"],"sourcesContent":["/**\n * Colour helpers for text drawn on top of chart fills.\n */\n\n/** Parses `#rgb`, `#rrggbb`, `rgb()` and `rgba()`. Anything else → null. */\nexport function parseRgb(color: string): [number, number, number] | null {\n const hex = color.trim().match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);\n if (hex) {\n const h = hex[1];\n const full = h.length === 3 ? h.split('').map(c => c + c).join('') : h;\n return [0, 2, 4].map(i => parseInt(full.slice(i, i + 2), 16)) as [number, number, number];\n }\n const rgb = color.match(/^rgba?\\(([^)]+)\\)/i);\n if (rgb) {\n const p = rgb[1].split(',').map(s => parseFloat(s));\n if (p.length >= 3 && p.every(n => !Number.isNaN(n))) return [p[0], p[1], p[2]];\n }\n return null;\n}\n\n/**\n * Ink that stays readable on `fill`, or `null` when that cannot be decided.\n *\n * A literal colour (`#…`, `rgb()`) is measured by its relative luminance and\n * gets a dark or light ink. A `var(--…)` token can't be resolved without the\n * DOM — and its resolution flips with the theme — so `null` is returned and\n * the caller should draw the label in `--color-text-primary` with a\n * `--color-surface` halo (`paint-order: stroke`), which reads on any fill in\n * both themes.\n */\nexport function readableInk(fill: string): string | null {\n const rgb = parseRgb(fill);\n if (!rgb) return null;\n const [r, g, b] = rgb.map(c => {\n const s = c / 255;\n return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);\n });\n const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;\n return luminance > 0.4 ? '#111827' : '#f9fafb';\n}\n","/**\n * Default categorical palette for the chart family.\n *\n * Every entry is a theme token whose light *and* dark resolutions sit clearly\n * against `--color-surface`: the 500 brand shades and the status defaults flip\n * to their pastel tints in the dark theme, the 700 shades to their light tints,\n * so consecutive hues stay distinguishable on both themes. (The 300 shades and\n * `-light` status tints some charts used before resolve to dark, low-contrast\n * colours on the dark theme, which is why they are not in this list.)\n *\n * Charts fall back to this list when a series/segment brings no `color` of its\n * own; per-item colours always win.\n *\n * 3.37 (request 057, 056 F-1, WCAG 1.4.11): entries 3 and 4 are the status\n * inks, not the status fills. `--color-success-default` measured 2.47–2.72:1\n * and `--color-warning-default` 2.05–2.26:1 on light pages; the inks reach\n * 5.30 and 6.03:1 there (8.40 and 7.65:1 dark). Every entry keeps 3:1 against\n * `--color-background` and `--color-surface` in both themes.\n */\nexport const CHART_PALETTE: readonly string[] = [\n 'var(--color-primary-500)',\n 'var(--color-secondary-500)',\n 'var(--color-text-success)',\n 'var(--color-text-warning)',\n 'var(--color-error-default)',\n 'var(--color-info-default)',\n 'var(--color-primary-700)',\n 'var(--color-secondary-700)',\n];\n\n/** Palette colour for the series/segment at `index`, wrapping around. */\nexport function chartColor(index: number): string {\n return CHART_PALETTE[index % CHART_PALETTE.length];\n}\n","/**\n * SVG path builders shared by the line-shaped charts (line, area, sparkline).\n */\n\nexport interface ChartPoint {\n x: number;\n y: number;\n}\n\n/** `M x,y L x,y …` polyline through the points; '' for fewer than two points. */\nexport function linearPath(points: readonly ChartPoint[]): string {\n if (points.length < 2) return '';\n return points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' ');\n}\n\n/**\n * Smooth cubic path through the points (Catmull-Rom → Bézier approximation);\n * '' for fewer than two points.\n */\nexport function smoothPath(points: readonly ChartPoint[]): string {\n if (points.length < 2) return '';\n let d = `M${points[0].x},${points[0].y}`;\n for (let i = 0; i < points.length - 1; i++) {\n const p0 = points[Math.max(i - 1, 0)];\n const p1 = points[i];\n const p2 = points[i + 1];\n const p3 = points[Math.min(i + 2, points.length - 1)];\n const cp1x = p1.x + (p2.x - p0.x) / 6;\n const cp1y = p1.y + (p2.y - p0.y) / 6;\n const cp2x = p2.x - (p3.x - p1.x) / 6;\n const cp2y = p2.y - (p3.y - p1.y) / 6;\n d += ` C${cp1x},${cp1y} ${cp2x},${cp2y} ${p2.x},${p2.y}`;\n }\n return d;\n}\n","/**\n * Numeric helpers shared by the chart family: a \"nice\" linear scale for axes\n * and grids, float-safe value formatting, and a NaN guard for caller data.\n *\n * Every chart used to place its grid on its own ad-hoc rounding\n * (`Math.ceil(max / 4)`, `Math.round(v * 10) / 10`, `toFixed`), which let the\n * top tick disagree with the value at the plot edge and leaked binary float\n * noise (`0.30000000000000004`) into tick labels. This module is the one\n * routine they all go through instead.\n */\n\n/** Signature of a chart's `formatValue` input. */\nexport type ChartValueFormatter = (value: number) => string;\n\n/** `value` if it is a finite number, otherwise `fallback` (NaN, ±Infinity, undefined, null…). */\nexport function toFinite(value: unknown, fallback = 0): number {\n return typeof value === 'number' && Number.isFinite(value) ? value : fallback;\n}\n\n/** Strips binary float noise (0.1 + 0.2 → 0.3) and normalises -0 to 0. */\nexport function cleanNumber(value: number): number {\n if (!Number.isFinite(value)) return 0;\n const v = Number(value.toPrecision(12));\n return v === 0 ? 0 : v;\n}\n\n/** Default tick/value formatter: float-clean `String(value)`, no locale, no unit. */\nexport function formatChartValue(value: number): string {\n return String(cleanNumber(value));\n}\n\nexport interface NiceScale {\n /** Lower bound — a multiple of `step`, ≤ the requested min. */\n min: number;\n /** Upper bound — a multiple of `step`, ≥ the requested max. */\n max: number;\n /** Tick interval: 1, 2, 2.5 or 5 × 10ⁿ. */\n step: number;\n /** All tick values from `min` to `max` inclusive. */\n ticks: number[];\n}\n\n/** Rounds a raw interval up to the nearest 1, 2, 2.5 or 5 × 10ⁿ. */\nexport function niceStep(raw: number): number {\n if (!Number.isFinite(raw) || raw <= 0) return 1;\n const magnitude = Math.pow(10, Math.floor(Math.log10(raw)));\n const fraction = raw / magnitude;\n const nice = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 2.5 ? 2.5 : fraction <= 5 ? 5 : 10;\n return cleanNumber(nice * magnitude);\n}\n\n/**\n * Linear scale whose bounds are multiples of a nice step, so every tick label\n * is a round number and the outermost ticks equal the values at the plot\n * edges. Bounds are only ever extended outward, never shrunk. A degenerate\n * range (`min === max`) is widened towards zero, or to [0, 1] when both are 0.\n *\n * `intervals` is the *target* number of steps; the result may have one more\n * or fewer because the bounds snap to the step.\n */\nexport function niceScale(min: number, max: number, intervals = 4): NiceScale {\n let lo = Math.min(toFinite(min), toFinite(max));\n let hi = Math.max(toFinite(min), toFinite(max));\n if (lo === hi) {\n if (lo > 0) lo = 0;\n else if (lo < 0) hi = 0;\n else hi = 1;\n }\n const step = niceStep((hi - lo) / Math.max(1, intervals));\n // cleanNumber before floor/ceil: 0.3 / 0.1 is 2.9999999999999996, which would\n // otherwise floor to 2 and pull the bound one step too far out.\n const niceMin = cleanNumber(Math.floor(cleanNumber(lo / step)) * step);\n const niceMax = cleanNumber(Math.ceil(cleanNumber(hi / step)) * step);\n const count = Math.round((niceMax - niceMin) / step);\n const ticks: number[] = [];\n for (let i = 0; i <= count; i++) ticks.push(cleanNumber(niceMin + i * step));\n return { min: niceMin, max: niceMax, step, ticks };\n}\n"],"mappings":"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"}
|
|
@@ -36,6 +36,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
36
36
|
}]
|
|
37
37
|
}]
|
|
38
38
|
});
|
|
39
|
+
let nextListId = 0;
|
|
39
40
|
var ListComponent = class ListComponent {
|
|
40
41
|
itemTemplate = contentChild(ListItemTemplateDirective, ...ngDevMode ? [{ debugName: "itemTemplate" }] : /* istanbul ignore next */ []);
|
|
41
42
|
items = input([], ...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
|
|
@@ -65,9 +66,13 @@ var ListComponent = class ListComponent {
|
|
|
65
66
|
this.pendingItemFocus = afterNextRender(() => {
|
|
66
67
|
this.pendingItemFocus = void 0;
|
|
67
68
|
const index = (this.items() ?? []).findIndex((item) => item.id === id);
|
|
68
|
-
((index < 0 ? null : this.listEl()?.nativeElement.children.item(index))?.querySelector(part === "action" ? ".lc-list__action-area button" : "a.lc-list__item, .lc-list__item[role=button]:not([aria-disabled=true])"))?.focus();
|
|
69
|
+
((index < 0 ? null : this.listEl()?.nativeElement.children.item(index))?.querySelector(part === "action" ? ".lc-list__action-area button" : "a.lc-list__item, .lc-list__item[role=button]:not([aria-disabled=true]), .lc-list__item-button:not([aria-disabled=true])"))?.focus();
|
|
69
70
|
}, { injector: this.injector });
|
|
70
71
|
}
|
|
72
|
+
uid = `lc-list-${nextListId++}`;
|
|
73
|
+
rowId(index) {
|
|
74
|
+
return `${this.uid}-row-${index}`;
|
|
75
|
+
}
|
|
71
76
|
isLinkRow(item) {
|
|
72
77
|
return !!item.href && !item.disabled;
|
|
73
78
|
}
|
|
@@ -217,8 +222,8 @@ var ListComponent = class ListComponent {
|
|
|
217
222
|
isSignal: true
|
|
218
223
|
}],
|
|
219
224
|
ngImport: i0,
|
|
220
|
-
template: "<!--\n Row content is shared between the plain (legacy) row and the keyboard-\n operable row rendered when `clickable` is set.\n-->\n<ng-template #rowContent let-item>\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl.template; context: { $implicit: item }\"></ng-container>\n } @else {\n <!-- Leading: Avatar or Icon -->\n @if (item.avatar) {\n <div [class]=\"avatarClasses(item)\">\n @if (item.avatar.startsWith('http') || item.avatar.startsWith('/') || item.avatar.startsWith('data:')) {\n <img [src]=\"item.avatar\" [alt]=\"item.label\" class=\"lc-list__avatar-img\" />\n } @else {\n <span class=\"lc-list__avatar-initials\">{{ item.avatar }}</span>\n }\n </div>\n } @else if (item.icon) {\n <lc-icon [name]=\"item.icon\" class=\"lc-list__icon\" size=\"sm\" [decorative]=\"true\" />\n }\n\n <!-- Content: Label, Subtitle, Description -->\n <div class=\"lc-list__content\">\n <span class=\"lc-list__label\">{{ item.label }}</span>\n @if (item.subtitle) {\n <span class=\"lc-list__subtitle\">{{ item.subtitle }}</span>\n }\n @if (item.description) {\n <span class=\"lc-list__description\">{{ item.description }}</span>\n }\n </div>\n\n <!-- Trailing: Badge, Metadata, Action -->\n <div class=\"lc-list__trailing\">\n @if (item.badge) {\n <span class=\"lc-list__badge lc-list__badge--{{ item.badgeVariant || 'default' }}\">{{ item.badge }}</span>\n }\n @if (item.metadata) {\n <span class=\"lc-list__metadata\">{{ item.metadata }}</span>\n }\n @if (item.action && !isLinkRow(item)) {\n <!-- The action is its own control: its click must not also activate the row. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- only stops the action click from also activating the row; the action is a real button -->\n <span class=\"lc-list__action-area\" (click)=\"$event.stopPropagation()\">\n <lc-button\n [variant]=\"actionVariant()\"\n [size]=\"actionSize()\"\n [ariaLabel]=\"item.actionAriaLabel ?? ''\"\n class=\"lc-list__action\"\n (clicked)=\"onActionClick(item)\"\n >\n {{ item.action }}\n </lc-button>\n </span>\n }\n </div>\n\n <!-- 3.36: a decorative chevron ends a clickable or linked row. -->\n @if (showChevron() && (clickable() || !!item.href)) {\n <lc-icon name=\"chevron-right\" class=\"lc-list__chevron\" size=\"sm\" [decorative]=\"true\" />\n }\n }\n</ng-template>\n\n<div #listEl [class]=\"listClasses()\" role=\"list\">\n @for (item of items(); track item.id || $index) {\n @if (isLinkRow(item)) {\n <!-- A real link over the whole row (3.16, TD-4); the row element carries the item styles. -->\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <a\n [class]=\"getItemClasses(item) + ' lc-list__item--link'\"\n [href]=\"item.href\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onLinkClick($event, item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </a>\n </div>\n } @else if (clickable()) {\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <div\n [class]=\"getItemClasses(item)\"\n role=\"button\"\n [attr.tabindex]=\"item.disabled ? -1 : 0\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n (keydown)=\"onItemKeydown($event, item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n </div>\n } @else {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- non-clickable lists keep reporting mouse clicks (backward compatible); use clickable for keyboard rows -->\n <div\n [class]=\"getItemClasses(item)\"\n role=\"listitem\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n }\n }\n</div>\n",
|
|
221
|
-
styles: [".lc-list{display:flex;width:100%;background-color:var(--color-surface, #ffffff);border-radius:var(--border-radius-md);overflow:hidden}.lc-list--vertical{flex-direction:column}.lc-list--vertical .lc-list__item{border-bottom:1px solid transparent}.lc-list--vertical>.lc-list__item:last-child,.lc-list--vertical>.lc-list__item-wrapper:last-child .lc-list__item{border-bottom:none}.lc-list--vertical.lc-list--with-dividers .lc-list__item{border-bottom-color:var(--color-divider)}.lc-list--horizontal{flex-direction:row}.lc-list--horizontal .lc-list__item,.lc-list--horizontal .lc-list__item-wrapper{flex:1}.lc-list--horizontal .lc-list__item{border-right:1px solid transparent}.lc-list--horizontal>.lc-list__item:last-child,.lc-list--horizontal>.lc-list__item-wrapper:last-child .lc-list__item{border-right:none}.lc-list--horizontal.lc-list--with-dividers .lc-list__item{border-right-color:var(--color-divider)}.lc-list__item-wrapper{display:flex;min-width:0}.lc-list__item-wrapper>.lc-list__item{flex:1;min-width:0}.lc-list__item{display:flex;align-items:center;gap:var(--spacing-3);padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));transition:background-color .2s ease}.lc-list__item:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--color-primary-500)}.lc-list__item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.lc-list__icon{flex-shrink:0;color:var(--color-text-tertiary)}.lc-list__label{flex:1;min-width:0;overflow-wrap:anywhere;color:var(--color-text-primary, #111827);font-size:var(--font-size-base);line-height:var(--line-height-base)}.lc-list__avatar{flex-shrink:0;width:40px;height:40px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background-color:var(--color-primary-100, #dbeafe)}.lc-list__avatar-img{width:100%;height:100%;object-fit:cover}.lc-list__avatar-initials{font-size:var(--font-size-sm, .875rem);font-weight:600;color:var(--color-primary-700, #1d4ed8);text-transform:uppercase;line-height:1;-webkit-user-select:none;user-select:none}.lc-list__avatar--member-1{background-color:var(--color-member-1, #1a6a79)}.lc-list__avatar--member-2{background-color:var(--color-member-2, #b04a22)}.lc-list__avatar--member-3{background-color:var(--color-member-3, #4e3f84)}.lc-list__avatar--member-4{background-color:var(--color-member-4, #5f7150)}.lc-list__avatar--member-5{background-color:var(--color-member-5, #9e3846)}.lc-list__avatar--member-6{background-color:var(--color-member-6, #5a798c)}.lc-list__avatar--member .lc-list__avatar-initials{color:var(--color-on-member, #ffffff);font-weight:700;letter-spacing:.02em}.lc-list__content{flex:1;display:flex;flex-direction:column;gap:2px;min-width:0}.lc-list__subtitle{font-size:var(--font-size-sm, .875rem);color:var(--color-text-tertiary);line-height:var(--line-height-sm, 1.25rem);overflow-wrap:anywhere}.lc-list__description{overflow-wrap:anywhere;font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);line-height:var(--line-height-xs, 1rem);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.lc-list--no-clamp .lc-list__description{display:block;-webkit-line-clamp:unset;overflow:visible}.lc-list__trailing{flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:4px}.lc-list__action{flex-shrink:0}.lc-list__chevron{flex-shrink:0;color:var(--color-text-tertiary)}.lc-list__chevron:dir(rtl){transform:scaleX(-1)}.lc-list--clickable .lc-list__item{cursor:pointer}.lc-list--clickable .lc-list__item:hover:not(.lc-list__item--disabled){background-color:var(--color-surface-hover)}.lc-list--clickable .lc-list__item:active:not(.lc-list__item--disabled){background-color:var(--color-surface-sunken)}.lc-list__item--link{min-height:var(--size-min-touch-height, 2.75rem);color:inherit;text-decoration:none;cursor:pointer}.lc-list__item--link:hover{background-color:var(--color-surface-hover)}.lc-list__item--link:active{background-color:var(--color-surface-sunken)}.lc-list__item--link.lc-list__item--selected:hover{background-color:var(--color-primary-100, #dbeafe)}@media(forced-colors:active){.lc-list__item:focus-visible{outline:2px solid Highlight;outline-offset:-2px}}.lc-list__badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:9999px;font-size:var(--font-size-xs, .75rem);font-weight:500;line-height:1.25rem;white-space:nowrap}.lc-list__badge--default{background-color:var(--color-surface-hover);color:var(--color-text-secondary)}.lc-list__badge--primary{background-color:var(--color-primary-100, #dbeafe);color:var(--color-primary-700, #1d4ed8)}.lc-list__badge--success{background-color:var(--color-success-subtle);color:var(--color-on-success-subtle)}.lc-list__badge--warning{background-color:var(--color-warning-subtle);color:var(--color-on-warning-subtle)}.lc-list__badge--error{background-color:var(--color-error-100, #fee2e2);color:var(--color-on-error-subtle)}.lc-list__metadata{font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);white-space:nowrap}.lc-list__item--selected{background-color:var(--color-primary-50, #eff6ff)}.lc-list--clickable .lc-list__item--selected:hover:not(.lc-list__item--disabled){background-color:var(--color-primary-100, #dbeafe)}.lc-list--sm .lc-list__item{padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));gap:var(--lc-density-gap-sm, var(--spacing-2))}.lc-list--sm .lc-list__avatar{width:32px;height:32px}.lc-list--sm .lc-list__avatar-initials{font-size:var(--font-size-xs, .75rem)}.lc-list--sm .lc-list__label{font-size:var(--font-size-sm, .875rem)}.lc-list--sm .lc-list__subtitle{font-size:var(--font-size-xs, .75rem)}.lc-list--sm .lc-list__description{display:none}.lc-list--lg .lc-list__item{padding:var(--lc-density-padding-md, var(--spacing-4)) var(--spacing-5);gap:var(--lc-density-gap-md, var(--spacing-4))}.lc-list--lg .lc-list__avatar{width:48px;height:48px}.lc-list--lg .lc-list__avatar-initials{font-size:var(--font-size-base, 1rem)}.lc-list--lg .lc-list__label{font-size:var(--font-size-lg, 1.125rem)}.lc-list--lg .lc-list__content{gap:4px}.lc-list--card{background:transparent;gap:.5rem;overflow:visible}.lc-list--card .lc-list__item{padding:.75rem 1rem;border-radius:var(--border-radius-md, .5rem);background:var(--color-surface-2);border:1px solid var(--color-border);transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.lc-list--card.lc-list--clickable .lc-list__item:hover:not(.lc-list__item--disabled),.lc-list--card .lc-list__item--link:hover:not(.lc-list__item--disabled){background:var(--color-surface-hover);border-color:var(--color-border-strong);box-shadow:var(--elevation-1)}.lc-list--card.lc-list--clickable .lc-list__item:active:not(.lc-list__item--disabled),.lc-list--card .lc-list__item--link:active:not(.lc-list__item--disabled){background:var(--color-surface-sunken)}.lc-list--card.lc-list--with-dividers .lc-list__item{border-bottom-color:transparent}\n"],
|
|
225
|
+
template: "<!--\n Row content is shared between the plain (legacy) row and the keyboard-\n operable row rendered when `clickable` is set.\n-->\n<ng-template #rowContent let-item>\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl.template; context: { $implicit: item }\"></ng-container>\n } @else {\n <!-- Leading: Avatar or Icon -->\n @if (item.avatar) {\n <div [class]=\"avatarClasses(item)\">\n @if (item.avatar.startsWith('http') || item.avatar.startsWith('/') || item.avatar.startsWith('data:')) {\n <img [src]=\"item.avatar\" [alt]=\"item.label\" class=\"lc-list__avatar-img\" />\n } @else {\n <span class=\"lc-list__avatar-initials\">{{ item.avatar }}</span>\n }\n </div>\n } @else if (item.icon) {\n <lc-icon [name]=\"item.icon\" class=\"lc-list__icon\" size=\"sm\" [decorative]=\"true\" />\n }\n\n <!-- Content: Label, Subtitle, Description -->\n <div class=\"lc-list__content\">\n <span class=\"lc-list__label\">{{ item.label }}</span>\n @if (item.subtitle) {\n <span class=\"lc-list__subtitle\">{{ item.subtitle }}</span>\n }\n @if (item.description) {\n <span class=\"lc-list__description\">{{ item.description }}</span>\n }\n </div>\n\n <!-- Trailing: Badge, Metadata, Action -->\n <div class=\"lc-list__trailing\">\n @if (item.badge) {\n <span class=\"lc-list__badge lc-list__badge--{{ item.badgeVariant || 'default' }}\">{{ item.badge }}</span>\n }\n @if (item.metadata) {\n <span class=\"lc-list__metadata\">{{ item.metadata }}</span>\n }\n @if (item.action && !isLinkRow(item)) {\n <!-- The action is its own control: its click must not also activate the row. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- only stops the action click from also activating the row; the action is a real button -->\n <span class=\"lc-list__action-area\" (click)=\"$event.stopPropagation()\">\n <lc-button\n [variant]=\"actionVariant()\"\n [size]=\"actionSize()\"\n [ariaLabel]=\"item.actionAriaLabel ?? ''\"\n class=\"lc-list__action\"\n (clicked)=\"onActionClick(item)\"\n >\n {{ item.action }}\n </lc-button>\n </span>\n }\n </div>\n\n <!-- 3.36: a decorative chevron ends a clickable or linked row. -->\n @if (showChevron() && (clickable() || !!item.href)) {\n <lc-icon name=\"chevron-right\" class=\"lc-list__chevron\" size=\"sm\" [decorative]=\"true\" />\n }\n }\n</ng-template>\n\n<div #listEl [class]=\"listClasses()\" role=\"list\">\n @for (item of items(); track item.id || $index; let i = $index) {\n @if (isLinkRow(item)) {\n <!-- A real link over the whole row (3.16, TD-4); the row element carries the item styles. -->\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <a\n [class]=\"getItemClasses(item) + ' lc-list__item--link'\"\n [href]=\"item.href\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onLinkClick($event, item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </a>\n </div>\n } @else if (clickable() && item.action && !itemTemplate()) {\n <!-- 3.37 (request 057, 056 F-2): a clickable row with an action keeps the\n action out of the row's button. The row's native button is stretched\n over the row and named by it; the action area sits above it. -->\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- the row's native button is the control; its Enter/Space click bubbles here -->\n <div [class]=\"getItemClasses(item) + ' lc-list__item--split'\" [id]=\"rowId(i)\" (click)=\"onItemClick(item)\">\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content -- named by aria-labelledby (the row's text); text inside would repeat it -->\n <button\n type=\"button\"\n class=\"lc-list__item-button\"\n [attr.aria-labelledby]=\"rowId(i)\"\n [attr.tabindex]=\"item.disabled ? -1 : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n ></button>\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n </div>\n } @else if (clickable()) {\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <div\n [class]=\"getItemClasses(item)\"\n role=\"button\"\n [attr.tabindex]=\"item.disabled ? -1 : 0\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n (keydown)=\"onItemKeydown($event, item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n </div>\n } @else {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- non-clickable lists keep reporting mouse clicks (backward compatible); use clickable for keyboard rows -->\n <div\n [class]=\"getItemClasses(item)\"\n role=\"listitem\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n }\n }\n</div>\n",
|
|
226
|
+
styles: [".lc-list{display:flex;width:100%;background-color:var(--color-surface, #ffffff);border-radius:var(--border-radius-md);overflow:hidden}.lc-list--vertical{flex-direction:column}.lc-list--vertical .lc-list__item{border-bottom:1px solid transparent}.lc-list--vertical>.lc-list__item:last-child,.lc-list--vertical>.lc-list__item-wrapper:last-child .lc-list__item{border-bottom:none}.lc-list--vertical.lc-list--with-dividers .lc-list__item{border-bottom-color:var(--color-divider)}.lc-list--horizontal{flex-direction:row}.lc-list--horizontal .lc-list__item,.lc-list--horizontal .lc-list__item-wrapper{flex:1}.lc-list--horizontal .lc-list__item{border-right:1px solid transparent}.lc-list--horizontal>.lc-list__item:last-child,.lc-list--horizontal>.lc-list__item-wrapper:last-child .lc-list__item{border-right:none}.lc-list--horizontal.lc-list--with-dividers .lc-list__item{border-right-color:var(--color-divider)}.lc-list__item-wrapper{display:flex;min-width:0}.lc-list__item-wrapper>.lc-list__item{flex:1;min-width:0}.lc-list__item{display:flex;align-items:center;gap:var(--spacing-3);padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));transition:background-color .2s ease}.lc-list__item:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--color-primary-500)}.lc-list__item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.lc-list__icon{flex-shrink:0;color:var(--color-text-tertiary)}.lc-list__label{flex:1;min-width:0;overflow-wrap:anywhere;hyphens:auto;hyphenate-limit-chars:12 4 3;color:var(--color-text-primary, #111827);font-size:var(--font-size-base);line-height:var(--line-height-base)}.lc-list__avatar{flex-shrink:0;width:40px;height:40px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background-color:var(--color-primary-100, #dbeafe)}.lc-list__avatar-img{width:100%;height:100%;object-fit:cover}.lc-list__avatar-initials{font-size:var(--font-size-sm, .875rem);font-weight:600;color:var(--color-primary-700, #1d4ed8);text-transform:uppercase;line-height:1;-webkit-user-select:none;user-select:none}.lc-list__avatar--member-1{background-color:var(--color-member-1, #1a6a79)}.lc-list__avatar--member-2{background-color:var(--color-member-2, #b04a22)}.lc-list__avatar--member-3{background-color:var(--color-member-3, #4e3f84)}.lc-list__avatar--member-4{background-color:var(--color-member-4, #5f7150)}.lc-list__avatar--member-5{background-color:var(--color-member-5, #9e3846)}.lc-list__avatar--member-6{background-color:var(--color-member-6, #5a798c)}.lc-list__avatar--member .lc-list__avatar-initials{color:var(--color-on-member, #ffffff);font-weight:700;letter-spacing:.02em}.lc-list__content{flex:1;display:flex;flex-direction:column;gap:2px;min-width:0}.lc-list__subtitle{font-size:var(--font-size-sm, .875rem);color:var(--color-text-tertiary);line-height:var(--line-height-sm, 1.25rem);overflow-wrap:anywhere}.lc-list__description{overflow-wrap:anywhere;font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);line-height:var(--line-height-xs, 1rem);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.lc-list--no-clamp .lc-list__description{display:block;-webkit-line-clamp:unset;overflow:visible}.lc-list__trailing{flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:4px}.lc-list__action{flex-shrink:0}.lc-list__chevron{flex-shrink:0;color:var(--color-text-tertiary)}.lc-list__chevron:dir(rtl){transform:scaleX(-1)}.lc-list--clickable .lc-list__item{cursor:pointer}.lc-list--clickable .lc-list__item:hover:not(.lc-list__item--disabled){background-color:var(--color-surface-hover)}.lc-list--clickable .lc-list__item:active:not(.lc-list__item--disabled){background-color:var(--color-surface-sunken)}.lc-list__item--link{min-height:var(--size-min-touch-height, 2.75rem);color:inherit;text-decoration:none;cursor:pointer}.lc-list__item--link:hover{background-color:var(--color-surface-hover)}.lc-list__item--link:active{background-color:var(--color-surface-sunken)}.lc-list__item--link.lc-list__item--selected:hover{background-color:var(--color-primary-100, #dbeafe)}@media(forced-colors:active){.lc-list__item:focus-visible{outline:2px solid Highlight;outline-offset:-2px}}.lc-list__item--split{position:relative;isolation:isolate}.lc-list__item-button{position:absolute;inset:0;margin:0;padding:0;border:0;border-radius:inherit;background:none;font:inherit;color:inherit;cursor:inherit;outline:none}.lc-list__item--split .lc-list__action-area{position:relative;z-index:1}.lc-list__item:has(>.lc-list__item-button:focus-visible){box-shadow:inset 0 0 0 2px var(--color-primary-500)}@media(forced-colors:active){.lc-list__item:has(>.lc-list__item-button:focus-visible){outline:2px solid Highlight;outline-offset:-2px}}.lc-list__badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:9999px;font-size:var(--font-size-xs, .75rem);font-weight:500;line-height:1.25rem;white-space:nowrap}.lc-list__badge--default{background-color:var(--color-surface-hover);color:var(--color-text-secondary)}.lc-list__badge--primary{background-color:var(--color-primary-100, #dbeafe);color:var(--color-primary-700, #1d4ed8)}.lc-list__badge--success{background-color:var(--color-success-subtle);color:var(--color-on-success-subtle)}.lc-list__badge--warning{background-color:var(--color-warning-subtle);color:var(--color-on-warning-subtle)}.lc-list__badge--error{background-color:var(--color-error-100, #fee2e2);color:var(--color-on-error-subtle)}.lc-list__metadata{font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);white-space:nowrap}.lc-list__item--selected{background-color:var(--color-primary-50, #eff6ff)}.lc-list--clickable .lc-list__item--selected:hover:not(.lc-list__item--disabled){background-color:var(--color-primary-100, #dbeafe)}.lc-list--sm .lc-list__item{padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));gap:var(--lc-density-gap-sm, var(--spacing-2))}.lc-list--sm .lc-list__avatar{width:32px;height:32px}.lc-list--sm .lc-list__avatar-initials{font-size:var(--font-size-xs, .75rem)}.lc-list--sm .lc-list__label{font-size:var(--font-size-sm, .875rem)}.lc-list--sm .lc-list__subtitle{font-size:var(--font-size-xs, .75rem)}.lc-list--sm .lc-list__description{display:none}.lc-list--lg .lc-list__item{padding:var(--lc-density-padding-md, var(--spacing-4)) var(--spacing-5);gap:var(--lc-density-gap-md, var(--spacing-4))}.lc-list--lg .lc-list__avatar{width:48px;height:48px}.lc-list--lg .lc-list__avatar-initials{font-size:var(--font-size-base, 1rem)}.lc-list--lg .lc-list__label{font-size:var(--font-size-lg, 1.125rem)}.lc-list--lg .lc-list__content{gap:4px}.lc-list--card{background:transparent;gap:.5rem;overflow:visible}.lc-list--card .lc-list__item{padding:.75rem 1rem;border-radius:var(--border-radius-md, .5rem);background:var(--color-surface-2);border:1px solid var(--color-border);transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.lc-list--card.lc-list--clickable .lc-list__item:hover:not(.lc-list__item--disabled),.lc-list--card .lc-list__item--link:hover:not(.lc-list__item--disabled){background:var(--color-surface-hover);border-color:var(--color-border-strong);box-shadow:var(--elevation-1)}.lc-list--card.lc-list--clickable .lc-list__item:active:not(.lc-list__item--disabled),.lc-list--card .lc-list__item--link:active:not(.lc-list__item--disabled){background:var(--color-surface-sunken)}.lc-list--card.lc-list--with-dividers .lc-list__item{border-bottom-color:transparent}\n"],
|
|
222
227
|
dependencies: [
|
|
223
228
|
{
|
|
224
229
|
kind: "directive",
|
|
@@ -292,8 +297,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
292
297
|
],
|
|
293
298
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
294
299
|
viewProviders: [ɵprovideKitIcons([ICON_CHEVRON_RIGHT])],
|
|
295
|
-
template: "<!--\n Row content is shared between the plain (legacy) row and the keyboard-\n operable row rendered when `clickable` is set.\n-->\n<ng-template #rowContent let-item>\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl.template; context: { $implicit: item }\"></ng-container>\n } @else {\n <!-- Leading: Avatar or Icon -->\n @if (item.avatar) {\n <div [class]=\"avatarClasses(item)\">\n @if (item.avatar.startsWith('http') || item.avatar.startsWith('/') || item.avatar.startsWith('data:')) {\n <img [src]=\"item.avatar\" [alt]=\"item.label\" class=\"lc-list__avatar-img\" />\n } @else {\n <span class=\"lc-list__avatar-initials\">{{ item.avatar }}</span>\n }\n </div>\n } @else if (item.icon) {\n <lc-icon [name]=\"item.icon\" class=\"lc-list__icon\" size=\"sm\" [decorative]=\"true\" />\n }\n\n <!-- Content: Label, Subtitle, Description -->\n <div class=\"lc-list__content\">\n <span class=\"lc-list__label\">{{ item.label }}</span>\n @if (item.subtitle) {\n <span class=\"lc-list__subtitle\">{{ item.subtitle }}</span>\n }\n @if (item.description) {\n <span class=\"lc-list__description\">{{ item.description }}</span>\n }\n </div>\n\n <!-- Trailing: Badge, Metadata, Action -->\n <div class=\"lc-list__trailing\">\n @if (item.badge) {\n <span class=\"lc-list__badge lc-list__badge--{{ item.badgeVariant || 'default' }}\">{{ item.badge }}</span>\n }\n @if (item.metadata) {\n <span class=\"lc-list__metadata\">{{ item.metadata }}</span>\n }\n @if (item.action && !isLinkRow(item)) {\n <!-- The action is its own control: its click must not also activate the row. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- only stops the action click from also activating the row; the action is a real button -->\n <span class=\"lc-list__action-area\" (click)=\"$event.stopPropagation()\">\n <lc-button\n [variant]=\"actionVariant()\"\n [size]=\"actionSize()\"\n [ariaLabel]=\"item.actionAriaLabel ?? ''\"\n class=\"lc-list__action\"\n (clicked)=\"onActionClick(item)\"\n >\n {{ item.action }}\n </lc-button>\n </span>\n }\n </div>\n\n <!-- 3.36: a decorative chevron ends a clickable or linked row. -->\n @if (showChevron() && (clickable() || !!item.href)) {\n <lc-icon name=\"chevron-right\" class=\"lc-list__chevron\" size=\"sm\" [decorative]=\"true\" />\n }\n }\n</ng-template>\n\n<div #listEl [class]=\"listClasses()\" role=\"list\">\n @for (item of items(); track item.id || $index) {\n @if (isLinkRow(item)) {\n <!-- A real link over the whole row (3.16, TD-4); the row element carries the item styles. -->\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <a\n [class]=\"getItemClasses(item) + ' lc-list__item--link'\"\n [href]=\"item.href\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onLinkClick($event, item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </a>\n </div>\n } @else if (clickable()) {\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <div\n [class]=\"getItemClasses(item)\"\n role=\"button\"\n [attr.tabindex]=\"item.disabled ? -1 : 0\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n (keydown)=\"onItemKeydown($event, item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n </div>\n } @else {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- non-clickable lists keep reporting mouse clicks (backward compatible); use clickable for keyboard rows -->\n <div\n [class]=\"getItemClasses(item)\"\n role=\"listitem\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n }\n }\n</div>\n",
|
|
296
|
-
styles: [".lc-list{display:flex;width:100%;background-color:var(--color-surface, #ffffff);border-radius:var(--border-radius-md);overflow:hidden}.lc-list--vertical{flex-direction:column}.lc-list--vertical .lc-list__item{border-bottom:1px solid transparent}.lc-list--vertical>.lc-list__item:last-child,.lc-list--vertical>.lc-list__item-wrapper:last-child .lc-list__item{border-bottom:none}.lc-list--vertical.lc-list--with-dividers .lc-list__item{border-bottom-color:var(--color-divider)}.lc-list--horizontal{flex-direction:row}.lc-list--horizontal .lc-list__item,.lc-list--horizontal .lc-list__item-wrapper{flex:1}.lc-list--horizontal .lc-list__item{border-right:1px solid transparent}.lc-list--horizontal>.lc-list__item:last-child,.lc-list--horizontal>.lc-list__item-wrapper:last-child .lc-list__item{border-right:none}.lc-list--horizontal.lc-list--with-dividers .lc-list__item{border-right-color:var(--color-divider)}.lc-list__item-wrapper{display:flex;min-width:0}.lc-list__item-wrapper>.lc-list__item{flex:1;min-width:0}.lc-list__item{display:flex;align-items:center;gap:var(--spacing-3);padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));transition:background-color .2s ease}.lc-list__item:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--color-primary-500)}.lc-list__item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.lc-list__icon{flex-shrink:0;color:var(--color-text-tertiary)}.lc-list__label{flex:1;min-width:0;overflow-wrap:anywhere;color:var(--color-text-primary, #111827);font-size:var(--font-size-base);line-height:var(--line-height-base)}.lc-list__avatar{flex-shrink:0;width:40px;height:40px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background-color:var(--color-primary-100, #dbeafe)}.lc-list__avatar-img{width:100%;height:100%;object-fit:cover}.lc-list__avatar-initials{font-size:var(--font-size-sm, .875rem);font-weight:600;color:var(--color-primary-700, #1d4ed8);text-transform:uppercase;line-height:1;-webkit-user-select:none;user-select:none}.lc-list__avatar--member-1{background-color:var(--color-member-1, #1a6a79)}.lc-list__avatar--member-2{background-color:var(--color-member-2, #b04a22)}.lc-list__avatar--member-3{background-color:var(--color-member-3, #4e3f84)}.lc-list__avatar--member-4{background-color:var(--color-member-4, #5f7150)}.lc-list__avatar--member-5{background-color:var(--color-member-5, #9e3846)}.lc-list__avatar--member-6{background-color:var(--color-member-6, #5a798c)}.lc-list__avatar--member .lc-list__avatar-initials{color:var(--color-on-member, #ffffff);font-weight:700;letter-spacing:.02em}.lc-list__content{flex:1;display:flex;flex-direction:column;gap:2px;min-width:0}.lc-list__subtitle{font-size:var(--font-size-sm, .875rem);color:var(--color-text-tertiary);line-height:var(--line-height-sm, 1.25rem);overflow-wrap:anywhere}.lc-list__description{overflow-wrap:anywhere;font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);line-height:var(--line-height-xs, 1rem);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.lc-list--no-clamp .lc-list__description{display:block;-webkit-line-clamp:unset;overflow:visible}.lc-list__trailing{flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:4px}.lc-list__action{flex-shrink:0}.lc-list__chevron{flex-shrink:0;color:var(--color-text-tertiary)}.lc-list__chevron:dir(rtl){transform:scaleX(-1)}.lc-list--clickable .lc-list__item{cursor:pointer}.lc-list--clickable .lc-list__item:hover:not(.lc-list__item--disabled){background-color:var(--color-surface-hover)}.lc-list--clickable .lc-list__item:active:not(.lc-list__item--disabled){background-color:var(--color-surface-sunken)}.lc-list__item--link{min-height:var(--size-min-touch-height, 2.75rem);color:inherit;text-decoration:none;cursor:pointer}.lc-list__item--link:hover{background-color:var(--color-surface-hover)}.lc-list__item--link:active{background-color:var(--color-surface-sunken)}.lc-list__item--link.lc-list__item--selected:hover{background-color:var(--color-primary-100, #dbeafe)}@media(forced-colors:active){.lc-list__item:focus-visible{outline:2px solid Highlight;outline-offset:-2px}}.lc-list__badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:9999px;font-size:var(--font-size-xs, .75rem);font-weight:500;line-height:1.25rem;white-space:nowrap}.lc-list__badge--default{background-color:var(--color-surface-hover);color:var(--color-text-secondary)}.lc-list__badge--primary{background-color:var(--color-primary-100, #dbeafe);color:var(--color-primary-700, #1d4ed8)}.lc-list__badge--success{background-color:var(--color-success-subtle);color:var(--color-on-success-subtle)}.lc-list__badge--warning{background-color:var(--color-warning-subtle);color:var(--color-on-warning-subtle)}.lc-list__badge--error{background-color:var(--color-error-100, #fee2e2);color:var(--color-on-error-subtle)}.lc-list__metadata{font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);white-space:nowrap}.lc-list__item--selected{background-color:var(--color-primary-50, #eff6ff)}.lc-list--clickable .lc-list__item--selected:hover:not(.lc-list__item--disabled){background-color:var(--color-primary-100, #dbeafe)}.lc-list--sm .lc-list__item{padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));gap:var(--lc-density-gap-sm, var(--spacing-2))}.lc-list--sm .lc-list__avatar{width:32px;height:32px}.lc-list--sm .lc-list__avatar-initials{font-size:var(--font-size-xs, .75rem)}.lc-list--sm .lc-list__label{font-size:var(--font-size-sm, .875rem)}.lc-list--sm .lc-list__subtitle{font-size:var(--font-size-xs, .75rem)}.lc-list--sm .lc-list__description{display:none}.lc-list--lg .lc-list__item{padding:var(--lc-density-padding-md, var(--spacing-4)) var(--spacing-5);gap:var(--lc-density-gap-md, var(--spacing-4))}.lc-list--lg .lc-list__avatar{width:48px;height:48px}.lc-list--lg .lc-list__avatar-initials{font-size:var(--font-size-base, 1rem)}.lc-list--lg .lc-list__label{font-size:var(--font-size-lg, 1.125rem)}.lc-list--lg .lc-list__content{gap:4px}.lc-list--card{background:transparent;gap:.5rem;overflow:visible}.lc-list--card .lc-list__item{padding:.75rem 1rem;border-radius:var(--border-radius-md, .5rem);background:var(--color-surface-2);border:1px solid var(--color-border);transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.lc-list--card.lc-list--clickable .lc-list__item:hover:not(.lc-list__item--disabled),.lc-list--card .lc-list__item--link:hover:not(.lc-list__item--disabled){background:var(--color-surface-hover);border-color:var(--color-border-strong);box-shadow:var(--elevation-1)}.lc-list--card.lc-list--clickable .lc-list__item:active:not(.lc-list__item--disabled),.lc-list--card .lc-list__item--link:active:not(.lc-list__item--disabled){background:var(--color-surface-sunken)}.lc-list--card.lc-list--with-dividers .lc-list__item{border-bottom-color:transparent}\n"]
|
|
300
|
+
template: "<!--\n Row content is shared between the plain (legacy) row and the keyboard-\n operable row rendered when `clickable` is set.\n-->\n<ng-template #rowContent let-item>\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl.template; context: { $implicit: item }\"></ng-container>\n } @else {\n <!-- Leading: Avatar or Icon -->\n @if (item.avatar) {\n <div [class]=\"avatarClasses(item)\">\n @if (item.avatar.startsWith('http') || item.avatar.startsWith('/') || item.avatar.startsWith('data:')) {\n <img [src]=\"item.avatar\" [alt]=\"item.label\" class=\"lc-list__avatar-img\" />\n } @else {\n <span class=\"lc-list__avatar-initials\">{{ item.avatar }}</span>\n }\n </div>\n } @else if (item.icon) {\n <lc-icon [name]=\"item.icon\" class=\"lc-list__icon\" size=\"sm\" [decorative]=\"true\" />\n }\n\n <!-- Content: Label, Subtitle, Description -->\n <div class=\"lc-list__content\">\n <span class=\"lc-list__label\">{{ item.label }}</span>\n @if (item.subtitle) {\n <span class=\"lc-list__subtitle\">{{ item.subtitle }}</span>\n }\n @if (item.description) {\n <span class=\"lc-list__description\">{{ item.description }}</span>\n }\n </div>\n\n <!-- Trailing: Badge, Metadata, Action -->\n <div class=\"lc-list__trailing\">\n @if (item.badge) {\n <span class=\"lc-list__badge lc-list__badge--{{ item.badgeVariant || 'default' }}\">{{ item.badge }}</span>\n }\n @if (item.metadata) {\n <span class=\"lc-list__metadata\">{{ item.metadata }}</span>\n }\n @if (item.action && !isLinkRow(item)) {\n <!-- The action is its own control: its click must not also activate the row. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- only stops the action click from also activating the row; the action is a real button -->\n <span class=\"lc-list__action-area\" (click)=\"$event.stopPropagation()\">\n <lc-button\n [variant]=\"actionVariant()\"\n [size]=\"actionSize()\"\n [ariaLabel]=\"item.actionAriaLabel ?? ''\"\n class=\"lc-list__action\"\n (clicked)=\"onActionClick(item)\"\n >\n {{ item.action }}\n </lc-button>\n </span>\n }\n </div>\n\n <!-- 3.36: a decorative chevron ends a clickable or linked row. -->\n @if (showChevron() && (clickable() || !!item.href)) {\n <lc-icon name=\"chevron-right\" class=\"lc-list__chevron\" size=\"sm\" [decorative]=\"true\" />\n }\n }\n</ng-template>\n\n<div #listEl [class]=\"listClasses()\" role=\"list\">\n @for (item of items(); track item.id || $index; let i = $index) {\n @if (isLinkRow(item)) {\n <!-- A real link over the whole row (3.16, TD-4); the row element carries the item styles. -->\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <a\n [class]=\"getItemClasses(item) + ' lc-list__item--link'\"\n [href]=\"item.href\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onLinkClick($event, item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </a>\n </div>\n } @else if (clickable() && item.action && !itemTemplate()) {\n <!-- 3.37 (request 057, 056 F-2): a clickable row with an action keeps the\n action out of the row's button. The row's native button is stretched\n over the row and named by it; the action area sits above it. -->\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- the row's native button is the control; its Enter/Space click bubbles here -->\n <div [class]=\"getItemClasses(item) + ' lc-list__item--split'\" [id]=\"rowId(i)\" (click)=\"onItemClick(item)\">\n <!-- eslint-disable-next-line @angular-eslint/template/elements-content -- named by aria-labelledby (the row's text); text inside would repeat it -->\n <button\n type=\"button\"\n class=\"lc-list__item-button\"\n [attr.aria-labelledby]=\"rowId(i)\"\n [attr.tabindex]=\"item.disabled ? -1 : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n ></button>\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n </div>\n } @else if (clickable()) {\n <div class=\"lc-list__item-wrapper\" role=\"listitem\">\n <div\n [class]=\"getItemClasses(item)\"\n role=\"button\"\n [attr.tabindex]=\"item.disabled ? -1 : 0\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n (keydown)=\"onItemKeydown($event, item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n </div>\n } @else {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -- non-clickable lists keep reporting mouse clicks (backward compatible); use clickable for keyboard rows -->\n <div\n [class]=\"getItemClasses(item)\"\n role=\"listitem\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent; context: { $implicit: item }\"></ng-container>\n </div>\n }\n }\n</div>\n",
|
|
301
|
+
styles: [".lc-list{display:flex;width:100%;background-color:var(--color-surface, #ffffff);border-radius:var(--border-radius-md);overflow:hidden}.lc-list--vertical{flex-direction:column}.lc-list--vertical .lc-list__item{border-bottom:1px solid transparent}.lc-list--vertical>.lc-list__item:last-child,.lc-list--vertical>.lc-list__item-wrapper:last-child .lc-list__item{border-bottom:none}.lc-list--vertical.lc-list--with-dividers .lc-list__item{border-bottom-color:var(--color-divider)}.lc-list--horizontal{flex-direction:row}.lc-list--horizontal .lc-list__item,.lc-list--horizontal .lc-list__item-wrapper{flex:1}.lc-list--horizontal .lc-list__item{border-right:1px solid transparent}.lc-list--horizontal>.lc-list__item:last-child,.lc-list--horizontal>.lc-list__item-wrapper:last-child .lc-list__item{border-right:none}.lc-list--horizontal.lc-list--with-dividers .lc-list__item{border-right-color:var(--color-divider)}.lc-list__item-wrapper{display:flex;min-width:0}.lc-list__item-wrapper>.lc-list__item{flex:1;min-width:0}.lc-list__item{display:flex;align-items:center;gap:var(--spacing-3);padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));transition:background-color .2s ease}.lc-list__item:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--color-primary-500)}.lc-list__item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.lc-list__icon{flex-shrink:0;color:var(--color-text-tertiary)}.lc-list__label{flex:1;min-width:0;overflow-wrap:anywhere;hyphens:auto;hyphenate-limit-chars:12 4 3;color:var(--color-text-primary, #111827);font-size:var(--font-size-base);line-height:var(--line-height-base)}.lc-list__avatar{flex-shrink:0;width:40px;height:40px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background-color:var(--color-primary-100, #dbeafe)}.lc-list__avatar-img{width:100%;height:100%;object-fit:cover}.lc-list__avatar-initials{font-size:var(--font-size-sm, .875rem);font-weight:600;color:var(--color-primary-700, #1d4ed8);text-transform:uppercase;line-height:1;-webkit-user-select:none;user-select:none}.lc-list__avatar--member-1{background-color:var(--color-member-1, #1a6a79)}.lc-list__avatar--member-2{background-color:var(--color-member-2, #b04a22)}.lc-list__avatar--member-3{background-color:var(--color-member-3, #4e3f84)}.lc-list__avatar--member-4{background-color:var(--color-member-4, #5f7150)}.lc-list__avatar--member-5{background-color:var(--color-member-5, #9e3846)}.lc-list__avatar--member-6{background-color:var(--color-member-6, #5a798c)}.lc-list__avatar--member .lc-list__avatar-initials{color:var(--color-on-member, #ffffff);font-weight:700;letter-spacing:.02em}.lc-list__content{flex:1;display:flex;flex-direction:column;gap:2px;min-width:0}.lc-list__subtitle{font-size:var(--font-size-sm, .875rem);color:var(--color-text-tertiary);line-height:var(--line-height-sm, 1.25rem);overflow-wrap:anywhere}.lc-list__description{overflow-wrap:anywhere;font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);line-height:var(--line-height-xs, 1rem);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.lc-list--no-clamp .lc-list__description{display:block;-webkit-line-clamp:unset;overflow:visible}.lc-list__trailing{flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:4px}.lc-list__action{flex-shrink:0}.lc-list__chevron{flex-shrink:0;color:var(--color-text-tertiary)}.lc-list__chevron:dir(rtl){transform:scaleX(-1)}.lc-list--clickable .lc-list__item{cursor:pointer}.lc-list--clickable .lc-list__item:hover:not(.lc-list__item--disabled){background-color:var(--color-surface-hover)}.lc-list--clickable .lc-list__item:active:not(.lc-list__item--disabled){background-color:var(--color-surface-sunken)}.lc-list__item--link{min-height:var(--size-min-touch-height, 2.75rem);color:inherit;text-decoration:none;cursor:pointer}.lc-list__item--link:hover{background-color:var(--color-surface-hover)}.lc-list__item--link:active{background-color:var(--color-surface-sunken)}.lc-list__item--link.lc-list__item--selected:hover{background-color:var(--color-primary-100, #dbeafe)}@media(forced-colors:active){.lc-list__item:focus-visible{outline:2px solid Highlight;outline-offset:-2px}}.lc-list__item--split{position:relative;isolation:isolate}.lc-list__item-button{position:absolute;inset:0;margin:0;padding:0;border:0;border-radius:inherit;background:none;font:inherit;color:inherit;cursor:inherit;outline:none}.lc-list__item--split .lc-list__action-area{position:relative;z-index:1}.lc-list__item:has(>.lc-list__item-button:focus-visible){box-shadow:inset 0 0 0 2px var(--color-primary-500)}@media(forced-colors:active){.lc-list__item:has(>.lc-list__item-button:focus-visible){outline:2px solid Highlight;outline-offset:-2px}}.lc-list__badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:9999px;font-size:var(--font-size-xs, .75rem);font-weight:500;line-height:1.25rem;white-space:nowrap}.lc-list__badge--default{background-color:var(--color-surface-hover);color:var(--color-text-secondary)}.lc-list__badge--primary{background-color:var(--color-primary-100, #dbeafe);color:var(--color-primary-700, #1d4ed8)}.lc-list__badge--success{background-color:var(--color-success-subtle);color:var(--color-on-success-subtle)}.lc-list__badge--warning{background-color:var(--color-warning-subtle);color:var(--color-on-warning-subtle)}.lc-list__badge--error{background-color:var(--color-error-100, #fee2e2);color:var(--color-on-error-subtle)}.lc-list__metadata{font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);white-space:nowrap}.lc-list__item--selected{background-color:var(--color-primary-50, #eff6ff)}.lc-list--clickable .lc-list__item--selected:hover:not(.lc-list__item--disabled){background-color:var(--color-primary-100, #dbeafe)}.lc-list--sm .lc-list__item{padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));gap:var(--lc-density-gap-sm, var(--spacing-2))}.lc-list--sm .lc-list__avatar{width:32px;height:32px}.lc-list--sm .lc-list__avatar-initials{font-size:var(--font-size-xs, .75rem)}.lc-list--sm .lc-list__label{font-size:var(--font-size-sm, .875rem)}.lc-list--sm .lc-list__subtitle{font-size:var(--font-size-xs, .75rem)}.lc-list--sm .lc-list__description{display:none}.lc-list--lg .lc-list__item{padding:var(--lc-density-padding-md, var(--spacing-4)) var(--spacing-5);gap:var(--lc-density-gap-md, var(--spacing-4))}.lc-list--lg .lc-list__avatar{width:48px;height:48px}.lc-list--lg .lc-list__avatar-initials{font-size:var(--font-size-base, 1rem)}.lc-list--lg .lc-list__label{font-size:var(--font-size-lg, 1.125rem)}.lc-list--lg .lc-list__content{gap:4px}.lc-list--card{background:transparent;gap:.5rem;overflow:visible}.lc-list--card .lc-list__item{padding:.75rem 1rem;border-radius:var(--border-radius-md, .5rem);background:var(--color-surface-2);border:1px solid var(--color-border);transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.lc-list--card.lc-list--clickable .lc-list__item:hover:not(.lc-list__item--disabled),.lc-list--card .lc-list__item--link:hover:not(.lc-list__item--disabled){background:var(--color-surface-hover);border-color:var(--color-border-strong);box-shadow:var(--elevation-1)}.lc-list--card.lc-list--clickable .lc-list__item:active:not(.lc-list__item--disabled),.lc-list--card .lc-list__item--link:active:not(.lc-list__item--disabled){background:var(--color-surface-sunken)}.lc-list--card.lc-list--with-dividers .lc-list__item{border-bottom-color:transparent}\n"]
|
|
297
302
|
}]
|
|
298
303
|
}],
|
|
299
304
|
ctorParameters: () => [],
|