@sdcorejs/angular 20.0.6 → 20.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/assets/STYLE-GUIDE.md +13 -0
- package/components/autoid-inspector/index.d.ts +47 -137
- package/components/index.d.ts +1 -0
- package/components/upload-file/index.d.ts +7 -4
- package/fesm2022/sdcorejs-angular-components-anchor.mjs +11 -12
- package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +210 -40
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-avatar.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-badge.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-base.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-button.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-chart.mjs +12 -12
- package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-code-editor.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs +11 -12
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-editor.mjs +6 -6
- package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs +203 -203
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-history.mjs +7 -7
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs +10 -10
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-inform.mjs +7 -7
- package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-mini-editor.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +5 -5
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-operator.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs +7 -7
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-preview.mjs +9 -9
- package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs +31 -31
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-quick-action.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-section.mjs +7 -7
- package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +8 -6
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-splitter.mjs +28 -14
- package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-stepper.mjs +6 -6
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs +18 -18
- package/fesm2022/sdcorejs-angular-components-tab.mjs +6 -6
- package/fesm2022/sdcorejs-angular-components-table.mjs +110 -111
- package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tree.mjs +7 -7
- package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs +37 -32
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-view.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components.mjs +1 -0
- package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-directives.mjs +21 -21
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +6 -7
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +6 -6
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +9 -9
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip.mjs +9 -9
- package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs +11 -12
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date.mjs +8 -9
- package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs +14 -15
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-directives.mjs +12 -12
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs +4 -4
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs +3 -3
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs +7 -8
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input.mjs +6 -6
- package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-label.mjs +3 -3
- package/fesm2022/sdcorejs-angular-forms-radio.mjs +6 -7
- package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-select.mjs +7 -7
- package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-switch.mjs +6 -7
- package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs +7 -9
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms.mjs +4 -4
- package/fesm2022/sdcorejs-angular-handlers.mjs +3 -3
- package/fesm2022/sdcorejs-angular-i18n.mjs +6 -6
- package/fesm2022/sdcorejs-angular-interceptors.mjs +6 -6
- package/fesm2022/sdcorejs-angular-modules-auth.mjs +9 -9
- package/fesm2022/sdcorejs-angular-modules-authom.mjs +7 -7
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +37 -14
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-layout.mjs +75 -76
- package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-permission.mjs +9 -9
- package/fesm2022/sdcorejs-angular-pipes.mjs +14 -14
- package/fesm2022/sdcorejs-angular-services-api.mjs +11 -12
- package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-cache.mjs +3 -3
- package/fesm2022/sdcorejs-angular-services-confirm.mjs +8 -8
- package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-docx.mjs +3 -3
- package/fesm2022/sdcorejs-angular-services-excel.mjs +3 -3
- package/fesm2022/sdcorejs-angular-services-license.mjs +3 -3
- package/fesm2022/sdcorejs-angular-services-loading.mjs +3 -3
- package/fesm2022/sdcorejs-angular-services-notify.mjs +9 -9
- package/fesm2022/sdcorejs-angular-services-storage.mjs +3 -3
- package/forms/input-number/index.d.ts +0 -1
- package/modules/keycloak/htmls/auth-keycloak-error.html +54 -0
- package/modules/keycloak/htmls/silent-renew.html +7 -0
- package/modules/keycloak/index.d.ts +30 -0
- package/package.json +1 -1
|
@@ -10,10 +10,10 @@ class SdOrgChartItemDefDirective {
|
|
|
10
10
|
return true;
|
|
11
11
|
}
|
|
12
12
|
templateRef = inject(TemplateRef);
|
|
13
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
14
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.
|
|
13
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdOrgChartItemDefDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
14
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.25", type: SdOrgChartItemDefDirective, isStandalone: true, selector: "[sdOrgChartItemDef]", ngImport: i0 });
|
|
15
15
|
}
|
|
16
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
16
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdOrgChartItemDefDirective, decorators: [{
|
|
17
17
|
type: Directive,
|
|
18
18
|
args: [{
|
|
19
19
|
selector: '[sdOrgChartItemDef]',
|
|
@@ -92,14 +92,14 @@ class SdOrgChart {
|
|
|
92
92
|
#autoIdKey = (item) => {
|
|
93
93
|
return this.#itemKey(item).replace(/[^a-zA-Z0-9_-]/g, '-');
|
|
94
94
|
};
|
|
95
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
96
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.
|
|
95
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdOrgChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
96
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SdOrgChart, isStandalone: true, selector: "sd-org-chart", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, option: { classPropertyName: "option", publicName: "option", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-autoid": "autoId()" } }, queries: [{ propertyName: "itemDef", first: true, predicate: SdOrgChartItemDefDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@let _resolvedItems = resolvedItems();\n@let _resolvedItemTemplate = resolvedItemTemplate();\n\n<div class=\"sd-org-chart\" role=\"tree\">\n <ul class=\"sd-org-chart__tree\">\n @for (item of _resolvedItems; track trackByItem($index, item)) {\n <ng-container\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: item, item: item, depth: 0, parent: null, templateRef: _resolvedItemTemplate }\" />\n }\n </ul>\n</div>\n\n<ng-template #nodeTemplate let-item let-depth=\"depth\" let-parent=\"parent\" let-templateRef=\"templateRef\">\n @let _children = childrenOf(item);\n @let _hasChildren = _children.length > 0;\n @let _expanded = isExpanded(item);\n @let _context = createContext(item, depth, parent);\n\n <li\n class=\"sd-org-chart__node\"\n [class.sd-org-chart__node--expanded]=\"_hasChildren && _expanded\"\n [class.sd-org-chart__node--collapsed]=\"_hasChildren && !_expanded\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"_hasChildren ? _expanded : null\">\n <div class=\"sd-org-chart__node-shell\">\n <div\n class=\"sd-org-chart__card\"\n [class.sd-org-chart__card--no-image]=\"!item.image\"\n [class.sd-org-chart__card--compact]=\"!item.image && !item.description\"\n [attr.data-node-id]=\"item.id\"\n [attr.data-autoid]=\"nodeAutoId(item, 'node')\"\n [attr.data-depth]=\"depth\"\n [style.--sd-org-node-color]=\"item.color || null\">\n @if (templateRef) {\n <ng-container *ngTemplateOutlet=\"templateRef; context: _context\" />\n } @else {\n @if (item.image) {\n <img class=\"sd-org-chart__image\" [src]=\"item.image\" [alt]=\"item.title\" [attr.data-autoid]=\"nodeAutoId(item, 'image')\" />\n }\n <div class=\"sd-org-chart__title\" [attr.data-autoid]=\"nodeAutoId(item, 'title')\">{{ item.title }}</div>\n @if (item.description) {\n <div class=\"sd-org-chart__description\" [attr.data-autoid]=\"nodeAutoId(item, 'description')\">{{ item.description }}</div>\n }\n }\n </div>\n\n @if (_hasChildren && collapsible()) {\n <button\n type=\"button\"\n class=\"sd-org-chart__toggle\"\n [attr.aria-label]=\"_expanded ? 'Collapse children' : 'Expand children'\"\n [attr.aria-expanded]=\"_expanded\"\n [attr.data-autoid]=\"nodeAutoId(item, 'toggle')\"\n (click)=\"toggle(item, $event)\">\n <mat-icon>{{ _expanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n }\n </div>\n\n @if (_hasChildren && _expanded) {\n <ul class=\"sd-org-chart__children\" role=\"group\">\n @for (child of _children; track trackByItem($index, child)) {\n <ng-container\n *ngTemplateOutlet=\"\n nodeTemplate;\n context: { $implicit: child, item: child, depth: depth + 1, parent: item, templateRef: templateRef }\n \" />\n }\n </ul>\n }\n </li>\n</ng-template>\n", styles: [":host{--sd-org-line: #d9e2ef;--sd-org-card-bg: #ffffff;--sd-org-text: #102047;--sd-org-text-muted: #4d5b73;--sd-org-shadow: 0 8px 20px rgba(24, 39, 75, .08);--sd-org-gap-x: 20px;--sd-org-gap-y: 32px;display:block;overflow-x:auto;overflow-y:hidden;padding:8px 0 12px}.sd-org-chart{display:inline-block;min-width:100%;padding:8px 16px 0}.sd-org-chart__tree,.sd-org-chart__children{display:flex;justify-content:center;align-items:flex-start;margin:0;padding:0;list-style:none}.sd-org-chart__node{position:relative;flex:0 0 auto;padding:var(--sd-org-gap-y) var(--sd-org-gap-x) 0;text-align:center}.sd-org-chart__tree>.sd-org-chart__node{padding-top:0}.sd-org-chart__children>.sd-org-chart__node:before,.sd-org-chart__children>.sd-org-chart__node:after{position:absolute;top:0;width:50%;height:calc(var(--sd-org-gap-y) / 2);border-top:1px solid var(--sd-org-line);content:\"\"}.sd-org-chart__children>.sd-org-chart__node:before{right:50%}.sd-org-chart__children>.sd-org-chart__node:after{left:50%}.sd-org-chart__children>.sd-org-chart__node:first-child:before,.sd-org-chart__children>.sd-org-chart__node:last-child:after{border-top:0}.sd-org-chart__children>.sd-org-chart__node:only-child{padding-top:calc(var(--sd-org-gap-y) / 2)}.sd-org-chart__children>.sd-org-chart__node:only-child:before,.sd-org-chart__children>.sd-org-chart__node:only-child:after{display:none}.sd-org-chart__node-shell{position:relative;display:flex;flex-direction:column;align-items:center}.sd-org-chart__children>.sd-org-chart__node>.sd-org-chart__node-shell:before{position:absolute;top:calc(var(--sd-org-gap-y) * -1);left:50%;width:0;height:var(--sd-org-gap-y);border-left:1px solid var(--sd-org-line);content:\"\"}.sd-org-chart__tree>.sd-org-chart__node>.sd-org-chart__node-shell:before{display:none}.sd-org-chart__card{position:relative;z-index:1;min-width:128px;min-height:110px;box-sizing:border-box;padding:16px 14px 14px;color:var(--sd-org-text);background:var(--sd-org-node-color, var(--sd-org-card-bg));border:1px solid color-mix(in srgb,var(--sd-org-node-color, var(--sd-org-line)) 36%,var(--sd-org-line));border-radius:6px;box-shadow:var(--sd-org-shadow)}.sd-org-chart__card--compact{min-width:74px;min-height:40px;padding:10px 16px}.sd-org-chart__card--no-image:not(.sd-org-chart__card--compact){min-height:78px}.sd-org-chart__image{display:block;width:44px;height:44px;margin:0 auto 10px;object-fit:cover;border-radius:50%}.sd-org-chart__title{max-width:150px;margin:0 auto;overflow-wrap:anywhere;font-size:14px;font-weight:700;line-height:1.35}.sd-org-chart__description{max-width:150px;margin:5px auto 0;overflow-wrap:anywhere;color:var(--sd-org-text-muted);font-size:13px;line-height:1.3}.sd-org-chart__toggle{position:relative;z-index:2;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin-top:-1px;padding:0;color:#52708f;background:#fff;border:1px solid var(--sd-org-line);border-radius:50%;cursor:pointer}.sd-org-chart__toggle:hover{background:#f4f7fb}.sd-org-chart__toggle:focus-visible{outline:2px solid var(--sd-primary, #2a66f4);outline-offset:2px}.sd-org-chart__toggle mat-icon{width:18px;height:18px;font-size:18px;line-height:18px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
97
97
|
}
|
|
98
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
98
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdOrgChart, decorators: [{
|
|
99
99
|
type: Component,
|
|
100
100
|
args: [{ selector: 'sd-org-chart', standalone: true, imports: [CommonModule, MatIconModule], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
101
101
|
'[attr.data-autoid]': 'autoId()',
|
|
102
|
-
}, template: "@let
|
|
102
|
+
}, template: "@let _resolvedItems = resolvedItems();\n@let _resolvedItemTemplate = resolvedItemTemplate();\n\n<div class=\"sd-org-chart\" role=\"tree\">\n <ul class=\"sd-org-chart__tree\">\n @for (item of _resolvedItems; track trackByItem($index, item)) {\n <ng-container\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: item, item: item, depth: 0, parent: null, templateRef: _resolvedItemTemplate }\" />\n }\n </ul>\n</div>\n\n<ng-template #nodeTemplate let-item let-depth=\"depth\" let-parent=\"parent\" let-templateRef=\"templateRef\">\n @let _children = childrenOf(item);\n @let _hasChildren = _children.length > 0;\n @let _expanded = isExpanded(item);\n @let _context = createContext(item, depth, parent);\n\n <li\n class=\"sd-org-chart__node\"\n [class.sd-org-chart__node--expanded]=\"_hasChildren && _expanded\"\n [class.sd-org-chart__node--collapsed]=\"_hasChildren && !_expanded\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"_hasChildren ? _expanded : null\">\n <div class=\"sd-org-chart__node-shell\">\n <div\n class=\"sd-org-chart__card\"\n [class.sd-org-chart__card--no-image]=\"!item.image\"\n [class.sd-org-chart__card--compact]=\"!item.image && !item.description\"\n [attr.data-node-id]=\"item.id\"\n [attr.data-autoid]=\"nodeAutoId(item, 'node')\"\n [attr.data-depth]=\"depth\"\n [style.--sd-org-node-color]=\"item.color || null\">\n @if (templateRef) {\n <ng-container *ngTemplateOutlet=\"templateRef; context: _context\" />\n } @else {\n @if (item.image) {\n <img class=\"sd-org-chart__image\" [src]=\"item.image\" [alt]=\"item.title\" [attr.data-autoid]=\"nodeAutoId(item, 'image')\" />\n }\n <div class=\"sd-org-chart__title\" [attr.data-autoid]=\"nodeAutoId(item, 'title')\">{{ item.title }}</div>\n @if (item.description) {\n <div class=\"sd-org-chart__description\" [attr.data-autoid]=\"nodeAutoId(item, 'description')\">{{ item.description }}</div>\n }\n }\n </div>\n\n @if (_hasChildren && collapsible()) {\n <button\n type=\"button\"\n class=\"sd-org-chart__toggle\"\n [attr.aria-label]=\"_expanded ? 'Collapse children' : 'Expand children'\"\n [attr.aria-expanded]=\"_expanded\"\n [attr.data-autoid]=\"nodeAutoId(item, 'toggle')\"\n (click)=\"toggle(item, $event)\">\n <mat-icon>{{ _expanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n }\n </div>\n\n @if (_hasChildren && _expanded) {\n <ul class=\"sd-org-chart__children\" role=\"group\">\n @for (child of _children; track trackByItem($index, child)) {\n <ng-container\n *ngTemplateOutlet=\"\n nodeTemplate;\n context: { $implicit: child, item: child, depth: depth + 1, parent: item, templateRef: templateRef }\n \" />\n }\n </ul>\n }\n </li>\n</ng-template>\n", styles: [":host{--sd-org-line: #d9e2ef;--sd-org-card-bg: #ffffff;--sd-org-text: #102047;--sd-org-text-muted: #4d5b73;--sd-org-shadow: 0 8px 20px rgba(24, 39, 75, .08);--sd-org-gap-x: 20px;--sd-org-gap-y: 32px;display:block;overflow-x:auto;overflow-y:hidden;padding:8px 0 12px}.sd-org-chart{display:inline-block;min-width:100%;padding:8px 16px 0}.sd-org-chart__tree,.sd-org-chart__children{display:flex;justify-content:center;align-items:flex-start;margin:0;padding:0;list-style:none}.sd-org-chart__node{position:relative;flex:0 0 auto;padding:var(--sd-org-gap-y) var(--sd-org-gap-x) 0;text-align:center}.sd-org-chart__tree>.sd-org-chart__node{padding-top:0}.sd-org-chart__children>.sd-org-chart__node:before,.sd-org-chart__children>.sd-org-chart__node:after{position:absolute;top:0;width:50%;height:calc(var(--sd-org-gap-y) / 2);border-top:1px solid var(--sd-org-line);content:\"\"}.sd-org-chart__children>.sd-org-chart__node:before{right:50%}.sd-org-chart__children>.sd-org-chart__node:after{left:50%}.sd-org-chart__children>.sd-org-chart__node:first-child:before,.sd-org-chart__children>.sd-org-chart__node:last-child:after{border-top:0}.sd-org-chart__children>.sd-org-chart__node:only-child{padding-top:calc(var(--sd-org-gap-y) / 2)}.sd-org-chart__children>.sd-org-chart__node:only-child:before,.sd-org-chart__children>.sd-org-chart__node:only-child:after{display:none}.sd-org-chart__node-shell{position:relative;display:flex;flex-direction:column;align-items:center}.sd-org-chart__children>.sd-org-chart__node>.sd-org-chart__node-shell:before{position:absolute;top:calc(var(--sd-org-gap-y) * -1);left:50%;width:0;height:var(--sd-org-gap-y);border-left:1px solid var(--sd-org-line);content:\"\"}.sd-org-chart__tree>.sd-org-chart__node>.sd-org-chart__node-shell:before{display:none}.sd-org-chart__card{position:relative;z-index:1;min-width:128px;min-height:110px;box-sizing:border-box;padding:16px 14px 14px;color:var(--sd-org-text);background:var(--sd-org-node-color, var(--sd-org-card-bg));border:1px solid color-mix(in srgb,var(--sd-org-node-color, var(--sd-org-line)) 36%,var(--sd-org-line));border-radius:6px;box-shadow:var(--sd-org-shadow)}.sd-org-chart__card--compact{min-width:74px;min-height:40px;padding:10px 16px}.sd-org-chart__card--no-image:not(.sd-org-chart__card--compact){min-height:78px}.sd-org-chart__image{display:block;width:44px;height:44px;margin:0 auto 10px;object-fit:cover;border-radius:50%}.sd-org-chart__title{max-width:150px;margin:0 auto;overflow-wrap:anywhere;font-size:14px;font-weight:700;line-height:1.35}.sd-org-chart__description{max-width:150px;margin:5px auto 0;overflow-wrap:anywhere;color:var(--sd-org-text-muted);font-size:13px;line-height:1.3}.sd-org-chart__toggle{position:relative;z-index:2;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin-top:-1px;padding:0;color:#52708f;background:#fff;border:1px solid var(--sd-org-line);border-radius:50%;cursor:pointer}.sd-org-chart__toggle:hover{background:#f4f7fb}.sd-org-chart__toggle:focus-visible{outline:2px solid var(--sd-primary, #2a66f4);outline-offset:2px}.sd-org-chart__toggle mat-icon{width:18px;height:18px;font-size:18px;line-height:18px}\n"] }]
|
|
103
103
|
}], propDecorators: { autoIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoId", required: false }] }], option: [{ type: i0.Input, args: [{ isSignal: true, alias: "option", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], itemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemTemplate", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], itemDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SdOrgChartItemDefDirective), { isSignal: true }] }] } });
|
|
104
104
|
|
|
105
105
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdcorejs-angular-components-org-chart.mjs","sources":["../../../projects/sdcorejs-angular/components/org-chart/src/org-chart-item-def.directive.ts","../../../projects/sdcorejs-angular/components/org-chart/src/org-chart.component.ts","../../../projects/sdcorejs-angular/components/org-chart/src/org-chart.component.html","../../../projects/sdcorejs-angular/components/org-chart/sdcorejs-angular-components-org-chart.ts"],"sourcesContent":["import { Directive, TemplateRef, inject } from '@angular/core';\nimport { SdOrgChartItem, SdOrgChartItemContext } from './org-chart.model';\n\n@Directive({\n selector: '[sdOrgChartItemDef]',\n})\nexport class SdOrgChartItemDefDirective<T extends SdOrgChartItem = SdOrgChartItem> {\n static ngTemplateContextGuard<T extends SdOrgChartItem>(\n _dir: SdOrgChartItemDefDirective<T>,\n _ctx: unknown\n ): _ctx is SdOrgChartItemContext<T> {\n return true;\n }\n\n readonly templateRef: TemplateRef<SdOrgChartItemContext<T>> = inject(TemplateRef);\n}\n","import { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, TemplateRef, booleanAttribute, computed, contentChild, input, signal } from '@angular/core';\nimport { MatIconModule } from '@angular/material/icon';\nimport { SdOrgChartItemDefDirective } from './org-chart-item-def.directive';\nimport { SdOrgChartItem, SdOrgChartItemContext, SdOrgChartOption } from './org-chart.model';\n\n@Component({\n selector: 'sd-org-chart',\n standalone: true,\n imports: [CommonModule, MatIconModule],\n templateUrl: './org-chart.component.html',\n styleUrls: ['./org-chart.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[attr.data-autoid]': 'autoId()',\n },\n})\nexport class SdOrgChart {\n readonly autoIdInput = input<string | undefined | null>(undefined, { alias: 'autoId' });\n readonly option = input<SdOrgChartOption | undefined>(undefined);\n readonly autoId = computed(() => {\n const scope = this.option()?.autoId ?? this.autoIdInput();\n return scope ? `components-org-chart-${scope}` : undefined;\n });\n\n readonly items = input<SdOrgChartItem[] | undefined>(undefined);\n readonly itemTemplate = input<TemplateRef<SdOrgChartItemContext> | undefined | null>(undefined);\n readonly collapsible = input(true, { transform: booleanAttribute });\n\n readonly itemDef = contentChild(SdOrgChartItemDefDirective);\n readonly resolvedItems = computed(() => this.option()?.items ?? this.items() ?? []);\n readonly resolvedCollapsible = computed(() => this.option()?.collapsible ?? this.collapsible());\n\n readonly resolvedItemTemplate = computed<TemplateRef<SdOrgChartItemContext> | undefined>(() => {\n return this.itemDef()?.templateRef || this.option()?.itemTemplate || this.itemTemplate() || undefined;\n });\n\n readonly #expandedState = signal<Record<string, boolean>>({});\n\n readonly trackByItem = (_index: number, item: SdOrgChartItem) => item.id;\n\n hasChildren = (item: SdOrgChartItem): boolean => {\n return this.childrenOf(item).length > 0;\n };\n\n childrenOf = (item: SdOrgChartItem): SdOrgChartItem[] => {\n return item.children || [];\n };\n\n isExpanded = (item: SdOrgChartItem): boolean => {\n if (!this.resolvedCollapsible()) {\n return true;\n }\n\n const key = this.#itemKey(item);\n const state = this.#expandedState();\n return state[key] ?? item.expanded ?? true;\n };\n\n toggle = (item: SdOrgChartItem, event?: Event): void => {\n event?.stopPropagation();\n\n if (!this.resolvedCollapsible() || !this.hasChildren(item)) {\n return;\n }\n\n const key = this.#itemKey(item);\n const expanded = !(this.#expandedState()[key] ?? item.expanded ?? true);\n this.#expandedState.update(state => ({\n ...state,\n [key]: expanded,\n }));\n this.option()?.onToggle?.({ item, expanded });\n };\n\n createContext = (item: SdOrgChartItem, depth: number, parent: SdOrgChartItem | null): SdOrgChartItemContext => {\n const hasChildren = this.hasChildren(item);\n const expanded = this.isExpanded(item);\n\n return {\n $implicit: item,\n item,\n depth,\n parent,\n expanded,\n hasChildren,\n isLeaf: !hasChildren,\n toggle: () => this.toggle(item),\n };\n };\n\n nodeAutoId = (item: SdOrgChartItem, part: 'node' | 'image' | 'title' | 'description' | 'toggle'): string | undefined => {\n const base = this.autoId();\n if (!base) {\n return undefined;\n }\n\n return `${base}-${part}-${this.#autoIdKey(item)}`;\n };\n\n #itemKey = (item: SdOrgChartItem): string => {\n return String(item.id);\n };\n\n #autoIdKey = (item: SdOrgChartItem): string => {\n return this.#itemKey(item).replace(/[^a-zA-Z0-9_-]/g, '-');\n };\n}\n","@let _items = resolvedItems();\n@let _templateRef = resolvedItemTemplate();\n\n<div class=\"sd-org-chart\" role=\"tree\">\n <ul class=\"sd-org-chart__tree\">\n @for (item of _items; track trackByItem($index, item)) {\n <ng-container\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: item, item: item, depth: 0, parent: null, templateRef: _templateRef }\" />\n }\n </ul>\n</div>\n\n<ng-template #nodeTemplate let-item let-depth=\"depth\" let-parent=\"parent\" let-templateRef=\"templateRef\">\n @let _children = childrenOf(item);\n @let _hasChildren = _children.length > 0;\n @let _expanded = isExpanded(item);\n @let _context = createContext(item, depth, parent);\n\n <li\n class=\"sd-org-chart__node\"\n [class.sd-org-chart__node--expanded]=\"_hasChildren && _expanded\"\n [class.sd-org-chart__node--collapsed]=\"_hasChildren && !_expanded\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"_hasChildren ? _expanded : null\">\n <div class=\"sd-org-chart__node-shell\">\n <div\n class=\"sd-org-chart__card\"\n [class.sd-org-chart__card--no-image]=\"!item.image\"\n [class.sd-org-chart__card--compact]=\"!item.image && !item.description\"\n [attr.data-node-id]=\"item.id\"\n [attr.data-autoid]=\"nodeAutoId(item, 'node')\"\n [attr.data-depth]=\"depth\"\n [style.--sd-org-node-color]=\"item.color || null\">\n @if (templateRef) {\n <ng-container *ngTemplateOutlet=\"templateRef; context: _context\" />\n } @else {\n @if (item.image) {\n <img class=\"sd-org-chart__image\" [src]=\"item.image\" [alt]=\"item.title\" [attr.data-autoid]=\"nodeAutoId(item, 'image')\" />\n }\n <div class=\"sd-org-chart__title\" [attr.data-autoid]=\"nodeAutoId(item, 'title')\">{{ item.title }}</div>\n @if (item.description) {\n <div class=\"sd-org-chart__description\" [attr.data-autoid]=\"nodeAutoId(item, 'description')\">{{ item.description }}</div>\n }\n }\n </div>\n\n @if (_hasChildren && collapsible()) {\n <button\n type=\"button\"\n class=\"sd-org-chart__toggle\"\n [attr.aria-label]=\"_expanded ? 'Collapse children' : 'Expand children'\"\n [attr.aria-expanded]=\"_expanded\"\n [attr.data-autoid]=\"nodeAutoId(item, 'toggle')\"\n (click)=\"toggle(item, $event)\">\n <mat-icon>{{ _expanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n }\n </div>\n\n @if (_hasChildren && _expanded) {\n <ul class=\"sd-org-chart__children\" role=\"group\">\n @for (child of _children; track trackByItem($index, child)) {\n <ng-container\n *ngTemplateOutlet=\"\n nodeTemplate;\n context: { $implicit: child, item: child, depth: depth + 1, parent: item, templateRef: templateRef }\n \" />\n }\n </ul>\n }\n </li>\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sdcorejs-angular-components-org-chart.mjs","sources":["../../../projects/sdcorejs-angular/components/org-chart/src/org-chart-item-def.directive.ts","../../../projects/sdcorejs-angular/components/org-chart/src/org-chart.component.ts","../../../projects/sdcorejs-angular/components/org-chart/src/org-chart.component.html","../../../projects/sdcorejs-angular/components/org-chart/sdcorejs-angular-components-org-chart.ts"],"sourcesContent":["import { Directive, TemplateRef, inject } from '@angular/core';\nimport { SdOrgChartItem, SdOrgChartItemContext } from './org-chart.model';\n\n@Directive({\n selector: '[sdOrgChartItemDef]',\n})\nexport class SdOrgChartItemDefDirective<T extends SdOrgChartItem = SdOrgChartItem> {\n static ngTemplateContextGuard<T extends SdOrgChartItem>(\n _dir: SdOrgChartItemDefDirective<T>,\n _ctx: unknown\n ): _ctx is SdOrgChartItemContext<T> {\n return true;\n }\n\n readonly templateRef: TemplateRef<SdOrgChartItemContext<T>> = inject(TemplateRef);\n}\n","import { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, TemplateRef, booleanAttribute, computed, contentChild, input, signal } from '@angular/core';\nimport { MatIconModule } from '@angular/material/icon';\nimport { SdOrgChartItemDefDirective } from './org-chart-item-def.directive';\nimport { SdOrgChartItem, SdOrgChartItemContext, SdOrgChartOption } from './org-chart.model';\n\n@Component({\n selector: 'sd-org-chart',\n standalone: true,\n imports: [CommonModule, MatIconModule],\n templateUrl: './org-chart.component.html',\n styleUrls: ['./org-chart.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[attr.data-autoid]': 'autoId()',\n },\n})\nexport class SdOrgChart {\n readonly autoIdInput = input<string | undefined | null>(undefined, { alias: 'autoId' });\n readonly option = input<SdOrgChartOption | undefined>(undefined);\n readonly autoId = computed(() => {\n const scope = this.option()?.autoId ?? this.autoIdInput();\n return scope ? `components-org-chart-${scope}` : undefined;\n });\n\n readonly items = input<SdOrgChartItem[] | undefined>(undefined);\n readonly itemTemplate = input<TemplateRef<SdOrgChartItemContext> | undefined | null>(undefined);\n readonly collapsible = input(true, { transform: booleanAttribute });\n\n readonly itemDef = contentChild(SdOrgChartItemDefDirective);\n readonly resolvedItems = computed(() => this.option()?.items ?? this.items() ?? []);\n readonly resolvedCollapsible = computed(() => this.option()?.collapsible ?? this.collapsible());\n\n readonly resolvedItemTemplate = computed<TemplateRef<SdOrgChartItemContext> | undefined>(() => {\n return this.itemDef()?.templateRef || this.option()?.itemTemplate || this.itemTemplate() || undefined;\n });\n\n readonly #expandedState = signal<Record<string, boolean>>({});\n\n readonly trackByItem = (_index: number, item: SdOrgChartItem) => item.id;\n\n hasChildren = (item: SdOrgChartItem): boolean => {\n return this.childrenOf(item).length > 0;\n };\n\n childrenOf = (item: SdOrgChartItem): SdOrgChartItem[] => {\n return item.children || [];\n };\n\n isExpanded = (item: SdOrgChartItem): boolean => {\n if (!this.resolvedCollapsible()) {\n return true;\n }\n\n const key = this.#itemKey(item);\n const state = this.#expandedState();\n return state[key] ?? item.expanded ?? true;\n };\n\n toggle = (item: SdOrgChartItem, event?: Event): void => {\n event?.stopPropagation();\n\n if (!this.resolvedCollapsible() || !this.hasChildren(item)) {\n return;\n }\n\n const key = this.#itemKey(item);\n const expanded = !(this.#expandedState()[key] ?? item.expanded ?? true);\n this.#expandedState.update(state => ({\n ...state,\n [key]: expanded,\n }));\n this.option()?.onToggle?.({ item, expanded });\n };\n\n createContext = (item: SdOrgChartItem, depth: number, parent: SdOrgChartItem | null): SdOrgChartItemContext => {\n const hasChildren = this.hasChildren(item);\n const expanded = this.isExpanded(item);\n\n return {\n $implicit: item,\n item,\n depth,\n parent,\n expanded,\n hasChildren,\n isLeaf: !hasChildren,\n toggle: () => this.toggle(item),\n };\n };\n\n nodeAutoId = (item: SdOrgChartItem, part: 'node' | 'image' | 'title' | 'description' | 'toggle'): string | undefined => {\n const base = this.autoId();\n if (!base) {\n return undefined;\n }\n\n return `${base}-${part}-${this.#autoIdKey(item)}`;\n };\n\n #itemKey = (item: SdOrgChartItem): string => {\n return String(item.id);\n };\n\n #autoIdKey = (item: SdOrgChartItem): string => {\n return this.#itemKey(item).replace(/[^a-zA-Z0-9_-]/g, '-');\n };\n}\n","@let _resolvedItems = resolvedItems();\n@let _resolvedItemTemplate = resolvedItemTemplate();\n\n<div class=\"sd-org-chart\" role=\"tree\">\n <ul class=\"sd-org-chart__tree\">\n @for (item of _resolvedItems; track trackByItem($index, item)) {\n <ng-container\n *ngTemplateOutlet=\"nodeTemplate; context: { $implicit: item, item: item, depth: 0, parent: null, templateRef: _resolvedItemTemplate }\" />\n }\n </ul>\n</div>\n\n<ng-template #nodeTemplate let-item let-depth=\"depth\" let-parent=\"parent\" let-templateRef=\"templateRef\">\n @let _children = childrenOf(item);\n @let _hasChildren = _children.length > 0;\n @let _expanded = isExpanded(item);\n @let _context = createContext(item, depth, parent);\n\n <li\n class=\"sd-org-chart__node\"\n [class.sd-org-chart__node--expanded]=\"_hasChildren && _expanded\"\n [class.sd-org-chart__node--collapsed]=\"_hasChildren && !_expanded\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"_hasChildren ? _expanded : null\">\n <div class=\"sd-org-chart__node-shell\">\n <div\n class=\"sd-org-chart__card\"\n [class.sd-org-chart__card--no-image]=\"!item.image\"\n [class.sd-org-chart__card--compact]=\"!item.image && !item.description\"\n [attr.data-node-id]=\"item.id\"\n [attr.data-autoid]=\"nodeAutoId(item, 'node')\"\n [attr.data-depth]=\"depth\"\n [style.--sd-org-node-color]=\"item.color || null\">\n @if (templateRef) {\n <ng-container *ngTemplateOutlet=\"templateRef; context: _context\" />\n } @else {\n @if (item.image) {\n <img class=\"sd-org-chart__image\" [src]=\"item.image\" [alt]=\"item.title\" [attr.data-autoid]=\"nodeAutoId(item, 'image')\" />\n }\n <div class=\"sd-org-chart__title\" [attr.data-autoid]=\"nodeAutoId(item, 'title')\">{{ item.title }}</div>\n @if (item.description) {\n <div class=\"sd-org-chart__description\" [attr.data-autoid]=\"nodeAutoId(item, 'description')\">{{ item.description }}</div>\n }\n }\n </div>\n\n @if (_hasChildren && collapsible()) {\n <button\n type=\"button\"\n class=\"sd-org-chart__toggle\"\n [attr.aria-label]=\"_expanded ? 'Collapse children' : 'Expand children'\"\n [attr.aria-expanded]=\"_expanded\"\n [attr.data-autoid]=\"nodeAutoId(item, 'toggle')\"\n (click)=\"toggle(item, $event)\">\n <mat-icon>{{ _expanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n }\n </div>\n\n @if (_hasChildren && _expanded) {\n <ul class=\"sd-org-chart__children\" role=\"group\">\n @for (child of _children; track trackByItem($index, child)) {\n <ng-container\n *ngTemplateOutlet=\"\n nodeTemplate;\n context: { $implicit: child, item: child, depth: depth + 1, parent: item, templateRef: templateRef }\n \" />\n }\n </ul>\n }\n </li>\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -2,10 +2,10 @@ import * as i1 from '@angular/common';
|
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { inject, ElementRef, DestroyRef, input, computed, output, signal, effect, afterNextRender, HostListener, ChangeDetectionStrategy, Component, InjectionToken, viewChild, viewChildren } from '@angular/core';
|
|
5
|
+
import { Utilities } from '@sdcorejs/utils/fns';
|
|
5
6
|
import * as i2 from '@angular/material/icon';
|
|
6
7
|
import { MatIconModule } from '@angular/material/icon';
|
|
7
8
|
import { TranslatePipe } from '@sdcorejs/angular/i18n';
|
|
8
|
-
import * as uuid from 'uuid';
|
|
9
9
|
import { FormsModule } from '@angular/forms';
|
|
10
10
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
11
11
|
|
|
@@ -579,7 +579,7 @@ class SdPreviewImage {
|
|
|
579
579
|
}
|
|
580
580
|
}
|
|
581
581
|
async #fromUrl(url, override) {
|
|
582
|
-
const id =
|
|
582
|
+
const id = Utilities.generateUuid();
|
|
583
583
|
// Lấy filename từ phần path cuối — bỏ query string.
|
|
584
584
|
const baseSrc = url.split('?')[0];
|
|
585
585
|
const inferredName = override?.name || baseSrc.substring(baseSrc.lastIndexOf('/') + 1) || 'image';
|
|
@@ -628,7 +628,7 @@ class SdPreviewImage {
|
|
|
628
628
|
const blobUrl = URL.createObjectURL(file);
|
|
629
629
|
this.#ownedBlobUrls.add(blobUrl);
|
|
630
630
|
return {
|
|
631
|
-
id:
|
|
631
|
+
id: Utilities.generateUuid(),
|
|
632
632
|
blobUrl,
|
|
633
633
|
name: override?.name || file.name,
|
|
634
634
|
size: file.size,
|
|
@@ -638,11 +638,11 @@ class SdPreviewImage {
|
|
|
638
638
|
error: false,
|
|
639
639
|
};
|
|
640
640
|
}
|
|
641
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
642
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: SdPreviewImage, isStandalone: true, selector: "sd-preview-image", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, thumbnailPosition: { classPropertyName: "thumbnailPosition", publicName: "thumbnailPosition", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, downloadable: { classPropertyName: "downloadable", publicName: "downloadable", isSignal: true, isRequired: false, transformFunction: null }, zoomable: { classPropertyName: "zoomable", publicName: "zoomable", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, startIndex: { classPropertyName: "startIndex", publicName: "startIndex", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close", activeIndexChange: "activeIndexChange", download: "download", imageError: "imageError" }, host: { attributes: { "tabindex": "0" }, listeners: { "keydown": "onKeyDown($event)" }, properties: { "attr.data-theme": "theme()", "class.sd-preview-image-host--fullscreen": "isFullscreen()" }, classAttribute: "sd-preview-image-host" }, ngImport: i0, template: "<!--\n Self-contained viewer shell. Component sizes to its parent (width:100%;\n height:100%) \u2014 consumer decides whether to wrap in <sd-modal>,\n <sd-side-drawer>, a page section, or use inline.\n-->\n<div [ngClass]=\"shellClass()\" role=\"region\">\n @let _stage = stage();\n @let _images = images();\n @let _thumbnailPosition = thumbnailPosition();\n @let _activeIndex = activeIndex();\n @let _activeImage = activeImage();\n\n <!-- ============================================\n HEADER BAR\n ============================================ -->\n @if (_stage !== 'empty' && _activeImage; as img) {\n <div class=\"sd-preview-header\">\n <div class=\"sd-preview-header__left\">\n <mat-icon class=\"sd-preview-header__icon\" fontIcon=\"image\"></mat-icon>\n <div class=\"sd-preview-header__meta\">\n <div class=\"sd-preview-header__name T14M\" [title]=\"img.name\">{{ img.name }}</div>\n @if (img.size) {\n <div class=\"sd-preview-header__sub\">\n {{ formatBytes(img.size) }}\n </div>\n }\n </div>\n </div>\n\n @if (_images.length > 1) {\n <div class=\"sd-preview-header__counter\" aria-live=\"polite\">\n {{ _activeIndex + 1 }} / {{ _images.length }}\n </div>\n }\n </div>\n } @else if (title()) {\n <!-- Optional override title even on empty state -->\n <div class=\"sd-preview-header sd-preview-header--simple\">\n <div class=\"sd-preview-header__name T14M\">{{ title() }}</div>\n </div>\n }\n\n <!-- ============================================\n BODY (stage + thumbnails per layout)\n ============================================ -->\n <div class=\"sd-preview-body\">\n\n <!-- STAGE ............................................................... -->\n <div\n class=\"sd-preview-stage\"\n [class.sd-preview-stage--dragging]=\"zoom() > 1\"\n (wheel)=\"onWheel($event)\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n (dblclick)=\"onImageDblClick()\">\n\n @switch (_stage) {\n @case ('empty') {\n <div class=\"sd-preview-status\">\n <div class=\"sd-preview-status__tile sd-preview-status__tile--muted\">\n <mat-icon fontIcon=\"image_not_supported\"></mat-icon>\n </div>\n <div class=\"sd-preview-status__title\">\n {{ 'core.component.preview-image.no-image' | translate }}\n </div>\n <div class=\"sd-preview-status__hint\">\n {{ 'core.component.preview-image.no-image-hint' | translate }}\n </div>\n </div>\n }\n @case ('loading') {\n <div class=\"sd-preview-status\">\n <div class=\"sd-preview-spinner\" role=\"progressbar\"></div>\n <div class=\"sd-preview-status__hint\">\n {{ 'core.component.preview-image.loading' | translate }}\n </div>\n </div>\n }\n @default {\n @if (_activeImage; as img) {\n @if (img.loading) {\n <!-- Per-image loading (retry inline) \u2014 gi\u1EEF nav/dots/thumbs visible -->\n <div class=\"sd-preview-image-loading\" role=\"status\"\n [attr.aria-label]=\"'core.component.preview-image.loading' | translate\">\n <div class=\"sd-preview-spinner\"></div>\n <div class=\"sd-preview-status__hint\">\n {{ 'core.component.preview-image.loading' | translate }}\n </div>\n </div>\n } @else if (img.error) {\n <!-- Inline broken-image placeholder \u2014 gi\u1EEF nav/dots/thumbs visible -->\n <div class=\"sd-preview-image-broken\" role=\"img\"\n [attr.aria-label]=\"'core.component.preview-image.load-error' | translate\">\n <div class=\"sd-preview-status__tile sd-preview-status__tile--danger\">\n <mat-icon fontIcon=\"broken_image\"></mat-icon>\n </div>\n <div class=\"sd-preview-status__title\">\n {{ 'core.component.preview-image.load-error' | translate }}\n </div>\n <div class=\"sd-preview-status__hint\">\n {{ 'core.component.preview-image.load-error-hint' | translate }}\n </div>\n <button type=\"button\" class=\"sd-preview-btn-primary\" (click)=\"retryActive()\" [attr.data-autoId]=\"autoIdRetry()\">\n <mat-icon fontIcon=\"refresh\"></mat-icon>\n <span>{{ 'core.component.preview-image.retry' | translate }}</span>\n </button>\n </div>\n } @else {\n <img\n class=\"sd-preview-image\"\n [src]=\"img.blobUrl || img.url\"\n [alt]=\"img.alt || img.name\"\n [style.transform]=\"imageTransform()\"\n (error)=\"onImageError()\"\n draggable=\"false\" />\n\n @if (img.caption) {\n <div class=\"sd-preview-caption\">{{ img.caption }}</div>\n }\n }\n }\n }\n }\n\n <!-- KEYBOARD HINT ............................................. -->\n @if (_stage === 'ready' && _images.length > 1) {\n <div class=\"sd-preview-kbd-hint\" aria-hidden=\"true\">\n <span class=\"sd-preview-kbd\">\u2190</span>\n <span class=\"sd-preview-kbd\">\u2192</span>\n <span class=\"sd-preview-kbd-text\">{{ 'core.component.preview-image.kbd-hint-nav' | translate }}</span>\n </div>\n }\n\n <!-- NAV ARROWS ............................................. -->\n @if (_stage === 'ready' && _images.length > 1) {\n <button\n type=\"button\"\n class=\"sd-preview-nav sd-preview-nav--prev\"\n [disabled]=\"!hasPrev()\"\n [attr.aria-label]=\"'core.component.preview-image.prev' | translate\"\n [attr.data-autoId]=\"autoIdPrev()\"\n (click)=\"updateCurrentImage(-1)\">\n <mat-icon fontIcon=\"chevron_left\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-nav sd-preview-nav--next\"\n [disabled]=\"!hasNext()\"\n [attr.aria-label]=\"'core.component.preview-image.next' | translate\"\n [attr.data-autoId]=\"autoIdNext()\"\n (click)=\"updateCurrentImage(1)\">\n <mat-icon fontIcon=\"chevron_right\"></mat-icon>\n </button>\n }\n\n <!-- DOTS INDICATOR ......................................... -->\n @if (_thumbnailPosition === 'dots' && _stage === 'ready' && _images.length > 1) {\n <div class=\"sd-preview-dots\" role=\"tablist\">\n @for (img of _images; track img.id; let i = $index) {\n <button\n type=\"button\"\n class=\"sd-preview-dot\"\n [class.sd-preview-dot--active]=\"i === _activeIndex\"\n [attr.aria-label]=\"'core.component.preview-image.next' | translate\"\n [attr.data-autoId]=\"autoIdDot(i)\"\n (click)=\"onClickThumbnailImage(i)\"></button>\n }\n </div>\n }\n\n <!-- FLOATING TOOLBAR ....................................... -->\n @if (showToolbar() && _stage === 'ready') {\n <div class=\"sd-preview-toolbar\" role=\"toolbar\">\n @if (zoomable()) {\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.zoom-out' | translate\"\n [attr.title]=\"'core.component.preview-image.zoom-out' | translate\"\n [attr.data-autoId]=\"autoIdZoomOut()\"\n (click)=\"zoomOut()\">\n <mat-icon fontIcon=\"zoom_out\"></mat-icon>\n </button>\n <span class=\"sd-preview-toolbar__readout\">{{ zoomPercent() }}%</span>\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.zoom-in' | translate\"\n [attr.title]=\"'core.component.preview-image.zoom-in' | translate\"\n [attr.data-autoId]=\"autoIdZoomIn()\"\n (click)=\"zoomIn()\">\n <mat-icon fontIcon=\"zoom_in\"></mat-icon>\n </button>\n <span class=\"sd-preview-toolbar__divider\"></span>\n }\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn sd-preview-toolbar__btn--with-label\"\n [attr.aria-label]=\"'core.component.preview-image.fit' | translate\"\n [attr.data-autoId]=\"autoIdFit()\"\n (click)=\"fitToScreen()\">\n <mat-icon fontIcon=\"fit_screen\"></mat-icon>\n <span class=\"sd-preview-toolbar__btn-label\">{{ 'core.component.preview-image.fit' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.rotate' | translate\"\n [attr.title]=\"'core.component.preview-image.rotate' | translate\"\n [attr.data-autoId]=\"autoIdRotate()\"\n (click)=\"rotate('right')\">\n <mat-icon fontIcon=\"rotate_right\"></mat-icon>\n </button>\n <span class=\"sd-preview-toolbar__divider\"></span>\n @if (downloadable()) {\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.download' | translate\"\n [attr.title]=\"'core.component.preview-image.download' | translate\"\n [attr.data-autoId]=\"autoIdDownload()\"\n (click)=\"downloadCurrent()\">\n <mat-icon fontIcon=\"download\"></mat-icon>\n </button>\n }\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.fullscreen' | translate\"\n [attr.title]=\"'core.component.preview-image.fullscreen' | translate\"\n [attr.data-autoId]=\"autoIdFullscreen()\"\n (click)=\"toggleFullscreen()\">\n <mat-icon [fontIcon]=\"isFullscreen() ? 'fullscreen_exit' : 'fullscreen'\"></mat-icon>\n </button>\n </div>\n }\n </div>\n\n <!-- THUMBNAIL STRIP .................................................... -->\n @if (\n _stage === 'ready' &&\n _images.length > 1 &&\n _thumbnailPosition !== 'none' &&\n _thumbnailPosition !== 'dots'\n ) {\n <div\n class=\"sd-preview-thumbs\"\n [class.sd-preview-thumbs--vertical]=\"_thumbnailPosition === 'left' || _thumbnailPosition === 'right'\">\n @for (img of _images; track trackByImage($index, img); let i = $index) {\n <button\n type=\"button\"\n class=\"sd-preview-thumb\"\n [class.sd-preview-thumb--active]=\"i === _activeIndex\"\n [id]=\"'sd-preview-thumb-' + i\"\n [attr.aria-label]=\"img.name\"\n [attr.aria-current]=\"i === _activeIndex ? 'true' : null\"\n [attr.data-autoId]=\"autoIdThumb(i)\"\n (click)=\"onClickThumbnailImage(i)\">\n @if (img.error) {\n <div class=\"sd-preview-thumb__broken\">\n <mat-icon fontIcon=\"broken_image\"></mat-icon>\n </div>\n } @else {\n <img class=\"sd-preview-thumb__img\" [src]=\"img.blobUrl || img.url\" [alt]=\"img.alt || img.name\" />\n }\n <span class=\"sd-preview-thumb__badge\">{{ i + 1 }}</span>\n @if (_thumbnailPosition === 'right' || _thumbnailPosition === 'left') {\n <span class=\"sd-preview-thumb__name\" [title]=\"img.name\">{{ img.name }}</span>\n }\n </button>\n }\n </div>\n }\n </div>\n</div>\n", styles: [":host{--sd-preview-shell-bg: #0d0e10;--sd-preview-shell-bg-2: #17191c;--sd-preview-panel-bg: rgba(15, 17, 20, .92);--sd-preview-divider: rgba(255, 255, 255, .08);--sd-preview-fg: #f5f6f7;--sd-preview-fg-muted: rgba(255, 255, 255, .6);--sd-preview-fg-subtle: rgba(255, 255, 255, .4);--sd-preview-accent: var(--sd-primary, #3b82f6);--sd-preview-accent-soft: rgba(59, 130, 246, .2);--sd-preview-danger: var(--sd-error, #ef4444);--sd-preview-success: var(--sd-success, #22c55e);--sd-preview-danger-soft: rgba(239, 68, 68, .1);--sd-preview-danger-border: rgba(239, 68, 68, .3);--sd-preview-hover-bg: rgba(255, 255, 255, .1);display:block;width:100%;height:100%;min-height:320px;outline:none}:host([data-theme=light]){--sd-preview-shell-bg: #f7f8fa;--sd-preview-shell-bg-2: #ffffff;--sd-preview-panel-bg: rgba(255, 255, 255, .94);--sd-preview-divider: rgba(0, 0, 0, .08);--sd-preview-fg: #1a1c1f;--sd-preview-fg-muted: rgba(0, 0, 0, .62);--sd-preview-fg-subtle: rgba(0, 0, 0, .42);--sd-preview-accent: var(--sd-primary, #1f49bf);--sd-preview-accent-soft: rgba(31, 73, 191, .18);--sd-preview-danger: var(--sd-error, #ef4444);--sd-preview-success: var(--sd-success, #22c55e);--sd-preview-danger-soft: rgba(239, 68, 68, .08);--sd-preview-danger-border: rgba(239, 68, 68, .25);--sd-preview-hover-bg: rgba(0, 0, 0, .06)}.sd-preview-shell{position:relative;display:flex;flex-direction:column;width:100%;height:100%;background:var(--sd-preview-shell-bg);color:var(--sd-preview-fg);border-radius:12px;overflow:hidden;box-shadow:0 30px 80px #0000008c,0 0 0 1px #ffffff0a;font-family:inherit}.sd-preview-shell--fullscreen{height:100vh;width:100vw;border-radius:0}:host(.sd-preview-image-host--fullscreen){width:100vw;height:100vh;min-height:0}.sd-preview-header{position:relative;display:flex;align-items:center;height:68px;padding:0 16px;background:var(--sd-preview-panel-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-bottom:1px solid var(--sd-preview-divider);flex:0 0 auto;z-index:2}.sd-preview-header--simple{justify-content:space-between}.sd-preview-header__left{display:flex;align-items:center;gap:12px;min-width:0;flex:1 1 auto}.sd-preview-header__icon{color:var(--sd-preview-fg-muted);font-size:20px;width:20px;height:20px}.sd-preview-header__meta{display:flex;flex-direction:column;min-width:0}.sd-preview-header__name{color:var(--sd-preview-fg);max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-preview-header__sub{font-size:12px;color:var(--sd-preview-fg-muted);margin-top:2px}.sd-preview-header__counter{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);font-size:13px;font-weight:500;color:var(--sd-preview-fg-muted);background:#ffffff14;padding:4px 12px;border-radius:999px;font-variant-numeric:tabular-nums}.sd-preview-body{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}.sd-preview-shell--pos-bottom .sd-preview-body{flex-direction:column}.sd-preview-shell--pos-top .sd-preview-body{flex-direction:column-reverse}.sd-preview-shell--pos-right .sd-preview-body{flex-direction:row}.sd-preview-shell--pos-left .sd-preview-body{flex-direction:row-reverse}.sd-preview-shell--pos-dots .sd-preview-body,.sd-preview-shell--pos-none .sd-preview-body{flex-direction:column}.sd-preview-stage{position:relative;flex:1 1 auto;min-height:0;min-width:0;background:var(--sd-preview-shell-bg);background-image:linear-gradient(45deg,rgba(255,255,255,.02) 25%,transparent 25%),linear-gradient(-45deg,rgba(255,255,255,.02) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(255,255,255,.02) 75%),linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.02) 75%);background-size:24px 24px;background-position:0 0,0 12px,12px -12px,-12px 0;display:flex;align-items:center;justify-content:center;overflow:hidden;touch-action:none;-webkit-user-select:none;user-select:none}.sd-preview-stage--dragging{cursor:grab}:host([data-theme=light]) .sd-preview-stage{background-image:linear-gradient(45deg,rgba(0,0,0,.015) 25%,transparent 25%),linear-gradient(-45deg,rgba(0,0,0,.015) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(0,0,0,.015) 75%),linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.015) 75%)}.sd-preview-image{max-width:100%;max-height:100%;object-fit:contain;transform-origin:center center;transition:transform .2s ease;will-change:transform;pointer-events:none}.sd-preview-caption{position:absolute;bottom:96px;left:50%;transform:translate(-50%);max-width:70%;padding:6px 12px;background:#0f1114b3;color:var(--sd-preview-fg);border-radius:8px;font-size:13px;text-align:center}.sd-preview-image-broken,.sd-preview-image-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;width:100%;max-width:480px;padding:24px;text-align:center}.sd-preview-nav{position:absolute;top:50%;transform:translateY(-50%);width:48px;height:48px;border-radius:999px;border:none;background:#14141699;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);color:var(--sd-preview-fg);display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 16px #0000004d;transition:background .12s;z-index:3}.sd-preview-nav mat-icon{font-size:28px;width:28px;height:28px}.sd-preview-nav:hover:not(:disabled){background:#ffffff2e}.sd-preview-nav:focus-visible{outline:2px solid var(--sd-preview-accent);outline-offset:2px}.sd-preview-nav:disabled{background:#ffffff0a;opacity:.35;cursor:not-allowed}.sd-preview-nav--prev{left:16px}.sd-preview-nav--next{right:16px}.sd-preview-toolbar{position:absolute;bottom:24px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:4px;padding:6px 8px;background:var(--sd-preview-panel-bg);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border:1px solid var(--sd-preview-divider);border-radius:12px;box-shadow:0 8px 30px #0006;z-index:3}.sd-preview-toolbar__btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:36px;height:36px;padding:0 8px;background:transparent;border:none;color:var(--sd-preview-fg);border-radius:8px;cursor:pointer;transition:background .12s}.sd-preview-toolbar__btn mat-icon{font-size:20px;width:20px;height:20px}.sd-preview-toolbar__btn--with-label{padding:0 12px}.sd-preview-toolbar__btn:hover:not(:disabled){background:var(--sd-preview-hover-bg)}.sd-preview-toolbar__btn:focus-visible{outline:2px solid var(--sd-preview-accent);outline-offset:2px}.sd-preview-toolbar__btn-label{font-size:13px;font-weight:500}.sd-preview-toolbar__readout{min-width:56px;text-align:center;color:var(--sd-preview-fg);font-size:13px;font-weight:500;font-variant-numeric:tabular-nums}.sd-preview-toolbar__divider{width:1px;height:20px;background:var(--sd-preview-divider);margin:0 4px}.sd-preview-thumbs{display:flex;gap:8px;padding:12px;background:var(--sd-preview-shell-bg-2);overflow:auto;flex:0 0 auto;flex-direction:row;height:116px}.sd-preview-thumbs--vertical{flex-direction:column;width:152px;height:100%}.sd-preview-thumb{position:relative;flex:0 0 auto;width:120px;height:76px;padding:0;border:none;background:transparent;border-radius:8px;outline:1px solid var(--sd-preview-divider);outline-offset:-1px;opacity:.7;overflow:hidden;cursor:pointer;transition:opacity .12s,outline-color .12s}.sd-preview-thumb:hover{opacity:1}.sd-preview-thumb--active{opacity:1;outline:2px solid var(--sd-preview-accent);outline-offset:-2px;box-shadow:inset 0 0 0 2px var(--sd-preview-accent)}.sd-preview-thumb:focus-visible{outline:2px solid var(--sd-preview-accent);outline-offset:2px}.sd-preview-thumb__img{width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}.sd-preview-thumb__broken{display:flex;align-items:center;justify-content:center;width:100%;height:100%;background:var(--sd-preview-danger-soft);color:var(--sd-preview-danger);pointer-events:none}.sd-preview-thumb__broken mat-icon{font-size:24px;width:24px;height:24px}.sd-preview-thumb__badge{position:absolute;top:4px;right:4px;background:#000000b3;color:#fff;font-size:10px;font-weight:600;padding:1px 5px;border-radius:4px;pointer-events:none}.sd-preview-thumb__name{position:absolute;left:0;right:0;bottom:0;padding:14px 6px 4px;color:var(--sd-preview-fg);font-size:11px;line-height:1.3;background:linear-gradient(to top,rgba(0,0,0,.85),transparent);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;pointer-events:none}.sd-preview-thumbs--vertical .sd-preview-thumb{width:128px}.sd-preview-dots{position:absolute;bottom:24px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:6px;z-index:3}.sd-preview-dot{width:8px;height:8px;border:none;background:#ffffff4d;border-radius:999px;padding:0;cursor:pointer;transition:width .18s,background .18s}.sd-preview-dot--active{width:24px;background:#f5f6f7}.sd-preview-dot:focus-visible{outline:2px solid var(--sd-preview-accent);outline-offset:2px}.sd-preview-status{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;text-align:center;padding:24px}.sd-preview-status__tile{width:96px;height:96px;border-radius:24px;display:flex;align-items:center;justify-content:center;border:1px solid var(--sd-preview-divider);background:#ffffff0d}.sd-preview-status__tile mat-icon{font-size:48px;width:48px;height:48px;color:var(--sd-preview-fg-subtle)}.sd-preview-status__tile--muted{background:#ffffff0d;border-color:var(--sd-preview-divider)}.sd-preview-status__tile--danger{background:var(--sd-preview-danger-soft);border-color:var(--sd-preview-danger-border)}.sd-preview-status__tile--danger mat-icon{color:var(--sd-preview-danger)}.sd-preview-status__title{font-size:16px;font-weight:500;color:var(--sd-preview-fg)}.sd-preview-status__hint{font-size:13px;color:var(--sd-preview-fg-muted);max-width:320px}.sd-preview-spinner{width:56px;height:56px;border-radius:999px;border:3px solid rgba(255,255,255,.08);border-top-color:var(--sd-preview-accent);animation:sd-preview-spin .9s linear infinite}@keyframes sd-preview-spin{to{transform:rotate(360deg)}}.sd-preview-btn-primary{display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 16px;background:var(--sd-preview-accent);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:filter .12s}.sd-preview-btn-primary mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-btn-primary:hover{filter:brightness(1.1)}.sd-preview-btn-primary:focus-visible{outline:2px solid #fff;outline-offset:2px}.sd-preview-kbd-hint{position:absolute;top:16px;left:16px;display:flex;align-items:center;gap:6px;z-index:2;pointer-events:none}.sd-preview-kbd{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 5px;border:1px solid var(--sd-preview-divider);background:#ffffff0a;color:var(--sd-preview-fg-muted);border-radius:4px;font:500 11px/1 ui-monospace,SFMono-Regular,Menlo,monospace}.sd-preview-kbd-text,.sd-preview-kbd-dot{font-size:11px;color:var(--sd-preview-fg-subtle)}.sd-preview-kbd-dot{margin:0 2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
641
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdPreviewImage, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
642
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SdPreviewImage, isStandalone: true, selector: "sd-preview-image", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, thumbnailPosition: { classPropertyName: "thumbnailPosition", publicName: "thumbnailPosition", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, downloadable: { classPropertyName: "downloadable", publicName: "downloadable", isSignal: true, isRequired: false, transformFunction: null }, zoomable: { classPropertyName: "zoomable", publicName: "zoomable", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, startIndex: { classPropertyName: "startIndex", publicName: "startIndex", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close", activeIndexChange: "activeIndexChange", download: "download", imageError: "imageError" }, host: { attributes: { "tabindex": "0" }, listeners: { "keydown": "onKeyDown($event)" }, properties: { "attr.data-theme": "theme()", "class.sd-preview-image-host--fullscreen": "isFullscreen()" }, classAttribute: "sd-preview-image-host" }, ngImport: i0, template: "<!--\n Self-contained viewer shell. Component sizes to its parent (width:100%;\n height:100%) \u2014 consumer decides whether to wrap in <sd-modal>,\n <sd-side-drawer>, a page section, or use inline.\n-->\n<div [ngClass]=\"shellClass()\" role=\"region\">\n @let _stage = stage();\n @let _images = images();\n @let _thumbnailPosition = thumbnailPosition();\n @let _activeIndex = activeIndex();\n @let _activeImage = activeImage();\n\n <!-- ============================================\n HEADER BAR\n ============================================ -->\n @if (_stage !== 'empty' && _activeImage; as img) {\n <div class=\"sd-preview-header\">\n <div class=\"sd-preview-header__left\">\n <mat-icon class=\"sd-preview-header__icon\" fontIcon=\"image\"></mat-icon>\n <div class=\"sd-preview-header__meta\">\n <div class=\"sd-preview-header__name T14M\" [title]=\"img.name\">{{ img.name }}</div>\n @if (img.size) {\n <div class=\"sd-preview-header__sub\">\n {{ formatBytes(img.size) }}\n </div>\n }\n </div>\n </div>\n\n @if (_images.length > 1) {\n <div class=\"sd-preview-header__counter\" aria-live=\"polite\">\n {{ _activeIndex + 1 }} / {{ _images.length }}\n </div>\n }\n </div>\n } @else if (title()) {\n <!-- Optional override title even on empty state -->\n <div class=\"sd-preview-header sd-preview-header--simple\">\n <div class=\"sd-preview-header__name T14M\">{{ title() }}</div>\n </div>\n }\n\n <!-- ============================================\n BODY (stage + thumbnails per layout)\n ============================================ -->\n <div class=\"sd-preview-body\">\n\n <!-- STAGE ............................................................... -->\n <div\n class=\"sd-preview-stage\"\n [class.sd-preview-stage--dragging]=\"zoom() > 1\"\n (wheel)=\"onWheel($event)\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n (dblclick)=\"onImageDblClick()\">\n\n @switch (_stage) {\n @case ('empty') {\n <div class=\"sd-preview-status\">\n <div class=\"sd-preview-status__tile sd-preview-status__tile--muted\">\n <mat-icon fontIcon=\"image_not_supported\"></mat-icon>\n </div>\n <div class=\"sd-preview-status__title\">\n {{ 'core.component.preview-image.no-image' | translate }}\n </div>\n <div class=\"sd-preview-status__hint\">\n {{ 'core.component.preview-image.no-image-hint' | translate }}\n </div>\n </div>\n }\n @case ('loading') {\n <div class=\"sd-preview-status\">\n <div class=\"sd-preview-spinner\" role=\"progressbar\"></div>\n <div class=\"sd-preview-status__hint\">\n {{ 'core.component.preview-image.loading' | translate }}\n </div>\n </div>\n }\n @default {\n @if (_activeImage; as img) {\n @if (img.loading) {\n <!-- Per-image loading (retry inline) \u2014 gi\u1EEF nav/dots/thumbs visible -->\n <div class=\"sd-preview-image-loading\" role=\"status\"\n [attr.aria-label]=\"'core.component.preview-image.loading' | translate\">\n <div class=\"sd-preview-spinner\"></div>\n <div class=\"sd-preview-status__hint\">\n {{ 'core.component.preview-image.loading' | translate }}\n </div>\n </div>\n } @else if (img.error) {\n <!-- Inline broken-image placeholder \u2014 gi\u1EEF nav/dots/thumbs visible -->\n <div class=\"sd-preview-image-broken\" role=\"img\"\n [attr.aria-label]=\"'core.component.preview-image.load-error' | translate\">\n <div class=\"sd-preview-status__tile sd-preview-status__tile--danger\">\n <mat-icon fontIcon=\"broken_image\"></mat-icon>\n </div>\n <div class=\"sd-preview-status__title\">\n {{ 'core.component.preview-image.load-error' | translate }}\n </div>\n <div class=\"sd-preview-status__hint\">\n {{ 'core.component.preview-image.load-error-hint' | translate }}\n </div>\n <button type=\"button\" class=\"sd-preview-btn-primary\" (click)=\"retryActive()\" [attr.data-autoId]=\"autoIdRetry()\">\n <mat-icon fontIcon=\"refresh\"></mat-icon>\n <span>{{ 'core.component.preview-image.retry' | translate }}</span>\n </button>\n </div>\n } @else {\n <img\n class=\"sd-preview-image\"\n [src]=\"img.blobUrl || img.url\"\n [alt]=\"img.alt || img.name\"\n [style.transform]=\"imageTransform()\"\n (error)=\"onImageError()\"\n draggable=\"false\" />\n\n @if (img.caption) {\n <div class=\"sd-preview-caption\">{{ img.caption }}</div>\n }\n }\n }\n }\n }\n\n <!-- KEYBOARD HINT ............................................. -->\n @if (_stage === 'ready' && _images.length > 1) {\n <div class=\"sd-preview-kbd-hint\" aria-hidden=\"true\">\n <span class=\"sd-preview-kbd\">\u2190</span>\n <span class=\"sd-preview-kbd\">\u2192</span>\n <span class=\"sd-preview-kbd-text\">{{ 'core.component.preview-image.kbd-hint-nav' | translate }}</span>\n </div>\n }\n\n <!-- NAV ARROWS ............................................. -->\n @if (_stage === 'ready' && _images.length > 1) {\n <button\n type=\"button\"\n class=\"sd-preview-nav sd-preview-nav--prev\"\n [disabled]=\"!hasPrev()\"\n [attr.aria-label]=\"'core.component.preview-image.prev' | translate\"\n [attr.data-autoId]=\"autoIdPrev()\"\n (click)=\"updateCurrentImage(-1)\">\n <mat-icon fontIcon=\"chevron_left\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-nav sd-preview-nav--next\"\n [disabled]=\"!hasNext()\"\n [attr.aria-label]=\"'core.component.preview-image.next' | translate\"\n [attr.data-autoId]=\"autoIdNext()\"\n (click)=\"updateCurrentImage(1)\">\n <mat-icon fontIcon=\"chevron_right\"></mat-icon>\n </button>\n }\n\n <!-- DOTS INDICATOR ......................................... -->\n @if (_thumbnailPosition === 'dots' && _stage === 'ready' && _images.length > 1) {\n <div class=\"sd-preview-dots\" role=\"tablist\">\n @for (img of _images; track img.id; let i = $index) {\n <button\n type=\"button\"\n class=\"sd-preview-dot\"\n [class.sd-preview-dot--active]=\"i === _activeIndex\"\n [attr.aria-label]=\"'core.component.preview-image.next' | translate\"\n [attr.data-autoId]=\"autoIdDot(i)\"\n (click)=\"onClickThumbnailImage(i)\"></button>\n }\n </div>\n }\n\n <!-- FLOATING TOOLBAR ....................................... -->\n @if (showToolbar() && _stage === 'ready') {\n <div class=\"sd-preview-toolbar\" role=\"toolbar\">\n @if (zoomable()) {\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.zoom-out' | translate\"\n [attr.title]=\"'core.component.preview-image.zoom-out' | translate\"\n [attr.data-autoId]=\"autoIdZoomOut()\"\n (click)=\"zoomOut()\">\n <mat-icon fontIcon=\"zoom_out\"></mat-icon>\n </button>\n <span class=\"sd-preview-toolbar__readout\">{{ zoomPercent() }}%</span>\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.zoom-in' | translate\"\n [attr.title]=\"'core.component.preview-image.zoom-in' | translate\"\n [attr.data-autoId]=\"autoIdZoomIn()\"\n (click)=\"zoomIn()\">\n <mat-icon fontIcon=\"zoom_in\"></mat-icon>\n </button>\n <span class=\"sd-preview-toolbar__divider\"></span>\n }\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn sd-preview-toolbar__btn--with-label\"\n [attr.aria-label]=\"'core.component.preview-image.fit' | translate\"\n [attr.data-autoId]=\"autoIdFit()\"\n (click)=\"fitToScreen()\">\n <mat-icon fontIcon=\"fit_screen\"></mat-icon>\n <span class=\"sd-preview-toolbar__btn-label\">{{ 'core.component.preview-image.fit' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.rotate' | translate\"\n [attr.title]=\"'core.component.preview-image.rotate' | translate\"\n [attr.data-autoId]=\"autoIdRotate()\"\n (click)=\"rotate('right')\">\n <mat-icon fontIcon=\"rotate_right\"></mat-icon>\n </button>\n <span class=\"sd-preview-toolbar__divider\"></span>\n @if (downloadable()) {\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.download' | translate\"\n [attr.title]=\"'core.component.preview-image.download' | translate\"\n [attr.data-autoId]=\"autoIdDownload()\"\n (click)=\"downloadCurrent()\">\n <mat-icon fontIcon=\"download\"></mat-icon>\n </button>\n }\n <button\n type=\"button\"\n class=\"sd-preview-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-image.fullscreen' | translate\"\n [attr.title]=\"'core.component.preview-image.fullscreen' | translate\"\n [attr.data-autoId]=\"autoIdFullscreen()\"\n (click)=\"toggleFullscreen()\">\n <mat-icon [fontIcon]=\"isFullscreen() ? 'fullscreen_exit' : 'fullscreen'\"></mat-icon>\n </button>\n </div>\n }\n </div>\n\n <!-- THUMBNAIL STRIP .................................................... -->\n @if (\n _stage === 'ready' &&\n _images.length > 1 &&\n _thumbnailPosition !== 'none' &&\n _thumbnailPosition !== 'dots'\n ) {\n <div\n class=\"sd-preview-thumbs\"\n [class.sd-preview-thumbs--vertical]=\"_thumbnailPosition === 'left' || _thumbnailPosition === 'right'\">\n @for (img of _images; track trackByImage($index, img); let i = $index) {\n <button\n type=\"button\"\n class=\"sd-preview-thumb\"\n [class.sd-preview-thumb--active]=\"i === _activeIndex\"\n [id]=\"'sd-preview-thumb-' + i\"\n [attr.aria-label]=\"img.name\"\n [attr.aria-current]=\"i === _activeIndex ? 'true' : null\"\n [attr.data-autoId]=\"autoIdThumb(i)\"\n (click)=\"onClickThumbnailImage(i)\">\n @if (img.error) {\n <div class=\"sd-preview-thumb__broken\">\n <mat-icon fontIcon=\"broken_image\"></mat-icon>\n </div>\n } @else {\n <img class=\"sd-preview-thumb__img\" [src]=\"img.blobUrl || img.url\" [alt]=\"img.alt || img.name\" />\n }\n <span class=\"sd-preview-thumb__badge\">{{ i + 1 }}</span>\n @if (_thumbnailPosition === 'right' || _thumbnailPosition === 'left') {\n <span class=\"sd-preview-thumb__name\" [title]=\"img.name\">{{ img.name }}</span>\n }\n </button>\n }\n </div>\n }\n </div>\n</div>\n", styles: [":host{--sd-preview-shell-bg: #0d0e10;--sd-preview-shell-bg-2: #17191c;--sd-preview-panel-bg: rgba(15, 17, 20, .92);--sd-preview-divider: rgba(255, 255, 255, .08);--sd-preview-fg: #f5f6f7;--sd-preview-fg-muted: rgba(255, 255, 255, .6);--sd-preview-fg-subtle: rgba(255, 255, 255, .4);--sd-preview-accent: var(--sd-primary, #3b82f6);--sd-preview-accent-soft: rgba(59, 130, 246, .2);--sd-preview-danger: var(--sd-error, #ef4444);--sd-preview-success: var(--sd-success, #22c55e);--sd-preview-danger-soft: rgba(239, 68, 68, .1);--sd-preview-danger-border: rgba(239, 68, 68, .3);--sd-preview-hover-bg: rgba(255, 255, 255, .1);display:block;width:100%;height:100%;min-height:320px;outline:none}:host([data-theme=light]){--sd-preview-shell-bg: #f7f8fa;--sd-preview-shell-bg-2: #ffffff;--sd-preview-panel-bg: rgba(255, 255, 255, .94);--sd-preview-divider: rgba(0, 0, 0, .08);--sd-preview-fg: #1a1c1f;--sd-preview-fg-muted: rgba(0, 0, 0, .62);--sd-preview-fg-subtle: rgba(0, 0, 0, .42);--sd-preview-accent: var(--sd-primary, #1f49bf);--sd-preview-accent-soft: rgba(31, 73, 191, .18);--sd-preview-danger: var(--sd-error, #ef4444);--sd-preview-success: var(--sd-success, #22c55e);--sd-preview-danger-soft: rgba(239, 68, 68, .08);--sd-preview-danger-border: rgba(239, 68, 68, .25);--sd-preview-hover-bg: rgba(0, 0, 0, .06)}.sd-preview-shell{position:relative;display:flex;flex-direction:column;width:100%;height:100%;background:var(--sd-preview-shell-bg);color:var(--sd-preview-fg);border-radius:12px;overflow:hidden;box-shadow:0 30px 80px #0000008c,0 0 0 1px #ffffff0a;font-family:inherit}.sd-preview-shell--fullscreen{height:100vh;width:100vw;border-radius:0}:host(.sd-preview-image-host--fullscreen){width:100vw;height:100vh;min-height:0}.sd-preview-header{position:relative;display:flex;align-items:center;height:68px;padding:0 16px;background:var(--sd-preview-panel-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-bottom:1px solid var(--sd-preview-divider);flex:0 0 auto;z-index:2}.sd-preview-header--simple{justify-content:space-between}.sd-preview-header__left{display:flex;align-items:center;gap:12px;min-width:0;flex:1 1 auto}.sd-preview-header__icon{color:var(--sd-preview-fg-muted);font-size:20px;width:20px;height:20px}.sd-preview-header__meta{display:flex;flex-direction:column;min-width:0}.sd-preview-header__name{color:var(--sd-preview-fg);max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-preview-header__sub{font-size:12px;color:var(--sd-preview-fg-muted);margin-top:2px}.sd-preview-header__counter{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);font-size:13px;font-weight:500;color:var(--sd-preview-fg-muted);background:#ffffff14;padding:4px 12px;border-radius:999px;font-variant-numeric:tabular-nums}.sd-preview-body{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}.sd-preview-shell--pos-bottom .sd-preview-body{flex-direction:column}.sd-preview-shell--pos-top .sd-preview-body{flex-direction:column-reverse}.sd-preview-shell--pos-right .sd-preview-body{flex-direction:row}.sd-preview-shell--pos-left .sd-preview-body{flex-direction:row-reverse}.sd-preview-shell--pos-dots .sd-preview-body,.sd-preview-shell--pos-none .sd-preview-body{flex-direction:column}.sd-preview-stage{position:relative;flex:1 1 auto;min-height:0;min-width:0;background:var(--sd-preview-shell-bg);background-image:linear-gradient(45deg,rgba(255,255,255,.02) 25%,transparent 25%),linear-gradient(-45deg,rgba(255,255,255,.02) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(255,255,255,.02) 75%),linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.02) 75%);background-size:24px 24px;background-position:0 0,0 12px,12px -12px,-12px 0;display:flex;align-items:center;justify-content:center;overflow:hidden;touch-action:none;-webkit-user-select:none;user-select:none}.sd-preview-stage--dragging{cursor:grab}:host([data-theme=light]) .sd-preview-stage{background-image:linear-gradient(45deg,rgba(0,0,0,.015) 25%,transparent 25%),linear-gradient(-45deg,rgba(0,0,0,.015) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(0,0,0,.015) 75%),linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.015) 75%)}.sd-preview-image{max-width:100%;max-height:100%;object-fit:contain;transform-origin:center center;transition:transform .2s ease;will-change:transform;pointer-events:none}.sd-preview-caption{position:absolute;bottom:96px;left:50%;transform:translate(-50%);max-width:70%;padding:6px 12px;background:#0f1114b3;color:var(--sd-preview-fg);border-radius:8px;font-size:13px;text-align:center}.sd-preview-image-broken,.sd-preview-image-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;width:100%;max-width:480px;padding:24px;text-align:center}.sd-preview-nav{position:absolute;top:50%;transform:translateY(-50%);width:48px;height:48px;border-radius:999px;border:none;background:#14141699;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);color:var(--sd-preview-fg);display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 16px #0000004d;transition:background .12s;z-index:3}.sd-preview-nav mat-icon{font-size:28px;width:28px;height:28px}.sd-preview-nav:hover:not(:disabled){background:#ffffff2e}.sd-preview-nav:focus-visible{outline:2px solid var(--sd-preview-accent);outline-offset:2px}.sd-preview-nav:disabled{background:#ffffff0a;opacity:.35;cursor:not-allowed}.sd-preview-nav--prev{left:16px}.sd-preview-nav--next{right:16px}.sd-preview-toolbar{position:absolute;bottom:24px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:4px;padding:6px 8px;background:var(--sd-preview-panel-bg);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border:1px solid var(--sd-preview-divider);border-radius:12px;box-shadow:0 8px 30px #0006;z-index:3}.sd-preview-toolbar__btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:36px;height:36px;padding:0 8px;background:transparent;border:none;color:var(--sd-preview-fg);border-radius:8px;cursor:pointer;transition:background .12s}.sd-preview-toolbar__btn mat-icon{font-size:20px;width:20px;height:20px}.sd-preview-toolbar__btn--with-label{padding:0 12px}.sd-preview-toolbar__btn:hover:not(:disabled){background:var(--sd-preview-hover-bg)}.sd-preview-toolbar__btn:focus-visible{outline:2px solid var(--sd-preview-accent);outline-offset:2px}.sd-preview-toolbar__btn-label{font-size:13px;font-weight:500}.sd-preview-toolbar__readout{min-width:56px;text-align:center;color:var(--sd-preview-fg);font-size:13px;font-weight:500;font-variant-numeric:tabular-nums}.sd-preview-toolbar__divider{width:1px;height:20px;background:var(--sd-preview-divider);margin:0 4px}.sd-preview-thumbs{display:flex;gap:8px;padding:12px;background:var(--sd-preview-shell-bg-2);overflow:auto;flex:0 0 auto;flex-direction:row;height:116px}.sd-preview-thumbs--vertical{flex-direction:column;width:152px;height:100%}.sd-preview-thumb{position:relative;flex:0 0 auto;width:120px;height:76px;padding:0;border:none;background:transparent;border-radius:8px;outline:1px solid var(--sd-preview-divider);outline-offset:-1px;opacity:.7;overflow:hidden;cursor:pointer;transition:opacity .12s,outline-color .12s}.sd-preview-thumb:hover{opacity:1}.sd-preview-thumb--active{opacity:1;outline:2px solid var(--sd-preview-accent);outline-offset:-2px;box-shadow:inset 0 0 0 2px var(--sd-preview-accent)}.sd-preview-thumb:focus-visible{outline:2px solid var(--sd-preview-accent);outline-offset:2px}.sd-preview-thumb__img{width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}.sd-preview-thumb__broken{display:flex;align-items:center;justify-content:center;width:100%;height:100%;background:var(--sd-preview-danger-soft);color:var(--sd-preview-danger);pointer-events:none}.sd-preview-thumb__broken mat-icon{font-size:24px;width:24px;height:24px}.sd-preview-thumb__badge{position:absolute;top:4px;right:4px;background:#000000b3;color:#fff;font-size:10px;font-weight:600;padding:1px 5px;border-radius:4px;pointer-events:none}.sd-preview-thumb__name{position:absolute;left:0;right:0;bottom:0;padding:14px 6px 4px;color:var(--sd-preview-fg);font-size:11px;line-height:1.3;background:linear-gradient(to top,rgba(0,0,0,.85),transparent);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;pointer-events:none}.sd-preview-thumbs--vertical .sd-preview-thumb{width:128px}.sd-preview-dots{position:absolute;bottom:24px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:6px;z-index:3}.sd-preview-dot{width:8px;height:8px;border:none;background:#ffffff4d;border-radius:999px;padding:0;cursor:pointer;transition:width .18s,background .18s}.sd-preview-dot--active{width:24px;background:#f5f6f7}.sd-preview-dot:focus-visible{outline:2px solid var(--sd-preview-accent);outline-offset:2px}.sd-preview-status{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;text-align:center;padding:24px}.sd-preview-status__tile{width:96px;height:96px;border-radius:24px;display:flex;align-items:center;justify-content:center;border:1px solid var(--sd-preview-divider);background:#ffffff0d}.sd-preview-status__tile mat-icon{font-size:48px;width:48px;height:48px;color:var(--sd-preview-fg-subtle)}.sd-preview-status__tile--muted{background:#ffffff0d;border-color:var(--sd-preview-divider)}.sd-preview-status__tile--danger{background:var(--sd-preview-danger-soft);border-color:var(--sd-preview-danger-border)}.sd-preview-status__tile--danger mat-icon{color:var(--sd-preview-danger)}.sd-preview-status__title{font-size:16px;font-weight:500;color:var(--sd-preview-fg)}.sd-preview-status__hint{font-size:13px;color:var(--sd-preview-fg-muted);max-width:320px}.sd-preview-spinner{width:56px;height:56px;border-radius:999px;border:3px solid rgba(255,255,255,.08);border-top-color:var(--sd-preview-accent);animation:sd-preview-spin .9s linear infinite}@keyframes sd-preview-spin{to{transform:rotate(360deg)}}.sd-preview-btn-primary{display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 16px;background:var(--sd-preview-accent);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:filter .12s}.sd-preview-btn-primary mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-btn-primary:hover{filter:brightness(1.1)}.sd-preview-btn-primary:focus-visible{outline:2px solid #fff;outline-offset:2px}.sd-preview-kbd-hint{position:absolute;top:16px;left:16px;display:flex;align-items:center;gap:6px;z-index:2;pointer-events:none}.sd-preview-kbd{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 5px;border:1px solid var(--sd-preview-divider);background:#ffffff0a;color:var(--sd-preview-fg-muted);border-radius:4px;font:500 11px/1 ui-monospace,SFMono-Regular,Menlo,monospace}.sd-preview-kbd-text,.sd-preview-kbd-dot{font-size:11px;color:var(--sd-preview-fg-subtle)}.sd-preview-kbd-dot{margin:0 2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
643
643
|
}
|
|
644
644
|
_a$1 = SdPreviewImage;
|
|
645
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
645
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdPreviewImage, decorators: [{
|
|
646
646
|
type: Component,
|
|
647
647
|
args: [{ selector: 'sd-preview-image', standalone: true, imports: [CommonModule, MatIconModule, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
648
648
|
tabindex: '0',
|
|
@@ -1959,11 +1959,11 @@ class SdPreviewPdf {
|
|
|
1959
1959
|
};
|
|
1960
1960
|
img.src = dataUrl;
|
|
1961
1961
|
}
|
|
1962
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
1963
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: SdPreviewPdf, isStandalone: true, selector: "sd-preview-pdf", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, startPage: { classPropertyName: "startPage", publicName: "startPage", isSignal: true, isRequired: false, transformFunction: null }, initialZoom: { classPropertyName: "initialZoom", publicName: "initialZoom", isSignal: true, isRequired: false, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: false, transformFunction: null }, sidebarOpen: { classPropertyName: "sidebarOpen", publicName: "sidebarOpen", isSignal: true, isRequired: false, transformFunction: null }, scrollMode: { classPropertyName: "scrollMode", publicName: "scrollMode", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, downloadable: { classPropertyName: "downloadable", publicName: "downloadable", isSignal: true, isRequired: false, transformFunction: null }, password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, httpHeaders: { classPropertyName: "httpHeaders", publicName: "httpHeaders", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close", loaded: "loaded", pageChange: "pageChange", zoomChange: "zoomChange", download: "download", loadError: "loadError", searchChange: "searchChange" }, host: { attributes: { "tabindex": "0" }, listeners: { "keydown": "onKeyDown($event)" }, properties: { "attr.data-theme": "theme()", "class.sd-preview-pdf-host--fullscreen": "isFullscreen()" }, classAttribute: "sd-preview-pdf-host" }, viewQueries: [{ propertyName: "pageCanvasRef", first: true, predicate: ["pageCanvas"], descendants: true, isSignal: true }, { propertyName: "stageEl", first: true, predicate: ["stageRef"], descendants: true, isSignal: true }, { propertyName: "pageInputRef", first: true, predicate: ["pageInput"], descendants: true, isSignal: true }, { propertyName: "searchInputRef", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }, { propertyName: "thumbCanvases", predicate: ["thumbCanvas"], descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n sd-preview-pdf shell. Self-contained \u2014 sizes to its parent. Consumer wraps\n in <sd-modal>/<sd-side-drawer>/page section. Header + sidebar + stage +\n floating toolbar mirror Artboards A / C / E from the design handoff.\n-->\n<div class=\"sd-preview-pdf-shell\" role=\"region\">\n @let _stage = stage();\n @let _numPages = numPages();\n @let _activePage = activePage();\n @let _isSidebarOpen = isSidebarOpen();\n @let _searchBarOpen = searchBarOpen();\n @let _searchTerm = searchTerm();\n @let _searchTotal = searchTotal();\n\n <!-- ============================================\n HEADER BAR \u2014 hidden in empty + loading per design\n ============================================ -->\n @if (_stage === 'ready') {\n <div class=\"sd-preview-pdf-header\">\n <div class=\"sd-preview-pdf-header__left\">\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [class.sd-preview-pdf-iconbtn--active]=\"_isSidebarOpen\"\n [attr.aria-label]=\"'core.component.preview-pdf.toggle-sidebar' | translate\"\n [attr.title]=\"'core.component.preview-pdf.toggle-sidebar' | translate\"\n [attr.data-autoId]=\"autoIdSidebarToggle()\"\n (click)=\"toggleSidebar()\">\n <mat-icon fontIcon=\"menu\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-header__divider\"></span>\n <div class=\"sd-preview-pdf-fileicon\" aria-hidden=\"true\">PDF</div>\n <div class=\"sd-preview-pdf-header__meta\">\n <div class=\"sd-preview-pdf-header__name\" [title]=\"title() || filename()\">\n {{ title() || filename() }}\n </div>\n <div class=\"sd-preview-pdf-header__sub\">\n {{ 'core.component.preview-pdf.pages-count' | translate: { count: _numPages } }}\n </div>\n </div>\n </div>\n\n <div class=\"sd-preview-pdf-header__right\">\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [class.sd-preview-pdf-iconbtn--active]=\"_searchBarOpen\"\n [attr.aria-label]=\"'core.component.preview-pdf.search' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search' | translate\"\n [attr.data-autoId]=\"autoIdSearchToggle()\"\n (click)=\"searchBarOpen() ? closeSearch() : openSearch()\">\n <mat-icon fontIcon=\"search\"></mat-icon>\n </button>\n @if (downloadable()) {\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [attr.aria-label]=\"'core.component.preview-pdf.download' | translate\"\n [attr.title]=\"'core.component.preview-pdf.download' | translate\"\n [attr.data-autoId]=\"autoIdDownload()\"\n (click)=\"downloadFile()\">\n <mat-icon fontIcon=\"download\"></mat-icon>\n </button>\n }\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [attr.aria-label]=\"'core.component.preview-pdf.fullscreen' | translate\"\n [attr.title]=\"'core.component.preview-pdf.fullscreen' | translate\"\n [attr.data-autoId]=\"autoIdFullscreen()\"\n (click)=\"toggleFullscreen()\">\n <mat-icon [fontIcon]=\"isFullscreen() ? 'fullscreen_exit' : 'fullscreen'\"></mat-icon>\n </button>\n </div>\n </div>\n\n <!-- ============================================\n SEARCH BAR \u2014 between header + body, only when bar is open\n ============================================ -->\n @if (_searchBarOpen) {\n <div class=\"sd-preview-pdf-searchbar\" role=\"search\">\n <mat-icon class=\"sd-preview-pdf-searchbar__icon\" fontIcon=\"search\"></mat-icon>\n <input\n #searchInput\n type=\"text\"\n class=\"sd-preview-pdf-searchbar__input\"\n [attr.placeholder]=\"'core.component.preview-pdf.search-placeholder' | translate\"\n [value]=\"_searchTerm\"\n [attr.data-autoId]=\"autoIdSearchInput()\"\n (input)=\"onSearchInput($any($event.target).value)\" />\n <span class=\"sd-preview-pdf-searchbar__counter\" aria-live=\"polite\">\n {{ searchCurrent() }} / {{ _searchTotal }}\n </span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [disabled]=\"_searchTotal === 0\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-prev' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-prev' | translate\"\n [attr.data-autoId]=\"autoIdSearchPrev()\"\n (click)=\"searchPrev()\">\n <mat-icon fontIcon=\"keyboard_arrow_up\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [disabled]=\"_searchTotal === 0\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-next' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-next' | translate\"\n [attr.data-autoId]=\"autoIdSearchNext()\"\n (click)=\"searchNext()\">\n <mat-icon fontIcon=\"keyboard_arrow_down\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-searchbar__divider\"></span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [class.sd-preview-pdf-iconbtn--active]=\"searchCaseSensitive()\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-case' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-case' | translate\"\n [attr.data-autoId]=\"autoIdSearchCase()\"\n (click)=\"toggleSearchCaseSensitive()\">\n <mat-icon fontIcon=\"match_case\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [class.sd-preview-pdf-iconbtn--active]=\"searchWholeWord()\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-whole' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-whole' | translate\"\n [attr.data-autoId]=\"autoIdSearchWhole()\"\n (click)=\"toggleSearchWholeWord()\">\n <mat-icon fontIcon=\"text_fields\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-searchbar__spacer\"></span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-close' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-close' | translate\"\n [attr.data-autoId]=\"autoIdSearchClose()\"\n (click)=\"closeSearch()\">\n <mat-icon fontIcon=\"close\"></mat-icon>\n </button>\n </div>\n }\n }\n\n <!-- ============================================\n BODY \u2014 sidebar + stage\n ============================================ -->\n <div class=\"sd-preview-pdf-body\">\n\n <!-- SIDEBAR ............................................................. -->\n @if (_stage === 'ready' && _isSidebarOpen) {\n <aside class=\"sd-preview-pdf-sidebar\" role=\"complementary\">\n @let _sidebarMode = sidebarMode();\n <div class=\"sd-preview-pdf-sidebar__tabs\" role=\"tablist\">\n <button\n type=\"button\"\n class=\"sd-preview-pdf-sidebar__tab\"\n role=\"tab\"\n [class.sd-preview-pdf-sidebar__tab--active]=\"_sidebarMode === 'thumbnails'\"\n [attr.data-autoId]=\"autoIdTabThumbnails()\"\n (click)=\"setSidebarMode('thumbnails')\">\n <mat-icon fontIcon=\"view_carousel\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.tab.thumbnails' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-sidebar__tab\"\n role=\"tab\"\n [class.sd-preview-pdf-sidebar__tab--active]=\"_sidebarMode === 'outline'\"\n [attr.data-autoId]=\"autoIdTabOutline()\"\n (click)=\"setSidebarMode('outline')\">\n <mat-icon fontIcon=\"list\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.tab.outline' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-sidebar__tab\"\n role=\"tab\"\n [class.sd-preview-pdf-sidebar__tab--active]=\"_sidebarMode === 'search'\"\n [attr.data-autoId]=\"autoIdTabSearch()\"\n (click)=\"setSidebarMode('search')\">\n <mat-icon fontIcon=\"search\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.tab.search' | translate }}</span>\n </button>\n </div>\n\n <div class=\"sd-preview-pdf-sidebar__content\">\n @switch (_sidebarMode) {\n @case ('thumbnails') {\n <ul class=\"sd-preview-pdf-thumb-list\">\n @for (p of pageNumbers(); track trackByPage($index, p); let pi = $index) {\n <li>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-thumb\"\n [class.sd-preview-pdf-thumb--active]=\"p === _activePage\"\n [attr.aria-current]=\"p === _activePage ? 'page' : null\"\n [attr.aria-label]=\"('core.component.preview-pdf.page-of' | translate: { current: p, total: _numPages })\"\n [attr.data-autoId]=\"autoIdThumb(pi)\"\n (click)=\"goToPage(p)\">\n <div class=\"sd-preview-pdf-thumb__page\">\n <canvas\n #thumbCanvas\n class=\"sd-preview-pdf-thumb__canvas\"\n [attr.data-page]=\"p\"\n aria-hidden=\"true\"></canvas>\n </div>\n <span class=\"sd-preview-pdf-thumb__label\">{{ p }}</span>\n </button>\n </li>\n }\n </ul>\n }\n @case ('outline') {\n <!-- TODO(preview-pdf): outline tree (pdfDoc.getOutline()) deferred to follow-up commit. -->\n <div class=\"sd-preview-pdf-sidebar__deferred\">\n <mat-icon fontIcon=\"list\"></mat-icon>\n <p>{{ 'core.component.preview-pdf.deferred.outline' | translate }}</p>\n </div>\n }\n @case ('search') {\n @if (!_searchTerm) {\n <div class=\"sd-preview-pdf-sidebar__deferred\">\n <mat-icon fontIcon=\"search\"></mat-icon>\n <p>{{ 'core.component.preview-pdf.search-placeholder' | translate }}</p>\n </div>\n } @else if (_searchTotal === 0) {\n <div class=\"sd-preview-pdf-sidebar__deferred\">\n <mat-icon fontIcon=\"search_off\"></mat-icon>\n <p>{{ 'core.component.preview-pdf.search-no-results' | translate }}</p>\n </div>\n } @else {\n <ul class=\"sd-preview-pdf-search-list\">\n @for (r of searchResults(); track $index; let i = $index) {\n <li>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-search-result\"\n [class.sd-preview-pdf-search-result--active]=\"i === searchActiveIndex()\"\n [attr.data-autoId]=\"autoIdResult(i)\"\n (click)=\"goToPage(r.page)\">\n <span class=\"sd-preview-pdf-search-result__snippet\">\n {{ r.before }}<mark>{{ r.term }}</mark>{{ r.after }}\n </span>\n <span class=\"sd-preview-pdf-search-result__page\">{{ r.page }}</span>\n </button>\n </li>\n }\n </ul>\n }\n }\n @default {\n <div class=\"sd-preview-pdf-sidebar__deferred\"></div>\n }\n }\n </div>\n </aside>\n }\n\n <!-- STAGE ............................................................... -->\n <div class=\"sd-preview-pdf-stage\" #stageRef (wheel)=\"onWheel($event)\">\n @switch (_stage) {\n @case ('empty') {\n <div class=\"sd-preview-pdf-status\">\n <div class=\"sd-preview-pdf-status__tile sd-preview-pdf-status__tile--muted\">\n <mat-icon fontIcon=\"picture_as_pdf\"></mat-icon>\n </div>\n <div class=\"sd-preview-pdf-status__title\">\n {{ 'core.component.preview-pdf.empty.title' | translate }}\n </div>\n <div class=\"sd-preview-pdf-status__hint\">\n {{ 'core.component.preview-pdf.empty.subtitle' | translate }}\n </div>\n </div>\n }\n @case ('loading') {\n @let _loadPercent = loadPercent();\n <div class=\"sd-preview-pdf-status\">\n <div class=\"sd-preview-pdf-spinner\" role=\"progressbar\"></div>\n <div class=\"sd-preview-pdf-status__title\">\n {{ 'core.component.preview-pdf.loading' | translate }}\n @if (_loadPercent > 0) {\n <span class=\"sd-preview-pdf-progress-pct\"> {{ _loadPercent }}%</span>\n }\n </div>\n <div class=\"sd-preview-pdf-progress\">\n <div class=\"sd-preview-pdf-progress__fill\" [style.width.%]=\"_loadPercent\"></div>\n </div>\n </div>\n }\n @case ('error') {\n @if (loadError$(); as err) {\n <div class=\"sd-preview-pdf-status\">\n <div class=\"sd-preview-pdf-status__tile sd-preview-pdf-status__tile--danger\">\n <mat-icon fontIcon=\"error_outline\"></mat-icon>\n </div>\n <div class=\"sd-preview-pdf-status__title\">\n {{ ('core.component.preview-pdf.error.' + err.reason + '.title') | translate }}\n </div>\n <div class=\"sd-preview-pdf-status__hint\">\n {{ ('core.component.preview-pdf.error.' + err.reason + '.body') | translate }}\n </div>\n <div class=\"sd-preview-pdf-status__actions\">\n <button type=\"button\" class=\"sd-preview-pdf-btn-primary\" (click)=\"retryLoad()\" [attr.data-autoId]=\"autoIdRetry()\">\n <mat-icon fontIcon=\"refresh\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.error.retry' | translate }}</span>\n </button>\n @if (downloadable()) {\n <button type=\"button\" class=\"sd-preview-pdf-btn-secondary\" (click)=\"downloadFile()\">\n <mat-icon fontIcon=\"download\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.error.download-raw' | translate }}</span>\n </button>\n }\n </div>\n </div>\n }\n }\n @default {\n <div class=\"sd-preview-pdf-page-wrap\">\n <canvas\n #pageCanvas\n class=\"sd-preview-pdf-page\"\n role=\"img\"\n [attr.aria-label]=\"('core.component.preview-pdf.page-of' | translate: { current: _activePage, total: _numPages })\">\n </canvas>\n </div>\n }\n }\n\n <!-- FLOATING TOOLBAR ........................................ -->\n @if (showToolbar() && _stage === 'ready') {\n @let _canPrev = canPrev();\n @let _canNext = canNext();\n @let _zoomMode = zoomMode();\n @let _scrollModeCurrent = scrollModeCurrent();\n <div class=\"sd-preview-pdf-toolbar\" role=\"toolbar\">\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [disabled]=\"!_canPrev\"\n [attr.aria-label]=\"'core.component.preview-pdf.first-page' | translate\"\n [attr.title]=\"'core.component.preview-pdf.first-page' | translate\"\n [attr.data-autoId]=\"autoIdFirst()\"\n (click)=\"firstPage()\">\n <mat-icon fontIcon=\"first_page\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [disabled]=\"!_canPrev\"\n [attr.aria-label]=\"'core.component.preview-pdf.prev-page' | translate\"\n [attr.title]=\"'core.component.preview-pdf.prev-page' | translate\"\n [attr.data-autoId]=\"autoIdPrev()\"\n (click)=\"prevPage()\">\n <mat-icon fontIcon=\"chevron_left\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-toolbar__page\">\n <input\n type=\"text\"\n inputmode=\"numeric\"\n class=\"sd-preview-pdf-toolbar__page-input\"\n [value]=\"_activePage\"\n #pageInput\n (keydown.enter)=\"onPageInputEnter($event)\"\n (blur)=\"onPageInputBlur($event)\"\n [attr.aria-label]=\"'core.component.preview-pdf.page-of' | translate: { current: _activePage, total: _numPages }\"\n [attr.data-autoId]=\"autoIdPageInput()\" />\n <span class=\"sd-preview-pdf-toolbar__page-total\">/ {{ _numPages }}</span>\n </span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [disabled]=\"!_canNext\"\n [attr.aria-label]=\"'core.component.preview-pdf.next-page' | translate\"\n [attr.title]=\"'core.component.preview-pdf.next-page' | translate\"\n [attr.data-autoId]=\"autoIdNext()\"\n (click)=\"nextPage()\">\n <mat-icon fontIcon=\"chevron_right\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [disabled]=\"!_canNext\"\n [attr.aria-label]=\"'core.component.preview-pdf.last-page' | translate\"\n [attr.title]=\"'core.component.preview-pdf.last-page' | translate\"\n [attr.data-autoId]=\"autoIdLast()\"\n (click)=\"lastPage()\">\n <mat-icon fontIcon=\"last_page\"></mat-icon>\n </button>\n\n <span class=\"sd-preview-pdf-toolbar__divider\"></span>\n\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-pdf.zoom-out' | translate\"\n [attr.title]=\"'core.component.preview-pdf.zoom-out' | translate\"\n [attr.data-autoId]=\"autoIdZoomOut()\"\n (click)=\"zoomOut()\">\n <mat-icon fontIcon=\"remove\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-toolbar__zoom\" aria-live=\"polite\" [attr.data-autoId]=\"autoIdZoomReadout()\">{{ zoomPercent() }}%</span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-pdf.zoom-in' | translate\"\n [attr.title]=\"'core.component.preview-pdf.zoom-in' | translate\"\n [attr.data-autoId]=\"autoIdZoomIn()\"\n (click)=\"zoomIn()\">\n <mat-icon fontIcon=\"add\"></mat-icon>\n </button>\n\n <span class=\"sd-preview-pdf-toolbar__divider\"></span>\n\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn sd-preview-pdf-toolbar__btn--with-label\"\n [class.sd-preview-pdf-toolbar__btn--active]=\"_zoomMode === 'page-fit'\"\n [attr.data-autoId]=\"autoIdFitPage()\"\n (click)=\"setZoom('page-fit')\">\n <mat-icon fontIcon=\"fit_screen\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.fit-page' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn sd-preview-pdf-toolbar__btn--with-label\"\n [class.sd-preview-pdf-toolbar__btn--active]=\"_zoomMode === 'page-width'\"\n [attr.data-autoId]=\"autoIdFitWidth()\"\n (click)=\"setZoom('page-width')\">\n <mat-icon fontIcon=\"swap_horiz\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.fit-width' | translate }}</span>\n </button>\n\n <span class=\"sd-preview-pdf-toolbar__divider\"></span>\n\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-pdf.rotate' | translate\"\n [attr.title]=\"'core.component.preview-pdf.rotate' | translate\"\n [attr.data-autoId]=\"autoIdRotate()\"\n (click)=\"rotate('right')\">\n <mat-icon fontIcon=\"rotate_right\"></mat-icon>\n </button>\n\n <!-- TODO(preview-pdf): scroll mode toggle is signature-only;\n clicking switches the state but rendering stays single-page\n until the continuous scroll feature lands. -->\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn sd-preview-pdf-toolbar__btn--with-label\"\n [attr.data-autoId]=\"autoIdScrollMode()\"\n (click)=\"setScrollMode(_scrollModeCurrent === 'page' ? 'continuous' : 'page')\">\n <mat-icon [fontIcon]=\"_scrollModeCurrent === 'page' ? 'description' : 'view_day'\"></mat-icon>\n <span>\n {{ (_scrollModeCurrent === 'page'\n ? 'core.component.preview-pdf.scroll-page'\n : 'core.component.preview-pdf.scroll-continuous') | translate }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [":host{--sd-pdf-shell-bg: #1a1c1f;--sd-pdf-sidebar-bg: #22252a;--sd-pdf-toolbar-bg: rgba(20, 22, 25, .94);--sd-pdf-page-bg: #ffffff;--sd-pdf-page-shadow: 0 4px 16px rgba(0, 0, 0, .4);--sd-pdf-divider: rgba(255, 255, 255, .08);--sd-pdf-fg: #f5f6f7;--sd-pdf-fg-muted: rgba(255, 255, 255, .6);--sd-pdf-fg-subtle: rgba(255, 255, 255, .4);--sd-pdf-accent: var(--sd-primary, #3b82f6);--sd-pdf-accent-soft: rgba(59, 130, 246, .2);--sd-pdf-danger: var(--sd-error, #ef4444);--sd-pdf-success: var(--sd-success, #22c55e);--sd-pdf-danger-soft: rgba(239, 68, 68, .1);--sd-pdf-danger-border: rgba(239, 68, 68, .3);--sd-pdf-danger-tint: rgba(239, 68, 68, .15);--sd-pdf-hover-bg: rgba(255, 255, 255, .1);--sd-pdf-search-hi: rgba(250, 204, 21, .55);--sd-pdf-search-hi-active: rgba(249, 115, 22, .85);display:block;width:100%;height:100%;min-height:320px;outline:none}:host([data-theme=light]){--sd-pdf-shell-bg: #f7f8fa;--sd-pdf-sidebar-bg: #ffffff;--sd-pdf-toolbar-bg: rgba(255, 255, 255, .94);--sd-pdf-page-bg: #ffffff;--sd-pdf-page-shadow: 0 4px 16px rgba(0, 0, 0, .12);--sd-pdf-divider: rgba(0, 0, 0, .08);--sd-pdf-fg: #1a1c1f;--sd-pdf-fg-muted: rgba(0, 0, 0, .62);--sd-pdf-fg-subtle: rgba(0, 0, 0, .42);--sd-pdf-accent: var(--sd-primary, #1f49bf);--sd-pdf-accent-soft: rgba(31, 73, 191, .18);--sd-pdf-danger: var(--sd-error, #ef4444);--sd-pdf-success: var(--sd-success, #22c55e);--sd-pdf-danger-soft: rgba(239, 68, 68, .08);--sd-pdf-danger-border: rgba(239, 68, 68, .25);--sd-pdf-danger-tint: rgba(239, 68, 68, .12);--sd-pdf-hover-bg: rgba(0, 0, 0, .06);--sd-pdf-search-hi: rgba(250, 204, 21, .55);--sd-pdf-search-hi-active: rgba(250, 204, 21, .9)}:host(.sd-preview-pdf-host--fullscreen){width:100vw;height:100vh;min-height:0}.sd-preview-pdf-shell{position:relative;display:flex;flex-direction:column;width:100%;height:100%;background:var(--sd-pdf-shell-bg);color:var(--sd-pdf-fg);border-radius:12px;overflow:hidden;box-shadow:0 30px 80px #0000008c,0 0 0 1px #ffffff0a;font-family:inherit}.sd-preview-pdf-header{display:flex;align-items:center;justify-content:space-between;gap:12px;height:57px;padding:0 12px;background:var(--sd-pdf-toolbar-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-bottom:1px solid var(--sd-pdf-divider);flex:0 0 auto;z-index:2}.sd-preview-pdf-header__left{display:flex;align-items:center;gap:8px;min-width:0;flex:1 1 auto}.sd-preview-pdf-header__right{display:flex;align-items:center;gap:4px;flex-shrink:0}.sd-preview-pdf-header__divider{display:inline-block;width:1px;height:20px;background:var(--sd-pdf-divider)}.sd-preview-pdf-header__meta{display:flex;flex-direction:column;min-width:0}.sd-preview-pdf-header__name{font-size:14px;font-weight:500;color:var(--sd-pdf-fg);max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-preview-pdf-header__sub{font-size:11px;color:var(--sd-pdf-fg-muted);margin-top:2px}.sd-preview-pdf-fileicon{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:6px;background:var(--sd-pdf-danger-tint);border:1px solid var(--sd-pdf-danger-border);color:var(--sd-error-light, #f87171);font:700 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace}.sd-preview-pdf-iconbtn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:32px;height:32px;padding:0 8px;background:transparent;border:none;color:var(--sd-pdf-fg);border-radius:6px;cursor:pointer;transition:background .12s,color .12s;white-space:nowrap;flex-shrink:0}.sd-preview-pdf-iconbtn mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-pdf-iconbtn__label{font-size:13px;font-weight:500}.sd-preview-pdf-iconbtn:hover:not(:disabled){background:var(--sd-pdf-hover-bg)}.sd-preview-pdf-iconbtn:focus-visible{outline:2px solid var(--sd-pdf-accent);outline-offset:2px}.sd-preview-pdf-iconbtn:disabled{opacity:.35;cursor:not-allowed}.sd-preview-pdf-iconbtn--active{background:var(--sd-pdf-accent-soft);color:var(--sd-pdf-accent)}.sd-preview-pdf-searchbar{display:flex;align-items:center;gap:6px;height:46px;padding:0 12px;background:var(--sd-pdf-toolbar-bg);border-bottom:1px solid var(--sd-pdf-divider);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);flex:0 0 auto;z-index:2}.sd-preview-pdf-searchbar__icon{color:var(--sd-pdf-fg-muted);font-size:18px;width:18px;height:18px;flex-shrink:0}.sd-preview-pdf-searchbar__input{flex:0 1 360px;min-width:160px;height:30px;background:#ffffff0f;border:1px solid rgba(255,255,255,.08);color:var(--sd-pdf-fg);border-radius:6px;padding:0 10px;font-size:13px;outline:none}.sd-preview-pdf-searchbar__input::placeholder{color:var(--sd-pdf-fg-subtle)}.sd-preview-pdf-searchbar__input:focus{border-color:var(--sd-pdf-accent);background:#ffffff17}.sd-preview-pdf-searchbar__counter{color:var(--sd-pdf-fg-muted);font-size:12px;font-variant-numeric:tabular-nums;min-width:48px;text-align:center;flex-shrink:0}.sd-preview-pdf-searchbar__divider{width:1px;height:20px;background:var(--sd-pdf-divider);flex-shrink:0}.sd-preview-pdf-searchbar__spacer{flex:1 1 auto}.sd-pdf-search-overlay{position:absolute;top:8px;left:50%;transform:translate(-50%);display:flex;flex-wrap:wrap;gap:4px;max-width:80%;pointer-events:none;z-index:5}.sd-pdf-search-hi{display:inline-block;padding:1px 4px;border-radius:2px;background:var(--sd-pdf-search-hi);color:#000;font-size:12px;font-weight:500}.sd-pdf-search-hi--active{background:var(--sd-pdf-search-hi-active);color:#fff;box-shadow:0 0 0 2px #fff6}.sd-preview-pdf-body{position:relative;flex:1 1 auto;min-height:0;display:flex;flex-direction:row;overflow:hidden}.sd-preview-pdf-sidebar{width:240px;display:flex;flex-direction:column;background:var(--sd-pdf-sidebar-bg);border-right:1px solid var(--sd-pdf-divider);flex-shrink:0;min-height:0}.sd-preview-pdf-sidebar__tabs{display:flex;gap:4px;padding:8px;border-bottom:1px solid var(--sd-pdf-divider)}.sd-preview-pdf-sidebar__tab{flex:1 1 0;display:inline-flex;align-items:center;justify-content:center;gap:4px;height:32px;padding:0 4px;background:transparent;border:none;color:var(--sd-pdf-fg-muted);border-radius:6px;cursor:pointer;font-size:12px;font-weight:500;white-space:nowrap;flex-shrink:0;transition:background .12s,color .12s}.sd-preview-pdf-sidebar__tab mat-icon{font-size:14px;width:14px;height:14px}.sd-preview-pdf-sidebar__tab:hover{background:#ffffff0f;color:var(--sd-pdf-fg)}.sd-preview-pdf-sidebar__tab--active{background:var(--sd-pdf-accent-soft);color:var(--sd-pdf-accent)}.sd-preview-pdf-sidebar__content{flex:1 1 auto;overflow:auto;padding:12px}.sd-preview-pdf-sidebar__deferred{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:32px 16px;text-align:center;color:var(--sd-pdf-fg-subtle)}.sd-preview-pdf-sidebar__deferred mat-icon{font-size:28px;width:28px;height:28px;opacity:.6}.sd-preview-pdf-sidebar__deferred p{margin:0;font-size:12px;line-height:1.5}.sd-preview-pdf-thumb-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}.sd-preview-pdf-thumb{display:flex;flex-direction:column;align-items:center;gap:4px;width:100%;padding:0;background:transparent;border:none;cursor:pointer}.sd-preview-pdf-thumb__page{width:152px;aspect-ratio:612/792;background:var(--sd-pdf-page-bg);border-radius:2px;outline:1px solid rgba(255,255,255,.08);outline-offset:-1px;box-shadow:0 2px 6px #0000004d;display:flex;align-items:center;justify-content:center;overflow:hidden;-webkit-user-select:none;user-select:none;background-image:linear-gradient(90deg,#0000,#0000000a,#0000);background-size:200% 100%;animation:sd-preview-pdf-thumb-skel 1.6s ease-in-out infinite}.sd-preview-pdf-thumb__canvas{display:block;max-width:100%;max-height:100%;background:var(--sd-pdf-page-bg)}.sd-preview-pdf-thumb__label{font-size:11px;color:var(--sd-pdf-fg-muted);font-variant-numeric:tabular-nums}.sd-preview-pdf-thumb--active .sd-preview-pdf-thumb__page{outline:2px solid var(--sd-pdf-accent);outline-offset:-2px}.sd-preview-pdf-thumb--active .sd-preview-pdf-thumb__label{color:var(--sd-pdf-accent);font-weight:600}.sd-preview-pdf-thumb:focus-visible .sd-preview-pdf-thumb__page{outline:2px solid var(--sd-pdf-accent);outline-offset:2px}.sd-preview-pdf-stage{position:relative;flex:1 1 auto;min-width:0;min-height:0;background:var(--sd-pdf-shell-bg);background-image:linear-gradient(45deg,rgba(255,255,255,.015) 25%,transparent 25%),linear-gradient(-45deg,rgba(255,255,255,.015) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(255,255,255,.015) 75%),linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.015) 75%);background-size:24px 24px;background-position:0 0,0 12px,12px -12px,-12px 0;overflow:auto;padding:32px 24px 96px;display:flex;justify-content:center;align-items:flex-start}:host([data-theme=light]) .sd-preview-pdf-stage{background-image:linear-gradient(45deg,rgba(0,0,0,.015) 25%,transparent 25%),linear-gradient(-45deg,rgba(0,0,0,.015) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(0,0,0,.015) 75%),linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.015) 75%)}.sd-preview-pdf-page-wrap{display:inline-block;position:relative}.sd-preview-pdf-page{display:block;background:var(--sd-pdf-page-bg);border-radius:2px;box-shadow:var(--sd-pdf-page-shadow);max-width:100%}.sd-preview-pdf-toolbar{position:absolute;bottom:20px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:2px;padding:5px 6px;background:var(--sd-pdf-toolbar-bg);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border:1px solid var(--sd-pdf-divider);border-radius:10px;box-shadow:0 8px 30px #0006;z-index:4;max-width:calc(100% - 32px);overflow-x:auto}.sd-preview-pdf-toolbar__btn{display:inline-flex;align-items:center;justify-content:center;gap:4px;min-width:30px;height:28px;padding:0 6px;background:transparent;border:none;color:var(--sd-pdf-fg);border-radius:6px;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background .12s,color .12s}.sd-preview-pdf-toolbar__btn mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-pdf-toolbar__btn span{font-size:13px;font-weight:500}.sd-preview-pdf-toolbar__btn--with-label{padding:0 10px}.sd-preview-pdf-toolbar__btn--active{background:var(--sd-pdf-accent-soft);color:var(--sd-pdf-accent)}.sd-preview-pdf-toolbar__btn:hover:not(:disabled):not(.sd-preview-pdf-toolbar__btn--active){background:var(--sd-pdf-hover-bg)}.sd-preview-pdf-toolbar__btn:focus-visible{outline:2px solid var(--sd-pdf-accent);outline-offset:2px}.sd-preview-pdf-toolbar__btn:disabled{opacity:.35;cursor:not-allowed}.sd-preview-pdf-toolbar__page{display:inline-flex;align-items:center;gap:4px;padding:0 6px;flex-shrink:0}.sd-preview-pdf-toolbar__page-input{width:36px;height:24px;background:#ffffff14;border:1px solid rgba(255,255,255,.08);color:var(--sd-pdf-fg);border-radius:4px;text-align:center;font-size:13px;font-variant-numeric:tabular-nums;outline:none}.sd-preview-pdf-toolbar__page-input:focus{border-color:var(--sd-pdf-accent)}.sd-preview-pdf-toolbar__page-total{font-size:13px;color:var(--sd-pdf-fg-muted);font-variant-numeric:tabular-nums}.sd-preview-pdf-toolbar__zoom{min-width:56px;text-align:center;color:var(--sd-pdf-fg);font-size:13px;font-weight:500;font-variant-numeric:tabular-nums;background:#ffffff14;border-radius:4px;padding:2px 8px}.sd-preview-pdf-toolbar__divider{width:1px;height:20px;background:var(--sd-pdf-divider);margin:0 4px;flex-shrink:0}.sd-preview-pdf-status{margin:auto;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;text-align:center;padding:32px;max-width:420px}.sd-preview-pdf-status__tile{width:96px;height:96px;border-radius:24px;display:flex;align-items:center;justify-content:center;border:1px solid var(--sd-pdf-divider)}.sd-preview-pdf-status__tile mat-icon{font-size:48px;width:48px;height:48px}.sd-preview-pdf-status__tile--muted{background:#ffffff0d}.sd-preview-pdf-status__tile--muted mat-icon{color:var(--sd-pdf-fg-subtle)}.sd-preview-pdf-status__tile--danger{background:var(--sd-pdf-danger-soft);border-color:var(--sd-pdf-danger-border)}.sd-preview-pdf-status__tile--danger mat-icon{color:var(--sd-pdf-danger)}.sd-preview-pdf-status__title{font-size:16px;font-weight:500;color:var(--sd-pdf-fg)}.sd-preview-pdf-status__hint{font-size:13px;color:var(--sd-pdf-fg-muted);line-height:1.5}.sd-preview-pdf-status__actions{display:flex;gap:8px;margin-top:4px}.sd-preview-pdf-progress-pct{font-variant-numeric:tabular-nums;color:var(--sd-pdf-fg-muted)}.sd-preview-pdf-progress{width:240px;height:4px;background:#ffffff14;border-radius:999px;overflow:hidden}.sd-preview-pdf-progress__fill{height:100%;background:var(--sd-pdf-accent);transition:width .12s linear}.sd-preview-pdf-spinner{width:56px;height:56px;border-radius:999px;border:3px solid rgba(255,255,255,.08);border-top-color:var(--sd-pdf-accent);animation:sd-preview-pdf-spin .9s linear infinite}@keyframes sd-preview-pdf-spin{to{transform:rotate(360deg)}}@keyframes sd-preview-pdf-thumb-skel{0%{background-position:200% 0}to{background-position:-200% 0}}.sd-preview-pdf-search-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.sd-preview-pdf-search-result{width:100%;display:flex;align-items:flex-start;gap:8px;padding:8px 10px;background:#ffffff0a;border:1px solid transparent;border-radius:6px;color:var(--sd-pdf-fg);cursor:pointer;text-align:left;transition:background .12s,border-color .12s}.sd-preview-pdf-search-result:hover{background:#ffffff12}.sd-preview-pdf-search-result--active{background:var(--sd-pdf-accent-soft);border-color:#3b82f673}.sd-preview-pdf-search-result__snippet{flex:1 1 auto;font-size:12px;line-height:1.4;color:var(--sd-pdf-fg);word-break:break-word}.sd-preview-pdf-search-result__snippet mark{background:var(--sd-pdf-search-hi);color:#000;padding:0 2px;border-radius:2px}.sd-preview-pdf-search-result__page{flex:0 0 auto;font-size:11px;font-variant-numeric:tabular-nums;color:var(--sd-pdf-fg-muted);background:#ffffff0f;padding:2px 6px;border-radius:4px}.sd-preview-pdf-btn-primary{display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 16px;background:var(--sd-pdf-accent);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:filter .12s}.sd-preview-pdf-btn-primary mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-pdf-btn-primary:hover{filter:brightness(1.1)}.sd-preview-pdf-btn-primary:focus-visible{outline:2px solid #fff;outline-offset:2px}.sd-preview-pdf-btn-secondary{display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 16px;background:transparent;color:var(--sd-pdf-fg);border:1px solid var(--sd-pdf-divider);border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:background .12s}.sd-preview-pdf-btn-secondary mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-pdf-btn-secondary:hover{background:#ffffff0f}.sd-preview-pdf-btn-secondary:focus-visible{outline:2px solid var(--sd-pdf-accent);outline-offset:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1962
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdPreviewPdf, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1963
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SdPreviewPdf, isStandalone: true, selector: "sd-preview-pdf", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, startPage: { classPropertyName: "startPage", publicName: "startPage", isSignal: true, isRequired: false, transformFunction: null }, initialZoom: { classPropertyName: "initialZoom", publicName: "initialZoom", isSignal: true, isRequired: false, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: false, transformFunction: null }, sidebarOpen: { classPropertyName: "sidebarOpen", publicName: "sidebarOpen", isSignal: true, isRequired: false, transformFunction: null }, scrollMode: { classPropertyName: "scrollMode", publicName: "scrollMode", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, downloadable: { classPropertyName: "downloadable", publicName: "downloadable", isSignal: true, isRequired: false, transformFunction: null }, password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, httpHeaders: { classPropertyName: "httpHeaders", publicName: "httpHeaders", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close", loaded: "loaded", pageChange: "pageChange", zoomChange: "zoomChange", download: "download", loadError: "loadError", searchChange: "searchChange" }, host: { attributes: { "tabindex": "0" }, listeners: { "keydown": "onKeyDown($event)" }, properties: { "attr.data-theme": "theme()", "class.sd-preview-pdf-host--fullscreen": "isFullscreen()" }, classAttribute: "sd-preview-pdf-host" }, viewQueries: [{ propertyName: "pageCanvasRef", first: true, predicate: ["pageCanvas"], descendants: true, isSignal: true }, { propertyName: "stageEl", first: true, predicate: ["stageRef"], descendants: true, isSignal: true }, { propertyName: "pageInputRef", first: true, predicate: ["pageInput"], descendants: true, isSignal: true }, { propertyName: "searchInputRef", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }, { propertyName: "thumbCanvases", predicate: ["thumbCanvas"], descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n sd-preview-pdf shell. Self-contained \u2014 sizes to its parent. Consumer wraps\n in <sd-modal>/<sd-side-drawer>/page section. Header + sidebar + stage +\n floating toolbar mirror Artboards A / C / E from the design handoff.\n-->\n<div class=\"sd-preview-pdf-shell\" role=\"region\">\n @let _stage = stage();\n @let _numPages = numPages();\n @let _activePage = activePage();\n @let _isSidebarOpen = isSidebarOpen();\n @let _searchBarOpen = searchBarOpen();\n @let _searchTerm = searchTerm();\n @let _searchTotal = searchTotal();\n\n <!-- ============================================\n HEADER BAR \u2014 hidden in empty + loading per design\n ============================================ -->\n @if (_stage === 'ready') {\n <div class=\"sd-preview-pdf-header\">\n <div class=\"sd-preview-pdf-header__left\">\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [class.sd-preview-pdf-iconbtn--active]=\"_isSidebarOpen\"\n [attr.aria-label]=\"'core.component.preview-pdf.toggle-sidebar' | translate\"\n [attr.title]=\"'core.component.preview-pdf.toggle-sidebar' | translate\"\n [attr.data-autoId]=\"autoIdSidebarToggle()\"\n (click)=\"toggleSidebar()\">\n <mat-icon fontIcon=\"menu\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-header__divider\"></span>\n <div class=\"sd-preview-pdf-fileicon\" aria-hidden=\"true\">PDF</div>\n <div class=\"sd-preview-pdf-header__meta\">\n <div class=\"sd-preview-pdf-header__name\" [title]=\"title() || filename()\">\n {{ title() || filename() }}\n </div>\n <div class=\"sd-preview-pdf-header__sub\">\n {{ 'core.component.preview-pdf.pages-count' | translate: { count: _numPages } }}\n </div>\n </div>\n </div>\n\n <div class=\"sd-preview-pdf-header__right\">\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [class.sd-preview-pdf-iconbtn--active]=\"_searchBarOpen\"\n [attr.aria-label]=\"'core.component.preview-pdf.search' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search' | translate\"\n [attr.data-autoId]=\"autoIdSearchToggle()\"\n (click)=\"searchBarOpen() ? closeSearch() : openSearch()\">\n <mat-icon fontIcon=\"search\"></mat-icon>\n </button>\n @if (downloadable()) {\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [attr.aria-label]=\"'core.component.preview-pdf.download' | translate\"\n [attr.title]=\"'core.component.preview-pdf.download' | translate\"\n [attr.data-autoId]=\"autoIdDownload()\"\n (click)=\"downloadFile()\">\n <mat-icon fontIcon=\"download\"></mat-icon>\n </button>\n }\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [attr.aria-label]=\"'core.component.preview-pdf.fullscreen' | translate\"\n [attr.title]=\"'core.component.preview-pdf.fullscreen' | translate\"\n [attr.data-autoId]=\"autoIdFullscreen()\"\n (click)=\"toggleFullscreen()\">\n <mat-icon [fontIcon]=\"isFullscreen() ? 'fullscreen_exit' : 'fullscreen'\"></mat-icon>\n </button>\n </div>\n </div>\n\n <!-- ============================================\n SEARCH BAR \u2014 between header + body, only when bar is open\n ============================================ -->\n @if (_searchBarOpen) {\n <div class=\"sd-preview-pdf-searchbar\" role=\"search\">\n <mat-icon class=\"sd-preview-pdf-searchbar__icon\" fontIcon=\"search\"></mat-icon>\n <input\n #searchInput\n type=\"text\"\n class=\"sd-preview-pdf-searchbar__input\"\n [attr.placeholder]=\"'core.component.preview-pdf.search-placeholder' | translate\"\n [value]=\"_searchTerm\"\n [attr.data-autoId]=\"autoIdSearchInput()\"\n (input)=\"onSearchInput($any($event.target).value)\" />\n <span class=\"sd-preview-pdf-searchbar__counter\" aria-live=\"polite\">\n {{ searchCurrent() }} / {{ _searchTotal }}\n </span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [disabled]=\"_searchTotal === 0\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-prev' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-prev' | translate\"\n [attr.data-autoId]=\"autoIdSearchPrev()\"\n (click)=\"searchPrev()\">\n <mat-icon fontIcon=\"keyboard_arrow_up\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [disabled]=\"_searchTotal === 0\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-next' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-next' | translate\"\n [attr.data-autoId]=\"autoIdSearchNext()\"\n (click)=\"searchNext()\">\n <mat-icon fontIcon=\"keyboard_arrow_down\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-searchbar__divider\"></span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [class.sd-preview-pdf-iconbtn--active]=\"searchCaseSensitive()\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-case' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-case' | translate\"\n [attr.data-autoId]=\"autoIdSearchCase()\"\n (click)=\"toggleSearchCaseSensitive()\">\n <mat-icon fontIcon=\"match_case\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [class.sd-preview-pdf-iconbtn--active]=\"searchWholeWord()\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-whole' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-whole' | translate\"\n [attr.data-autoId]=\"autoIdSearchWhole()\"\n (click)=\"toggleSearchWholeWord()\">\n <mat-icon fontIcon=\"text_fields\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-searchbar__spacer\"></span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-iconbtn\"\n [attr.aria-label]=\"'core.component.preview-pdf.search-close' | translate\"\n [attr.title]=\"'core.component.preview-pdf.search-close' | translate\"\n [attr.data-autoId]=\"autoIdSearchClose()\"\n (click)=\"closeSearch()\">\n <mat-icon fontIcon=\"close\"></mat-icon>\n </button>\n </div>\n }\n }\n\n <!-- ============================================\n BODY \u2014 sidebar + stage\n ============================================ -->\n <div class=\"sd-preview-pdf-body\">\n\n <!-- SIDEBAR ............................................................. -->\n @if (_stage === 'ready' && _isSidebarOpen) {\n <aside class=\"sd-preview-pdf-sidebar\" role=\"complementary\">\n @let _sidebarMode = sidebarMode();\n <div class=\"sd-preview-pdf-sidebar__tabs\" role=\"tablist\">\n <button\n type=\"button\"\n class=\"sd-preview-pdf-sidebar__tab\"\n role=\"tab\"\n [class.sd-preview-pdf-sidebar__tab--active]=\"_sidebarMode === 'thumbnails'\"\n [attr.data-autoId]=\"autoIdTabThumbnails()\"\n (click)=\"setSidebarMode('thumbnails')\">\n <mat-icon fontIcon=\"view_carousel\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.tab.thumbnails' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-sidebar__tab\"\n role=\"tab\"\n [class.sd-preview-pdf-sidebar__tab--active]=\"_sidebarMode === 'outline'\"\n [attr.data-autoId]=\"autoIdTabOutline()\"\n (click)=\"setSidebarMode('outline')\">\n <mat-icon fontIcon=\"list\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.tab.outline' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-sidebar__tab\"\n role=\"tab\"\n [class.sd-preview-pdf-sidebar__tab--active]=\"_sidebarMode === 'search'\"\n [attr.data-autoId]=\"autoIdTabSearch()\"\n (click)=\"setSidebarMode('search')\">\n <mat-icon fontIcon=\"search\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.tab.search' | translate }}</span>\n </button>\n </div>\n\n <div class=\"sd-preview-pdf-sidebar__content\">\n @switch (_sidebarMode) {\n @case ('thumbnails') {\n <ul class=\"sd-preview-pdf-thumb-list\">\n @for (p of pageNumbers(); track trackByPage($index, p); let pi = $index) {\n <li>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-thumb\"\n [class.sd-preview-pdf-thumb--active]=\"p === _activePage\"\n [attr.aria-current]=\"p === _activePage ? 'page' : null\"\n [attr.aria-label]=\"('core.component.preview-pdf.page-of' | translate: { current: p, total: _numPages })\"\n [attr.data-autoId]=\"autoIdThumb(pi)\"\n (click)=\"goToPage(p)\">\n <div class=\"sd-preview-pdf-thumb__page\">\n <canvas\n #thumbCanvas\n class=\"sd-preview-pdf-thumb__canvas\"\n [attr.data-page]=\"p\"\n aria-hidden=\"true\"></canvas>\n </div>\n <span class=\"sd-preview-pdf-thumb__label\">{{ p }}</span>\n </button>\n </li>\n }\n </ul>\n }\n @case ('outline') {\n <!-- TODO(preview-pdf): outline tree (pdfDoc.getOutline()) deferred to follow-up commit. -->\n <div class=\"sd-preview-pdf-sidebar__deferred\">\n <mat-icon fontIcon=\"list\"></mat-icon>\n <p>{{ 'core.component.preview-pdf.deferred.outline' | translate }}</p>\n </div>\n }\n @case ('search') {\n @if (!_searchTerm) {\n <div class=\"sd-preview-pdf-sidebar__deferred\">\n <mat-icon fontIcon=\"search\"></mat-icon>\n <p>{{ 'core.component.preview-pdf.search-placeholder' | translate }}</p>\n </div>\n } @else if (_searchTotal === 0) {\n <div class=\"sd-preview-pdf-sidebar__deferred\">\n <mat-icon fontIcon=\"search_off\"></mat-icon>\n <p>{{ 'core.component.preview-pdf.search-no-results' | translate }}</p>\n </div>\n } @else {\n <ul class=\"sd-preview-pdf-search-list\">\n @for (r of searchResults(); track $index; let i = $index) {\n <li>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-search-result\"\n [class.sd-preview-pdf-search-result--active]=\"i === searchActiveIndex()\"\n [attr.data-autoId]=\"autoIdResult(i)\"\n (click)=\"goToPage(r.page)\">\n <span class=\"sd-preview-pdf-search-result__snippet\">\n {{ r.before }}<mark>{{ r.term }}</mark>{{ r.after }}\n </span>\n <span class=\"sd-preview-pdf-search-result__page\">{{ r.page }}</span>\n </button>\n </li>\n }\n </ul>\n }\n }\n @default {\n <div class=\"sd-preview-pdf-sidebar__deferred\"></div>\n }\n }\n </div>\n </aside>\n }\n\n <!-- STAGE ............................................................... -->\n <div class=\"sd-preview-pdf-stage\" #stageRef (wheel)=\"onWheel($event)\">\n @switch (_stage) {\n @case ('empty') {\n <div class=\"sd-preview-pdf-status\">\n <div class=\"sd-preview-pdf-status__tile sd-preview-pdf-status__tile--muted\">\n <mat-icon fontIcon=\"picture_as_pdf\"></mat-icon>\n </div>\n <div class=\"sd-preview-pdf-status__title\">\n {{ 'core.component.preview-pdf.empty.title' | translate }}\n </div>\n <div class=\"sd-preview-pdf-status__hint\">\n {{ 'core.component.preview-pdf.empty.subtitle' | translate }}\n </div>\n </div>\n }\n @case ('loading') {\n @let _loadPercent = loadPercent();\n <div class=\"sd-preview-pdf-status\">\n <div class=\"sd-preview-pdf-spinner\" role=\"progressbar\"></div>\n <div class=\"sd-preview-pdf-status__title\">\n {{ 'core.component.preview-pdf.loading' | translate }}\n @if (_loadPercent > 0) {\n <span class=\"sd-preview-pdf-progress-pct\"> {{ _loadPercent }}%</span>\n }\n </div>\n <div class=\"sd-preview-pdf-progress\">\n <div class=\"sd-preview-pdf-progress__fill\" [style.width.%]=\"_loadPercent\"></div>\n </div>\n </div>\n }\n @case ('error') {\n @if (loadError$(); as err) {\n <div class=\"sd-preview-pdf-status\">\n <div class=\"sd-preview-pdf-status__tile sd-preview-pdf-status__tile--danger\">\n <mat-icon fontIcon=\"error_outline\"></mat-icon>\n </div>\n <div class=\"sd-preview-pdf-status__title\">\n {{ ('core.component.preview-pdf.error.' + err.reason + '.title') | translate }}\n </div>\n <div class=\"sd-preview-pdf-status__hint\">\n {{ ('core.component.preview-pdf.error.' + err.reason + '.body') | translate }}\n </div>\n <div class=\"sd-preview-pdf-status__actions\">\n <button type=\"button\" class=\"sd-preview-pdf-btn-primary\" (click)=\"retryLoad()\" [attr.data-autoId]=\"autoIdRetry()\">\n <mat-icon fontIcon=\"refresh\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.error.retry' | translate }}</span>\n </button>\n @if (downloadable()) {\n <button type=\"button\" class=\"sd-preview-pdf-btn-secondary\" (click)=\"downloadFile()\">\n <mat-icon fontIcon=\"download\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.error.download-raw' | translate }}</span>\n </button>\n }\n </div>\n </div>\n }\n }\n @default {\n <div class=\"sd-preview-pdf-page-wrap\">\n <canvas\n #pageCanvas\n class=\"sd-preview-pdf-page\"\n role=\"img\"\n [attr.aria-label]=\"('core.component.preview-pdf.page-of' | translate: { current: _activePage, total: _numPages })\">\n </canvas>\n </div>\n }\n }\n\n <!-- FLOATING TOOLBAR ........................................ -->\n @if (showToolbar() && _stage === 'ready') {\n @let _canPrev = canPrev();\n @let _canNext = canNext();\n @let _zoomMode = zoomMode();\n @let _scrollModeCurrent = scrollModeCurrent();\n <div class=\"sd-preview-pdf-toolbar\" role=\"toolbar\">\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [disabled]=\"!_canPrev\"\n [attr.aria-label]=\"'core.component.preview-pdf.first-page' | translate\"\n [attr.title]=\"'core.component.preview-pdf.first-page' | translate\"\n [attr.data-autoId]=\"autoIdFirst()\"\n (click)=\"firstPage()\">\n <mat-icon fontIcon=\"first_page\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [disabled]=\"!_canPrev\"\n [attr.aria-label]=\"'core.component.preview-pdf.prev-page' | translate\"\n [attr.title]=\"'core.component.preview-pdf.prev-page' | translate\"\n [attr.data-autoId]=\"autoIdPrev()\"\n (click)=\"prevPage()\">\n <mat-icon fontIcon=\"chevron_left\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-toolbar__page\">\n <input\n type=\"text\"\n inputmode=\"numeric\"\n class=\"sd-preview-pdf-toolbar__page-input\"\n [value]=\"_activePage\"\n #pageInput\n (keydown.enter)=\"onPageInputEnter($event)\"\n (blur)=\"onPageInputBlur($event)\"\n [attr.aria-label]=\"'core.component.preview-pdf.page-of' | translate: { current: _activePage, total: _numPages }\"\n [attr.data-autoId]=\"autoIdPageInput()\" />\n <span class=\"sd-preview-pdf-toolbar__page-total\">/ {{ _numPages }}</span>\n </span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [disabled]=\"!_canNext\"\n [attr.aria-label]=\"'core.component.preview-pdf.next-page' | translate\"\n [attr.title]=\"'core.component.preview-pdf.next-page' | translate\"\n [attr.data-autoId]=\"autoIdNext()\"\n (click)=\"nextPage()\">\n <mat-icon fontIcon=\"chevron_right\"></mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [disabled]=\"!_canNext\"\n [attr.aria-label]=\"'core.component.preview-pdf.last-page' | translate\"\n [attr.title]=\"'core.component.preview-pdf.last-page' | translate\"\n [attr.data-autoId]=\"autoIdLast()\"\n (click)=\"lastPage()\">\n <mat-icon fontIcon=\"last_page\"></mat-icon>\n </button>\n\n <span class=\"sd-preview-pdf-toolbar__divider\"></span>\n\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-pdf.zoom-out' | translate\"\n [attr.title]=\"'core.component.preview-pdf.zoom-out' | translate\"\n [attr.data-autoId]=\"autoIdZoomOut()\"\n (click)=\"zoomOut()\">\n <mat-icon fontIcon=\"remove\"></mat-icon>\n </button>\n <span class=\"sd-preview-pdf-toolbar__zoom\" aria-live=\"polite\" [attr.data-autoId]=\"autoIdZoomReadout()\">{{ zoomPercent() }}%</span>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-pdf.zoom-in' | translate\"\n [attr.title]=\"'core.component.preview-pdf.zoom-in' | translate\"\n [attr.data-autoId]=\"autoIdZoomIn()\"\n (click)=\"zoomIn()\">\n <mat-icon fontIcon=\"add\"></mat-icon>\n </button>\n\n <span class=\"sd-preview-pdf-toolbar__divider\"></span>\n\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn sd-preview-pdf-toolbar__btn--with-label\"\n [class.sd-preview-pdf-toolbar__btn--active]=\"_zoomMode === 'page-fit'\"\n [attr.data-autoId]=\"autoIdFitPage()\"\n (click)=\"setZoom('page-fit')\">\n <mat-icon fontIcon=\"fit_screen\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.fit-page' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn sd-preview-pdf-toolbar__btn--with-label\"\n [class.sd-preview-pdf-toolbar__btn--active]=\"_zoomMode === 'page-width'\"\n [attr.data-autoId]=\"autoIdFitWidth()\"\n (click)=\"setZoom('page-width')\">\n <mat-icon fontIcon=\"swap_horiz\"></mat-icon>\n <span>{{ 'core.component.preview-pdf.fit-width' | translate }}</span>\n </button>\n\n <span class=\"sd-preview-pdf-toolbar__divider\"></span>\n\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn\"\n [attr.aria-label]=\"'core.component.preview-pdf.rotate' | translate\"\n [attr.title]=\"'core.component.preview-pdf.rotate' | translate\"\n [attr.data-autoId]=\"autoIdRotate()\"\n (click)=\"rotate('right')\">\n <mat-icon fontIcon=\"rotate_right\"></mat-icon>\n </button>\n\n <!-- TODO(preview-pdf): scroll mode toggle is signature-only;\n clicking switches the state but rendering stays single-page\n until the continuous scroll feature lands. -->\n <button\n type=\"button\"\n class=\"sd-preview-pdf-toolbar__btn sd-preview-pdf-toolbar__btn--with-label\"\n [attr.data-autoId]=\"autoIdScrollMode()\"\n (click)=\"setScrollMode(_scrollModeCurrent === 'page' ? 'continuous' : 'page')\">\n <mat-icon [fontIcon]=\"_scrollModeCurrent === 'page' ? 'description' : 'view_day'\"></mat-icon>\n <span>\n {{ (_scrollModeCurrent === 'page'\n ? 'core.component.preview-pdf.scroll-page'\n : 'core.component.preview-pdf.scroll-continuous') | translate }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [":host{--sd-pdf-shell-bg: #1a1c1f;--sd-pdf-sidebar-bg: #22252a;--sd-pdf-toolbar-bg: rgba(20, 22, 25, .94);--sd-pdf-page-bg: #ffffff;--sd-pdf-page-shadow: 0 4px 16px rgba(0, 0, 0, .4);--sd-pdf-divider: rgba(255, 255, 255, .08);--sd-pdf-fg: #f5f6f7;--sd-pdf-fg-muted: rgba(255, 255, 255, .6);--sd-pdf-fg-subtle: rgba(255, 255, 255, .4);--sd-pdf-accent: var(--sd-primary, #3b82f6);--sd-pdf-accent-soft: rgba(59, 130, 246, .2);--sd-pdf-danger: var(--sd-error, #ef4444);--sd-pdf-success: var(--sd-success, #22c55e);--sd-pdf-danger-soft: rgba(239, 68, 68, .1);--sd-pdf-danger-border: rgba(239, 68, 68, .3);--sd-pdf-danger-tint: rgba(239, 68, 68, .15);--sd-pdf-hover-bg: rgba(255, 255, 255, .1);--sd-pdf-search-hi: rgba(250, 204, 21, .55);--sd-pdf-search-hi-active: rgba(249, 115, 22, .85);display:block;width:100%;height:100%;min-height:320px;outline:none}:host([data-theme=light]){--sd-pdf-shell-bg: #f7f8fa;--sd-pdf-sidebar-bg: #ffffff;--sd-pdf-toolbar-bg: rgba(255, 255, 255, .94);--sd-pdf-page-bg: #ffffff;--sd-pdf-page-shadow: 0 4px 16px rgba(0, 0, 0, .12);--sd-pdf-divider: rgba(0, 0, 0, .08);--sd-pdf-fg: #1a1c1f;--sd-pdf-fg-muted: rgba(0, 0, 0, .62);--sd-pdf-fg-subtle: rgba(0, 0, 0, .42);--sd-pdf-accent: var(--sd-primary, #1f49bf);--sd-pdf-accent-soft: rgba(31, 73, 191, .18);--sd-pdf-danger: var(--sd-error, #ef4444);--sd-pdf-success: var(--sd-success, #22c55e);--sd-pdf-danger-soft: rgba(239, 68, 68, .08);--sd-pdf-danger-border: rgba(239, 68, 68, .25);--sd-pdf-danger-tint: rgba(239, 68, 68, .12);--sd-pdf-hover-bg: rgba(0, 0, 0, .06);--sd-pdf-search-hi: rgba(250, 204, 21, .55);--sd-pdf-search-hi-active: rgba(250, 204, 21, .9)}:host(.sd-preview-pdf-host--fullscreen){width:100vw;height:100vh;min-height:0}.sd-preview-pdf-shell{position:relative;display:flex;flex-direction:column;width:100%;height:100%;background:var(--sd-pdf-shell-bg);color:var(--sd-pdf-fg);border-radius:12px;overflow:hidden;box-shadow:0 30px 80px #0000008c,0 0 0 1px #ffffff0a;font-family:inherit}.sd-preview-pdf-header{display:flex;align-items:center;justify-content:space-between;gap:12px;height:57px;padding:0 12px;background:var(--sd-pdf-toolbar-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-bottom:1px solid var(--sd-pdf-divider);flex:0 0 auto;z-index:2}.sd-preview-pdf-header__left{display:flex;align-items:center;gap:8px;min-width:0;flex:1 1 auto}.sd-preview-pdf-header__right{display:flex;align-items:center;gap:4px;flex-shrink:0}.sd-preview-pdf-header__divider{display:inline-block;width:1px;height:20px;background:var(--sd-pdf-divider)}.sd-preview-pdf-header__meta{display:flex;flex-direction:column;min-width:0}.sd-preview-pdf-header__name{font-size:14px;font-weight:500;color:var(--sd-pdf-fg);max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-preview-pdf-header__sub{font-size:11px;color:var(--sd-pdf-fg-muted);margin-top:2px}.sd-preview-pdf-fileicon{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:6px;background:var(--sd-pdf-danger-tint);border:1px solid var(--sd-pdf-danger-border);color:var(--sd-error-light, #f87171);font:700 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace}.sd-preview-pdf-iconbtn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:32px;height:32px;padding:0 8px;background:transparent;border:none;color:var(--sd-pdf-fg);border-radius:6px;cursor:pointer;transition:background .12s,color .12s;white-space:nowrap;flex-shrink:0}.sd-preview-pdf-iconbtn mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-pdf-iconbtn__label{font-size:13px;font-weight:500}.sd-preview-pdf-iconbtn:hover:not(:disabled){background:var(--sd-pdf-hover-bg)}.sd-preview-pdf-iconbtn:focus-visible{outline:2px solid var(--sd-pdf-accent);outline-offset:2px}.sd-preview-pdf-iconbtn:disabled{opacity:.35;cursor:not-allowed}.sd-preview-pdf-iconbtn--active{background:var(--sd-pdf-accent-soft);color:var(--sd-pdf-accent)}.sd-preview-pdf-searchbar{display:flex;align-items:center;gap:6px;height:46px;padding:0 12px;background:var(--sd-pdf-toolbar-bg);border-bottom:1px solid var(--sd-pdf-divider);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);flex:0 0 auto;z-index:2}.sd-preview-pdf-searchbar__icon{color:var(--sd-pdf-fg-muted);font-size:18px;width:18px;height:18px;flex-shrink:0}.sd-preview-pdf-searchbar__input{flex:0 1 360px;min-width:160px;height:30px;background:#ffffff0f;border:1px solid rgba(255,255,255,.08);color:var(--sd-pdf-fg);border-radius:6px;padding:0 10px;font-size:13px;outline:none}.sd-preview-pdf-searchbar__input::placeholder{color:var(--sd-pdf-fg-subtle)}.sd-preview-pdf-searchbar__input:focus{border-color:var(--sd-pdf-accent);background:#ffffff17}.sd-preview-pdf-searchbar__counter{color:var(--sd-pdf-fg-muted);font-size:12px;font-variant-numeric:tabular-nums;min-width:48px;text-align:center;flex-shrink:0}.sd-preview-pdf-searchbar__divider{width:1px;height:20px;background:var(--sd-pdf-divider);flex-shrink:0}.sd-preview-pdf-searchbar__spacer{flex:1 1 auto}.sd-pdf-search-overlay{position:absolute;top:8px;left:50%;transform:translate(-50%);display:flex;flex-wrap:wrap;gap:4px;max-width:80%;pointer-events:none;z-index:5}.sd-pdf-search-hi{display:inline-block;padding:1px 4px;border-radius:2px;background:var(--sd-pdf-search-hi);color:#000;font-size:12px;font-weight:500}.sd-pdf-search-hi--active{background:var(--sd-pdf-search-hi-active);color:#fff;box-shadow:0 0 0 2px #fff6}.sd-preview-pdf-body{position:relative;flex:1 1 auto;min-height:0;display:flex;flex-direction:row;overflow:hidden}.sd-preview-pdf-sidebar{width:240px;display:flex;flex-direction:column;background:var(--sd-pdf-sidebar-bg);border-right:1px solid var(--sd-pdf-divider);flex-shrink:0;min-height:0}.sd-preview-pdf-sidebar__tabs{display:flex;gap:4px;padding:8px;border-bottom:1px solid var(--sd-pdf-divider)}.sd-preview-pdf-sidebar__tab{flex:1 1 0;display:inline-flex;align-items:center;justify-content:center;gap:4px;height:32px;padding:0 4px;background:transparent;border:none;color:var(--sd-pdf-fg-muted);border-radius:6px;cursor:pointer;font-size:12px;font-weight:500;white-space:nowrap;flex-shrink:0;transition:background .12s,color .12s}.sd-preview-pdf-sidebar__tab mat-icon{font-size:14px;width:14px;height:14px}.sd-preview-pdf-sidebar__tab:hover{background:#ffffff0f;color:var(--sd-pdf-fg)}.sd-preview-pdf-sidebar__tab--active{background:var(--sd-pdf-accent-soft);color:var(--sd-pdf-accent)}.sd-preview-pdf-sidebar__content{flex:1 1 auto;overflow:auto;padding:12px}.sd-preview-pdf-sidebar__deferred{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:32px 16px;text-align:center;color:var(--sd-pdf-fg-subtle)}.sd-preview-pdf-sidebar__deferred mat-icon{font-size:28px;width:28px;height:28px;opacity:.6}.sd-preview-pdf-sidebar__deferred p{margin:0;font-size:12px;line-height:1.5}.sd-preview-pdf-thumb-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}.sd-preview-pdf-thumb{display:flex;flex-direction:column;align-items:center;gap:4px;width:100%;padding:0;background:transparent;border:none;cursor:pointer}.sd-preview-pdf-thumb__page{width:152px;aspect-ratio:612/792;background:var(--sd-pdf-page-bg);border-radius:2px;outline:1px solid rgba(255,255,255,.08);outline-offset:-1px;box-shadow:0 2px 6px #0000004d;display:flex;align-items:center;justify-content:center;overflow:hidden;-webkit-user-select:none;user-select:none;background-image:linear-gradient(90deg,#0000,#0000000a,#0000);background-size:200% 100%;animation:sd-preview-pdf-thumb-skel 1.6s ease-in-out infinite}.sd-preview-pdf-thumb__canvas{display:block;max-width:100%;max-height:100%;background:var(--sd-pdf-page-bg)}.sd-preview-pdf-thumb__label{font-size:11px;color:var(--sd-pdf-fg-muted);font-variant-numeric:tabular-nums}.sd-preview-pdf-thumb--active .sd-preview-pdf-thumb__page{outline:2px solid var(--sd-pdf-accent);outline-offset:-2px}.sd-preview-pdf-thumb--active .sd-preview-pdf-thumb__label{color:var(--sd-pdf-accent);font-weight:600}.sd-preview-pdf-thumb:focus-visible .sd-preview-pdf-thumb__page{outline:2px solid var(--sd-pdf-accent);outline-offset:2px}.sd-preview-pdf-stage{position:relative;flex:1 1 auto;min-width:0;min-height:0;background:var(--sd-pdf-shell-bg);background-image:linear-gradient(45deg,rgba(255,255,255,.015) 25%,transparent 25%),linear-gradient(-45deg,rgba(255,255,255,.015) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(255,255,255,.015) 75%),linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.015) 75%);background-size:24px 24px;background-position:0 0,0 12px,12px -12px,-12px 0;overflow:auto;padding:32px 24px 96px;display:flex;justify-content:center;align-items:flex-start}:host([data-theme=light]) .sd-preview-pdf-stage{background-image:linear-gradient(45deg,rgba(0,0,0,.015) 25%,transparent 25%),linear-gradient(-45deg,rgba(0,0,0,.015) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(0,0,0,.015) 75%),linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.015) 75%)}.sd-preview-pdf-page-wrap{display:inline-block;position:relative}.sd-preview-pdf-page{display:block;background:var(--sd-pdf-page-bg);border-radius:2px;box-shadow:var(--sd-pdf-page-shadow);max-width:100%}.sd-preview-pdf-toolbar{position:absolute;bottom:20px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:2px;padding:5px 6px;background:var(--sd-pdf-toolbar-bg);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border:1px solid var(--sd-pdf-divider);border-radius:10px;box-shadow:0 8px 30px #0006;z-index:4;max-width:calc(100% - 32px);overflow-x:auto}.sd-preview-pdf-toolbar__btn{display:inline-flex;align-items:center;justify-content:center;gap:4px;min-width:30px;height:28px;padding:0 6px;background:transparent;border:none;color:var(--sd-pdf-fg);border-radius:6px;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background .12s,color .12s}.sd-preview-pdf-toolbar__btn mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-pdf-toolbar__btn span{font-size:13px;font-weight:500}.sd-preview-pdf-toolbar__btn--with-label{padding:0 10px}.sd-preview-pdf-toolbar__btn--active{background:var(--sd-pdf-accent-soft);color:var(--sd-pdf-accent)}.sd-preview-pdf-toolbar__btn:hover:not(:disabled):not(.sd-preview-pdf-toolbar__btn--active){background:var(--sd-pdf-hover-bg)}.sd-preview-pdf-toolbar__btn:focus-visible{outline:2px solid var(--sd-pdf-accent);outline-offset:2px}.sd-preview-pdf-toolbar__btn:disabled{opacity:.35;cursor:not-allowed}.sd-preview-pdf-toolbar__page{display:inline-flex;align-items:center;gap:4px;padding:0 6px;flex-shrink:0}.sd-preview-pdf-toolbar__page-input{width:36px;height:24px;background:#ffffff14;border:1px solid rgba(255,255,255,.08);color:var(--sd-pdf-fg);border-radius:4px;text-align:center;font-size:13px;font-variant-numeric:tabular-nums;outline:none}.sd-preview-pdf-toolbar__page-input:focus{border-color:var(--sd-pdf-accent)}.sd-preview-pdf-toolbar__page-total{font-size:13px;color:var(--sd-pdf-fg-muted);font-variant-numeric:tabular-nums}.sd-preview-pdf-toolbar__zoom{min-width:56px;text-align:center;color:var(--sd-pdf-fg);font-size:13px;font-weight:500;font-variant-numeric:tabular-nums;background:#ffffff14;border-radius:4px;padding:2px 8px}.sd-preview-pdf-toolbar__divider{width:1px;height:20px;background:var(--sd-pdf-divider);margin:0 4px;flex-shrink:0}.sd-preview-pdf-status{margin:auto;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;text-align:center;padding:32px;max-width:420px}.sd-preview-pdf-status__tile{width:96px;height:96px;border-radius:24px;display:flex;align-items:center;justify-content:center;border:1px solid var(--sd-pdf-divider)}.sd-preview-pdf-status__tile mat-icon{font-size:48px;width:48px;height:48px}.sd-preview-pdf-status__tile--muted{background:#ffffff0d}.sd-preview-pdf-status__tile--muted mat-icon{color:var(--sd-pdf-fg-subtle)}.sd-preview-pdf-status__tile--danger{background:var(--sd-pdf-danger-soft);border-color:var(--sd-pdf-danger-border)}.sd-preview-pdf-status__tile--danger mat-icon{color:var(--sd-pdf-danger)}.sd-preview-pdf-status__title{font-size:16px;font-weight:500;color:var(--sd-pdf-fg)}.sd-preview-pdf-status__hint{font-size:13px;color:var(--sd-pdf-fg-muted);line-height:1.5}.sd-preview-pdf-status__actions{display:flex;gap:8px;margin-top:4px}.sd-preview-pdf-progress-pct{font-variant-numeric:tabular-nums;color:var(--sd-pdf-fg-muted)}.sd-preview-pdf-progress{width:240px;height:4px;background:#ffffff14;border-radius:999px;overflow:hidden}.sd-preview-pdf-progress__fill{height:100%;background:var(--sd-pdf-accent);transition:width .12s linear}.sd-preview-pdf-spinner{width:56px;height:56px;border-radius:999px;border:3px solid rgba(255,255,255,.08);border-top-color:var(--sd-pdf-accent);animation:sd-preview-pdf-spin .9s linear infinite}@keyframes sd-preview-pdf-spin{to{transform:rotate(360deg)}}@keyframes sd-preview-pdf-thumb-skel{0%{background-position:200% 0}to{background-position:-200% 0}}.sd-preview-pdf-search-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.sd-preview-pdf-search-result{width:100%;display:flex;align-items:flex-start;gap:8px;padding:8px 10px;background:#ffffff0a;border:1px solid transparent;border-radius:6px;color:var(--sd-pdf-fg);cursor:pointer;text-align:left;transition:background .12s,border-color .12s}.sd-preview-pdf-search-result:hover{background:#ffffff12}.sd-preview-pdf-search-result--active{background:var(--sd-pdf-accent-soft);border-color:#3b82f673}.sd-preview-pdf-search-result__snippet{flex:1 1 auto;font-size:12px;line-height:1.4;color:var(--sd-pdf-fg);word-break:break-word}.sd-preview-pdf-search-result__snippet mark{background:var(--sd-pdf-search-hi);color:#000;padding:0 2px;border-radius:2px}.sd-preview-pdf-search-result__page{flex:0 0 auto;font-size:11px;font-variant-numeric:tabular-nums;color:var(--sd-pdf-fg-muted);background:#ffffff0f;padding:2px 6px;border-radius:4px}.sd-preview-pdf-btn-primary{display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 16px;background:var(--sd-pdf-accent);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:filter .12s}.sd-preview-pdf-btn-primary mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-pdf-btn-primary:hover{filter:brightness(1.1)}.sd-preview-pdf-btn-primary:focus-visible{outline:2px solid #fff;outline-offset:2px}.sd-preview-pdf-btn-secondary{display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 16px;background:transparent;color:var(--sd-pdf-fg);border:1px solid var(--sd-pdf-divider);border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;transition:background .12s}.sd-preview-pdf-btn-secondary mat-icon{font-size:18px;width:18px;height:18px}.sd-preview-pdf-btn-secondary:hover{background:#ffffff0f}.sd-preview-pdf-btn-secondary:focus-visible{outline:2px solid var(--sd-pdf-accent);outline-offset:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1964
1964
|
}
|
|
1965
1965
|
_a = SdPreviewPdf;
|
|
1966
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
1966
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdPreviewPdf, decorators: [{
|
|
1967
1967
|
type: Component,
|
|
1968
1968
|
args: [{ selector: 'sd-preview-pdf', standalone: true, imports: [CommonModule, FormsModule, MatIconModule, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1969
1969
|
tabindex: '0',
|