@truenas/ui-components 0.1.76 → 0.1.77
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.
|
@@ -1779,6 +1779,14 @@ class TnButtonComponent {
|
|
|
1779
1779
|
backgroundColor = input(undefined, ...(ngDevMode ? [{ debugName: "backgroundColor" }] : []));
|
|
1780
1780
|
label = input('Button', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
1781
1781
|
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
1782
|
+
/**
|
|
1783
|
+
* Native `type` of the rendered `<button>`. Defaults to `button` so stray
|
|
1784
|
+
* clicks never submit an enclosing form. Set to `submit` for a form's save
|
|
1785
|
+
* button — this is what makes pressing Enter in a form field fire the
|
|
1786
|
+
* form's `(submit)`/`(ngSubmit)` handler; a `(onClick)` binding alone does
|
|
1787
|
+
* not. Ignored in anchor mode (`href`/`routerLink`).
|
|
1788
|
+
*/
|
|
1789
|
+
type = input('button', ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
1782
1790
|
/**
|
|
1783
1791
|
* Semantic test-id base for the rendered element. The library prepends the
|
|
1784
1792
|
* element type (`button`) and renders the result under whichever attribute
|
|
@@ -1877,12 +1885,12 @@ class TnButtonComponent {
|
|
|
1877
1885
|
host.focus = (options) => inner.focus(options);
|
|
1878
1886
|
}
|
|
1879
1887
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1880
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnButtonComponent, isStandalone: true, selector: "tn-button", inputs: { primary: { classPropertyName: "primary", publicName: "primary", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null }, href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, queryParams: { classPropertyName: "queryParams", publicName: "queryParams", isSignal: true, isRequired: false, transformFunction: null }, fragment: { classPropertyName: "fragment", publicName: "fragment", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, viewQueries: [{ propertyName: "innerRef", first: true, predicate: ["button"], descendants: true, isSignal: true }], ngImport: i0, template: "@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 {{ label() }}\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 {{ label() }}\n </a>\n} @else {\n <button\n #button\n
|
|
1888
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnButtonComponent, isStandalone: true, selector: "tn-button", inputs: { primary: { classPropertyName: "primary", publicName: "primary", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null }, href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, queryParams: { classPropertyName: "queryParams", publicName: "queryParams", isSignal: true, isRequired: false, transformFunction: null }, fragment: { classPropertyName: "fragment", publicName: "fragment", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, viewQueries: [{ propertyName: "innerRef", first: true, predicate: ["button"], descendants: true, isSignal: true }], ngImport: i0, template: "@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 {{ label() }}\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 {{ label() }}\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 {{ label() }}\n </button>\n}\n", styles: [":host{display:inline-block;width:fit-content;justify-self:center}.storybook-button{display:inline-block;cursor:pointer;border:0;font-weight:500;line-height:1;font-family:IBM Plex Sans,Helvetica Neue,Helvetica,Arial,sans-serif}.storybook-button:disabled,.storybook-button.is-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}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"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }] });
|
|
1881
1889
|
}
|
|
1882
1890
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnButtonComponent, decorators: [{
|
|
1883
1891
|
type: Component,
|
|
1884
|
-
args: [{ selector: 'tn-button', standalone: true, imports: [CommonModule, RouterLink, TnTestIdDirective], template: "@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 {{ label() }}\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 {{ label() }}\n </a>\n} @else {\n <button\n #button\n
|
|
1885
|
-
}], 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", 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 }] }] } });
|
|
1892
|
+
args: [{ selector: 'tn-button', standalone: true, imports: [CommonModule, RouterLink, TnTestIdDirective], template: "@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 {{ label() }}\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 {{ label() }}\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 {{ label() }}\n </button>\n}\n", styles: [":host{display:inline-block;width:fit-content;justify-self:center}.storybook-button{display:inline-block;cursor:pointer;border:0;font-weight:500;line-height:1;font-family:IBM Plex Sans,Helvetica Neue,Helvetica,Arial,sans-serif}.storybook-button:disabled,.storybook-button.is-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}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"] }]
|
|
1893
|
+
}], 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", 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 }] }] } });
|
|
1886
1894
|
|
|
1887
1895
|
/**
|
|
1888
1896
|
* Harness for interacting with tn-button in tests.
|
|
@@ -1963,6 +1971,24 @@ class TnButtonHarness extends ComponentHarness {
|
|
|
1963
1971
|
}
|
|
1964
1972
|
return (await button.getProperty('disabled')) ?? false;
|
|
1965
1973
|
}
|
|
1974
|
+
/**
|
|
1975
|
+
* Gets the native `type` of the rendered `<button>` (`button`, `submit`, or
|
|
1976
|
+
* `reset`). Returns `null` for anchor-mode renders.
|
|
1977
|
+
*
|
|
1978
|
+
* @example
|
|
1979
|
+
* ```typescript
|
|
1980
|
+
* const saveBtn = await loader.getHarness(TnButtonHarness.with({ label: 'Save' }));
|
|
1981
|
+
* expect(await saveBtn.getType()).toBe('submit');
|
|
1982
|
+
* ```
|
|
1983
|
+
*/
|
|
1984
|
+
async getType() {
|
|
1985
|
+
const button = await this._button();
|
|
1986
|
+
const tagName = (await button.getProperty('tagName')).toLowerCase();
|
|
1987
|
+
if (tagName !== 'button') {
|
|
1988
|
+
return null;
|
|
1989
|
+
}
|
|
1990
|
+
return button.getAttribute('type');
|
|
1991
|
+
}
|
|
1966
1992
|
/**
|
|
1967
1993
|
* Gets the resolved URL of the rendered element. Returns the `href` for
|
|
1968
1994
|
* anchor-mode renders (both plain `href` and `routerLink`) and `null` for
|
|
@@ -4122,7 +4148,7 @@ class TnCardComponent {
|
|
|
4122
4148
|
return type ? `tn-card__status--${type}` : 'tn-card__status--neutral';
|
|
4123
4149
|
}
|
|
4124
4150
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4125
|
-
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 }, 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 }, 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 } }, queries: [{ propertyName: "projectedHeader", first: true, predicate: TnCardHeaderDirective, descendants: true, 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\n class=\"tn-card__title\"\n [class.tn-card__title--link]=\"titleLink()\"\n [attr.tabindex]=\"titleLink() ? 0 : null\"\n [attr.role]=\"titleLink() ? 'button' : null\"\n (click)=\"onTitleClick()\"\n (keydown.enter)=\"onTitleClick()\"\n (keydown.space)=\"onTitleClick()\">\n {{ title() }}\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 <!-- 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 </div>\n </div>\n }\n</div>", styles: [".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{margin:0;font-size:1.125rem;font-weight:600;color:var(--tn-fg1, #1f2937);line-height:1.5}.tn-card__title--link{cursor:pointer;transition:color .2s ease}.tn-card__title--link:hover{color:var(--tn-primary, #2563eb)}.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: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "disabled", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }, { 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", "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"] }] });
|
|
4151
|
+
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 }, 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 }, 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 } }, queries: [{ propertyName: "projectedHeader", first: true, predicate: TnCardHeaderDirective, descendants: true, 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\n class=\"tn-card__title\"\n [class.tn-card__title--link]=\"titleLink()\"\n [attr.tabindex]=\"titleLink() ? 0 : null\"\n [attr.role]=\"titleLink() ? 'button' : null\"\n (click)=\"onTitleClick()\"\n (keydown.enter)=\"onTitleClick()\"\n (keydown.space)=\"onTitleClick()\">\n {{ title() }}\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 <!-- 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 </div>\n </div>\n }\n</div>", styles: [".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{margin:0;font-size:1.125rem;font-weight:600;color:var(--tn-fg1, #1f2937);line-height:1.5}.tn-card__title--link{cursor:pointer;transition:color .2s ease}.tn-card__title--link:hover{color:var(--tn-primary, #2563eb)}.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: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "disabled", "type", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }, { 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", "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"] }] });
|
|
4126
4152
|
}
|
|
4127
4153
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnCardComponent, decorators: [{
|
|
4128
4154
|
type: Component,
|
|
@@ -8036,7 +8062,7 @@ class TnEmptyComponent {
|
|
|
8036
8062
|
return this.size() === 'compact' ? 'lg' : 'xl';
|
|
8037
8063
|
}, ...(ngDevMode ? [{ debugName: "iconSizePreset" }] : []));
|
|
8038
8064
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnEmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8039
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnEmptyComponent, isStandalone: true, selector: "tn-empty", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, iconLibrary: { classPropertyName: "iconLibrary", publicName: "iconLibrary", isSignal: true, isRequired: false, transformFunction: null }, iconSize: { classPropertyName: "iconSize", publicName: "iconSize", isSignal: true, isRequired: false, transformFunction: null }, actionText: { classPropertyName: "actionText", publicName: "actionText", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, host: { attributes: { "role": "status" }, properties: { "class.tn-empty--compact": "size() === \"compact\"", "class.tn-empty--bordered": "bordered()" }, classAttribute: "tn-empty" }, ngImport: i0, template: "@if (icon()) {\n <div class=\"tn-empty__icon\">\n <tn-icon\n aria-hidden=\"true\"\n [name]=\"icon()!\"\n [library]=\"iconLibrary()\"\n [size]=\"iconSizePreset()\"\n [customSize]=\"iconSize()\"\n />\n </div>\n}\n\n<div class=\"tn-empty__title\">\n {{ title() }}\n</div>\n\n@if (description()) {\n <div class=\"tn-empty__description\">\n {{ description() }}\n </div>\n}\n\n@if (hasAction()) {\n <div class=\"tn-empty__action\">\n <tn-button\n color=\"primary\"\n variant=\"outline\"\n [label]=\"actionText()!\"\n (onClick)=\"onAction.emit()\"\n />\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:8px;padding:48px 24px;border-radius:8px}:host(.tn-empty--bordered){border:1px solid var(--tn-lines)}:host(.tn-empty--compact){padding:24px 16px}:host(.tn-empty--compact) .tn-empty__title{font-size:1rem}:host(.tn-empty--compact) .tn-empty__description{font-size:.8125rem}:host(.tn-empty--compact) .tn-empty__icon{margin-bottom:4px}:host(.tn-empty--compact) .tn-empty__action{margin-top:4px}.tn-empty__icon{color:var(--tn-fg2, #6b7280);margin-bottom:8px}.tn-empty__title{font-size:1.125rem;font-weight:600;color:var(--tn-fg1, #e5e7eb);line-height:1.4}.tn-empty__description{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;max-width:420px}.tn-empty__action{margin-top:8px}\n"], dependencies: [{ kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "disabled", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }] });
|
|
8065
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnEmptyComponent, isStandalone: true, selector: "tn-empty", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, iconLibrary: { classPropertyName: "iconLibrary", publicName: "iconLibrary", isSignal: true, isRequired: false, transformFunction: null }, iconSize: { classPropertyName: "iconSize", publicName: "iconSize", isSignal: true, isRequired: false, transformFunction: null }, actionText: { classPropertyName: "actionText", publicName: "actionText", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, host: { attributes: { "role": "status" }, properties: { "class.tn-empty--compact": "size() === \"compact\"", "class.tn-empty--bordered": "bordered()" }, classAttribute: "tn-empty" }, ngImport: i0, template: "@if (icon()) {\n <div class=\"tn-empty__icon\">\n <tn-icon\n aria-hidden=\"true\"\n [name]=\"icon()!\"\n [library]=\"iconLibrary()\"\n [size]=\"iconSizePreset()\"\n [customSize]=\"iconSize()\"\n />\n </div>\n}\n\n<div class=\"tn-empty__title\">\n {{ title() }}\n</div>\n\n@if (description()) {\n <div class=\"tn-empty__description\">\n {{ description() }}\n </div>\n}\n\n@if (hasAction()) {\n <div class=\"tn-empty__action\">\n <tn-button\n color=\"primary\"\n variant=\"outline\"\n [label]=\"actionText()!\"\n (onClick)=\"onAction.emit()\"\n />\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:8px;padding:48px 24px;border-radius:8px}:host(.tn-empty--bordered){border:1px solid var(--tn-lines)}:host(.tn-empty--compact){padding:24px 16px}:host(.tn-empty--compact) .tn-empty__title{font-size:1rem}:host(.tn-empty--compact) .tn-empty__description{font-size:.8125rem}:host(.tn-empty--compact) .tn-empty__icon{margin-bottom:4px}:host(.tn-empty--compact) .tn-empty__action{margin-top:4px}.tn-empty__icon{color:var(--tn-fg2, #6b7280);margin-bottom:8px}.tn-empty__title{font-size:1.125rem;font-weight:600;color:var(--tn-fg1, #e5e7eb);line-height:1.4}.tn-empty__description{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;max-width:420px}.tn-empty__action{margin-top:8px}\n"], dependencies: [{ kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "disabled", "type", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }] });
|
|
8040
8066
|
}
|
|
8041
8067
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnEmptyComponent, decorators: [{
|
|
8042
8068
|
type: Component,
|
|
@@ -12876,7 +12902,7 @@ class TnConfirmDialogComponent {
|
|
|
12876
12902
|
ref = inject((DialogRef));
|
|
12877
12903
|
data = inject(DIALOG_DATA);
|
|
12878
12904
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnConfirmDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12879
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.0", type: TnConfirmDialogComponent, isStandalone: true, selector: "tn-confirm-dialog", host: { properties: { "class.tn-dialog--destructive": "data.destructive" }, classAttribute: "tn-dialog-shell" }, ngImport: i0, template: "<tn-dialog-shell [title]=\"data.title\">\n <p style=\"margin: 0;\">{{ data.message }}</p>\n <div tnDialogAction>\n <tn-button\n type=\"button\"\n variant=\"outline\"\n [label]=\"data.cancelText || 'Cancel'\"\n [testId]=\"data.cancelTestId || 'cancel'\"\n (click)=\"ref.close(false)\" />\n <tn-button\n type=\"button\"\n [color]=\"data.destructive ? 'warn' : 'primary'\"\n [label]=\"data.confirmText || 'OK'\"\n [testId]=\"data.confirmTestId || 'confirm'\"\n (click)=\"ref.close(true)\" />\n </div>\n</tn-dialog-shell>\n", dependencies: [{ kind: "component", type: TnDialogShellComponent, selector: "tn-dialog-shell", inputs: ["title", "showFullscreenButton", "testId"] }, { kind: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "disabled", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }] });
|
|
12905
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.0", type: TnConfirmDialogComponent, isStandalone: true, selector: "tn-confirm-dialog", host: { properties: { "class.tn-dialog--destructive": "data.destructive" }, classAttribute: "tn-dialog-shell" }, ngImport: i0, template: "<tn-dialog-shell [title]=\"data.title\">\n <p style=\"margin: 0;\">{{ data.message }}</p>\n <div tnDialogAction>\n <tn-button\n type=\"button\"\n variant=\"outline\"\n [label]=\"data.cancelText || 'Cancel'\"\n [testId]=\"data.cancelTestId || 'cancel'\"\n (click)=\"ref.close(false)\" />\n <tn-button\n type=\"button\"\n [color]=\"data.destructive ? 'warn' : 'primary'\"\n [label]=\"data.confirmText || 'OK'\"\n [testId]=\"data.confirmTestId || 'confirm'\"\n (click)=\"ref.close(true)\" />\n </div>\n</tn-dialog-shell>\n", dependencies: [{ kind: "component", type: TnDialogShellComponent, selector: "tn-dialog-shell", inputs: ["title", "showFullscreenButton", "testId"] }, { kind: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "disabled", "type", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }] });
|
|
12880
12906
|
}
|
|
12881
12907
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnConfirmDialogComponent, decorators: [{
|
|
12882
12908
|
type: Component,
|
|
@@ -13885,7 +13911,7 @@ class TnFilePickerPopupComponent {
|
|
|
13885
13911
|
return `${(date.getMonth() + 1).toString().padStart(2, '0')}/${date.getDate().toString().padStart(2, '0')}/${date.getFullYear()} ${timePart}`;
|
|
13886
13912
|
}
|
|
13887
13913
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnFilePickerPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13888
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnFilePickerPopupComponent, isStandalone: true, selector: "tn-file-picker-popup", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, multiSelect: { classPropertyName: "multiSelect", publicName: "multiSelect", isSignal: true, isRequired: false, transformFunction: null }, allowCreate: { classPropertyName: "allowCreate", publicName: "allowCreate", isSignal: true, isRequired: false, transformFunction: null }, allowDatasetCreate: { classPropertyName: "allowDatasetCreate", publicName: "allowDatasetCreate", isSignal: true, isRequired: false, transformFunction: null }, allowZvolCreate: { classPropertyName: "allowZvolCreate", publicName: "allowZvolCreate", isSignal: true, isRequired: false, transformFunction: null }, currentPath: { classPropertyName: "currentPath", publicName: "currentPath", isSignal: true, isRequired: false, transformFunction: null }, fileItems: { classPropertyName: "fileItems", publicName: "fileItems", isSignal: true, isRequired: false, transformFunction: null }, selectedItems: { classPropertyName: "selectedItems", publicName: "selectedItems", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, creationLoading: { classPropertyName: "creationLoading", publicName: "creationLoading", isSignal: true, isRequired: false, transformFunction: null }, fileExtensions: { classPropertyName: "fileExtensions", publicName: "fileExtensions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick", itemDoubleClick: "itemDoubleClick", pathNavigate: "pathNavigate", createFolder: "createFolder", clearSelection: "clearSelection", close: "close", submit: "submit", cancel: "cancel", submitFolderName: "submitFolderName", cancelFolderCreation: "cancelFolderCreation" }, host: { classAttribute: "tn-file-picker-popup" }, ngImport: i0, template: "<!-- Header with breadcrumb navigation -->\n<div class=\"tn-file-picker-header\">\n <nav class=\"tn-file-picker-breadcrumb\" aria-label=\"File path\">\n @for (segment of currentPath() | tnTruncatePath; track $index; let last = $last) {\n <button\n class=\"breadcrumb-segment\"\n [class.current]=\"last\"\n [class.parent-nav]=\"segment.name === '..'\"\n [disabled]=\"last\"\n (click)=\"navigateToPath(segment.path)\">\n {{ segment.name }}\n </button>\n }\n </nav>\n\n <div class=\"tn-file-picker-actions\">\n @if (allowCreate()) {\n <tn-button\n variant=\"outline\"\n label=\"New Folder\"\n [disabled]=\"isCreateDisabled()\"\n (onClick)=\"onCreateFolder()\" />\n }\n </div>\n</div>\n\n<!-- Loading indicator -->\n@if (loading()) {\n <div class=\"tn-file-picker-loading\">\n <tn-icon name=\"loading\" library=\"mdi\" />\n <span>Loading...</span>\n </div>\n}\n\n<!-- File table -->\n@if (!loading()) {\n <div class=\"tn-file-picker-content\">\n <tn-table\n [dataSource]=\"filteredFileItems()\"\n [displayedColumns]=\"multiSelect() ? displayedColumns : displayedColumns.slice(1)\">\n\n <!-- Selection column -->\n @if (multiSelect()) {\n <ng-container tnColumnDef=\"select\">\n <ng-template tnHeaderCellDef>\n <!-- Select all checkbox -->\n </ng-template>\n <ng-template let-item tnCellDef>\n <input \n type=\"checkbox\" \n [checked]=\"isSelected(item)\"\n [disabled]=\"!!item.disabled\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onItemClick(item)\">\n </ng-template>\n </ng-container>\n }\n\n <!-- Name column -->\n <ng-container tnColumnDef=\"name\">\n <ng-template tnHeaderCellDef>Name</ng-template>\n <ng-template let-item tnCellDef>\n\n <!-- NORMAL MODE: Display name -->\n @if (!item.isCreating) {\n <div\n class=\"file-name-cell\"\n [class.disabled]=\"!!item.disabled\"\n [class.zfs-object]=\"isZfsObject(item)\"\n [attr.tabindex]=\"item.disabled ? null : 0\"\n [attr.role]=\"'button'\"\n (click)=\"onItemClick(item)\"\n (dblclick)=\"onItemDoubleClick(item)\"\n (keydown.enter)=\"onItemDoubleClick(item)\"\n (keydown.space)=\"onItemClick(item)\">\n <tn-icon\n [name]=\"getItemIcon(item)\"\n [library]=\"getItemIconLibrary(item)\"\n [class]=\"'file-icon file-icon-' + item.type\" />\n <span class=\"file-name\">{{ item.name }}</span>\n\n <!-- ZFS badge -->\n @if (isZfsObject(item)) {\n <span\n [class]=\"'zfs-badge zfs-badge-' + item.type\">\n {{ getZfsBadge(item) }}\n </span>\n }\n\n <!-- Permission indicator -->\n @if (item.permissions === 'none') {\n <tn-icon\n name=\"lock\"\n library=\"mdi\"\n class=\"permission-icon\" />\n }\n </div>\n }\n\n <!-- EDIT MODE: Inline name input with error display -->\n @if (item.isCreating) {\n <div class=\"file-name-cell-wrapper\">\n <div class=\"file-name-cell editing\" [class.has-error]=\"!!item.creationError\">\n <tn-icon\n name=\"folder\"\n library=\"mdi\"\n class=\"file-icon file-icon-folder\" />\n <input\n #folderNameInput\n type=\"text\"\n role=\"textbox\"\n aria-label=\"Folder name\"\n class=\"folder-name-input\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n [class.error]=\"!!item.creationError\"\n [value]=\"item.name\"\n [disabled]=\"creationLoading()\"\n [attr.data-autofocus]=\"true\"\n (keydown)=\"onFolderNameKeyDown($event, item)\"\n (blur)=\"onFolderNameInputBlur($event, item)\">\n\n <!-- Loading indicator during submission -->\n @if (creationLoading()) {\n <tn-icon\n name=\"loading\"\n library=\"mdi\"\n class=\"creation-loading-icon\" />\n }\n </div>\n\n <!-- Inline error message -->\n @if (item.creationError) {\n <div class=\"folder-creation-error\">\n <tn-icon name=\"alert-circle\" library=\"mdi\" class=\"error-icon\" />\n <span class=\"error-text\">{{ item.creationError }}</span>\n </div>\n }\n </div>\n }\n\n </ng-template>\n </ng-container>\n\n <!-- Size column -->\n <ng-container tnColumnDef=\"size\">\n <ng-template tnHeaderCellDef>Size</ng-template>\n <ng-template let-item tnCellDef>\n @if (item.size !== undefined) {\n <span>{{ item.size | tnFileSize }}</span>\n }\n @if (item.size === undefined && item.type === 'folder') {\n <span class=\"folder-indicator\">--</span>\n }\n </ng-template>\n </ng-container>\n\n <!-- Modified column -->\n <ng-container tnColumnDef=\"modified\">\n <ng-template tnHeaderCellDef>Modified</ng-template>\n <ng-template let-item tnCellDef>\n @if (item.modified) {\n <span>{{ formatDate(item.modified) }}</span>\n }\n </ng-template>\n </ng-container>\n\n\n </tn-table>\n\n <!-- Empty state -->\n @if (filteredFileItems().length === 0) {\n <div class=\"empty-state\">\n <tn-icon name=\"folder-open\" library=\"mdi\" customSize=\"48px\" />\n <p>No items found</p>\n </div>\n }\n </div>\n}\n\n<!-- Footer -->\n@if (!loading()) {\n <div class=\"tn-file-picker-footer\">\n @if (selectedItems().length > 0) {\n <span class=\"selection-count\">\n {{ selectedItems().length }} item{{ selectedItems().length !== 1 ? 's' : '' }} selected\n </span>\n }\n @if (selectedItems().length === 0) {\n <span class=\"selection-count\">\n No items selected\n </span>\n }\n <div class=\"footer-actions\">\n <tn-button\n label=\"Select\"\n [disabled]=\"selectedItems().length === 0\"\n (onClick)=\"onSubmit()\" />\n </div>\n </div>\n}", styles: [":host{display:block;background:var(--tn-bg1, white);color:var(--tn-fg1, #333);padding:0;box-shadow:0 4px 16px #0000001f,0 1px 4px #00000014;border-radius:8px;border:1px solid var(--tn-lines, #e0e0e0);min-width:400px;max-width:600px;min-height:500px;max-height:600px;font-family:var(--tn-font-family-body);display:flex;flex-direction:column;overflow:hidden}.tn-file-picker-header{display:flex;align-items:center;justify-content:space-between;padding:var(--tn-content-padding, 24px);padding-bottom:16px;border-bottom:1px solid var(--tn-lines)}.tn-file-picker-breadcrumb{display:flex;align-items:center;gap:4px;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary);cursor:pointer;padding:4px 8px;border-radius:4px;font-size:1rem;white-space:nowrap;transition:background-color .15s ease-in-out}.tn-file-picker-breadcrumb .breadcrumb-segment:hover:not(:disabled){background:var(--tn-bg2)}.tn-file-picker-breadcrumb .breadcrumb-segment:disabled,.tn-file-picker-breadcrumb .breadcrumb-segment.current{color:var(--tn-fg1);cursor:default;font-weight:500}.tn-file-picker-breadcrumb .breadcrumb-segment:not(:last-child):after{content:\"/\";margin-left:8px;color:var(--tn-alt-fg1)}.tn-file-picker-actions{display:flex;align-items:center;gap:8px}.tn-file-picker-actions tn-button{font-size:1rem}.tn-file-picker-loading{display:flex;align-items:center;justify-content:center;gap:8px;padding:40px;color:var(--tn-fg2)}.tn-file-picker-loading tn-icon{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tn-file-picker-content{flex:1;min-height:0;overflow-y:auto}.file-list-viewport{width:100%;height:100%}.file-list-viewport .cdk-virtual-scroll-content-wrapper{width:100%}tn-table{width:100%}tn-table th,tn-table .tn-table__header-cell{font-weight:600;color:var(--tn-fg1);padding:12px 16px;border-bottom:2px solid var(--tn-lines)}tn-table td,tn-table .tn-table__cell{padding:8px 16px;border-bottom:1px solid var(--tn-lines)}.file-checkbox{display:flex;align-items:center}.file-checkbox input[type=checkbox]{margin:0;width:16px;height:16px}.file-name-cell{display:flex;align-items:center;gap:8px;cursor:pointer}.file-name-cell.disabled{opacity:.5;color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-name{color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-icon{opacity:.6}.file-name-cell.disabled:has(.file-icon-folder),.file-name-cell.disabled:has(.file-icon-dataset),.file-name-cell.disabled:has(.file-icon-mountpoint){cursor:pointer}.file-name-cell.disabled:not(:has(.file-icon-folder)):not(:has(.file-icon-dataset)):not(:has(.file-icon-mountpoint)){cursor:not-allowed}.file-name-cell.editing{display:flex;align-items:center;gap:8px;padding:2px;cursor:default}.file-name-cell.editing .folder-name-input{flex:1;border:2px solid var(--tn-primary, #0066cc);padding:4px 8px;font-size:inherit;font-family:inherit;background:var(--tn-bg1, white);color:var(--tn-fg1, black);outline:none;border-radius:3px;min-width:200px}.file-name-cell.editing .folder-name-input:focus{border-color:var(--tn-primary, #0066cc);box-shadow:0 0 0 3px #0066cc1a}.file-name-cell.editing .folder-name-input.error{border-color:var(--tn-error, #d32f2f)}.file-name-cell.editing .folder-name-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2, #f5f5f5)}.file-name-cell.editing .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary, #0066cc);flex-shrink:0}.file-name-cell-wrapper{display:flex;flex-direction:column;gap:4px}.folder-creation-error{display:flex;align-items:center;gap:6px;padding:4px 8px 4px 36px;margin-bottom:12px;background:#d32f2f1a;border-left:3px solid var(--tn-error, #d32f2f);border-radius:3px;font-size:1rem;color:var(--tn-error, #d32f2f)}.folder-creation-error .error-icon{flex-shrink:0;width:20px;height:20px}.folder-creation-error .error-text{flex:1}.file-icon{display:flex;align-items:center;justify-content:center;font-size:var(--tn-icon-md, 20px);flex-shrink:0;line-height:1}.file-icon.file-icon-folder{color:var(--tn-primary)}.file-icon.file-icon-dataset{color:var(--tn-blue, #007db3)}.file-icon.file-icon-zvol{color:var(--tn-green, #71BF44)}.file-icon.file-icon-mountpoint{color:var(--tn-orange, #E68D37)}.file-name{flex:1;font-weight:500;line-height:1.4}.zfs-badge{display:inline-flex;align-items:center;background:var(--tn-alt-bg2);color:var(--tn-alt-fg2);font-size:.625rem;font-weight:600;padding:2px 6px;border-radius:12px;text-transform:uppercase;letter-spacing:.5px;line-height:1}.zfs-badge.zfs-badge-dataset{background:var(--tn-blue);color:#fff}.zfs-badge.zfs-badge-zvol{background:var(--tn-green);color:#fff}.zfs-badge.zfs-badge-mountpoint{background:var(--tn-orange);color:#fff}.permission-icon{display:flex;align-items:center;justify-content:center;color:var(--tn-red);font-size:var(--tn-icon-sm, 16px);line-height:1}.file-type{font-size:1rem;padding:2px 8px;border-radius:12px}.file-type.type-folder{background:var(--tn-alt-bg1);color:var(--tn-alt-fg2)}.file-type.type-file{background:var(--tn-bg2);color:var(--tn-fg2)}.file-type.type-dataset{background:#007db31a;color:var(--tn-blue)}.file-type.type-zvol{background:#71bf441a;color:var(--tn-green)}.file-type.type-mountpoint{background:#e68d371a;color:var(--tn-orange)}.folder-indicator{color:var(--tn-alt-fg1);font-style:italic}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;color:var(--tn-alt-fg1);text-align:center}.empty-state tn-icon{margin-bottom:16px;opacity:.5}.empty-state p{margin:0;font-size:1rem}.tn-file-picker-footer{display:flex;align-items:center;justify-content:space-between;padding:16px var(--tn-content-padding, 24px);border-top:1px solid var(--tn-lines);background:var(--tn-bg2);border-bottom-left-radius:8px;border-bottom-right-radius:8px}.selection-count{font-size:1rem;color:var(--tn-fg2);font-weight:500}.footer-actions{display:flex;gap:8px}@media(prefers-reduced-motion:reduce){.file-item,.breadcrumb-segment{transition:none}.tn-file-picker-loading tn-icon{animation:none}}@media(prefers-contrast:high){:host{border-width:2px}.file-item:hover,.file-item.selected{border:2px solid var(--tn-fg1)}.zfs-badge{border:1px solid var(--tn-fg1)}}@media(max-width:768px){:host{min-width:300px;max-width:calc(100vw - 32px);max-height:calc(100vh - 64px)}.tn-file-picker-header{flex-direction:column;gap:12px;align-items:stretch}.tn-file-picker-breadcrumb{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.tn-file-picker-breadcrumb::-webkit-scrollbar{display:none}.file-item{padding:12px;min-height:56px}.file-info{font-size:1rem}}\n"], dependencies: [{ kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "disabled", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }, { kind: "component", type: TnTableComponent, selector: "tn-table", inputs: ["dataSource", "displayedColumns", "trackBy", "emptyMessage", "emptyIcon", "selectable", "expandable", "bordered", "activeRow", "activeBg", "activeIndicator", "loading", "loadingMessage", "clickable"], outputs: ["sortChange", "selectionChange", "rowClick"] }, { kind: "directive", type: TnTableColumnDirective, selector: "[tnColumnDef]", inputs: ["tnColumnDef", "sortable", "width"], exportAs: ["tnColumnDef"] }, { kind: "directive", type: TnHeaderCellDefDirective, selector: "[tnHeaderCellDef]" }, { kind: "directive", type: TnCellDefDirective, selector: "[tnCellDef]" }, { kind: "ngmodule", type: ScrollingModule }, { kind: "ngmodule", type: A11yModule }, { kind: "pipe", type: FileSizePipe, name: "tnFileSize" }, { kind: "pipe", type: TruncatePathPipe, name: "tnTruncatePath" }] });
|
|
13914
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnFilePickerPopupComponent, isStandalone: true, selector: "tn-file-picker-popup", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, multiSelect: { classPropertyName: "multiSelect", publicName: "multiSelect", isSignal: true, isRequired: false, transformFunction: null }, allowCreate: { classPropertyName: "allowCreate", publicName: "allowCreate", isSignal: true, isRequired: false, transformFunction: null }, allowDatasetCreate: { classPropertyName: "allowDatasetCreate", publicName: "allowDatasetCreate", isSignal: true, isRequired: false, transformFunction: null }, allowZvolCreate: { classPropertyName: "allowZvolCreate", publicName: "allowZvolCreate", isSignal: true, isRequired: false, transformFunction: null }, currentPath: { classPropertyName: "currentPath", publicName: "currentPath", isSignal: true, isRequired: false, transformFunction: null }, fileItems: { classPropertyName: "fileItems", publicName: "fileItems", isSignal: true, isRequired: false, transformFunction: null }, selectedItems: { classPropertyName: "selectedItems", publicName: "selectedItems", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, creationLoading: { classPropertyName: "creationLoading", publicName: "creationLoading", isSignal: true, isRequired: false, transformFunction: null }, fileExtensions: { classPropertyName: "fileExtensions", publicName: "fileExtensions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick", itemDoubleClick: "itemDoubleClick", pathNavigate: "pathNavigate", createFolder: "createFolder", clearSelection: "clearSelection", close: "close", submit: "submit", cancel: "cancel", submitFolderName: "submitFolderName", cancelFolderCreation: "cancelFolderCreation" }, host: { classAttribute: "tn-file-picker-popup" }, ngImport: i0, template: "<!-- Header with breadcrumb navigation -->\n<div class=\"tn-file-picker-header\">\n <nav class=\"tn-file-picker-breadcrumb\" aria-label=\"File path\">\n @for (segment of currentPath() | tnTruncatePath; track $index; let last = $last) {\n <button\n class=\"breadcrumb-segment\"\n [class.current]=\"last\"\n [class.parent-nav]=\"segment.name === '..'\"\n [disabled]=\"last\"\n (click)=\"navigateToPath(segment.path)\">\n {{ segment.name }}\n </button>\n }\n </nav>\n\n <div class=\"tn-file-picker-actions\">\n @if (allowCreate()) {\n <tn-button\n variant=\"outline\"\n label=\"New Folder\"\n [disabled]=\"isCreateDisabled()\"\n (onClick)=\"onCreateFolder()\" />\n }\n </div>\n</div>\n\n<!-- Loading indicator -->\n@if (loading()) {\n <div class=\"tn-file-picker-loading\">\n <tn-icon name=\"loading\" library=\"mdi\" />\n <span>Loading...</span>\n </div>\n}\n\n<!-- File table -->\n@if (!loading()) {\n <div class=\"tn-file-picker-content\">\n <tn-table\n [dataSource]=\"filteredFileItems()\"\n [displayedColumns]=\"multiSelect() ? displayedColumns : displayedColumns.slice(1)\">\n\n <!-- Selection column -->\n @if (multiSelect()) {\n <ng-container tnColumnDef=\"select\">\n <ng-template tnHeaderCellDef>\n <!-- Select all checkbox -->\n </ng-template>\n <ng-template let-item tnCellDef>\n <input \n type=\"checkbox\" \n [checked]=\"isSelected(item)\"\n [disabled]=\"!!item.disabled\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onItemClick(item)\">\n </ng-template>\n </ng-container>\n }\n\n <!-- Name column -->\n <ng-container tnColumnDef=\"name\">\n <ng-template tnHeaderCellDef>Name</ng-template>\n <ng-template let-item tnCellDef>\n\n <!-- NORMAL MODE: Display name -->\n @if (!item.isCreating) {\n <div\n class=\"file-name-cell\"\n [class.disabled]=\"!!item.disabled\"\n [class.zfs-object]=\"isZfsObject(item)\"\n [attr.tabindex]=\"item.disabled ? null : 0\"\n [attr.role]=\"'button'\"\n (click)=\"onItemClick(item)\"\n (dblclick)=\"onItemDoubleClick(item)\"\n (keydown.enter)=\"onItemDoubleClick(item)\"\n (keydown.space)=\"onItemClick(item)\">\n <tn-icon\n [name]=\"getItemIcon(item)\"\n [library]=\"getItemIconLibrary(item)\"\n [class]=\"'file-icon file-icon-' + item.type\" />\n <span class=\"file-name\">{{ item.name }}</span>\n\n <!-- ZFS badge -->\n @if (isZfsObject(item)) {\n <span\n [class]=\"'zfs-badge zfs-badge-' + item.type\">\n {{ getZfsBadge(item) }}\n </span>\n }\n\n <!-- Permission indicator -->\n @if (item.permissions === 'none') {\n <tn-icon\n name=\"lock\"\n library=\"mdi\"\n class=\"permission-icon\" />\n }\n </div>\n }\n\n <!-- EDIT MODE: Inline name input with error display -->\n @if (item.isCreating) {\n <div class=\"file-name-cell-wrapper\">\n <div class=\"file-name-cell editing\" [class.has-error]=\"!!item.creationError\">\n <tn-icon\n name=\"folder\"\n library=\"mdi\"\n class=\"file-icon file-icon-folder\" />\n <input\n #folderNameInput\n type=\"text\"\n role=\"textbox\"\n aria-label=\"Folder name\"\n class=\"folder-name-input\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n [class.error]=\"!!item.creationError\"\n [value]=\"item.name\"\n [disabled]=\"creationLoading()\"\n [attr.data-autofocus]=\"true\"\n (keydown)=\"onFolderNameKeyDown($event, item)\"\n (blur)=\"onFolderNameInputBlur($event, item)\">\n\n <!-- Loading indicator during submission -->\n @if (creationLoading()) {\n <tn-icon\n name=\"loading\"\n library=\"mdi\"\n class=\"creation-loading-icon\" />\n }\n </div>\n\n <!-- Inline error message -->\n @if (item.creationError) {\n <div class=\"folder-creation-error\">\n <tn-icon name=\"alert-circle\" library=\"mdi\" class=\"error-icon\" />\n <span class=\"error-text\">{{ item.creationError }}</span>\n </div>\n }\n </div>\n }\n\n </ng-template>\n </ng-container>\n\n <!-- Size column -->\n <ng-container tnColumnDef=\"size\">\n <ng-template tnHeaderCellDef>Size</ng-template>\n <ng-template let-item tnCellDef>\n @if (item.size !== undefined) {\n <span>{{ item.size | tnFileSize }}</span>\n }\n @if (item.size === undefined && item.type === 'folder') {\n <span class=\"folder-indicator\">--</span>\n }\n </ng-template>\n </ng-container>\n\n <!-- Modified column -->\n <ng-container tnColumnDef=\"modified\">\n <ng-template tnHeaderCellDef>Modified</ng-template>\n <ng-template let-item tnCellDef>\n @if (item.modified) {\n <span>{{ formatDate(item.modified) }}</span>\n }\n </ng-template>\n </ng-container>\n\n\n </tn-table>\n\n <!-- Empty state -->\n @if (filteredFileItems().length === 0) {\n <div class=\"empty-state\">\n <tn-icon name=\"folder-open\" library=\"mdi\" customSize=\"48px\" />\n <p>No items found</p>\n </div>\n }\n </div>\n}\n\n<!-- Footer -->\n@if (!loading()) {\n <div class=\"tn-file-picker-footer\">\n @if (selectedItems().length > 0) {\n <span class=\"selection-count\">\n {{ selectedItems().length }} item{{ selectedItems().length !== 1 ? 's' : '' }} selected\n </span>\n }\n @if (selectedItems().length === 0) {\n <span class=\"selection-count\">\n No items selected\n </span>\n }\n <div class=\"footer-actions\">\n <tn-button\n label=\"Select\"\n [disabled]=\"selectedItems().length === 0\"\n (onClick)=\"onSubmit()\" />\n </div>\n </div>\n}", styles: [":host{display:block;background:var(--tn-bg1, white);color:var(--tn-fg1, #333);padding:0;box-shadow:0 4px 16px #0000001f,0 1px 4px #00000014;border-radius:8px;border:1px solid var(--tn-lines, #e0e0e0);min-width:400px;max-width:600px;min-height:500px;max-height:600px;font-family:var(--tn-font-family-body);display:flex;flex-direction:column;overflow:hidden}.tn-file-picker-header{display:flex;align-items:center;justify-content:space-between;padding:var(--tn-content-padding, 24px);padding-bottom:16px;border-bottom:1px solid var(--tn-lines)}.tn-file-picker-breadcrumb{display:flex;align-items:center;gap:4px;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary);cursor:pointer;padding:4px 8px;border-radius:4px;font-size:1rem;white-space:nowrap;transition:background-color .15s ease-in-out}.tn-file-picker-breadcrumb .breadcrumb-segment:hover:not(:disabled){background:var(--tn-bg2)}.tn-file-picker-breadcrumb .breadcrumb-segment:disabled,.tn-file-picker-breadcrumb .breadcrumb-segment.current{color:var(--tn-fg1);cursor:default;font-weight:500}.tn-file-picker-breadcrumb .breadcrumb-segment:not(:last-child):after{content:\"/\";margin-left:8px;color:var(--tn-alt-fg1)}.tn-file-picker-actions{display:flex;align-items:center;gap:8px}.tn-file-picker-actions tn-button{font-size:1rem}.tn-file-picker-loading{display:flex;align-items:center;justify-content:center;gap:8px;padding:40px;color:var(--tn-fg2)}.tn-file-picker-loading tn-icon{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tn-file-picker-content{flex:1;min-height:0;overflow-y:auto}.file-list-viewport{width:100%;height:100%}.file-list-viewport .cdk-virtual-scroll-content-wrapper{width:100%}tn-table{width:100%}tn-table th,tn-table .tn-table__header-cell{font-weight:600;color:var(--tn-fg1);padding:12px 16px;border-bottom:2px solid var(--tn-lines)}tn-table td,tn-table .tn-table__cell{padding:8px 16px;border-bottom:1px solid var(--tn-lines)}.file-checkbox{display:flex;align-items:center}.file-checkbox input[type=checkbox]{margin:0;width:16px;height:16px}.file-name-cell{display:flex;align-items:center;gap:8px;cursor:pointer}.file-name-cell.disabled{opacity:.5;color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-name{color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-icon{opacity:.6}.file-name-cell.disabled:has(.file-icon-folder),.file-name-cell.disabled:has(.file-icon-dataset),.file-name-cell.disabled:has(.file-icon-mountpoint){cursor:pointer}.file-name-cell.disabled:not(:has(.file-icon-folder)):not(:has(.file-icon-dataset)):not(:has(.file-icon-mountpoint)){cursor:not-allowed}.file-name-cell.editing{display:flex;align-items:center;gap:8px;padding:2px;cursor:default}.file-name-cell.editing .folder-name-input{flex:1;border:2px solid var(--tn-primary, #0066cc);padding:4px 8px;font-size:inherit;font-family:inherit;background:var(--tn-bg1, white);color:var(--tn-fg1, black);outline:none;border-radius:3px;min-width:200px}.file-name-cell.editing .folder-name-input:focus{border-color:var(--tn-primary, #0066cc);box-shadow:0 0 0 3px #0066cc1a}.file-name-cell.editing .folder-name-input.error{border-color:var(--tn-error, #d32f2f)}.file-name-cell.editing .folder-name-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2, #f5f5f5)}.file-name-cell.editing .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary, #0066cc);flex-shrink:0}.file-name-cell-wrapper{display:flex;flex-direction:column;gap:4px}.folder-creation-error{display:flex;align-items:center;gap:6px;padding:4px 8px 4px 36px;margin-bottom:12px;background:#d32f2f1a;border-left:3px solid var(--tn-error, #d32f2f);border-radius:3px;font-size:1rem;color:var(--tn-error, #d32f2f)}.folder-creation-error .error-icon{flex-shrink:0;width:20px;height:20px}.folder-creation-error .error-text{flex:1}.file-icon{display:flex;align-items:center;justify-content:center;font-size:var(--tn-icon-md, 20px);flex-shrink:0;line-height:1}.file-icon.file-icon-folder{color:var(--tn-primary)}.file-icon.file-icon-dataset{color:var(--tn-blue, #007db3)}.file-icon.file-icon-zvol{color:var(--tn-green, #71BF44)}.file-icon.file-icon-mountpoint{color:var(--tn-orange, #E68D37)}.file-name{flex:1;font-weight:500;line-height:1.4}.zfs-badge{display:inline-flex;align-items:center;background:var(--tn-alt-bg2);color:var(--tn-alt-fg2);font-size:.625rem;font-weight:600;padding:2px 6px;border-radius:12px;text-transform:uppercase;letter-spacing:.5px;line-height:1}.zfs-badge.zfs-badge-dataset{background:var(--tn-blue);color:#fff}.zfs-badge.zfs-badge-zvol{background:var(--tn-green);color:#fff}.zfs-badge.zfs-badge-mountpoint{background:var(--tn-orange);color:#fff}.permission-icon{display:flex;align-items:center;justify-content:center;color:var(--tn-red);font-size:var(--tn-icon-sm, 16px);line-height:1}.file-type{font-size:1rem;padding:2px 8px;border-radius:12px}.file-type.type-folder{background:var(--tn-alt-bg1);color:var(--tn-alt-fg2)}.file-type.type-file{background:var(--tn-bg2);color:var(--tn-fg2)}.file-type.type-dataset{background:#007db31a;color:var(--tn-blue)}.file-type.type-zvol{background:#71bf441a;color:var(--tn-green)}.file-type.type-mountpoint{background:#e68d371a;color:var(--tn-orange)}.folder-indicator{color:var(--tn-alt-fg1);font-style:italic}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;color:var(--tn-alt-fg1);text-align:center}.empty-state tn-icon{margin-bottom:16px;opacity:.5}.empty-state p{margin:0;font-size:1rem}.tn-file-picker-footer{display:flex;align-items:center;justify-content:space-between;padding:16px var(--tn-content-padding, 24px);border-top:1px solid var(--tn-lines);background:var(--tn-bg2);border-bottom-left-radius:8px;border-bottom-right-radius:8px}.selection-count{font-size:1rem;color:var(--tn-fg2);font-weight:500}.footer-actions{display:flex;gap:8px}@media(prefers-reduced-motion:reduce){.file-item,.breadcrumb-segment{transition:none}.tn-file-picker-loading tn-icon{animation:none}}@media(prefers-contrast:high){:host{border-width:2px}.file-item:hover,.file-item.selected{border:2px solid var(--tn-fg1)}.zfs-badge{border:1px solid var(--tn-fg1)}}@media(max-width:768px){:host{min-width:300px;max-width:calc(100vw - 32px);max-height:calc(100vh - 64px)}.tn-file-picker-header{flex-direction:column;gap:12px;align-items:stretch}.tn-file-picker-breadcrumb{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.tn-file-picker-breadcrumb::-webkit-scrollbar{display:none}.file-item{padding:12px;min-height:56px}.file-info{font-size:1rem}}\n"], dependencies: [{ kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "component", type: TnButtonComponent, selector: "tn-button", inputs: ["primary", "color", "variant", "backgroundColor", "label", "disabled", "type", "testId", "href", "routerLink", "queryParams", "fragment", "target", "rel", "ariaLabel"], outputs: ["onClick"] }, { kind: "component", type: TnTableComponent, selector: "tn-table", inputs: ["dataSource", "displayedColumns", "trackBy", "emptyMessage", "emptyIcon", "selectable", "expandable", "bordered", "activeRow", "activeBg", "activeIndicator", "loading", "loadingMessage", "clickable"], outputs: ["sortChange", "selectionChange", "rowClick"] }, { kind: "directive", type: TnTableColumnDirective, selector: "[tnColumnDef]", inputs: ["tnColumnDef", "sortable", "width"], exportAs: ["tnColumnDef"] }, { kind: "directive", type: TnHeaderCellDefDirective, selector: "[tnHeaderCellDef]" }, { kind: "directive", type: TnCellDefDirective, selector: "[tnCellDef]" }, { kind: "ngmodule", type: ScrollingModule }, { kind: "ngmodule", type: A11yModule }, { kind: "pipe", type: FileSizePipe, name: "tnFileSize" }, { kind: "pipe", type: TruncatePathPipe, name: "tnTruncatePath" }] });
|
|
13889
13915
|
}
|
|
13890
13916
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnFilePickerPopupComponent, decorators: [{
|
|
13891
13917
|
type: Component,
|