@truenas/ui-components 0.4.11 → 0.4.12
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.
|
@@ -6,7 +6,7 @@ import * as i1$3 from '@angular/forms';
|
|
|
6
6
|
import { NgControl, NG_VALUE_ACCESSOR, FormsModule, Validators } from '@angular/forms';
|
|
7
7
|
import { ComponentHarness, HarnessPredicate, TestKey, parallel } from '@angular/cdk/testing';
|
|
8
8
|
import * as i1 from '@angular/cdk/a11y';
|
|
9
|
-
import { A11yModule, FocusMonitor, _IdGenerator } from '@angular/cdk/a11y';
|
|
9
|
+
import { A11yModule, AriaDescriber, FocusMonitor, _IdGenerator } from '@angular/cdk/a11y';
|
|
10
10
|
import * as i1$2 from '@angular/common';
|
|
11
11
|
import { DOCUMENT, NgTemplateOutlet, CommonModule, AsyncPipe, isPlatformBrowser } from '@angular/common';
|
|
12
12
|
import { mdiCheckCircle, mdiAlertCircle, mdiAlert, mdiInformation, mdiOpenInNew, mdiHelpCircle, mdiDotsVertical, mdiClose } from '@mdi/js';
|
|
@@ -2589,6 +2589,22 @@ class TnButtonComponent {
|
|
|
2589
2589
|
this.onClick.emit(event);
|
|
2590
2590
|
}
|
|
2591
2591
|
hostRef = inject((ElementRef));
|
|
2592
|
+
constructor() {
|
|
2593
|
+
// A disabled native <button> suppresses its own click events, but its
|
|
2594
|
+
// pointer-events: none style retargets clicks over it to this host element —
|
|
2595
|
+
// where consumers commonly bind (click). Halt those here so a disabled
|
|
2596
|
+
// tn-button is inert for every consumer, matching what handleAnchorClick
|
|
2597
|
+
// does for the anchor variants. Registered in the constructor (before any
|
|
2598
|
+
// template listener on the host) and capture-phase, so it runs first and
|
|
2599
|
+
// stopImmediatePropagation() reliably blocks host (click) handlers.
|
|
2600
|
+
const host = this.hostRef.nativeElement;
|
|
2601
|
+
host.addEventListener('click', (event) => {
|
|
2602
|
+
if (this.disabled()) {
|
|
2603
|
+
event.preventDefault();
|
|
2604
|
+
event.stopImmediatePropagation();
|
|
2605
|
+
}
|
|
2606
|
+
}, { capture: true });
|
|
2607
|
+
}
|
|
2592
2608
|
// The template renders exactly one of `<a [routerLink]>`, `<a [href]>`, or
|
|
2593
2609
|
// `<button>` via `@if/@else`, and each carries the `#button` ref — so this
|
|
2594
2610
|
// resolves to whichever variant is active. Using a viewChild instead of a
|
|
@@ -2626,7 +2642,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
2626
2642
|
args: [{ selector: 'tn-button', standalone: true, imports: [CommonModule, RouterLink, TnTestIdDirective, LabelMarkupPipe, TnIconComponent], host: {
|
|
2627
2643
|
'[class.tn-button--full-width]': 'fullWidth()',
|
|
2628
2644
|
}, template: "<ng-template #content>\n @if (icon() && iconPosition() === 'left') {\n <tn-icon class=\"storybook-button__icon\" size=\"sm\" aria-hidden=\"true\" [name]=\"icon()!\" />\n }\n <span class=\"storybook-button__label\" [innerHTML]=\"label() | tnLabelMarkup\"></span>\n @if (icon() && iconPosition() === 'right') {\n <tn-icon class=\"storybook-button__icon\" size=\"sm\" aria-hidden=\"true\" [name]=\"icon()!\" />\n }\n</ng-template>\n\n@if (isRouterLink()) {\n <a\n #button\n tnTestIdType=\"button\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [routerLink]=\"disabled() ? null : routerLink()\"\n [queryParams]=\"queryParams()\"\n [fragment]=\"fragment()\"\n [target]=\"target()\"\n [rel]=\"rel()\"\n [attr.aria-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.tabindex]=\"disabled() ? -1 : null\"\n [class.is-disabled]=\"disabled()\"\n [tnTestId]=\"testId()\"\n (click)=\"handleAnchorClick($event)\"\n >\n <ng-container [ngTemplateOutlet]=\"content\" />\n </a>\n} @else if (isAnchor()) {\n <a\n #button\n tnTestIdType=\"button\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [attr.href]=\"disabled() ? null : href()\"\n [target]=\"target()\"\n [rel]=\"rel()\"\n [attr.aria-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.tabindex]=\"disabled() ? -1 : null\"\n [class.is-disabled]=\"disabled()\"\n [tnTestId]=\"testId()\"\n (click)=\"handleAnchorClick($event)\"\n >\n <ng-container [ngTemplateOutlet]=\"content\" />\n </a>\n} @else {\n <button\n #button\n tnTestIdType=\"button\"\n [attr.type]=\"type()\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n [tnTestId]=\"testId()\"\n (click)=\"onClick.emit($event)\"\n >\n <ng-container [ngTemplateOutlet]=\"content\" />\n </button>\n}\n", styles: [":host{display:inline-block;width:fit-content;justify-self:center}:host(.tn-button--full-width){display:block;width:100%;justify-self:stretch}:host(.tn-button--full-width) .storybook-button{width:100%}.storybook-button ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.storybook-button{display:inline-block;cursor:pointer;border:1px solid transparent;font-weight:500;line-height:1;font-family:IBM Plex Sans,Helvetica Neue,Helvetica,Arial,sans-serif;white-space:nowrap}.storybook-button:disabled,.storybook-button.is-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.storybook-button--has-icon{display:inline-flex;align-items:center;justify-content:center;gap:8px}.storybook-button__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}a.storybook-button{text-decoration:none;text-align:center}.button-primary{background-color:var(--tn-primary);color:var(--tn-primary-txt)}.button-default{box-shadow:#00000026 0 0 0 1px inset;background-color:var(--tn-btn-default-bg);color:var(--tn-btn-default-txt)}.button-outline-primary{background-color:transparent;border:1px solid var(--tn-primary);color:var(--tn-primary);transition:background-color .2s ease-in-out,border-color .2s ease-in-out,color .2s ease-in-out}.button-outline-primary:hover{background-color:var(--tn-primary);border:1px solid var(--tn-primary);color:var(--tn-primary-txt)}.button-outline-default{background-color:transparent;border:1px solid var(--tn-lines, #e5e7eb);color:var(--tn-fg1, #000000);transition:background-color .2s ease-in-out,border-color .2s ease-in-out,color .2s ease-in-out}.button-outline-default:hover{background-color:var(--tn-btn-default-bg);border:1px solid var(--tn-btn-default-bg);color:var(--tn-btn-default-txt);box-shadow:#00000026 0 0 0 1px inset}.button-warn{background-color:var(--tn-red);color:#fff}.button-outline-warn{background-color:transparent;border:1px solid var(--tn-red);color:var(--tn-red);transition:background-color .2s ease-in-out,border-color .2s ease-in-out,color .2s ease-in-out}.button-outline-warn:hover{background-color:var(--tn-red);border:1px solid var(--tn-red);color:#fff}.storybook-button--small{padding:10px 16px;font-size:12px}.storybook-button--medium{padding:11px 20px;font-size:14px}.storybook-button--large{padding:12px 24px;font-size:1rem}\n"] }]
|
|
2629
|
-
}], propDecorators: { primary: [{ type: i0.Input, args: [{ isSignal: true, alias: "primary", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], backgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "backgroundColor", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], queryParams: [{ type: i0.Input, args: [{ isSignal: true, alias: "queryParams", required: false }] }], fragment: [{ type: i0.Input, args: [{ isSignal: true, alias: "fragment", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], rel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rel", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], onClick: [{ type: i0.Output, args: ["onClick"] }], innerRef: [{ type: i0.ViewChild, args: ['button', { isSignal: true }] }] } });
|
|
2645
|
+
}], ctorParameters: () => [], propDecorators: { primary: [{ type: i0.Input, args: [{ isSignal: true, alias: "primary", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], backgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "backgroundColor", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], queryParams: [{ type: i0.Input, args: [{ isSignal: true, alias: "queryParams", required: false }] }], fragment: [{ type: i0.Input, args: [{ isSignal: true, alias: "fragment", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], rel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rel", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], onClick: [{ type: i0.Output, args: ["onClick"] }], innerRef: [{ type: i0.ViewChild, args: ['button', { isSignal: true }] }] } });
|
|
2630
2646
|
|
|
2631
2647
|
/**
|
|
2632
2648
|
* Harness for interacting with tn-button in tests.
|
|
@@ -2815,6 +2831,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
2815
2831
|
/* eslint-disable @angular-eslint/no-input-rename */
|
|
2816
2832
|
// Input aliasing is intentional for directive API consistency (e.g., ixTooltip, ixTooltipPosition)
|
|
2817
2833
|
// This follows the standard Angular pattern used by Material and other directive-based components
|
|
2834
|
+
/**
|
|
2835
|
+
* Elements that can receive focus / are read by assistive tech. Used to decide whether
|
|
2836
|
+
* the directive's host is itself the interactive element, or a wrapper (e.g. `<tn-button>`)
|
|
2837
|
+
* whose inner control should carry `aria-describedby`.
|
|
2838
|
+
*/
|
|
2839
|
+
const INTERACTIVE_SELECTOR = 'button, a[href], input, select, textarea, [tabindex]';
|
|
2818
2840
|
class TnTooltipDirective {
|
|
2819
2841
|
message = input('', { ...(ngDevMode ? { debugName: "message" } : {}), alias: 'tnTooltip' });
|
|
2820
2842
|
position = input('above', { ...(ngDevMode ? { debugName: "position" } : {}), alias: 'tnTooltipPosition' });
|
|
@@ -2828,27 +2850,99 @@ class TnTooltipDirective {
|
|
|
2828
2850
|
_hideTimeout = null;
|
|
2829
2851
|
_isTooltipVisible = false;
|
|
2830
2852
|
_positionSub = null;
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
* Only point `aria-describedby` at the tooltip when there is actually a message to
|
|
2834
|
-
* describe. Otherwise every host (e.g. an icon button with no tooltip) would carry a
|
|
2835
|
-
* dangling reference to a tooltip element that is never rendered.
|
|
2836
|
-
*/
|
|
2837
|
-
get _ariaDescribedBy() {
|
|
2838
|
-
return !this.disabled() && this.message() ? this._tooltipId : null;
|
|
2839
|
-
}
|
|
2853
|
+
// Unique ID for the overlay tooltip element
|
|
2854
|
+
_tooltipId = `tn-tooltip-${Math.random().toString(36).substr(2, 9)}`;
|
|
2840
2855
|
_overlay = inject(Overlay);
|
|
2841
2856
|
_elementRef = inject((ElementRef));
|
|
2842
2857
|
_viewContainerRef = inject(ViewContainerRef);
|
|
2843
2858
|
_overlayPositionBuilder = inject(OverlayPositionBuilder);
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2859
|
+
_ariaDescriber = inject(AriaDescriber);
|
|
2860
|
+
_viewInitialized = false;
|
|
2861
|
+
_describedTarget = null;
|
|
2862
|
+
_describedMessage = '';
|
|
2863
|
+
_innerObserver = null;
|
|
2864
|
+
/**
|
|
2865
|
+
* Re-sync the description (see ngAfterViewInit) when the inputs change. The initial
|
|
2866
|
+
* write cannot happen here: on the first run the host's child components (e.g.
|
|
2867
|
+
* tn-button's inner `<button>`) have not rendered yet.
|
|
2868
|
+
*/
|
|
2869
|
+
_syncDescriptionOnInputChange = effect(() => {
|
|
2870
|
+
this.disabled();
|
|
2871
|
+
this.message();
|
|
2872
|
+
if (this._viewInitialized) {
|
|
2873
|
+
this._syncAriaDescription();
|
|
2874
|
+
}
|
|
2875
|
+
}, ...(ngDevMode ? [{ debugName: "_syncDescriptionOnInputChange" }] : []));
|
|
2876
|
+
/**
|
|
2877
|
+
* Expose the message to assistive tech via CDK's AriaDescriber: it keeps the text in
|
|
2878
|
+
* a persistent visually-hidden element (so `aria-describedby` never dangles — the
|
|
2879
|
+
* overlay tooltip only exists while shown) and adds/removes only its own id token,
|
|
2880
|
+
* leaving descriptions the control already carries (form hints, error ids) intact.
|
|
2881
|
+
* The description goes on the interactive element itself: the host when it is one,
|
|
2882
|
+
* otherwise the first interactive descendant (e.g. `<tn-button>`'s inner `<button>`),
|
|
2883
|
+
* because screen readers read descriptions off the focused control, not wrappers.
|
|
2884
|
+
*/
|
|
2885
|
+
ngAfterViewInit() {
|
|
2886
|
+
this._viewInitialized = true;
|
|
2887
|
+
this._syncAriaDescription();
|
|
2888
|
+
const host = this._elementRef.nativeElement;
|
|
2889
|
+
if (!host.matches(INTERACTIVE_SELECTOR) && typeof MutationObserver !== 'undefined') {
|
|
2890
|
+
// The inner control can render after view init (@if branches inside the wrapper
|
|
2891
|
+
// swapping, deferred content) — re-describe when the host's subtree changes.
|
|
2892
|
+
// AriaDescriber writes attributes only, which produces no childList mutations,
|
|
2893
|
+
// so this cannot loop.
|
|
2894
|
+
this._innerObserver = new MutationObserver(() => this._syncAriaDescription());
|
|
2895
|
+
this._innerObserver.observe(host, { childList: true, subtree: true });
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
_syncAriaDescription() {
|
|
2899
|
+
const host = this._elementRef.nativeElement;
|
|
2900
|
+
let target = host;
|
|
2901
|
+
if (!host.matches(INTERACTIVE_SELECTOR)) {
|
|
2902
|
+
// Forward the description only when it is unambiguous: a wrapper with exactly
|
|
2903
|
+
// one interactive descendant (e.g. tn-button's inner <button>). A container
|
|
2904
|
+
// holding several controls keeps the description on the host — describing an
|
|
2905
|
+
// arbitrary first control would attach the text to the wrong element.
|
|
2906
|
+
const candidates = host.querySelectorAll(INTERACTIVE_SELECTOR);
|
|
2907
|
+
if (candidates.length === 1) {
|
|
2908
|
+
target = candidates[0];
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
const message = !this.disabled() ? this._plainTextMessage(this.message()) : '';
|
|
2912
|
+
if (this._describedTarget === target && this._describedMessage === message) {
|
|
2913
|
+
return;
|
|
2914
|
+
}
|
|
2915
|
+
this._removeAriaDescription();
|
|
2916
|
+
if (message) {
|
|
2917
|
+
this._ariaDescriber.describe(target, message);
|
|
2918
|
+
this._describedTarget = target;
|
|
2919
|
+
this._describedMessage = message;
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
/**
|
|
2923
|
+
* The overlay tooltip renders its message as HTML (`[innerHTML]`), but AriaDescriber
|
|
2924
|
+
* writes the description as plain text — strip any markup so screen readers never
|
|
2925
|
+
* announce literal tags. DOMParser parses inert markup (no script execution).
|
|
2926
|
+
*/
|
|
2927
|
+
_plainTextMessage(message) {
|
|
2928
|
+
if (!message.includes('<') && !message.includes('&')) {
|
|
2929
|
+
return message;
|
|
2930
|
+
}
|
|
2931
|
+
return new DOMParser().parseFromString(message, 'text/html').body.textContent ?? '';
|
|
2932
|
+
}
|
|
2933
|
+
_removeAriaDescription() {
|
|
2934
|
+
if (this._describedTarget && this._describedMessage) {
|
|
2935
|
+
this._ariaDescriber.removeDescription(this._describedTarget, this._describedMessage);
|
|
2936
|
+
}
|
|
2937
|
+
this._describedTarget = null;
|
|
2938
|
+
this._describedMessage = '';
|
|
2847
2939
|
}
|
|
2848
2940
|
ngOnDestroy() {
|
|
2849
2941
|
this._clearTimeouts();
|
|
2850
2942
|
this.hide(0);
|
|
2851
2943
|
this._positionSub?.unsubscribe();
|
|
2944
|
+
this._innerObserver?.disconnect();
|
|
2945
|
+
this._removeAriaDescription();
|
|
2852
2946
|
if (this._overlayRef) {
|
|
2853
2947
|
this._overlayRef.dispose();
|
|
2854
2948
|
this._overlayRef = null;
|
|
@@ -2862,12 +2956,22 @@ class TnTooltipDirective {
|
|
|
2862
2956
|
_onMouseLeave() {
|
|
2863
2957
|
this.hide(this.hideDelay());
|
|
2864
2958
|
}
|
|
2865
|
-
|
|
2959
|
+
// focusin/focusout (not focus/blur): focus does not bubble, so on a wrapper host
|
|
2960
|
+
// (e.g. `<tn-button>`) a focus listener never fires when the inner control is
|
|
2961
|
+
// focused via keyboard. focusin/focusout bubble and cover both shapes.
|
|
2962
|
+
_onFocusIn() {
|
|
2866
2963
|
if (!this.disabled() && this.message()) {
|
|
2867
2964
|
this.show(this.showDelay());
|
|
2868
2965
|
}
|
|
2869
2966
|
}
|
|
2870
|
-
|
|
2967
|
+
_onFocusOut(event) {
|
|
2968
|
+
// focusout bubbles for every focus move inside the host too — only hide when
|
|
2969
|
+
// focus actually leaves the host, or a wrapper-internal move would tear down
|
|
2970
|
+
// the visible tooltip via the armed hide timeout.
|
|
2971
|
+
const next = event.relatedTarget;
|
|
2972
|
+
if (next && this._elementRef.nativeElement.contains(next)) {
|
|
2973
|
+
return;
|
|
2974
|
+
}
|
|
2871
2975
|
this.hide(this.hideDelay());
|
|
2872
2976
|
}
|
|
2873
2977
|
_onKeydown(event) {
|
|
@@ -2877,10 +2981,16 @@ class TnTooltipDirective {
|
|
|
2877
2981
|
}
|
|
2878
2982
|
/** Shows the tooltip */
|
|
2879
2983
|
show(delay = 0) {
|
|
2880
|
-
if (this.disabled() || !this.message()
|
|
2984
|
+
if (this.disabled() || !this.message()) {
|
|
2881
2985
|
return;
|
|
2882
2986
|
}
|
|
2987
|
+
// Cancel any pending hide even when already visible: a show intent while the
|
|
2988
|
+
// tooltip is up (e.g. focus or pointer re-entering) must keep it up, not let a
|
|
2989
|
+
// previously armed hide timeout tear it down.
|
|
2883
2990
|
this._clearTimeouts();
|
|
2991
|
+
if (this._isTooltipVisible) {
|
|
2992
|
+
return;
|
|
2993
|
+
}
|
|
2884
2994
|
this._showTimeout = setTimeout(() => {
|
|
2885
2995
|
if (!this._overlayRef) {
|
|
2886
2996
|
this._createOverlay();
|
|
@@ -3001,16 +3111,13 @@ class TnTooltipDirective {
|
|
|
3001
3111
|
}
|
|
3002
3112
|
}
|
|
3003
3113
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3004
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: TnTooltipDirective, isStandalone: true, selector: "[tnTooltip]", inputs: { message: { classPropertyName: "message", publicName: "tnTooltip", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "tnTooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "tnTooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, showDelay: { classPropertyName: "showDelay", publicName: "tnTooltipShowDelay", isSignal: true, isRequired: false, transformFunction: null }, hideDelay: { classPropertyName: "hideDelay", publicName: "tnTooltipHideDelay", isSignal: true, isRequired: false, transformFunction: null }, tooltipClass: { classPropertyName: "tooltipClass", publicName: "tnTooltipClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "_onMouseEnter()", "mouseleave": "_onMouseLeave()", "
|
|
3114
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: TnTooltipDirective, isStandalone: true, selector: "[tnTooltip]", inputs: { message: { classPropertyName: "message", publicName: "tnTooltip", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "tnTooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "tnTooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, showDelay: { classPropertyName: "showDelay", publicName: "tnTooltipShowDelay", isSignal: true, isRequired: false, transformFunction: null }, hideDelay: { classPropertyName: "hideDelay", publicName: "tnTooltipHideDelay", isSignal: true, isRequired: false, transformFunction: null }, tooltipClass: { classPropertyName: "tooltipClass", publicName: "tnTooltipClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "_onMouseEnter()", "mouseleave": "_onMouseLeave()", "focusin": "_onFocusIn()", "focusout": "_onFocusOut($event)", "keydown": "_onKeydown($event)" } }, ngImport: i0 });
|
|
3005
3115
|
}
|
|
3006
3116
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnTooltipDirective, decorators: [{
|
|
3007
3117
|
type: Directive,
|
|
3008
3118
|
args: [{
|
|
3009
3119
|
selector: '[tnTooltip]',
|
|
3010
3120
|
standalone: true,
|
|
3011
|
-
host: {
|
|
3012
|
-
'[attr.aria-describedby]': '_ariaDescribedBy',
|
|
3013
|
-
}
|
|
3014
3121
|
}]
|
|
3015
3122
|
}], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "tnTooltip", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "tnTooltipPosition", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "tnTooltipDisabled", required: false }] }], showDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "tnTooltipShowDelay", required: false }] }], hideDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "tnTooltipHideDelay", required: false }] }], tooltipClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "tnTooltipClass", required: false }] }], _onMouseEnter: [{
|
|
3016
3123
|
type: HostListener,
|
|
@@ -3018,12 +3125,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
3018
3125
|
}], _onMouseLeave: [{
|
|
3019
3126
|
type: HostListener,
|
|
3020
3127
|
args: ['mouseleave']
|
|
3021
|
-
}],
|
|
3128
|
+
}], _onFocusIn: [{
|
|
3022
3129
|
type: HostListener,
|
|
3023
|
-
args: ['
|
|
3024
|
-
}],
|
|
3130
|
+
args: ['focusin']
|
|
3131
|
+
}], _onFocusOut: [{
|
|
3025
3132
|
type: HostListener,
|
|
3026
|
-
args: ['
|
|
3133
|
+
args: ['focusout', ['$event']]
|
|
3027
3134
|
}], _onKeydown: [{
|
|
3028
3135
|
type: HostListener,
|
|
3029
3136
|
args: ['keydown', ['$event']]
|
|
@@ -6314,7 +6421,7 @@ class TnCardComponent {
|
|
|
6314
6421
|
return type ? `tn-card__status--${type}` : 'tn-card__status--neutral';
|
|
6315
6422
|
}
|
|
6316
6423
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6317
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnCardComponent, isStandalone: true, selector: "tn-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, titleLink: { classPropertyName: "titleLink", publicName: "titleLink", isSignal: true, isRequired: false, transformFunction: null }, titleRouterLink: { classPropertyName: "titleRouterLink", publicName: "titleRouterLink", isSignal: true, isRequired: false, transformFunction: null }, titleQueryParams: { classPropertyName: "titleQueryParams", publicName: "titleQueryParams", isSignal: true, isRequired: false, transformFunction: null }, titleTooltip: { classPropertyName: "titleTooltip", publicName: "titleTooltip", isSignal: true, isRequired: false, transformFunction: null }, elevation: { classPropertyName: "elevation", publicName: "elevation", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, padContent: { classPropertyName: "padContent", publicName: "padContent", isSignal: true, isRequired: false, transformFunction: null }, fillHeight: { classPropertyName: "fillHeight", publicName: "fillHeight", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null }, headerStatus: { classPropertyName: "headerStatus", publicName: "headerStatus", isSignal: true, isRequired: false, transformFunction: null }, headerControl: { classPropertyName: "headerControl", publicName: "headerControl", isSignal: true, isRequired: false, transformFunction: null }, headerMenu: { classPropertyName: "headerMenu", publicName: "headerMenu", isSignal: true, isRequired: false, transformFunction: null }, headerMenuTriggerTestId: { classPropertyName: "headerMenuTriggerTestId", publicName: "headerMenuTriggerTestId", isSignal: true, isRequired: false, transformFunction: null }, primaryAction: { classPropertyName: "primaryAction", publicName: "primaryAction", isSignal: true, isRequired: false, transformFunction: null }, secondaryAction: { classPropertyName: "secondaryAction", publicName: "secondaryAction", isSignal: true, isRequired: false, transformFunction: null }, footerLink: { classPropertyName: "footerLink", publicName: "footerLink", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.tn-card-host--content-height": "!fillHeight()" } }, queries: [{ propertyName: "projectedHeader", first: true, predicate: TnCardHeaderDirective, descendants: true, isSignal: true }, { propertyName: "headerActions", first: true, predicate: TnCardHeaderActionsDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "footerActions", first: true, predicate: TnCardFooterActionsDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "<div [ngClass]=\"classes()\">\n <!-- Header section -->\n @if (hasHeader()) {\n <div class=\"tn-card__header\">\n <div class=\"tn-card__header-left\">\n <ng-content select=\"[tnCardHeader]\" />\n @if (!projectedHeader() && title()) {\n <h3 class=\"tn-card__title\">\n @if (isTitleRouterLink()) {\n <a\n class=\"tn-card__title-link\"\n [routerLink]=\"titleRouterLink()\"\n [queryParams]=\"titleQueryParams()\">\n {{ title() }}\n <tn-icon class=\"tn-card__title-link-icon\" name=\"open-in-new\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </a>\n } @else if (titleLink()) {\n <span\n class=\"tn-card__title-link\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"onTitleClick()\"\n (keydown.enter)=\"onTitleClick()\"\n (keydown.space)=\"onTitleClick(); $event.preventDefault()\">\n {{ title() }}\n <tn-icon class=\"tn-card__title-link-icon\" name=\"open-in-new\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </span>\n } @else {\n {{ title() }}\n }\n\n @if (titleTooltip(); as tooltip) {\n <button\n type=\"button\"\n class=\"tn-card__title-tooltip\"\n aria-label=\"More information\"\n [tnTooltip]=\"tooltip\">\n <tn-icon name=\"help-circle\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </button>\n }\n </h3>\n }\n </div>\n\n @if (hasHeaderRight()) {\n <div class=\"tn-card__header-right\">\n <!-- Header Status -->\n @if (headerStatus(); as status) {\n <div\n class=\"tn-card__status\"\n [ngClass]=\"getStatusClass(status?.type)\"\n [tnTestId]=\"status.testId\">\n {{ status.label }}\n </div>\n }\n\n <!-- Header Control (Slide Toggle) -->\n @if (headerControl(); as control) {\n <div class=\"tn-card__control\">\n <tn-slide-toggle\n [label]=\"control.label\"\n [checked]=\"control.checked\"\n [disabled]=\"control.disabled || false\"\n [testId]=\"control.testId\"\n (change)=\"onControlChange($event)\" />\n </div>\n }\n\n <!-- Projected header actions (escape hatch for custom/permission-gated controls) -->\n @if (headerActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions\" />\n }\n\n <!-- Header Menu -->\n @if (headerMenu(); as menu) {\n @if (menu.length) {\n <div class=\"tn-card__menu\">\n <tn-icon-button\n name=\"dots-vertical\"\n library=\"mdi\"\n size=\"md\"\n ariaLabel=\"Card menu\"\n [testId]=\"headerMenuTriggerTestId()\"\n [tnMenuTriggerFor]=\"cardMenu\" />\n <tn-menu\n #cardMenu\n [items]=\"menu\"\n (menuItemClick)=\"onHeaderMenuItemClick($event)\" />\n </div>\n }\n }\n </div>\n }\n </div>\n }\n\n <!-- Content section -->\n <div class=\"tn-card__content\">\n <ng-content />\n </div>\n\n <!-- Footer section -->\n @if (hasFooter()) {\n <div class=\"tn-card__footer\">\n <div class=\"tn-card__footer-left\">\n @if (footerLink(); as link) {\n <button\n type=\"button\"\n class=\"tn-card__footer-link\"\n tnTestIdType=\"link\"\n [tnTestId]=\"link.testId\"\n (click)=\"link.handler()\">\n {{ link.label }}\n </button>\n }\n </div>\n\n <div class=\"tn-card__footer-right\">\n @if (secondaryAction(); as action) {\n <tn-button\n variant=\"outline\"\n color=\"default\"\n [label]=\"action.label\"\n [disabled]=\"action.disabled || false\"\n [testId]=\"action.testId\"\n (click)=\"action.handler()\" />\n }\n\n @if (primaryAction(); as action) {\n <tn-button\n variant=\"filled\"\n color=\"primary\"\n [label]=\"action.label\"\n [disabled]=\"action.disabled || false\"\n [testId]=\"action.testId\"\n (click)=\"action.handler()\" />\n }\n\n <!-- Projected footer actions (escape hatch for custom/permission-gated controls) -->\n @if (footerActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions\" />\n }\n </div>\n </div>\n }\n</div>", styles: [":host{display:block}:host(.tn-card-host--content-height){height:auto}:host(.tn-card-host--content-height) .tn-card{height:auto}.tn-card{height:100%;display:flex;flex-direction:column;border-radius:8px;transition:box-shadow .3s ease;overflow:hidden}.tn-card--elevation-none{box-shadow:none}.tn-card--elevation-low{box-shadow:0 1px 3px #0000001a}.tn-card--elevation-medium{box-shadow:0 4px 6px #0000001a}.tn-card--elevation-high{box-shadow:0 10px 15px #0000001a}.tn-card--bordered{border:1px solid var(--tn-lines, #e5e7eb)}.tn-card--background{background-color:var(--tn-bg2, #ffffff)}.tn-card--padding-small .tn-card__header{padding:12px 16px}.tn-card--padding-medium .tn-card__header{padding:16px 24px}.tn-card--padding-large .tn-card__header{padding:24px 32px}.tn-card--content-padding-none .tn-card__content{padding:0}.tn-card--content-padding-small .tn-card__content{padding:16px}.tn-card--content-padding-medium .tn-card__content{padding:24px}.tn-card--content-padding-large .tn-card__content{padding:32px}.tn-card__content{flex:1;min-height:0;font-size:14px}.tn-card__header{display:flex;align-items:center;justify-content:space-between;gap:16px;border-bottom:1px solid var(--tn-lines, #e5e7eb)}.tn-card__header-left{flex:1;min-width:0}.tn-card__header-right{display:flex;align-items:center;gap:12px;flex-shrink:0}.tn-card__title{display:inline-flex;align-items:center;gap:8px;margin:0;font-size:1.125rem;font-weight:600;color:var(--tn-fg1, #1f2937);line-height:1.5}.tn-card__title-link{display:inline-flex;align-items:center;gap:4px;color:inherit;cursor:pointer;text-decoration:none;transition:color .2s ease}.tn-card__title-link:hover{color:var(--tn-primary, #2563eb)}.tn-card__title-link-icon{flex-shrink:0}.tn-card__title-tooltip{display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--tn-fg2, #6c757d);cursor:help;line-height:0}.tn-card__title-tooltip:hover,.tn-card__title-tooltip:focus-visible{color:var(--tn-fg1, #1f2937)}.tn-card__status{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.tn-card__status--success{background-color:#10b9811a;color:var(--tn-success, #10b981)}.tn-card__status--warning{background-color:#f59e0b1a;color:var(--tn-warning, #f59e0b)}.tn-card__status--error{background-color:#ef44441a;color:var(--tn-error, #ef4444)}.tn-card__status--info{background-color:#3b82f61a;color:var(--tn-info, #3b82f6)}.tn-card__status--neutral{background-color:#6b72801a;color:var(--tn-fg2, #6b7280)}.tn-card__control,.tn-card__menu{display:flex;align-items:center}.tn-card__footer{display:flex;align-items:center;justify-content:space-between;gap:16px;border-top:1px solid var(--tn-lines, #e5e7eb);padding:16px 24px}.tn-card--padding-small .tn-card__footer{padding:12px 16px}.tn-card--padding-large .tn-card__footer{padding:24px 32px}.tn-card__footer-left{flex:1;min-width:0}.tn-card__footer-right{display:flex;align-items:center;gap:8px;flex-shrink:0}.tn-card__footer-link{border:none;background:transparent;color:var(--tn-primary, #2563eb);font-size:1rem;font-weight:600;cursor:pointer;padding:0;text-decoration:none;transition:color .2s ease}.tn-card__footer-link:hover{color:var(--tn-primary-dark, #1d4ed8);text-decoration:underline}.tn-card__footer-link:focus{outline:2px solid var(--tn-primary, #2563eb);outline-offset:2px;border-radius:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "icon", "iconPosition", "disabled", "fullWidth", "type", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }, { kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "component", type: TnIconButtonComponent, selector: "tn-icon-button", inputs: ["disabled", "dense", "ariaLabel", "ariaExpanded", "testId", "name", "size", "color", "tooltip", "tooltipPosition", "library", "iconClass"], outputs: ["onClick"] }, { kind: "component", type: TnSlideToggleComponent, selector: "tn-slide-toggle", inputs: ["labelPosition", "label", "fullWidth", "disabled", "required", "color", "testId", "ariaLabel", "ariaLabelledby", "checked"], outputs: ["change", "toggleChange"] }, { kind: "component", type: TnMenuComponent, selector: "tn-menu", inputs: ["items", "contextMenu", "testId"], outputs: ["menuItemClick", "menuOpen", "menuClose"] }, { kind: "directive", type: TnMenuTriggerDirective, selector: "[tnMenuTriggerFor]", inputs: ["tnMenuTriggerFor", "tnMenuPosition"], exportAs: ["tnMenuTrigger"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "directive", type: TnTooltipDirective, selector: "[tnTooltip]", inputs: ["tnTooltip", "tnTooltipPosition", "tnTooltipDisabled", "tnTooltipShowDelay", "tnTooltipHideDelay", "tnTooltipClass"] }] });
|
|
6424
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnCardComponent, isStandalone: true, selector: "tn-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, titleLink: { classPropertyName: "titleLink", publicName: "titleLink", isSignal: true, isRequired: false, transformFunction: null }, titleRouterLink: { classPropertyName: "titleRouterLink", publicName: "titleRouterLink", isSignal: true, isRequired: false, transformFunction: null }, titleQueryParams: { classPropertyName: "titleQueryParams", publicName: "titleQueryParams", isSignal: true, isRequired: false, transformFunction: null }, titleTooltip: { classPropertyName: "titleTooltip", publicName: "titleTooltip", isSignal: true, isRequired: false, transformFunction: null }, elevation: { classPropertyName: "elevation", publicName: "elevation", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, padContent: { classPropertyName: "padContent", publicName: "padContent", isSignal: true, isRequired: false, transformFunction: null }, fillHeight: { classPropertyName: "fillHeight", publicName: "fillHeight", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null }, headerStatus: { classPropertyName: "headerStatus", publicName: "headerStatus", isSignal: true, isRequired: false, transformFunction: null }, headerControl: { classPropertyName: "headerControl", publicName: "headerControl", isSignal: true, isRequired: false, transformFunction: null }, headerMenu: { classPropertyName: "headerMenu", publicName: "headerMenu", isSignal: true, isRequired: false, transformFunction: null }, headerMenuTriggerTestId: { classPropertyName: "headerMenuTriggerTestId", publicName: "headerMenuTriggerTestId", isSignal: true, isRequired: false, transformFunction: null }, primaryAction: { classPropertyName: "primaryAction", publicName: "primaryAction", isSignal: true, isRequired: false, transformFunction: null }, secondaryAction: { classPropertyName: "secondaryAction", publicName: "secondaryAction", isSignal: true, isRequired: false, transformFunction: null }, footerLink: { classPropertyName: "footerLink", publicName: "footerLink", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.tn-card-host--content-height": "!fillHeight()" } }, queries: [{ propertyName: "projectedHeader", first: true, predicate: TnCardHeaderDirective, descendants: true, isSignal: true }, { propertyName: "headerActions", first: true, predicate: TnCardHeaderActionsDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "footerActions", first: true, predicate: TnCardFooterActionsDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "<div [ngClass]=\"classes()\">\n <!-- Header section -->\n @if (hasHeader()) {\n <div class=\"tn-card__header\">\n <div class=\"tn-card__header-left\">\n <ng-content select=\"[tnCardHeader]\" />\n @if (!projectedHeader() && title()) {\n <h3 class=\"tn-card__title\">\n @if (isTitleRouterLink()) {\n <a\n class=\"tn-card__title-link\"\n [routerLink]=\"titleRouterLink()\"\n [queryParams]=\"titleQueryParams()\">\n {{ title() }}\n <tn-icon class=\"tn-card__title-link-icon\" name=\"open-in-new\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </a>\n } @else if (titleLink()) {\n <span\n class=\"tn-card__title-link\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"onTitleClick()\"\n (keydown.enter)=\"onTitleClick()\"\n (keydown.space)=\"onTitleClick(); $event.preventDefault()\">\n {{ title() }}\n <tn-icon class=\"tn-card__title-link-icon\" name=\"open-in-new\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </span>\n } @else {\n {{ title() }}\n }\n\n @if (titleTooltip(); as tooltip) {\n <button\n type=\"button\"\n class=\"tn-card__title-tooltip\"\n aria-label=\"More information\"\n [tnTooltip]=\"tooltip\">\n <tn-icon name=\"help-circle\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </button>\n }\n </h3>\n }\n </div>\n\n @if (hasHeaderRight()) {\n <div class=\"tn-card__header-right\">\n <!-- Header Status -->\n @if (headerStatus(); as status) {\n <div\n class=\"tn-card__status\"\n [ngClass]=\"getStatusClass(status?.type)\"\n [tnTestId]=\"status.testId\">\n {{ status.label }}\n </div>\n }\n\n <!-- Header Control (Slide Toggle) -->\n @if (headerControl(); as control) {\n <div class=\"tn-card__control\">\n <tn-slide-toggle\n [label]=\"control.label\"\n [checked]=\"control.checked\"\n [disabled]=\"control.disabled || false\"\n [testId]=\"control.testId\"\n (change)=\"onControlChange($event)\" />\n </div>\n }\n\n <!-- Projected header actions (escape hatch for custom/permission-gated controls) -->\n @if (headerActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions\" />\n }\n\n <!-- Header Menu -->\n @if (headerMenu(); as menu) {\n @if (menu.length) {\n <div class=\"tn-card__menu\">\n <tn-icon-button\n name=\"dots-vertical\"\n library=\"mdi\"\n size=\"md\"\n ariaLabel=\"Card menu\"\n [testId]=\"headerMenuTriggerTestId()\"\n [tnMenuTriggerFor]=\"cardMenu\" />\n <tn-menu\n #cardMenu\n [items]=\"menu\"\n (menuItemClick)=\"onHeaderMenuItemClick($event)\" />\n </div>\n }\n }\n </div>\n }\n </div>\n }\n\n <!-- Content section -->\n <div class=\"tn-card__content\">\n <ng-content />\n </div>\n\n <!-- Footer section -->\n @if (hasFooter()) {\n <div class=\"tn-card__footer\">\n <div class=\"tn-card__footer-left\">\n @if (footerLink(); as link) {\n <button\n type=\"button\"\n class=\"tn-card__footer-link\"\n tnTestIdType=\"link\"\n [tnTestId]=\"link.testId\"\n (click)=\"link.handler()\">\n {{ link.label }}\n </button>\n }\n </div>\n\n <div class=\"tn-card__footer-right\">\n @if (secondaryAction(); as action) {\n <tn-button\n variant=\"outline\"\n color=\"default\"\n [label]=\"action.label\"\n [disabled]=\"action.disabled || false\"\n [testId]=\"action.testId\"\n [tnTooltip]=\"action.tooltip || ''\"\n (click)=\"action.handler()\" />\n }\n\n @if (primaryAction(); as action) {\n <tn-button\n variant=\"filled\"\n color=\"primary\"\n [label]=\"action.label\"\n [disabled]=\"action.disabled || false\"\n [testId]=\"action.testId\"\n [tnTooltip]=\"action.tooltip || ''\"\n (click)=\"action.handler()\" />\n }\n\n <!-- Projected footer actions (escape hatch for custom/permission-gated controls) -->\n @if (footerActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions\" />\n }\n </div>\n </div>\n }\n</div>", styles: [":host{display:block}:host(.tn-card-host--content-height){height:auto}:host(.tn-card-host--content-height) .tn-card{height:auto}.tn-card{height:100%;display:flex;flex-direction:column;border-radius:8px;transition:box-shadow .3s ease;overflow:hidden}.tn-card--elevation-none{box-shadow:none}.tn-card--elevation-low{box-shadow:0 1px 3px #0000001a}.tn-card--elevation-medium{box-shadow:0 4px 6px #0000001a}.tn-card--elevation-high{box-shadow:0 10px 15px #0000001a}.tn-card--bordered{border:1px solid var(--tn-lines, #e5e7eb)}.tn-card--background{background-color:var(--tn-bg2, #ffffff)}.tn-card--padding-small .tn-card__header{padding:12px 16px}.tn-card--padding-medium .tn-card__header{padding:16px 24px}.tn-card--padding-large .tn-card__header{padding:24px 32px}.tn-card--content-padding-none .tn-card__content{padding:0}.tn-card--content-padding-small .tn-card__content{padding:16px}.tn-card--content-padding-medium .tn-card__content{padding:24px}.tn-card--content-padding-large .tn-card__content{padding:32px}.tn-card__content{flex:1;min-height:0;font-size:14px}.tn-card__header{display:flex;align-items:center;justify-content:space-between;gap:16px;border-bottom:1px solid var(--tn-lines, #e5e7eb)}.tn-card__header-left{flex:1;min-width:0}.tn-card__header-right{display:flex;align-items:center;gap:12px;flex-shrink:0}.tn-card__title{display:inline-flex;align-items:center;gap:8px;margin:0;font-size:1.125rem;font-weight:600;color:var(--tn-fg1, #1f2937);line-height:1.5}.tn-card__title-link{display:inline-flex;align-items:center;gap:4px;color:inherit;cursor:pointer;text-decoration:none;transition:color .2s ease}.tn-card__title-link:hover{color:var(--tn-primary, #2563eb)}.tn-card__title-link-icon{flex-shrink:0}.tn-card__title-tooltip{display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--tn-fg2, #6c757d);cursor:help;line-height:0}.tn-card__title-tooltip:hover,.tn-card__title-tooltip:focus-visible{color:var(--tn-fg1, #1f2937)}.tn-card__status{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.tn-card__status--success{background-color:#10b9811a;color:var(--tn-success, #10b981)}.tn-card__status--warning{background-color:#f59e0b1a;color:var(--tn-warning, #f59e0b)}.tn-card__status--error{background-color:#ef44441a;color:var(--tn-error, #ef4444)}.tn-card__status--info{background-color:#3b82f61a;color:var(--tn-info, #3b82f6)}.tn-card__status--neutral{background-color:#6b72801a;color:var(--tn-fg2, #6b7280)}.tn-card__control,.tn-card__menu{display:flex;align-items:center}.tn-card__footer{display:flex;align-items:center;justify-content:space-between;gap:16px;border-top:1px solid var(--tn-lines, #e5e7eb);padding:16px 24px}.tn-card--padding-small .tn-card__footer{padding:12px 16px}.tn-card--padding-large .tn-card__footer{padding:24px 32px}.tn-card__footer-left{flex:1;min-width:0}.tn-card__footer-right{display:flex;align-items:center;gap:8px;flex-shrink:0}.tn-card__footer-link{border:none;background:transparent;color:var(--tn-primary, #2563eb);font-size:1rem;font-weight:600;cursor:pointer;padding:0;text-decoration:none;transition:color .2s ease}.tn-card__footer-link:hover{color:var(--tn-primary-dark, #1d4ed8);text-decoration:underline}.tn-card__footer-link:focus{outline:2px solid var(--tn-primary, #2563eb);outline-offset:2px;border-radius:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "icon", "iconPosition", "disabled", "fullWidth", "type", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }, { kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "component", type: TnIconButtonComponent, selector: "tn-icon-button", inputs: ["disabled", "dense", "ariaLabel", "ariaExpanded", "testId", "name", "size", "color", "tooltip", "tooltipPosition", "library", "iconClass"], outputs: ["onClick"] }, { kind: "component", type: TnSlideToggleComponent, selector: "tn-slide-toggle", inputs: ["labelPosition", "label", "fullWidth", "disabled", "required", "color", "testId", "ariaLabel", "ariaLabelledby", "checked"], outputs: ["change", "toggleChange"] }, { kind: "component", type: TnMenuComponent, selector: "tn-menu", inputs: ["items", "contextMenu", "testId"], outputs: ["menuItemClick", "menuOpen", "menuClose"] }, { kind: "directive", type: TnMenuTriggerDirective, selector: "[tnMenuTriggerFor]", inputs: ["tnMenuTriggerFor", "tnMenuPosition"], exportAs: ["tnMenuTrigger"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "directive", type: TnTooltipDirective, selector: "[tnTooltip]", inputs: ["tnTooltip", "tnTooltipPosition", "tnTooltipDisabled", "tnTooltipShowDelay", "tnTooltipHideDelay", "tnTooltipClass"] }] });
|
|
6318
6425
|
}
|
|
6319
6426
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnCardComponent, decorators: [{
|
|
6320
6427
|
type: Component,
|
|
@@ -6331,7 +6438,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
6331
6438
|
TnTooltipDirective,
|
|
6332
6439
|
], host: {
|
|
6333
6440
|
'[class.tn-card-host--content-height]': '!fillHeight()',
|
|
6334
|
-
}, template: "<div [ngClass]=\"classes()\">\n <!-- Header section -->\n @if (hasHeader()) {\n <div class=\"tn-card__header\">\n <div class=\"tn-card__header-left\">\n <ng-content select=\"[tnCardHeader]\" />\n @if (!projectedHeader() && title()) {\n <h3 class=\"tn-card__title\">\n @if (isTitleRouterLink()) {\n <a\n class=\"tn-card__title-link\"\n [routerLink]=\"titleRouterLink()\"\n [queryParams]=\"titleQueryParams()\">\n {{ title() }}\n <tn-icon class=\"tn-card__title-link-icon\" name=\"open-in-new\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </a>\n } @else if (titleLink()) {\n <span\n class=\"tn-card__title-link\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"onTitleClick()\"\n (keydown.enter)=\"onTitleClick()\"\n (keydown.space)=\"onTitleClick(); $event.preventDefault()\">\n {{ title() }}\n <tn-icon class=\"tn-card__title-link-icon\" name=\"open-in-new\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </span>\n } @else {\n {{ title() }}\n }\n\n @if (titleTooltip(); as tooltip) {\n <button\n type=\"button\"\n class=\"tn-card__title-tooltip\"\n aria-label=\"More information\"\n [tnTooltip]=\"tooltip\">\n <tn-icon name=\"help-circle\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </button>\n }\n </h3>\n }\n </div>\n\n @if (hasHeaderRight()) {\n <div class=\"tn-card__header-right\">\n <!-- Header Status -->\n @if (headerStatus(); as status) {\n <div\n class=\"tn-card__status\"\n [ngClass]=\"getStatusClass(status?.type)\"\n [tnTestId]=\"status.testId\">\n {{ status.label }}\n </div>\n }\n\n <!-- Header Control (Slide Toggle) -->\n @if (headerControl(); as control) {\n <div class=\"tn-card__control\">\n <tn-slide-toggle\n [label]=\"control.label\"\n [checked]=\"control.checked\"\n [disabled]=\"control.disabled || false\"\n [testId]=\"control.testId\"\n (change)=\"onControlChange($event)\" />\n </div>\n }\n\n <!-- Projected header actions (escape hatch for custom/permission-gated controls) -->\n @if (headerActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions\" />\n }\n\n <!-- Header Menu -->\n @if (headerMenu(); as menu) {\n @if (menu.length) {\n <div class=\"tn-card__menu\">\n <tn-icon-button\n name=\"dots-vertical\"\n library=\"mdi\"\n size=\"md\"\n ariaLabel=\"Card menu\"\n [testId]=\"headerMenuTriggerTestId()\"\n [tnMenuTriggerFor]=\"cardMenu\" />\n <tn-menu\n #cardMenu\n [items]=\"menu\"\n (menuItemClick)=\"onHeaderMenuItemClick($event)\" />\n </div>\n }\n }\n </div>\n }\n </div>\n }\n\n <!-- Content section -->\n <div class=\"tn-card__content\">\n <ng-content />\n </div>\n\n <!-- Footer section -->\n @if (hasFooter()) {\n <div class=\"tn-card__footer\">\n <div class=\"tn-card__footer-left\">\n @if (footerLink(); as link) {\n <button\n type=\"button\"\n class=\"tn-card__footer-link\"\n tnTestIdType=\"link\"\n [tnTestId]=\"link.testId\"\n (click)=\"link.handler()\">\n {{ link.label }}\n </button>\n }\n </div>\n\n <div class=\"tn-card__footer-right\">\n @if (secondaryAction(); as action) {\n <tn-button\n variant=\"outline\"\n color=\"default\"\n [label]=\"action.label\"\n [disabled]=\"action.disabled || false\"\n [testId]=\"action.testId\"\n (click)=\"action.handler()\" />\n }\n\n @if (primaryAction(); as action) {\n <tn-button\n variant=\"filled\"\n color=\"primary\"\n [label]=\"action.label\"\n [disabled]=\"action.disabled || false\"\n [testId]=\"action.testId\"\n (click)=\"action.handler()\" />\n }\n\n <!-- Projected footer actions (escape hatch for custom/permission-gated controls) -->\n @if (footerActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions\" />\n }\n </div>\n </div>\n }\n</div>", styles: [":host{display:block}:host(.tn-card-host--content-height){height:auto}:host(.tn-card-host--content-height) .tn-card{height:auto}.tn-card{height:100%;display:flex;flex-direction:column;border-radius:8px;transition:box-shadow .3s ease;overflow:hidden}.tn-card--elevation-none{box-shadow:none}.tn-card--elevation-low{box-shadow:0 1px 3px #0000001a}.tn-card--elevation-medium{box-shadow:0 4px 6px #0000001a}.tn-card--elevation-high{box-shadow:0 10px 15px #0000001a}.tn-card--bordered{border:1px solid var(--tn-lines, #e5e7eb)}.tn-card--background{background-color:var(--tn-bg2, #ffffff)}.tn-card--padding-small .tn-card__header{padding:12px 16px}.tn-card--padding-medium .tn-card__header{padding:16px 24px}.tn-card--padding-large .tn-card__header{padding:24px 32px}.tn-card--content-padding-none .tn-card__content{padding:0}.tn-card--content-padding-small .tn-card__content{padding:16px}.tn-card--content-padding-medium .tn-card__content{padding:24px}.tn-card--content-padding-large .tn-card__content{padding:32px}.tn-card__content{flex:1;min-height:0;font-size:14px}.tn-card__header{display:flex;align-items:center;justify-content:space-between;gap:16px;border-bottom:1px solid var(--tn-lines, #e5e7eb)}.tn-card__header-left{flex:1;min-width:0}.tn-card__header-right{display:flex;align-items:center;gap:12px;flex-shrink:0}.tn-card__title{display:inline-flex;align-items:center;gap:8px;margin:0;font-size:1.125rem;font-weight:600;color:var(--tn-fg1, #1f2937);line-height:1.5}.tn-card__title-link{display:inline-flex;align-items:center;gap:4px;color:inherit;cursor:pointer;text-decoration:none;transition:color .2s ease}.tn-card__title-link:hover{color:var(--tn-primary, #2563eb)}.tn-card__title-link-icon{flex-shrink:0}.tn-card__title-tooltip{display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--tn-fg2, #6c757d);cursor:help;line-height:0}.tn-card__title-tooltip:hover,.tn-card__title-tooltip:focus-visible{color:var(--tn-fg1, #1f2937)}.tn-card__status{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.tn-card__status--success{background-color:#10b9811a;color:var(--tn-success, #10b981)}.tn-card__status--warning{background-color:#f59e0b1a;color:var(--tn-warning, #f59e0b)}.tn-card__status--error{background-color:#ef44441a;color:var(--tn-error, #ef4444)}.tn-card__status--info{background-color:#3b82f61a;color:var(--tn-info, #3b82f6)}.tn-card__status--neutral{background-color:#6b72801a;color:var(--tn-fg2, #6b7280)}.tn-card__control,.tn-card__menu{display:flex;align-items:center}.tn-card__footer{display:flex;align-items:center;justify-content:space-between;gap:16px;border-top:1px solid var(--tn-lines, #e5e7eb);padding:16px 24px}.tn-card--padding-small .tn-card__footer{padding:12px 16px}.tn-card--padding-large .tn-card__footer{padding:24px 32px}.tn-card__footer-left{flex:1;min-width:0}.tn-card__footer-right{display:flex;align-items:center;gap:8px;flex-shrink:0}.tn-card__footer-link{border:none;background:transparent;color:var(--tn-primary, #2563eb);font-size:1rem;font-weight:600;cursor:pointer;padding:0;text-decoration:none;transition:color .2s ease}.tn-card__footer-link:hover{color:var(--tn-primary-dark, #1d4ed8);text-decoration:underline}.tn-card__footer-link:focus{outline:2px solid var(--tn-primary, #2563eb);outline-offset:2px;border-radius:2px}\n"] }]
|
|
6441
|
+
}, template: "<div [ngClass]=\"classes()\">\n <!-- Header section -->\n @if (hasHeader()) {\n <div class=\"tn-card__header\">\n <div class=\"tn-card__header-left\">\n <ng-content select=\"[tnCardHeader]\" />\n @if (!projectedHeader() && title()) {\n <h3 class=\"tn-card__title\">\n @if (isTitleRouterLink()) {\n <a\n class=\"tn-card__title-link\"\n [routerLink]=\"titleRouterLink()\"\n [queryParams]=\"titleQueryParams()\">\n {{ title() }}\n <tn-icon class=\"tn-card__title-link-icon\" name=\"open-in-new\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </a>\n } @else if (titleLink()) {\n <span\n class=\"tn-card__title-link\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"onTitleClick()\"\n (keydown.enter)=\"onTitleClick()\"\n (keydown.space)=\"onTitleClick(); $event.preventDefault()\">\n {{ title() }}\n <tn-icon class=\"tn-card__title-link-icon\" name=\"open-in-new\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </span>\n } @else {\n {{ title() }}\n }\n\n @if (titleTooltip(); as tooltip) {\n <button\n type=\"button\"\n class=\"tn-card__title-tooltip\"\n aria-label=\"More information\"\n [tnTooltip]=\"tooltip\">\n <tn-icon name=\"help-circle\" library=\"mdi\" size=\"sm\" [attr.aria-hidden]=\"true\" />\n </button>\n }\n </h3>\n }\n </div>\n\n @if (hasHeaderRight()) {\n <div class=\"tn-card__header-right\">\n <!-- Header Status -->\n @if (headerStatus(); as status) {\n <div\n class=\"tn-card__status\"\n [ngClass]=\"getStatusClass(status?.type)\"\n [tnTestId]=\"status.testId\">\n {{ status.label }}\n </div>\n }\n\n <!-- Header Control (Slide Toggle) -->\n @if (headerControl(); as control) {\n <div class=\"tn-card__control\">\n <tn-slide-toggle\n [label]=\"control.label\"\n [checked]=\"control.checked\"\n [disabled]=\"control.disabled || false\"\n [testId]=\"control.testId\"\n (change)=\"onControlChange($event)\" />\n </div>\n }\n\n <!-- Projected header actions (escape hatch for custom/permission-gated controls) -->\n @if (headerActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions\" />\n }\n\n <!-- Header Menu -->\n @if (headerMenu(); as menu) {\n @if (menu.length) {\n <div class=\"tn-card__menu\">\n <tn-icon-button\n name=\"dots-vertical\"\n library=\"mdi\"\n size=\"md\"\n ariaLabel=\"Card menu\"\n [testId]=\"headerMenuTriggerTestId()\"\n [tnMenuTriggerFor]=\"cardMenu\" />\n <tn-menu\n #cardMenu\n [items]=\"menu\"\n (menuItemClick)=\"onHeaderMenuItemClick($event)\" />\n </div>\n }\n }\n </div>\n }\n </div>\n }\n\n <!-- Content section -->\n <div class=\"tn-card__content\">\n <ng-content />\n </div>\n\n <!-- Footer section -->\n @if (hasFooter()) {\n <div class=\"tn-card__footer\">\n <div class=\"tn-card__footer-left\">\n @if (footerLink(); as link) {\n <button\n type=\"button\"\n class=\"tn-card__footer-link\"\n tnTestIdType=\"link\"\n [tnTestId]=\"link.testId\"\n (click)=\"link.handler()\">\n {{ link.label }}\n </button>\n }\n </div>\n\n <div class=\"tn-card__footer-right\">\n @if (secondaryAction(); as action) {\n <tn-button\n variant=\"outline\"\n color=\"default\"\n [label]=\"action.label\"\n [disabled]=\"action.disabled || false\"\n [testId]=\"action.testId\"\n [tnTooltip]=\"action.tooltip || ''\"\n (click)=\"action.handler()\" />\n }\n\n @if (primaryAction(); as action) {\n <tn-button\n variant=\"filled\"\n color=\"primary\"\n [label]=\"action.label\"\n [disabled]=\"action.disabled || false\"\n [testId]=\"action.testId\"\n [tnTooltip]=\"action.tooltip || ''\"\n (click)=\"action.handler()\" />\n }\n\n <!-- Projected footer actions (escape hatch for custom/permission-gated controls) -->\n @if (footerActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions\" />\n }\n </div>\n </div>\n }\n</div>", styles: [":host{display:block}:host(.tn-card-host--content-height){height:auto}:host(.tn-card-host--content-height) .tn-card{height:auto}.tn-card{height:100%;display:flex;flex-direction:column;border-radius:8px;transition:box-shadow .3s ease;overflow:hidden}.tn-card--elevation-none{box-shadow:none}.tn-card--elevation-low{box-shadow:0 1px 3px #0000001a}.tn-card--elevation-medium{box-shadow:0 4px 6px #0000001a}.tn-card--elevation-high{box-shadow:0 10px 15px #0000001a}.tn-card--bordered{border:1px solid var(--tn-lines, #e5e7eb)}.tn-card--background{background-color:var(--tn-bg2, #ffffff)}.tn-card--padding-small .tn-card__header{padding:12px 16px}.tn-card--padding-medium .tn-card__header{padding:16px 24px}.tn-card--padding-large .tn-card__header{padding:24px 32px}.tn-card--content-padding-none .tn-card__content{padding:0}.tn-card--content-padding-small .tn-card__content{padding:16px}.tn-card--content-padding-medium .tn-card__content{padding:24px}.tn-card--content-padding-large .tn-card__content{padding:32px}.tn-card__content{flex:1;min-height:0;font-size:14px}.tn-card__header{display:flex;align-items:center;justify-content:space-between;gap:16px;border-bottom:1px solid var(--tn-lines, #e5e7eb)}.tn-card__header-left{flex:1;min-width:0}.tn-card__header-right{display:flex;align-items:center;gap:12px;flex-shrink:0}.tn-card__title{display:inline-flex;align-items:center;gap:8px;margin:0;font-size:1.125rem;font-weight:600;color:var(--tn-fg1, #1f2937);line-height:1.5}.tn-card__title-link{display:inline-flex;align-items:center;gap:4px;color:inherit;cursor:pointer;text-decoration:none;transition:color .2s ease}.tn-card__title-link:hover{color:var(--tn-primary, #2563eb)}.tn-card__title-link-icon{flex-shrink:0}.tn-card__title-tooltip{display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--tn-fg2, #6c757d);cursor:help;line-height:0}.tn-card__title-tooltip:hover,.tn-card__title-tooltip:focus-visible{color:var(--tn-fg1, #1f2937)}.tn-card__status{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.tn-card__status--success{background-color:#10b9811a;color:var(--tn-success, #10b981)}.tn-card__status--warning{background-color:#f59e0b1a;color:var(--tn-warning, #f59e0b)}.tn-card__status--error{background-color:#ef44441a;color:var(--tn-error, #ef4444)}.tn-card__status--info{background-color:#3b82f61a;color:var(--tn-info, #3b82f6)}.tn-card__status--neutral{background-color:#6b72801a;color:var(--tn-fg2, #6b7280)}.tn-card__control,.tn-card__menu{display:flex;align-items:center}.tn-card__footer{display:flex;align-items:center;justify-content:space-between;gap:16px;border-top:1px solid var(--tn-lines, #e5e7eb);padding:16px 24px}.tn-card--padding-small .tn-card__footer{padding:12px 16px}.tn-card--padding-large .tn-card__footer{padding:24px 32px}.tn-card__footer-left{flex:1;min-width:0}.tn-card__footer-right{display:flex;align-items:center;gap:8px;flex-shrink:0}.tn-card__footer-link{border:none;background:transparent;color:var(--tn-primary, #2563eb);font-size:1rem;font-weight:600;cursor:pointer;padding:0;text-decoration:none;transition:color .2s ease}.tn-card__footer-link:hover{color:var(--tn-primary-dark, #1d4ed8);text-decoration:underline}.tn-card__footer-link:focus{outline:2px solid var(--tn-primary, #2563eb);outline-offset:2px;border-radius:2px}\n"] }]
|
|
6335
6442
|
}], ctorParameters: () => [], propDecorators: { projectedHeader: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TnCardHeaderDirective), { isSignal: true }] }], headerActions: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TnCardHeaderActionsDirective), { ...{ read: TemplateRef }, isSignal: true }] }], footerActions: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TnCardFooterActionsDirective), { ...{ read: TemplateRef }, isSignal: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], titleLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleLink", required: false }] }], titleRouterLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleRouterLink", required: false }] }], titleQueryParams: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleQueryParams", required: false }] }], titleTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleTooltip", required: false }] }], elevation: [{ type: i0.Input, args: [{ isSignal: true, alias: "elevation", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], padContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "padContent", required: false }] }], fillHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillHeight", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], background: [{ type: i0.Input, args: [{ isSignal: true, alias: "background", required: false }] }], headerStatus: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerStatus", required: false }] }], headerControl: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerControl", required: false }] }], headerMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerMenu", required: false }] }], headerMenuTriggerTestId: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerMenuTriggerTestId", required: false }] }], primaryAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryAction", required: false }] }], secondaryAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondaryAction", required: false }] }], footerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerLink", required: false }] }] } });
|
|
6336
6443
|
|
|
6337
6444
|
class TnExpansionPanelComponent {
|