@truenas/ui-components 0.8.1 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2682,7 +2682,7 @@ var TnIconComponent = class TnIconComponent {
|
|
|
2682
2682
|
}],
|
|
2683
2683
|
ngImport: i0,
|
|
2684
2684
|
template: "<div\n class=\"tn-icon\"\n role=\"img\"\n tnTestIdType=\"icon\"\n [tnTestId]=\"testId()\"\n [attr.aria-label]=\"effectiveAriaLabel()\"\n [attr.title]=\"tooltip()\">\n \n\n @switch (iconResult().source) {\n <!-- Sprite icons (from generated sprite.svg) -->\n @case ('sprite') {\n <svg\n class=\"tn-icon__sprite\"\n aria-hidden=\"true\">\n <use [attr.href]=\"iconResult().spriteUrl\" />\n </svg>\n }\n\n <!-- SVG content (from third-party libraries or assets) -->\n @case ('svg') {\n <div\n #svgContainer\n class=\"tn-icon__svg\">\n </div>\n }\n\n <!-- CSS class icons (Font Awesome, Material Icons, etc.) -->\n @case ('css') {\n <i\n aria-hidden=\"true\"\n [class]=\"'tn-icon__css ' + iconResult().content\">\n </i>\n }\n\n <!-- Unicode characters -->\n @case ('unicode') {\n <span\n class=\"tn-icon__unicode\"\n aria-hidden=\"true\">{{ iconResult().content }}</span>\n }\n\n <!-- Text abbreviation fallback -->\n @default {\n <span\n class=\"tn-icon__text\"\n aria-hidden=\"true\">{{ iconResult().content }}</span>\n }\n }\n</div>",
|
|
2685
|
-
styles: ["tn-icon{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;color:var(--tn-icon-color, currentColor);width:var(--tn-icon-size, var(--tn-icon-md));height:var(--tn-icon-size, var(--tn-icon-md));min-width:var(--tn-icon-size, var(--tn-icon-md));min-height:var(--tn-icon-size, var(--tn-icon-md));font-size:var(--tn-icon-size, var(--tn-icon-md))}tn-icon[size=xs]{width:var(--tn-icon-xs);height:var(--tn-icon-xs);min-width:var(--tn-icon-xs);min-height:var(--tn-icon-xs);font-size:var(--tn-icon-xs)}tn-icon[size=sm]{width:var(--tn-icon-sm);height:var(--tn-icon-sm);min-width:var(--tn-icon-sm);min-height:var(--tn-icon-sm);font-size:var(--tn-icon-sm)}tn-icon[size=md]{width:var(--tn-icon-md);height:var(--tn-icon-md);min-width:var(--tn-icon-md);min-height:var(--tn-icon-md);font-size:var(--tn-icon-md)}tn-icon[size=lg]{width:var(--tn-icon-lg);height:var(--tn-icon-lg);min-width:var(--tn-icon-lg);min-height:var(--tn-icon-lg);font-size:var(--tn-icon-lg)}tn-icon[size=xl]{width:var(--tn-icon-xl);height:var(--tn-icon-xl);min-width:var(--tn-icon-xl);min-height:var(--tn-icon-xl);font-size:var(--tn-icon-xl)}.tn-icon{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.tn-icon__sprite{width:100%;height:100%;fill:currentColor;color:inherit}.tn-icon__svg{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.tn-icon__svg :global(svg){width:100%;height:100%;fill:currentColor;color:inherit}.tn-icon__css{font-size:inherit;line-height:1;color:inherit}.tn-icon__unicode{font-size:inherit;line-height:1;color:inherit;text-align:center}.tn-icon__text{font-size:.75em;font-weight:600;line-height:1;color:inherit;text-align:center
|
|
2685
|
+
styles: ["tn-icon{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;color:var(--tn-icon-color, currentColor);width:var(--tn-icon-size, var(--tn-icon-md));height:var(--tn-icon-size, var(--tn-icon-md));min-width:var(--tn-icon-size, var(--tn-icon-md));min-height:var(--tn-icon-size, var(--tn-icon-md));font-size:var(--tn-icon-size, var(--tn-icon-md))}tn-icon[size=xs]{width:var(--tn-icon-xs);height:var(--tn-icon-xs);min-width:var(--tn-icon-xs);min-height:var(--tn-icon-xs);font-size:var(--tn-icon-xs)}tn-icon[size=sm]{width:var(--tn-icon-sm);height:var(--tn-icon-sm);min-width:var(--tn-icon-sm);min-height:var(--tn-icon-sm);font-size:var(--tn-icon-sm)}tn-icon[size=md]{width:var(--tn-icon-md);height:var(--tn-icon-md);min-width:var(--tn-icon-md);min-height:var(--tn-icon-md);font-size:var(--tn-icon-md)}tn-icon[size=lg]{width:var(--tn-icon-lg);height:var(--tn-icon-lg);min-width:var(--tn-icon-lg);min-height:var(--tn-icon-lg);font-size:var(--tn-icon-lg)}tn-icon[size=xl]{width:var(--tn-icon-xl);height:var(--tn-icon-xl);min-width:var(--tn-icon-xl);min-height:var(--tn-icon-xl);font-size:var(--tn-icon-xl)}.tn-icon{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.tn-icon__sprite{width:100%;height:100%;fill:currentColor;color:inherit}.tn-icon__svg{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.tn-icon__svg :global(svg){width:100%;height:100%;fill:currentColor;color:inherit}.tn-icon__css{font-size:inherit;line-height:1;color:inherit}.tn-icon__unicode{font-size:inherit;line-height:1;color:inherit;text-align:center}.tn-icon__text{font-size:.75em;font-weight:600;line-height:1;color:inherit;text-align:center}\n"],
|
|
2686
2686
|
dependencies: [{
|
|
2687
2687
|
kind: "directive",
|
|
2688
2688
|
type: TnTestIdDirective,
|
|
@@ -2721,7 +2721,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2721
2721
|
"[style.color]": "color() || null"
|
|
2722
2722
|
},
|
|
2723
2723
|
template: "<div\n class=\"tn-icon\"\n role=\"img\"\n tnTestIdType=\"icon\"\n [tnTestId]=\"testId()\"\n [attr.aria-label]=\"effectiveAriaLabel()\"\n [attr.title]=\"tooltip()\">\n \n\n @switch (iconResult().source) {\n <!-- Sprite icons (from generated sprite.svg) -->\n @case ('sprite') {\n <svg\n class=\"tn-icon__sprite\"\n aria-hidden=\"true\">\n <use [attr.href]=\"iconResult().spriteUrl\" />\n </svg>\n }\n\n <!-- SVG content (from third-party libraries or assets) -->\n @case ('svg') {\n <div\n #svgContainer\n class=\"tn-icon__svg\">\n </div>\n }\n\n <!-- CSS class icons (Font Awesome, Material Icons, etc.) -->\n @case ('css') {\n <i\n aria-hidden=\"true\"\n [class]=\"'tn-icon__css ' + iconResult().content\">\n </i>\n }\n\n <!-- Unicode characters -->\n @case ('unicode') {\n <span\n class=\"tn-icon__unicode\"\n aria-hidden=\"true\">{{ iconResult().content }}</span>\n }\n\n <!-- Text abbreviation fallback -->\n @default {\n <span\n class=\"tn-icon__text\"\n aria-hidden=\"true\">{{ iconResult().content }}</span>\n }\n }\n</div>",
|
|
2724
|
-
styles: ["tn-icon{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;color:var(--tn-icon-color, currentColor);width:var(--tn-icon-size, var(--tn-icon-md));height:var(--tn-icon-size, var(--tn-icon-md));min-width:var(--tn-icon-size, var(--tn-icon-md));min-height:var(--tn-icon-size, var(--tn-icon-md));font-size:var(--tn-icon-size, var(--tn-icon-md))}tn-icon[size=xs]{width:var(--tn-icon-xs);height:var(--tn-icon-xs);min-width:var(--tn-icon-xs);min-height:var(--tn-icon-xs);font-size:var(--tn-icon-xs)}tn-icon[size=sm]{width:var(--tn-icon-sm);height:var(--tn-icon-sm);min-width:var(--tn-icon-sm);min-height:var(--tn-icon-sm);font-size:var(--tn-icon-sm)}tn-icon[size=md]{width:var(--tn-icon-md);height:var(--tn-icon-md);min-width:var(--tn-icon-md);min-height:var(--tn-icon-md);font-size:var(--tn-icon-md)}tn-icon[size=lg]{width:var(--tn-icon-lg);height:var(--tn-icon-lg);min-width:var(--tn-icon-lg);min-height:var(--tn-icon-lg);font-size:var(--tn-icon-lg)}tn-icon[size=xl]{width:var(--tn-icon-xl);height:var(--tn-icon-xl);min-width:var(--tn-icon-xl);min-height:var(--tn-icon-xl);font-size:var(--tn-icon-xl)}.tn-icon{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.tn-icon__sprite{width:100%;height:100%;fill:currentColor;color:inherit}.tn-icon__svg{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.tn-icon__svg :global(svg){width:100%;height:100%;fill:currentColor;color:inherit}.tn-icon__css{font-size:inherit;line-height:1;color:inherit}.tn-icon__unicode{font-size:inherit;line-height:1;color:inherit;text-align:center}.tn-icon__text{font-size:.75em;font-weight:600;line-height:1;color:inherit;text-align:center
|
|
2724
|
+
styles: ["tn-icon{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;color:var(--tn-icon-color, currentColor);width:var(--tn-icon-size, var(--tn-icon-md));height:var(--tn-icon-size, var(--tn-icon-md));min-width:var(--tn-icon-size, var(--tn-icon-md));min-height:var(--tn-icon-size, var(--tn-icon-md));font-size:var(--tn-icon-size, var(--tn-icon-md))}tn-icon[size=xs]{width:var(--tn-icon-xs);height:var(--tn-icon-xs);min-width:var(--tn-icon-xs);min-height:var(--tn-icon-xs);font-size:var(--tn-icon-xs)}tn-icon[size=sm]{width:var(--tn-icon-sm);height:var(--tn-icon-sm);min-width:var(--tn-icon-sm);min-height:var(--tn-icon-sm);font-size:var(--tn-icon-sm)}tn-icon[size=md]{width:var(--tn-icon-md);height:var(--tn-icon-md);min-width:var(--tn-icon-md);min-height:var(--tn-icon-md);font-size:var(--tn-icon-md)}tn-icon[size=lg]{width:var(--tn-icon-lg);height:var(--tn-icon-lg);min-width:var(--tn-icon-lg);min-height:var(--tn-icon-lg);font-size:var(--tn-icon-lg)}tn-icon[size=xl]{width:var(--tn-icon-xl);height:var(--tn-icon-xl);min-width:var(--tn-icon-xl);min-height:var(--tn-icon-xl);font-size:var(--tn-icon-xl)}.tn-icon{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.tn-icon__sprite{width:100%;height:100%;fill:currentColor;color:inherit}.tn-icon__svg{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.tn-icon__svg :global(svg){width:100%;height:100%;fill:currentColor;color:inherit}.tn-icon__css{font-size:inherit;line-height:1;color:inherit}.tn-icon__unicode{font-size:inherit;line-height:1;color:inherit;text-align:center}.tn-icon__text{font-size:.75em;font-weight:600;line-height:1;color:inherit;text-align:center}\n"]
|
|
2725
2725
|
}]
|
|
2726
2726
|
}],
|
|
2727
2727
|
ctorParameters: () => [],
|
|
@@ -2937,7 +2937,7 @@ var TnBannerComponent = class TnBannerComponent {
|
|
|
2937
2937
|
}],
|
|
2938
2938
|
ngImport: i0,
|
|
2939
2939
|
template: "<!--\n `ariaRole()` is the only thing declaring how urgently the banner announces:\n it implies the politeness, and an explicit `aria-live` here would override it\n — which is what the static `aria-live=\"polite\"` used to do, downgrading the\n two types deliberately made assertive. See `../a11y/live-region.ts`.\n-->\n<div\n tnTestIdType=\"banner\"\n [ngClass]=\"classes()\"\n [attr.role]=\"ariaRole()\"\n [tnTestId]=\"testId()\"\n>\n @if (hasStructuredContent()) {\n <div class=\"tn-banner__main\">\n <div class=\"tn-banner__icon\">\n <tn-icon\n library=\"mdi\"\n size=\"md\"\n aria-hidden=\"true\"\n [name]=\"iconName()\"\n />\n </div>\n\n <div class=\"tn-banner__content\">\n @if (heading()) {\n <div class=\"tn-banner__heading\">\n {{ heading() }}\n </div>\n }\n\n @if (message()) {\n <div class=\"tn-banner__message\">\n {{ message() }}\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"tn-banner__main\">\n <ng-content />\n </div>\n }\n\n @if (hasAction()) {\n <div class=\"tn-banner__action\">\n <ng-content select=\"[tnBannerAction]\" />\n </div>\n }\n</div>\n",
|
|
2940
|
-
styles: [".tn-banner{--tn-error-text: var(--tn-error, var(--tn-red, #bd2626));display:grid;gap:8px;align-items:center;padding:16px;border-radius:6px;border-left:4px solid;transition:opacity .2s ease}@media(prefers-reduced-motion:reduce){.tn-banner{transition:none}}.tn-banner--info{border-left-color:var(--tn-info, var(--tn-blue, #006997));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--info .tn-banner__heading,.tn-banner--info .tn-banner__icon{color:var(--tn-info, var(--tn-blue, #006997))}.tn-banner--warning{border-left-color:var(--tn-warning, var(--tn-orange, #955313));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--warning .tn-banner__heading,.tn-banner--warning .tn-banner__icon{color:var(--tn-warning, var(--tn-orange, #955313))}.tn-banner--error{border-left-color:var(--tn-error, var(--tn-red, #bd2626));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--error .tn-banner__heading,.tn-banner--error .tn-banner__icon{color:var(--tn-error, var(--tn-red, #bd2626))}.tn-banner--success{border-left-color:var(--tn-success, var(--tn-green, #416f26));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--success .tn-banner__heading,.tn-banner--success .tn-banner__icon{color:var(--tn-success, var(--tn-green, #416f26))}.tn-banner--bordered{border-top:1px solid var(--tn-lines, #404040);border-right:1px solid var(--tn-lines, #404040);border-bottom:1px solid var(--tn-lines, #404040)}.tn-banner__main{display:flex;align-items:flex-start;gap:12px;flex:1;min-width:0}.tn-banner__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;margin-top:2px}.tn-banner__content{flex:1;min-width:0}.tn-banner__heading{font-size:1rem;font-weight:600;line-height:1.5;margin:0}.tn-banner__message{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;margin-top:4px}.tn-banner__action{display:flex;align-items:center;gap:8px 16px;justify-content:flex-end}\n"],
|
|
2940
|
+
styles: [".tn-banner{--tn-error-text: var(--tn-error, var(--tn-red, #bd2626));display:grid;gap:8px;align-items:center;padding:16px;border-radius:6px;border-left:4px solid;transition:opacity .2s ease}@media(prefers-reduced-motion:reduce){.tn-banner{transition:none}}.tn-banner--info{border-left-color:var(--tn-info, var(--tn-blue, #006997));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--info .tn-banner__heading,.tn-banner--info .tn-banner__icon{color:var(--tn-info, var(--tn-blue, #006997))}.tn-banner--warning{border-left-color:var(--tn-warning, var(--tn-orange, #955313));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--warning .tn-banner__heading,.tn-banner--warning .tn-banner__icon{color:var(--tn-warning, var(--tn-orange, #955313))}.tn-banner--error{border-left-color:var(--tn-error, var(--tn-red, #bd2626));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--error .tn-banner__heading,.tn-banner--error .tn-banner__icon{color:var(--tn-error, var(--tn-red, #bd2626))}.tn-banner--success{border-left-color:var(--tn-success, var(--tn-green, #416f26));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--success .tn-banner__heading,.tn-banner--success .tn-banner__icon{color:var(--tn-success, var(--tn-green, #416f26))}.tn-banner--bordered{border-top:1px solid var(--tn-lines, #404040);border-right:1px solid var(--tn-lines, #404040);border-bottom:1px solid var(--tn-lines, #404040)}.tn-banner__main{display:flex;align-items:flex-start;gap:12px;flex:1;min-width:0}.tn-banner__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;margin-top:2px}.tn-banner__content{flex:1;min-width:0}.tn-banner__heading{font-size:1rem;font-weight:600;line-height:1.5;margin:0}.tn-banner__message{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;margin-top:4px}.tn-banner__action{--tn-error-text: var(--tn-error, var(--tn-red, #bd2626));display:flex;align-items:center;gap:8px 16px;justify-content:flex-end}\n"],
|
|
2941
2941
|
dependencies: [
|
|
2942
2942
|
{
|
|
2943
2943
|
kind: "ngmodule",
|
|
@@ -2992,7 +2992,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2992
2992
|
],
|
|
2993
2993
|
changeDetection: ChangeDetectionStrategy.Eager,
|
|
2994
2994
|
template: "<!--\n `ariaRole()` is the only thing declaring how urgently the banner announces:\n it implies the politeness, and an explicit `aria-live` here would override it\n — which is what the static `aria-live=\"polite\"` used to do, downgrading the\n two types deliberately made assertive. See `../a11y/live-region.ts`.\n-->\n<div\n tnTestIdType=\"banner\"\n [ngClass]=\"classes()\"\n [attr.role]=\"ariaRole()\"\n [tnTestId]=\"testId()\"\n>\n @if (hasStructuredContent()) {\n <div class=\"tn-banner__main\">\n <div class=\"tn-banner__icon\">\n <tn-icon\n library=\"mdi\"\n size=\"md\"\n aria-hidden=\"true\"\n [name]=\"iconName()\"\n />\n </div>\n\n <div class=\"tn-banner__content\">\n @if (heading()) {\n <div class=\"tn-banner__heading\">\n {{ heading() }}\n </div>\n }\n\n @if (message()) {\n <div class=\"tn-banner__message\">\n {{ message() }}\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"tn-banner__main\">\n <ng-content />\n </div>\n }\n\n @if (hasAction()) {\n <div class=\"tn-banner__action\">\n <ng-content select=\"[tnBannerAction]\" />\n </div>\n }\n</div>\n",
|
|
2995
|
-
styles: [".tn-banner{--tn-error-text: var(--tn-error, var(--tn-red, #bd2626));display:grid;gap:8px;align-items:center;padding:16px;border-radius:6px;border-left:4px solid;transition:opacity .2s ease}@media(prefers-reduced-motion:reduce){.tn-banner{transition:none}}.tn-banner--info{border-left-color:var(--tn-info, var(--tn-blue, #006997));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--info .tn-banner__heading,.tn-banner--info .tn-banner__icon{color:var(--tn-info, var(--tn-blue, #006997))}.tn-banner--warning{border-left-color:var(--tn-warning, var(--tn-orange, #955313));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--warning .tn-banner__heading,.tn-banner--warning .tn-banner__icon{color:var(--tn-warning, var(--tn-orange, #955313))}.tn-banner--error{border-left-color:var(--tn-error, var(--tn-red, #bd2626));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--error .tn-banner__heading,.tn-banner--error .tn-banner__icon{color:var(--tn-error, var(--tn-red, #bd2626))}.tn-banner--success{border-left-color:var(--tn-success, var(--tn-green, #416f26));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--success .tn-banner__heading,.tn-banner--success .tn-banner__icon{color:var(--tn-success, var(--tn-green, #416f26))}.tn-banner--bordered{border-top:1px solid var(--tn-lines, #404040);border-right:1px solid var(--tn-lines, #404040);border-bottom:1px solid var(--tn-lines, #404040)}.tn-banner__main{display:flex;align-items:flex-start;gap:12px;flex:1;min-width:0}.tn-banner__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;margin-top:2px}.tn-banner__content{flex:1;min-width:0}.tn-banner__heading{font-size:1rem;font-weight:600;line-height:1.5;margin:0}.tn-banner__message{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;margin-top:4px}.tn-banner__action{display:flex;align-items:center;gap:8px 16px;justify-content:flex-end}\n"]
|
|
2995
|
+
styles: [".tn-banner{--tn-error-text: var(--tn-error, var(--tn-red, #bd2626));display:grid;gap:8px;align-items:center;padding:16px;border-radius:6px;border-left:4px solid;transition:opacity .2s ease}@media(prefers-reduced-motion:reduce){.tn-banner{transition:none}}.tn-banner--info{border-left-color:var(--tn-info, var(--tn-blue, #006997));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--info .tn-banner__heading,.tn-banner--info .tn-banner__icon{color:var(--tn-info, var(--tn-blue, #006997))}.tn-banner--warning{border-left-color:var(--tn-warning, var(--tn-orange, #955313));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--warning .tn-banner__heading,.tn-banner--warning .tn-banner__icon{color:var(--tn-warning, var(--tn-orange, #955313))}.tn-banner--error{border-left-color:var(--tn-error, var(--tn-red, #bd2626));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--error .tn-banner__heading,.tn-banner--error .tn-banner__icon{color:var(--tn-error, var(--tn-red, #bd2626))}.tn-banner--success{border-left-color:var(--tn-success, var(--tn-green, #416f26));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--success .tn-banner__heading,.tn-banner--success .tn-banner__icon{color:var(--tn-success, var(--tn-green, #416f26))}.tn-banner--bordered{border-top:1px solid var(--tn-lines, #404040);border-right:1px solid var(--tn-lines, #404040);border-bottom:1px solid var(--tn-lines, #404040)}.tn-banner__main{display:flex;align-items:flex-start;gap:12px;flex:1;min-width:0}.tn-banner__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;margin-top:2px}.tn-banner__content{flex:1;min-width:0}.tn-banner__heading{font-size:1rem;font-weight:600;line-height:1.5;margin:0}.tn-banner__message{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;margin-top:4px}.tn-banner__action{--tn-error-text: var(--tn-error, var(--tn-red, #bd2626));display:flex;align-items:center;gap:8px 16px;justify-content:flex-end}\n"]
|
|
2996
2996
|
}]
|
|
2997
2997
|
}],
|
|
2998
2998
|
ctorParameters: () => [],
|
|
@@ -27127,8 +27127,8 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
27127
27127
|
},
|
|
27128
27128
|
host: { classAttribute: "tn-file-picker-popup" },
|
|
27129
27129
|
ngImport: i0,
|
|
27130
|
-
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 : rootPath(); track $index; let last = $last) {\n <button\n class=\"breadcrumb-segment\"\n tnTestIdType=\"button\"\n [tnTestId]=\"breadcrumbTestId(segment.name)\"\n [class.current]=\"last\"\n [class.nameless]=\"!segment.name\"\n [disabled]=\"last\"\n [attr.aria-label]=\"segment.name === '…' || !segment.name ? 'Navigate to ' + segment.path : null\"\n (click)=\"navigateToPath(segment.path)\">\n {{ segment.name }}\n </button>\n }\n </nav>\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\n <tn-table\n [dataSource]=\"filteredFileItems()\"\n [displayedColumns]=\"multiSelect() ? displayedColumns : displayedColumns.slice(1)\"\n [clickable]=\"true\"\n [activeWhen]=\"isRowSelected\"\n (rowClick)=\"onItemClick($event)\"\n (rowDoubleClick)=\"onItemDoubleClick($event)\">\n\n <!-- Selection column: explicit width so the auto table layout doesn't\n hand the near-empty column a share of the spare width -->\n @if (multiSelect()) {\n <ng-container tnColumnDef=\"select\" width=\"20px\"
|
|
27131
|
-
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);width:520px;max-width:calc(100vw - 32px);min-height:min(500px,100vh - 16px);max-height:min(600px,100vh - 16px);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;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary-text, var(--tn-primary, #0074a7));cursor:pointer;padding:4px 2px;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:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment:first-child:before{content:\"/\";margin-right:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment.nameless:not(:last-child):after{content:none}.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}.inline-create-cell{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.inline-create-row{display:flex;align-items:center;gap:8px}.inline-create-row .inline-create-input{flex:1;padding:4px 8px;border:2px solid var(--tn-primary);border-radius:3px;background:var(--tn-bg1);color:var(--tn-fg1);font-size:inherit;font-family:inherit;outline:none;min-width:0}.inline-create-row .inline-create-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-row .inline-create-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2)}.inline-create-row .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary);flex-shrink:0}.inline-create-error{display:flex;align-items:center;gap:6px;margin-top:4px;padding:4px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;font-size:1rem;color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-error .error-icon{flex-shrink:0}.inline-create-error .error-text{flex:1}.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;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-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-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{
|
|
27130
|
+
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 : rootPath(); track $index; let last = $last) {\n <button\n class=\"breadcrumb-segment\"\n tnTestIdType=\"button\"\n [tnTestId]=\"breadcrumbTestId(segment.name)\"\n [class.current]=\"last\"\n [class.nameless]=\"!segment.name\"\n [disabled]=\"last\"\n [attr.aria-label]=\"segment.name === '…' || !segment.name ? 'Navigate to ' + segment.path : null\"\n (click)=\"navigateToPath(segment.path)\">\n {{ segment.name }}\n </button>\n }\n </nav>\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\n <tn-table\n [dataSource]=\"filteredFileItems()\"\n [displayedColumns]=\"multiSelect() ? displayedColumns : displayedColumns.slice(1)\"\n [clickable]=\"true\"\n [activeWhen]=\"isRowSelected\"\n (rowClick)=\"onItemClick($event)\"\n (rowDoubleClick)=\"onItemDoubleClick($event)\">\n\n <!-- Selection column: explicit width so the auto table layout doesn't\n hand the near-empty column a share of the spare width -->\n @if (multiSelect()) {\n <!-- `hideLabel` rather than an empty `tnHeaderCellDef`: a <th> with no\n text fails axe `empty-table-header`, which is what the Storybook a11y\n run reported on Components/File Picker > Multi Select Workflow\n (#337). The empty template that used to sit here OVERRODE the header,\n so the column was unnamed for anyone reading the header row too —\n `hideLabel` renders the label into a `.cdk-visually-hidden` span\n instead, which is the same route tn-table's own row-actions column\n takes (#246). There is no select-all control, so the name describes\n what the column holds. -->\n <ng-container tnColumnDef=\"select\" width=\"20px\" label=\"Select\" [hideLabel]=\"true\">\n <ng-template let-item tnCellDef>\n @if (!item.inlineCreate) {\n <tn-checkbox\n [hideLabel]=\"true\"\n [label]=\"'Select ' + item.name\"\n [testId]=\"itemTestId(item)\"\n [checked]=\"isSelected(item)\"\n [disabled]=\"!!item.disabled\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onItemClick(item)\" />\n }\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 <!-- Inline creation row for create actions with a `create` callback -->\n @if (item.inlineCreate) {\n @if (inlineCreation(); as creation) {\n <div class=\"inline-create-cell\">\n <div class=\"inline-create-row\" [class.has-error]=\"!!creation.error\">\n <tn-icon class=\"file-icon\" [name]=\"creation.action.icon || 'mdi-folder'\" />\n <input\n type=\"text\"\n class=\"inline-create-input\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n tnTestIdType=\"input\"\n [tnTestId]=\"inlineCreateTestId()\"\n [attr.aria-label]=\"creation.action.label + ' name'\"\n [attr.aria-invalid]=\"creation.error ? true : null\"\n [attr.aria-describedby]=\"creation.error ? inlineErrorId : null\"\n [class.error]=\"!!creation.error\"\n [disabled]=\"creation.loading\"\n [value]=\"creation.name\"\n (input)=\"onInlineCreationInput($event)\"\n (keydown)=\"onInlineCreationKeyDown($event)\"\n (blur)=\"onInlineCreationBlur()\">\n @if (creation.loading) {\n <tn-icon name=\"mdi-loading\" class=\"creation-loading-icon\" aria-hidden=\"true\" />\n }\n </div>\n @if (creation.error) {\n <div class=\"inline-create-error\" role=\"alert\" [id]=\"inlineErrorId\">\n <tn-icon name=\"mdi-alert-circle\" class=\"error-icon\" aria-hidden=\"true\" />\n <span class=\"error-text\">{{ creation.error }}</span>\n </div>\n }\n </div>\n }\n } @else {\n <div\n class=\"file-name-cell\"\n tnTestIdType=\"option\"\n [tnTestId]=\"itemTestId(item)\"\n [class.selected]=\"isSelected(item)\"\n [class.disabled]=\"!!item.dimmed\"\n [class.zfs-object]=\"isZfsObject(item)\">\n <tn-icon\n [name]=\"getItemIcon(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\n <!-- Navigation affordance: single click opens the directory -->\n @if (isNavigatable(item)) {\n <button\n type=\"button\"\n class=\"navigate-button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"navigateTestId(item)\"\n [attr.aria-label]=\"'Open ' + item.name\"\n [attr.title]=\"'Open ' + item.name\"\n (click)=\"onNavigateClick($event, item)\"\n (dblclick)=\"$event.stopPropagation()\">\n <tn-icon name=\"mdi-chevron-right\" size=\"sm\" />\n </button>\n }\n </div>\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 <div class=\"footer-selection\">\n @if (selectedItems().length > 0) {\n <span class=\"selection-count\">\n {{ selectedItems().length }} item{{ selectedItems().length !== 1 ? 's' : '' }} selected\n </span>\n <tn-button\n variant=\"outline\"\n label=\"Clear Selection\"\n [testId]=\"clearSelectionTestId()\"\n (onClick)=\"onClearSelection()\" />\n } @else if (allowCurrentDirectorySelection()) {\n <span class=\"selection-count current-directory-selection\">\n Current directory selected\n </span>\n } @else {\n <span class=\"selection-count\">\n No items selected\n </span>\n }\n </div>\n <div class=\"footer-actions\">\n @for (action of createActions(); track action.id) {\n <tn-button\n variant=\"outline\"\n [label]=\"action.label\"\n [testId]=\"createActionTestId(action)\"\n [disabled]=\"!!inlineCreation()\"\n (onClick)=\"onCreateAction(action)\" />\n }\n <!-- Disabled while the inline creation row is open: its blur auto-submit\n would race the selection submit -->\n <tn-button\n label=\"Select\"\n [testId]=\"selectTestId()\"\n [disabled]=\"(selectedItems().length === 0 && !allowCurrentDirectorySelection()) || !!inlineCreation()\"\n (onClick)=\"onSubmit()\" />\n </div>\n </div>\n}",
|
|
27131
|
+
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);width:520px;max-width:calc(100vw - 32px);min-height:min(500px,100vh - 16px);max-height:min(600px,100vh - 16px);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;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary-text, var(--tn-primary, #0074a7));cursor:pointer;padding:4px 2px;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:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment:first-child:before{content:\"/\";margin-right:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment.nameless:not(:last-child):after{content:none}.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}.inline-create-cell{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.inline-create-row{display:flex;align-items:center;gap:8px}.inline-create-row .inline-create-input{flex:1;padding:4px 8px;border:2px solid var(--tn-primary);border-radius:3px;background:var(--tn-bg1);color:var(--tn-fg1);font-size:inherit;font-family:inherit;outline:none;min-width:0}.inline-create-row .inline-create-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-row .inline-create-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2)}.inline-create-row .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary);flex-shrink:0}.inline-create-error{display:flex;align-items:center;gap:6px;margin-top:4px;padding:4px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;font-size:1rem;color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-error .error-icon{flex-shrink:0}.inline-create-error .error-text{flex:1}.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;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-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-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);border:1px solid transparent;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{border-color:var(--tn-blue)}.zfs-badge.zfs-badge-zvol{border-color:var(--tn-green)}.zfs-badge.zfs-badge-mountpoint{border-color:var(--tn-orange)}.permission-icon{display:flex;align-items:center;justify-content:center;color:var(--tn-red);font-size:var(--tn-icon-sm, 16px);line-height:1}.navigate-button{display:flex;align-items:center;justify-content:center;margin-left:auto;padding:2px;background:none;border:none;border-radius:4px;color:var(--tn-fg2);cursor:pointer}.navigate-button:hover,.navigate-button:focus-visible{background:var(--tn-bg3);color:var(--tn-primary)}.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;gap:16px;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}.tn-file-picker-footer .footer-selection{display:flex;align-items:center;gap:12px}.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,.zfs-badge.zfs-badge-dataset,.zfs-badge.zfs-badge-zvol,.zfs-badge.zfs-badge-mountpoint{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"],
|
|
27132
27132
|
dependencies: [
|
|
27133
27133
|
{
|
|
27134
27134
|
kind: "component",
|
|
@@ -27315,8 +27315,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
27315
27315
|
],
|
|
27316
27316
|
changeDetection: ChangeDetectionStrategy.Eager,
|
|
27317
27317
|
host: { "class": "tn-file-picker-popup" },
|
|
27318
|
-
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 : rootPath(); track $index; let last = $last) {\n <button\n class=\"breadcrumb-segment\"\n tnTestIdType=\"button\"\n [tnTestId]=\"breadcrumbTestId(segment.name)\"\n [class.current]=\"last\"\n [class.nameless]=\"!segment.name\"\n [disabled]=\"last\"\n [attr.aria-label]=\"segment.name === '…' || !segment.name ? 'Navigate to ' + segment.path : null\"\n (click)=\"navigateToPath(segment.path)\">\n {{ segment.name }}\n </button>\n }\n </nav>\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\n <tn-table\n [dataSource]=\"filteredFileItems()\"\n [displayedColumns]=\"multiSelect() ? displayedColumns : displayedColumns.slice(1)\"\n [clickable]=\"true\"\n [activeWhen]=\"isRowSelected\"\n (rowClick)=\"onItemClick($event)\"\n (rowDoubleClick)=\"onItemDoubleClick($event)\">\n\n <!-- Selection column: explicit width so the auto table layout doesn't\n hand the near-empty column a share of the spare width -->\n @if (multiSelect()) {\n <ng-container tnColumnDef=\"select\" width=\"20px\"
|
|
27319
|
-
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);width:520px;max-width:calc(100vw - 32px);min-height:min(500px,100vh - 16px);max-height:min(600px,100vh - 16px);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;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary-text, var(--tn-primary, #0074a7));cursor:pointer;padding:4px 2px;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:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment:first-child:before{content:\"/\";margin-right:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment.nameless:not(:last-child):after{content:none}.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}.inline-create-cell{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.inline-create-row{display:flex;align-items:center;gap:8px}.inline-create-row .inline-create-input{flex:1;padding:4px 8px;border:2px solid var(--tn-primary);border-radius:3px;background:var(--tn-bg1);color:var(--tn-fg1);font-size:inherit;font-family:inherit;outline:none;min-width:0}.inline-create-row .inline-create-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-row .inline-create-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2)}.inline-create-row .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary);flex-shrink:0}.inline-create-error{display:flex;align-items:center;gap:6px;margin-top:4px;padding:4px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;font-size:1rem;color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-error .error-icon{flex-shrink:0}.inline-create-error .error-text{flex:1}.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;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-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-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{
|
|
27318
|
+
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 : rootPath(); track $index; let last = $last) {\n <button\n class=\"breadcrumb-segment\"\n tnTestIdType=\"button\"\n [tnTestId]=\"breadcrumbTestId(segment.name)\"\n [class.current]=\"last\"\n [class.nameless]=\"!segment.name\"\n [disabled]=\"last\"\n [attr.aria-label]=\"segment.name === '…' || !segment.name ? 'Navigate to ' + segment.path : null\"\n (click)=\"navigateToPath(segment.path)\">\n {{ segment.name }}\n </button>\n }\n </nav>\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\n <tn-table\n [dataSource]=\"filteredFileItems()\"\n [displayedColumns]=\"multiSelect() ? displayedColumns : displayedColumns.slice(1)\"\n [clickable]=\"true\"\n [activeWhen]=\"isRowSelected\"\n (rowClick)=\"onItemClick($event)\"\n (rowDoubleClick)=\"onItemDoubleClick($event)\">\n\n <!-- Selection column: explicit width so the auto table layout doesn't\n hand the near-empty column a share of the spare width -->\n @if (multiSelect()) {\n <!-- `hideLabel` rather than an empty `tnHeaderCellDef`: a <th> with no\n text fails axe `empty-table-header`, which is what the Storybook a11y\n run reported on Components/File Picker > Multi Select Workflow\n (#337). The empty template that used to sit here OVERRODE the header,\n so the column was unnamed for anyone reading the header row too —\n `hideLabel` renders the label into a `.cdk-visually-hidden` span\n instead, which is the same route tn-table's own row-actions column\n takes (#246). There is no select-all control, so the name describes\n what the column holds. -->\n <ng-container tnColumnDef=\"select\" width=\"20px\" label=\"Select\" [hideLabel]=\"true\">\n <ng-template let-item tnCellDef>\n @if (!item.inlineCreate) {\n <tn-checkbox\n [hideLabel]=\"true\"\n [label]=\"'Select ' + item.name\"\n [testId]=\"itemTestId(item)\"\n [checked]=\"isSelected(item)\"\n [disabled]=\"!!item.disabled\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onItemClick(item)\" />\n }\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 <!-- Inline creation row for create actions with a `create` callback -->\n @if (item.inlineCreate) {\n @if (inlineCreation(); as creation) {\n <div class=\"inline-create-cell\">\n <div class=\"inline-create-row\" [class.has-error]=\"!!creation.error\">\n <tn-icon class=\"file-icon\" [name]=\"creation.action.icon || 'mdi-folder'\" />\n <input\n type=\"text\"\n class=\"inline-create-input\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n tnTestIdType=\"input\"\n [tnTestId]=\"inlineCreateTestId()\"\n [attr.aria-label]=\"creation.action.label + ' name'\"\n [attr.aria-invalid]=\"creation.error ? true : null\"\n [attr.aria-describedby]=\"creation.error ? inlineErrorId : null\"\n [class.error]=\"!!creation.error\"\n [disabled]=\"creation.loading\"\n [value]=\"creation.name\"\n (input)=\"onInlineCreationInput($event)\"\n (keydown)=\"onInlineCreationKeyDown($event)\"\n (blur)=\"onInlineCreationBlur()\">\n @if (creation.loading) {\n <tn-icon name=\"mdi-loading\" class=\"creation-loading-icon\" aria-hidden=\"true\" />\n }\n </div>\n @if (creation.error) {\n <div class=\"inline-create-error\" role=\"alert\" [id]=\"inlineErrorId\">\n <tn-icon name=\"mdi-alert-circle\" class=\"error-icon\" aria-hidden=\"true\" />\n <span class=\"error-text\">{{ creation.error }}</span>\n </div>\n }\n </div>\n }\n } @else {\n <div\n class=\"file-name-cell\"\n tnTestIdType=\"option\"\n [tnTestId]=\"itemTestId(item)\"\n [class.selected]=\"isSelected(item)\"\n [class.disabled]=\"!!item.dimmed\"\n [class.zfs-object]=\"isZfsObject(item)\">\n <tn-icon\n [name]=\"getItemIcon(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\n <!-- Navigation affordance: single click opens the directory -->\n @if (isNavigatable(item)) {\n <button\n type=\"button\"\n class=\"navigate-button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"navigateTestId(item)\"\n [attr.aria-label]=\"'Open ' + item.name\"\n [attr.title]=\"'Open ' + item.name\"\n (click)=\"onNavigateClick($event, item)\"\n (dblclick)=\"$event.stopPropagation()\">\n <tn-icon name=\"mdi-chevron-right\" size=\"sm\" />\n </button>\n }\n </div>\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 <div class=\"footer-selection\">\n @if (selectedItems().length > 0) {\n <span class=\"selection-count\">\n {{ selectedItems().length }} item{{ selectedItems().length !== 1 ? 's' : '' }} selected\n </span>\n <tn-button\n variant=\"outline\"\n label=\"Clear Selection\"\n [testId]=\"clearSelectionTestId()\"\n (onClick)=\"onClearSelection()\" />\n } @else if (allowCurrentDirectorySelection()) {\n <span class=\"selection-count current-directory-selection\">\n Current directory selected\n </span>\n } @else {\n <span class=\"selection-count\">\n No items selected\n </span>\n }\n </div>\n <div class=\"footer-actions\">\n @for (action of createActions(); track action.id) {\n <tn-button\n variant=\"outline\"\n [label]=\"action.label\"\n [testId]=\"createActionTestId(action)\"\n [disabled]=\"!!inlineCreation()\"\n (onClick)=\"onCreateAction(action)\" />\n }\n <!-- Disabled while the inline creation row is open: its blur auto-submit\n would race the selection submit -->\n <tn-button\n label=\"Select\"\n [testId]=\"selectTestId()\"\n [disabled]=\"(selectedItems().length === 0 && !allowCurrentDirectorySelection()) || !!inlineCreation()\"\n (onClick)=\"onSubmit()\" />\n </div>\n </div>\n}",
|
|
27319
|
+
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);width:520px;max-width:calc(100vw - 32px);min-height:min(500px,100vh - 16px);max-height:min(600px,100vh - 16px);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;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary-text, var(--tn-primary, #0074a7));cursor:pointer;padding:4px 2px;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:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment:first-child:before{content:\"/\";margin-right:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment.nameless:not(:last-child):after{content:none}.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}.inline-create-cell{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.inline-create-row{display:flex;align-items:center;gap:8px}.inline-create-row .inline-create-input{flex:1;padding:4px 8px;border:2px solid var(--tn-primary);border-radius:3px;background:var(--tn-bg1);color:var(--tn-fg1);font-size:inherit;font-family:inherit;outline:none;min-width:0}.inline-create-row .inline-create-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-row .inline-create-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2)}.inline-create-row .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary);flex-shrink:0}.inline-create-error{display:flex;align-items:center;gap:6px;margin-top:4px;padding:4px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;font-size:1rem;color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-error .error-icon{flex-shrink:0}.inline-create-error .error-text{flex:1}.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;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-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-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);border:1px solid transparent;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{border-color:var(--tn-blue)}.zfs-badge.zfs-badge-zvol{border-color:var(--tn-green)}.zfs-badge.zfs-badge-mountpoint{border-color:var(--tn-orange)}.permission-icon{display:flex;align-items:center;justify-content:center;color:var(--tn-red);font-size:var(--tn-icon-sm, 16px);line-height:1}.navigate-button{display:flex;align-items:center;justify-content:center;margin-left:auto;padding:2px;background:none;border:none;border-radius:4px;color:var(--tn-fg2);cursor:pointer}.navigate-button:hover,.navigate-button:focus-visible{background:var(--tn-bg3);color:var(--tn-primary)}.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;gap:16px;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}.tn-file-picker-footer .footer-selection{display:flex;align-items:center;gap:12px}.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,.zfs-badge.zfs-badge-dataset,.zfs-badge.zfs-badge-zvol,.zfs-badge.zfs-badge-mountpoint{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"]
|
|
27320
27320
|
}]
|
|
27321
27321
|
}],
|
|
27322
27322
|
ctorParameters: () => [],
|