@sdcorejs/angular 20.0.1 → 21.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/README.md +15 -14
  2. package/fesm2022/sdcorejs-angular-components-anchor.mjs +28 -28
  3. package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
  4. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +34 -34
  5. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
  6. package/fesm2022/sdcorejs-angular-components-avatar.mjs +9 -9
  7. package/fesm2022/sdcorejs-angular-components-avatar.mjs.map +1 -1
  8. package/fesm2022/sdcorejs-angular-components-badge.mjs +25 -33
  9. package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
  10. package/fesm2022/sdcorejs-angular-components-base.mjs +3 -3
  11. package/fesm2022/sdcorejs-angular-components-button.mjs +19 -29
  12. package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
  13. package/fesm2022/sdcorejs-angular-components-chart.mjs +28 -28
  14. package/fesm2022/sdcorejs-angular-components-chart.mjs.map +1 -1
  15. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs +4 -4
  16. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs.map +1 -1
  17. package/fesm2022/sdcorejs-angular-components-code-editor.mjs +11 -11
  18. package/fesm2022/sdcorejs-angular-components-code-editor.mjs.map +1 -1
  19. package/fesm2022/sdcorejs-angular-components-document-builder.mjs +6 -6
  20. package/fesm2022/sdcorejs-angular-components-editor.mjs +36 -48
  21. package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
  22. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +212 -212
  23. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  24. package/fesm2022/sdcorejs-angular-components-history.mjs +8 -8
  25. package/fesm2022/sdcorejs-angular-components-history.mjs.map +1 -1
  26. package/fesm2022/sdcorejs-angular-components-import-excel.mjs +10 -10
  27. package/fesm2022/sdcorejs-angular-components-inform.mjs +35 -39
  28. package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
  29. package/fesm2022/sdcorejs-angular-components-mini-editor.mjs +3 -3
  30. package/fesm2022/sdcorejs-angular-components-modal.mjs +20 -20
  31. package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
  32. package/fesm2022/sdcorejs-angular-components-operator.mjs +11 -11
  33. package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
  34. package/fesm2022/sdcorejs-angular-components-preview.mjs +119 -119
  35. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  36. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +132 -141
  37. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  38. package/fesm2022/sdcorejs-angular-components-query-builder.mjs +3 -3
  39. package/fesm2022/sdcorejs-angular-components-quick-action.mjs +4 -4
  40. package/fesm2022/sdcorejs-angular-components-quick-action.mjs.map +1 -1
  41. package/fesm2022/sdcorejs-angular-components-section.mjs +18 -22
  42. package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
  43. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +14 -14
  44. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  45. package/fesm2022/sdcorejs-angular-components-splitter.mjs +36 -38
  46. package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
  47. package/fesm2022/sdcorejs-angular-components-stepper.mjs +24 -24
  48. package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
  49. package/fesm2022/sdcorejs-angular-components-tab-router.mjs +23 -23
  50. package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
  51. package/fesm2022/sdcorejs-angular-components-tab.mjs +23 -23
  52. package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
  53. package/fesm2022/sdcorejs-angular-components-table.mjs +225 -225
  54. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  55. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +70 -106
  56. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  57. package/fesm2022/sdcorejs-angular-components-view.mjs +14 -14
  58. package/fesm2022/sdcorejs-angular-components-view.mjs.map +1 -1
  59. package/fesm2022/sdcorejs-angular-directives.mjs +30 -30
  60. package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
  61. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +61 -76
  62. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  63. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +26 -49
  64. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  65. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +48 -83
  66. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  67. package/fesm2022/sdcorejs-angular-forms-chip.mjs +47 -82
  68. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  69. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +46 -61
  70. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  71. package/fesm2022/sdcorejs-angular-forms-date.mjs +53 -68
  72. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  73. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +74 -89
  74. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  75. package/fesm2022/sdcorejs-angular-forms-directives.mjs +12 -12
  76. package/fesm2022/sdcorejs-angular-forms-input-color.mjs +19 -19
  77. package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
  78. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +56 -71
  79. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  80. package/fesm2022/sdcorejs-angular-forms-input.mjs +58 -73
  81. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  82. package/fesm2022/sdcorejs-angular-forms-label.mjs +3 -3
  83. package/fesm2022/sdcorejs-angular-forms-models.mjs +2 -2
  84. package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
  85. package/fesm2022/sdcorejs-angular-forms-radio.mjs +39 -70
  86. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  87. package/fesm2022/sdcorejs-angular-forms-select.mjs +69 -86
  88. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  89. package/fesm2022/sdcorejs-angular-forms-switch.mjs +28 -49
  90. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  91. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +50 -77
  92. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  93. package/fesm2022/sdcorejs-angular-forms.mjs +4 -4
  94. package/fesm2022/sdcorejs-angular-handlers.mjs +3 -3
  95. package/fesm2022/sdcorejs-angular-i18n.mjs +9 -9
  96. package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
  97. package/fesm2022/sdcorejs-angular-interceptors.mjs +6 -6
  98. package/fesm2022/sdcorejs-angular-modules-auth.mjs +10 -10
  99. package/fesm2022/sdcorejs-angular-modules-auth.mjs.map +1 -1
  100. package/fesm2022/sdcorejs-angular-modules-authom.mjs +10 -10
  101. package/fesm2022/sdcorejs-angular-modules-authom.mjs.map +1 -1
  102. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +7 -7
  103. package/fesm2022/sdcorejs-angular-modules-layout.mjs +131 -131
  104. package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
  105. package/fesm2022/sdcorejs-angular-modules-permission.mjs +11 -11
  106. package/fesm2022/sdcorejs-angular-modules-permission.mjs.map +1 -1
  107. package/fesm2022/sdcorejs-angular-pipes.mjs +14 -14
  108. package/fesm2022/sdcorejs-angular-services-api.mjs +10 -10
  109. package/fesm2022/sdcorejs-angular-services-cache.mjs +3 -3
  110. package/fesm2022/sdcorejs-angular-services-confirm.mjs +6 -6
  111. package/fesm2022/sdcorejs-angular-services-docx.mjs +3 -3
  112. package/fesm2022/sdcorejs-angular-services-excel.mjs +3 -3
  113. package/fesm2022/sdcorejs-angular-services-license.mjs +3 -3
  114. package/fesm2022/sdcorejs-angular-services-loading.mjs +3 -3
  115. package/fesm2022/sdcorejs-angular-services-notify.mjs +12 -12
  116. package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
  117. package/fesm2022/sdcorejs-angular-services-storage.mjs +3 -3
  118. package/package.json +82 -82
  119. package/{forms/select/index.d.ts → types/sdcorejs-angular-forms-select.d.ts} +3 -3
  120. /package/{components/anchor/index.d.ts → types/sdcorejs-angular-components-anchor.d.ts} +0 -0
  121. /package/{components/autoid-inspector/index.d.ts → types/sdcorejs-angular-components-autoid-inspector.d.ts} +0 -0
  122. /package/{components/avatar/index.d.ts → types/sdcorejs-angular-components-avatar.d.ts} +0 -0
  123. /package/{components/badge/index.d.ts → types/sdcorejs-angular-components-badge.d.ts} +0 -0
  124. /package/{components/base/index.d.ts → types/sdcorejs-angular-components-base.d.ts} +0 -0
  125. /package/{components/button/index.d.ts → types/sdcorejs-angular-components-button.d.ts} +0 -0
  126. /package/{components/chart/index.d.ts → types/sdcorejs-angular-components-chart.d.ts} +0 -0
  127. /package/{components/ckeditor-styles/index.d.ts → types/sdcorejs-angular-components-ckeditor-styles.d.ts} +0 -0
  128. /package/{components/code-editor/index.d.ts → types/sdcorejs-angular-components-code-editor.d.ts} +0 -0
  129. /package/{components/document-builder/index.d.ts → types/sdcorejs-angular-components-document-builder.d.ts} +0 -0
  130. /package/{components/editor/index.d.ts → types/sdcorejs-angular-components-editor.d.ts} +0 -0
  131. /package/{components/form-generic/index.d.ts → types/sdcorejs-angular-components-form-generic.d.ts} +0 -0
  132. /package/{components/history/index.d.ts → types/sdcorejs-angular-components-history.d.ts} +0 -0
  133. /package/{components/import-excel/index.d.ts → types/sdcorejs-angular-components-import-excel.d.ts} +0 -0
  134. /package/{components/inform/index.d.ts → types/sdcorejs-angular-components-inform.d.ts} +0 -0
  135. /package/{components/mini-editor/index.d.ts → types/sdcorejs-angular-components-mini-editor.d.ts} +0 -0
  136. /package/{components/modal/index.d.ts → types/sdcorejs-angular-components-modal.d.ts} +0 -0
  137. /package/{components/operator/index.d.ts → types/sdcorejs-angular-components-operator.d.ts} +0 -0
  138. /package/{components/preview/index.d.ts → types/sdcorejs-angular-components-preview.d.ts} +0 -0
  139. /package/{components/query-bar/index.d.ts → types/sdcorejs-angular-components-query-bar.d.ts} +0 -0
  140. /package/{components/query-builder/index.d.ts → types/sdcorejs-angular-components-query-builder.d.ts} +0 -0
  141. /package/{components/quick-action/index.d.ts → types/sdcorejs-angular-components-quick-action.d.ts} +0 -0
  142. /package/{components/section/index.d.ts → types/sdcorejs-angular-components-section.d.ts} +0 -0
  143. /package/{components/side-drawer/index.d.ts → types/sdcorejs-angular-components-side-drawer.d.ts} +0 -0
  144. /package/{components/splitter/index.d.ts → types/sdcorejs-angular-components-splitter.d.ts} +0 -0
  145. /package/{components/stepper/index.d.ts → types/sdcorejs-angular-components-stepper.d.ts} +0 -0
  146. /package/{components/tab-router/index.d.ts → types/sdcorejs-angular-components-tab-router.d.ts} +0 -0
  147. /package/{components/tab/index.d.ts → types/sdcorejs-angular-components-tab.d.ts} +0 -0
  148. /package/{components/table/index.d.ts → types/sdcorejs-angular-components-table.d.ts} +0 -0
  149. /package/{components/upload-file/index.d.ts → types/sdcorejs-angular-components-upload-file.d.ts} +0 -0
  150. /package/{components/view/index.d.ts → types/sdcorejs-angular-components-view.d.ts} +0 -0
  151. /package/{components/index.d.ts → types/sdcorejs-angular-components.d.ts} +0 -0
  152. /package/{configurations/index.d.ts → types/sdcorejs-angular-configurations.d.ts} +0 -0
  153. /package/{directives/index.d.ts → types/sdcorejs-angular-directives.d.ts} +0 -0
  154. /package/{forms/autocomplete/index.d.ts → types/sdcorejs-angular-forms-autocomplete.d.ts} +0 -0
  155. /package/{forms/checkbox/index.d.ts → types/sdcorejs-angular-forms-checkbox.d.ts} +0 -0
  156. /package/{forms/chip-calendar/index.d.ts → types/sdcorejs-angular-forms-chip-calendar.d.ts} +0 -0
  157. /package/{forms/chip/index.d.ts → types/sdcorejs-angular-forms-chip.d.ts} +0 -0
  158. /package/{forms/date-range/index.d.ts → types/sdcorejs-angular-forms-date-range.d.ts} +0 -0
  159. /package/{forms/date/index.d.ts → types/sdcorejs-angular-forms-date.d.ts} +0 -0
  160. /package/{forms/datetime/index.d.ts → types/sdcorejs-angular-forms-datetime.d.ts} +0 -0
  161. /package/{forms/directives/index.d.ts → types/sdcorejs-angular-forms-directives.d.ts} +0 -0
  162. /package/{forms/input-color/index.d.ts → types/sdcorejs-angular-forms-input-color.d.ts} +0 -0
  163. /package/{forms/input-number/index.d.ts → types/sdcorejs-angular-forms-input-number.d.ts} +0 -0
  164. /package/{forms/input/index.d.ts → types/sdcorejs-angular-forms-input.d.ts} +0 -0
  165. /package/{forms/label/index.d.ts → types/sdcorejs-angular-forms-label.d.ts} +0 -0
  166. /package/{forms/models/index.d.ts → types/sdcorejs-angular-forms-models.d.ts} +0 -0
  167. /package/{forms/radio/index.d.ts → types/sdcorejs-angular-forms-radio.d.ts} +0 -0
  168. /package/{forms/switch/index.d.ts → types/sdcorejs-angular-forms-switch.d.ts} +0 -0
  169. /package/{forms/textarea/index.d.ts → types/sdcorejs-angular-forms-textarea.d.ts} +0 -0
  170. /package/{forms/index.d.ts → types/sdcorejs-angular-forms.d.ts} +0 -0
  171. /package/{handlers/index.d.ts → types/sdcorejs-angular-handlers.d.ts} +0 -0
  172. /package/{i18n/index.d.ts → types/sdcorejs-angular-i18n.d.ts} +0 -0
  173. /package/{interceptors/index.d.ts → types/sdcorejs-angular-interceptors.d.ts} +0 -0
  174. /package/{models/index.d.ts → types/sdcorejs-angular-models.d.ts} +0 -0
  175. /package/{modules/auth/index.d.ts → types/sdcorejs-angular-modules-auth.d.ts} +0 -0
  176. /package/{modules/authom/index.d.ts → types/sdcorejs-angular-modules-authom.d.ts} +0 -0
  177. /package/{modules/keycloak/index.d.ts → types/sdcorejs-angular-modules-keycloak.d.ts} +0 -0
  178. /package/{modules/layout/index.d.ts → types/sdcorejs-angular-modules-layout.d.ts} +0 -0
  179. /package/{modules/permission/index.d.ts → types/sdcorejs-angular-modules-permission.d.ts} +0 -0
  180. /package/{modules/index.d.ts → types/sdcorejs-angular-modules.d.ts} +0 -0
  181. /package/{pipes/index.d.ts → types/sdcorejs-angular-pipes.d.ts} +0 -0
  182. /package/{services/api/index.d.ts → types/sdcorejs-angular-services-api.d.ts} +0 -0
  183. /package/{services/cache/index.d.ts → types/sdcorejs-angular-services-cache.d.ts} +0 -0
  184. /package/{services/confirm/index.d.ts → types/sdcorejs-angular-services-confirm.d.ts} +0 -0
  185. /package/{services/docx/index.d.ts → types/sdcorejs-angular-services-docx.d.ts} +0 -0
  186. /package/{services/excel/index.d.ts → types/sdcorejs-angular-services-excel.d.ts} +0 -0
  187. /package/{services/license/index.d.ts → types/sdcorejs-angular-services-license.d.ts} +0 -0
  188. /package/{services/loading/index.d.ts → types/sdcorejs-angular-services-loading.d.ts} +0 -0
  189. /package/{services/notify/index.d.ts → types/sdcorejs-angular-services-notify.d.ts} +0 -0
  190. /package/{services/storage/index.d.ts → types/sdcorejs-angular-services-storage.d.ts} +0 -0
  191. /package/{services/index.d.ts → types/sdcorejs-angular-services.d.ts} +0 -0
  192. /package/{utilities/data-state/index.d.ts → types/sdcorejs-angular-utilities-data-state.d.ts} +0 -0
  193. /package/{utilities/extensions/index.d.ts → types/sdcorejs-angular-utilities-extensions.d.ts} +0 -0
  194. /package/{utilities/models/index.d.ts → types/sdcorejs-angular-utilities-models.d.ts} +0 -0
  195. /package/{utilities/index.d.ts → types/sdcorejs-angular-utilities.d.ts} +0 -0
  196. /package/{index.d.ts → types/sdcorejs-angular.d.ts} +0 -0
@@ -31,33 +31,33 @@ class SdPreviewImage {
31
31
  // Declarative items input — consumer drives state. Mỗi lần items() đổi,
32
32
  // effect() bên dưới sẽ normalize + load lại danh sách.
33
33
  // autoId prefix `preview-image-`. Per-element child autoIds derive `${autoId}-{suffix}`.
34
- autoIdInput = input(undefined, ...(ngDevMode ? [{ debugName: "autoIdInput", alias: 'autoId' }] : [{ alias: 'autoId' }]));
35
- autoId = computed(() => (this.autoIdInput() ? `components-preview-image-${this.autoIdInput()}` : undefined), ...(ngDevMode ? [{ debugName: "autoId" }] : []));
34
+ autoIdInput = input(undefined, { ...(ngDevMode ? { debugName: "autoIdInput" } : /* istanbul ignore next */ {}), alias: 'autoId' });
35
+ autoId = computed(() => (this.autoIdInput() ? `components-preview-image-${this.autoIdInput()}` : undefined), ...(ngDevMode ? [{ debugName: "autoId" }] : /* istanbul ignore next */ []));
36
36
  #childAutoId = (suffix) => {
37
37
  return this.autoId() ? `${this.autoId()}-${suffix}` : undefined;
38
38
  };
39
- autoIdPrev = computed(() => this.#childAutoId('prev'), ...(ngDevMode ? [{ debugName: "autoIdPrev" }] : []));
40
- autoIdNext = computed(() => this.#childAutoId('next'), ...(ngDevMode ? [{ debugName: "autoIdNext" }] : []));
41
- autoIdZoomIn = computed(() => this.#childAutoId('zoom-in'), ...(ngDevMode ? [{ debugName: "autoIdZoomIn" }] : []));
42
- autoIdZoomOut = computed(() => this.#childAutoId('zoom-out'), ...(ngDevMode ? [{ debugName: "autoIdZoomOut" }] : []));
43
- autoIdFit = computed(() => this.#childAutoId('fit'), ...(ngDevMode ? [{ debugName: "autoIdFit" }] : []));
44
- autoIdRotate = computed(() => this.#childAutoId('rotate'), ...(ngDevMode ? [{ debugName: "autoIdRotate" }] : []));
45
- autoIdDownload = computed(() => this.#childAutoId('download'), ...(ngDevMode ? [{ debugName: "autoIdDownload" }] : []));
46
- autoIdFullscreen = computed(() => this.#childAutoId('fullscreen'), ...(ngDevMode ? [{ debugName: "autoIdFullscreen" }] : []));
47
- autoIdRetry = computed(() => this.#childAutoId('retry'), ...(ngDevMode ? [{ debugName: "autoIdRetry" }] : []));
39
+ autoIdPrev = computed(() => this.#childAutoId('prev'), ...(ngDevMode ? [{ debugName: "autoIdPrev" }] : /* istanbul ignore next */ []));
40
+ autoIdNext = computed(() => this.#childAutoId('next'), ...(ngDevMode ? [{ debugName: "autoIdNext" }] : /* istanbul ignore next */ []));
41
+ autoIdZoomIn = computed(() => this.#childAutoId('zoom-in'), ...(ngDevMode ? [{ debugName: "autoIdZoomIn" }] : /* istanbul ignore next */ []));
42
+ autoIdZoomOut = computed(() => this.#childAutoId('zoom-out'), ...(ngDevMode ? [{ debugName: "autoIdZoomOut" }] : /* istanbul ignore next */ []));
43
+ autoIdFit = computed(() => this.#childAutoId('fit'), ...(ngDevMode ? [{ debugName: "autoIdFit" }] : /* istanbul ignore next */ []));
44
+ autoIdRotate = computed(() => this.#childAutoId('rotate'), ...(ngDevMode ? [{ debugName: "autoIdRotate" }] : /* istanbul ignore next */ []));
45
+ autoIdDownload = computed(() => this.#childAutoId('download'), ...(ngDevMode ? [{ debugName: "autoIdDownload" }] : /* istanbul ignore next */ []));
46
+ autoIdFullscreen = computed(() => this.#childAutoId('fullscreen'), ...(ngDevMode ? [{ debugName: "autoIdFullscreen" }] : /* istanbul ignore next */ []));
47
+ autoIdRetry = computed(() => this.#childAutoId('retry'), ...(ngDevMode ? [{ debugName: "autoIdRetry" }] : /* istanbul ignore next */ []));
48
48
  autoIdThumb = (i) => this.#childAutoId(`thumb-${i}`);
49
49
  autoIdDot = (i) => this.#childAutoId(`dot-${i}`);
50
- items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
51
- title = input(undefined, ...(ngDevMode ? [{ debugName: "title" }] : []));
52
- thumbnailPosition = input('bottom', ...(ngDevMode ? [{ debugName: "thumbnailPosition" }] : []));
53
- showToolbar = input(true, ...(ngDevMode ? [{ debugName: "showToolbar" }] : []));
54
- downloadable = input(true, ...(ngDevMode ? [{ debugName: "downloadable" }] : []));
55
- zoomable = input(true, ...(ngDevMode ? [{ debugName: "zoomable" }] : []));
56
- loop = input(true, ...(ngDevMode ? [{ debugName: "loop" }] : []));
57
- startIndex = input(0, ...(ngDevMode ? [{ debugName: "startIndex" }] : []));
50
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
51
+ title = input(undefined, ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
52
+ thumbnailPosition = input('bottom', ...(ngDevMode ? [{ debugName: "thumbnailPosition" }] : /* istanbul ignore next */ []));
53
+ showToolbar = input(true, ...(ngDevMode ? [{ debugName: "showToolbar" }] : /* istanbul ignore next */ []));
54
+ downloadable = input(true, ...(ngDevMode ? [{ debugName: "downloadable" }] : /* istanbul ignore next */ []));
55
+ zoomable = input(true, ...(ngDevMode ? [{ debugName: "zoomable" }] : /* istanbul ignore next */ []));
56
+ loop = input(true, ...(ngDevMode ? [{ debugName: "loop" }] : /* istanbul ignore next */ []));
57
+ startIndex = input(0, ...(ngDevMode ? [{ debugName: "startIndex" }] : /* istanbul ignore next */ []));
58
58
  // Theme variant — drives [data-theme] host attribute. Default 'dark' preserves
59
59
  // pre-existing visual contract; consumers opt-in to 'light' explicitly.
60
- theme = input('dark', ...(ngDevMode ? [{ debugName: "theme" }] : []));
60
+ theme = input('dark', ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
61
61
  // ==========================================
62
62
  // OUTPUTS
63
63
  // ==========================================
@@ -70,14 +70,14 @@ class SdPreviewImage {
70
70
  // ==========================================
71
71
  // STATE (signals)
72
72
  // ==========================================
73
- #activeIndex = signal(0, ...(ngDevMode ? [{ debugName: "#activeIndex" }] : []));
74
- #images = signal([], ...(ngDevMode ? [{ debugName: "#images" }] : []));
75
- #zoom = signal(1, ...(ngDevMode ? [{ debugName: "#zoom" }] : []));
76
- #rotation = signal(0, ...(ngDevMode ? [{ debugName: "#rotation" }] : []));
77
- #pan = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "#pan" }] : []));
78
- #stage = signal('empty', ...(ngDevMode ? [{ debugName: "#stage" }] : []));
79
- #isFullscreen = signal(false, ...(ngDevMode ? [{ debugName: "#isFullscreen" }] : []));
80
- #isDragging = signal(false, ...(ngDevMode ? [{ debugName: "#isDragging" }] : []));
73
+ #activeIndex = signal(0, ...(ngDevMode ? [{ debugName: "#activeIndex" }] : /* istanbul ignore next */ []));
74
+ #images = signal([], ...(ngDevMode ? [{ debugName: "#images" }] : /* istanbul ignore next */ []));
75
+ #zoom = signal(1, ...(ngDevMode ? [{ debugName: "#zoom" }] : /* istanbul ignore next */ []));
76
+ #rotation = signal(0, ...(ngDevMode ? [{ debugName: "#rotation" }] : /* istanbul ignore next */ []));
77
+ #pan = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "#pan" }] : /* istanbul ignore next */ []));
78
+ #stage = signal('empty', ...(ngDevMode ? [{ debugName: "#stage" }] : /* istanbul ignore next */ []));
79
+ #isFullscreen = signal(false, ...(ngDevMode ? [{ debugName: "#isFullscreen" }] : /* istanbul ignore next */ []));
80
+ #isDragging = signal(false, ...(ngDevMode ? [{ debugName: "#isDragging" }] : /* istanbul ignore next */ []));
81
81
  // Track every blob URL we created so we can revoke on destroy / re-normalize.
82
82
  // CDN strings hoá ra File→blob URL nội bộ — bắt buộc phải revoke để không leak.
83
83
  #ownedBlobUrls = new Set();
@@ -100,16 +100,16 @@ class SdPreviewImage {
100
100
  pan = this.#pan.asReadonly();
101
101
  stage = this.#stage.asReadonly();
102
102
  isFullscreen = this.#isFullscreen.asReadonly();
103
- activeImage = computed(() => this.#images()[this.#activeIndex()], ...(ngDevMode ? [{ debugName: "activeImage" }] : []));
103
+ activeImage = computed(() => this.#images()[this.#activeIndex()], ...(ngDevMode ? [{ debugName: "activeImage" }] : /* istanbul ignore next */ []));
104
104
  hasPrev = computed(() => {
105
105
  const len = this.#images().length;
106
106
  return len > 1 && (this.loop() || this.#activeIndex() > 0);
107
- }, ...(ngDevMode ? [{ debugName: "hasPrev" }] : []));
107
+ }, ...(ngDevMode ? [{ debugName: "hasPrev" }] : /* istanbul ignore next */ []));
108
108
  hasNext = computed(() => {
109
109
  const len = this.#images().length;
110
110
  return len > 1 && (this.loop() || this.#activeIndex() < len - 1);
111
- }, ...(ngDevMode ? [{ debugName: "hasNext" }] : []));
112
- zoomPercent = computed(() => Math.round(this.#zoom() * 100), ...(ngDevMode ? [{ debugName: "zoomPercent" }] : []));
111
+ }, ...(ngDevMode ? [{ debugName: "hasNext" }] : /* istanbul ignore next */ []));
112
+ zoomPercent = computed(() => Math.round(this.#zoom() * 100), ...(ngDevMode ? [{ debugName: "zoomPercent" }] : /* istanbul ignore next */ []));
113
113
  // Transform style cho ảnh stage. WHY: gom translate/scale/rotate vào 1 string
114
114
  // duy nhất để OnPush phát hiện thay đổi qua signal kéo theo computed.
115
115
  imageTransform = computed(() => {
@@ -117,7 +117,7 @@ class SdPreviewImage {
117
117
  const z = this.#zoom();
118
118
  const r = this.#rotation();
119
119
  return `translate(${p.x}px, ${p.y}px) scale(${z}) rotate(${r}deg)`;
120
- }, ...(ngDevMode ? [{ debugName: "imageTransform" }] : []));
120
+ }, ...(ngDevMode ? [{ debugName: "imageTransform" }] : /* istanbul ignore next */ []));
121
121
  shellClass = computed(() => {
122
122
  const pos = this.thumbnailPosition();
123
123
  return {
@@ -125,7 +125,7 @@ class SdPreviewImage {
125
125
  [`sd-preview-shell--pos-${pos}`]: true,
126
126
  'sd-preview-shell--fullscreen': this.#isFullscreen(),
127
127
  };
128
- }, ...(ngDevMode ? [{ debugName: "shellClass" }] : []));
128
+ }, ...(ngDevMode ? [{ debugName: "shellClass" }] : /* istanbul ignore next */ []));
129
129
  // ==========================================
130
130
  // CONSTRUCTOR — declarative wiring
131
131
  // ==========================================
@@ -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.23", ngImport: i0, type: SdPreviewImage, deps: [], target: i0.ɵɵFactoryTarget.Component });
642
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.23", 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\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: "21.2.15", ngImport: i0, type: SdPreviewImage, deps: [], target: i0.ɵɵFactoryTarget.Component });
642
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", 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\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.23", ngImport: i0, type: SdPreviewImage, decorators: [{
645
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", 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',
@@ -701,74 +701,74 @@ class SdPreviewPdf {
701
701
  // see through ES private fields (NG1053). `protected` keeps them invisible
702
702
  // to consumers but accessible to the template.
703
703
  // ==========================================
704
- pageCanvasRef = viewChild('pageCanvas', ...(ngDevMode ? [{ debugName: "pageCanvasRef" }] : []));
705
- stageEl = viewChild('stageRef', ...(ngDevMode ? [{ debugName: "stageEl" }] : []));
706
- pageInputRef = viewChild('pageInput', ...(ngDevMode ? [{ debugName: "pageInputRef" }] : []));
707
- searchInputRef = viewChild('searchInput', ...(ngDevMode ? [{ debugName: "searchInputRef" }] : []));
704
+ pageCanvasRef = viewChild('pageCanvas', ...(ngDevMode ? [{ debugName: "pageCanvasRef" }] : /* istanbul ignore next */ []));
705
+ stageEl = viewChild('stageRef', ...(ngDevMode ? [{ debugName: "stageEl" }] : /* istanbul ignore next */ []));
706
+ pageInputRef = viewChild('pageInput', ...(ngDevMode ? [{ debugName: "pageInputRef" }] : /* istanbul ignore next */ []));
707
+ searchInputRef = viewChild('searchInput', ...(ngDevMode ? [{ debugName: "searchInputRef" }] : /* istanbul ignore next */ []));
708
708
  // Every thumbnail <canvas> in the sidebar — populated when sidebar is open +
709
709
  // mode==='thumbnails'. We feed these to the IntersectionObserver below so a
710
710
  // thumb only renders when it scrolls into the viewport (lazy fill).
711
- thumbCanvases = viewChildren('thumbCanvas', ...(ngDevMode ? [{ debugName: "thumbCanvases" }] : []));
711
+ thumbCanvases = viewChildren('thumbCanvas', ...(ngDevMode ? [{ debugName: "thumbCanvases" }] : /* istanbul ignore next */ []));
712
712
  // ==========================================
713
713
  // INPUTS (signal-based, Angular 19 style)
714
714
  // ==========================================
715
715
  // autoId prefix `preview-pdf-`. Per-element child autoIds derive `${autoId}-{suffix}`.
716
- autoIdInput = input(undefined, ...(ngDevMode ? [{ debugName: "autoIdInput", alias: 'autoId' }] : [{ alias: 'autoId' }]));
717
- autoId = computed(() => (this.autoIdInput() ? `components-preview-pdf-${this.autoIdInput()}` : undefined), ...(ngDevMode ? [{ debugName: "autoId" }] : []));
716
+ autoIdInput = input(undefined, { ...(ngDevMode ? { debugName: "autoIdInput" } : /* istanbul ignore next */ {}), alias: 'autoId' });
717
+ autoId = computed(() => (this.autoIdInput() ? `components-preview-pdf-${this.autoIdInput()}` : undefined), ...(ngDevMode ? [{ debugName: "autoId" }] : /* istanbul ignore next */ []));
718
718
  #childAutoId = (suffix) => {
719
719
  return this.autoId() ? `${this.autoId()}-${suffix}` : undefined;
720
720
  };
721
721
  // Page navigation
722
- autoIdFirst = computed(() => this.#childAutoId('first'), ...(ngDevMode ? [{ debugName: "autoIdFirst" }] : []));
723
- autoIdPrev = computed(() => this.#childAutoId('prev'), ...(ngDevMode ? [{ debugName: "autoIdPrev" }] : []));
724
- autoIdNext = computed(() => this.#childAutoId('next'), ...(ngDevMode ? [{ debugName: "autoIdNext" }] : []));
725
- autoIdLast = computed(() => this.#childAutoId('last'), ...(ngDevMode ? [{ debugName: "autoIdLast" }] : []));
726
- autoIdPageInput = computed(() => this.#childAutoId('page-input'), ...(ngDevMode ? [{ debugName: "autoIdPageInput" }] : []));
722
+ autoIdFirst = computed(() => this.#childAutoId('first'), ...(ngDevMode ? [{ debugName: "autoIdFirst" }] : /* istanbul ignore next */ []));
723
+ autoIdPrev = computed(() => this.#childAutoId('prev'), ...(ngDevMode ? [{ debugName: "autoIdPrev" }] : /* istanbul ignore next */ []));
724
+ autoIdNext = computed(() => this.#childAutoId('next'), ...(ngDevMode ? [{ debugName: "autoIdNext" }] : /* istanbul ignore next */ []));
725
+ autoIdLast = computed(() => this.#childAutoId('last'), ...(ngDevMode ? [{ debugName: "autoIdLast" }] : /* istanbul ignore next */ []));
726
+ autoIdPageInput = computed(() => this.#childAutoId('page-input'), ...(ngDevMode ? [{ debugName: "autoIdPageInput" }] : /* istanbul ignore next */ []));
727
727
  // Zoom
728
- autoIdZoomIn = computed(() => this.#childAutoId('zoom-in'), ...(ngDevMode ? [{ debugName: "autoIdZoomIn" }] : []));
729
- autoIdZoomOut = computed(() => this.#childAutoId('zoom-out'), ...(ngDevMode ? [{ debugName: "autoIdZoomOut" }] : []));
730
- autoIdZoomReadout = computed(() => this.#childAutoId('zoom-readout'), ...(ngDevMode ? [{ debugName: "autoIdZoomReadout" }] : []));
728
+ autoIdZoomIn = computed(() => this.#childAutoId('zoom-in'), ...(ngDevMode ? [{ debugName: "autoIdZoomIn" }] : /* istanbul ignore next */ []));
729
+ autoIdZoomOut = computed(() => this.#childAutoId('zoom-out'), ...(ngDevMode ? [{ debugName: "autoIdZoomOut" }] : /* istanbul ignore next */ []));
730
+ autoIdZoomReadout = computed(() => this.#childAutoId('zoom-readout'), ...(ngDevMode ? [{ debugName: "autoIdZoomReadout" }] : /* istanbul ignore next */ []));
731
731
  // Modes
732
- autoIdFitPage = computed(() => this.#childAutoId('fit-page'), ...(ngDevMode ? [{ debugName: "autoIdFitPage" }] : []));
733
- autoIdFitWidth = computed(() => this.#childAutoId('fit-width'), ...(ngDevMode ? [{ debugName: "autoIdFitWidth" }] : []));
734
- autoIdRotate = computed(() => this.#childAutoId('rotate'), ...(ngDevMode ? [{ debugName: "autoIdRotate" }] : []));
735
- autoIdScrollMode = computed(() => this.#childAutoId('scroll-mode'), ...(ngDevMode ? [{ debugName: "autoIdScrollMode" }] : []));
732
+ autoIdFitPage = computed(() => this.#childAutoId('fit-page'), ...(ngDevMode ? [{ debugName: "autoIdFitPage" }] : /* istanbul ignore next */ []));
733
+ autoIdFitWidth = computed(() => this.#childAutoId('fit-width'), ...(ngDevMode ? [{ debugName: "autoIdFitWidth" }] : /* istanbul ignore next */ []));
734
+ autoIdRotate = computed(() => this.#childAutoId('rotate'), ...(ngDevMode ? [{ debugName: "autoIdRotate" }] : /* istanbul ignore next */ []));
735
+ autoIdScrollMode = computed(() => this.#childAutoId('scroll-mode'), ...(ngDevMode ? [{ debugName: "autoIdScrollMode" }] : /* istanbul ignore next */ []));
736
736
  // Header actions
737
- autoIdSearchToggle = computed(() => this.#childAutoId('search'), ...(ngDevMode ? [{ debugName: "autoIdSearchToggle" }] : []));
738
- autoIdPrint = computed(() => this.#childAutoId('print'), ...(ngDevMode ? [{ debugName: "autoIdPrint" }] : []));
739
- autoIdDownload = computed(() => this.#childAutoId('download'), ...(ngDevMode ? [{ debugName: "autoIdDownload" }] : []));
740
- autoIdFullscreen = computed(() => this.#childAutoId('fullscreen'), ...(ngDevMode ? [{ debugName: "autoIdFullscreen" }] : []));
741
- autoIdSidebarToggle = computed(() => this.#childAutoId('sidebar-toggle'), ...(ngDevMode ? [{ debugName: "autoIdSidebarToggle" }] : []));
737
+ autoIdSearchToggle = computed(() => this.#childAutoId('search'), ...(ngDevMode ? [{ debugName: "autoIdSearchToggle" }] : /* istanbul ignore next */ []));
738
+ autoIdPrint = computed(() => this.#childAutoId('print'), ...(ngDevMode ? [{ debugName: "autoIdPrint" }] : /* istanbul ignore next */ []));
739
+ autoIdDownload = computed(() => this.#childAutoId('download'), ...(ngDevMode ? [{ debugName: "autoIdDownload" }] : /* istanbul ignore next */ []));
740
+ autoIdFullscreen = computed(() => this.#childAutoId('fullscreen'), ...(ngDevMode ? [{ debugName: "autoIdFullscreen" }] : /* istanbul ignore next */ []));
741
+ autoIdSidebarToggle = computed(() => this.#childAutoId('sidebar-toggle'), ...(ngDevMode ? [{ debugName: "autoIdSidebarToggle" }] : /* istanbul ignore next */ []));
742
742
  // Sidebar tabs
743
- autoIdTabThumbnails = computed(() => this.#childAutoId('tab-thumbnails'), ...(ngDevMode ? [{ debugName: "autoIdTabThumbnails" }] : []));
744
- autoIdTabOutline = computed(() => this.#childAutoId('tab-outline'), ...(ngDevMode ? [{ debugName: "autoIdTabOutline" }] : []));
745
- autoIdTabSearch = computed(() => this.#childAutoId('tab-search'), ...(ngDevMode ? [{ debugName: "autoIdTabSearch" }] : []));
743
+ autoIdTabThumbnails = computed(() => this.#childAutoId('tab-thumbnails'), ...(ngDevMode ? [{ debugName: "autoIdTabThumbnails" }] : /* istanbul ignore next */ []));
744
+ autoIdTabOutline = computed(() => this.#childAutoId('tab-outline'), ...(ngDevMode ? [{ debugName: "autoIdTabOutline" }] : /* istanbul ignore next */ []));
745
+ autoIdTabSearch = computed(() => this.#childAutoId('tab-search'), ...(ngDevMode ? [{ debugName: "autoIdTabSearch" }] : /* istanbul ignore next */ []));
746
746
  // Search bar
747
- autoIdSearchInput = computed(() => this.#childAutoId('search-input'), ...(ngDevMode ? [{ debugName: "autoIdSearchInput" }] : []));
748
- autoIdSearchNext = computed(() => this.#childAutoId('search-next'), ...(ngDevMode ? [{ debugName: "autoIdSearchNext" }] : []));
749
- autoIdSearchPrev = computed(() => this.#childAutoId('search-prev'), ...(ngDevMode ? [{ debugName: "autoIdSearchPrev" }] : []));
750
- autoIdSearchCase = computed(() => this.#childAutoId('search-case'), ...(ngDevMode ? [{ debugName: "autoIdSearchCase" }] : []));
751
- autoIdSearchWhole = computed(() => this.#childAutoId('search-whole'), ...(ngDevMode ? [{ debugName: "autoIdSearchWhole" }] : []));
752
- autoIdSearchClose = computed(() => this.#childAutoId('search-close'), ...(ngDevMode ? [{ debugName: "autoIdSearchClose" }] : []));
747
+ autoIdSearchInput = computed(() => this.#childAutoId('search-input'), ...(ngDevMode ? [{ debugName: "autoIdSearchInput" }] : /* istanbul ignore next */ []));
748
+ autoIdSearchNext = computed(() => this.#childAutoId('search-next'), ...(ngDevMode ? [{ debugName: "autoIdSearchNext" }] : /* istanbul ignore next */ []));
749
+ autoIdSearchPrev = computed(() => this.#childAutoId('search-prev'), ...(ngDevMode ? [{ debugName: "autoIdSearchPrev" }] : /* istanbul ignore next */ []));
750
+ autoIdSearchCase = computed(() => this.#childAutoId('search-case'), ...(ngDevMode ? [{ debugName: "autoIdSearchCase" }] : /* istanbul ignore next */ []));
751
+ autoIdSearchWhole = computed(() => this.#childAutoId('search-whole'), ...(ngDevMode ? [{ debugName: "autoIdSearchWhole" }] : /* istanbul ignore next */ []));
752
+ autoIdSearchClose = computed(() => this.#childAutoId('search-close'), ...(ngDevMode ? [{ debugName: "autoIdSearchClose" }] : /* istanbul ignore next */ []));
753
753
  // Retry (error state)
754
- autoIdRetry = computed(() => this.#childAutoId('retry'), ...(ngDevMode ? [{ debugName: "autoIdRetry" }] : []));
754
+ autoIdRetry = computed(() => this.#childAutoId('retry'), ...(ngDevMode ? [{ debugName: "autoIdRetry" }] : /* istanbul ignore next */ []));
755
755
  // Per-index helpers (thumb + search result)
756
756
  autoIdThumb = (i) => this.#childAutoId(`thumb-${i}`);
757
757
  autoIdResult = (i) => this.#childAutoId(`result-${i}`);
758
- source = input(null, ...(ngDevMode ? [{ debugName: "source" }] : []));
759
- title = input(undefined, ...(ngDevMode ? [{ debugName: "title" }] : []));
760
- startPage = input(1, ...(ngDevMode ? [{ debugName: "startPage" }] : []));
761
- initialZoom = input('page-fit', ...(ngDevMode ? [{ debugName: "initialZoom" }] : []));
762
- sidebar = input('thumbnails', ...(ngDevMode ? [{ debugName: "sidebar" }] : []));
763
- sidebarOpen = input(true, ...(ngDevMode ? [{ debugName: "sidebarOpen" }] : []));
764
- scrollMode = input('page', ...(ngDevMode ? [{ debugName: "scrollMode" }] : []));
765
- showToolbar = input(true, ...(ngDevMode ? [{ debugName: "showToolbar" }] : []));
766
- downloadable = input(true, ...(ngDevMode ? [{ debugName: "downloadable" }] : []));
767
- password = input(undefined, ...(ngDevMode ? [{ debugName: "password" }] : []));
768
- httpHeaders = input(undefined, ...(ngDevMode ? [{ debugName: "httpHeaders" }] : []));
758
+ source = input(null, ...(ngDevMode ? [{ debugName: "source" }] : /* istanbul ignore next */ []));
759
+ title = input(undefined, ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
760
+ startPage = input(1, ...(ngDevMode ? [{ debugName: "startPage" }] : /* istanbul ignore next */ []));
761
+ initialZoom = input('page-fit', ...(ngDevMode ? [{ debugName: "initialZoom" }] : /* istanbul ignore next */ []));
762
+ sidebar = input('thumbnails', ...(ngDevMode ? [{ debugName: "sidebar" }] : /* istanbul ignore next */ []));
763
+ sidebarOpen = input(true, ...(ngDevMode ? [{ debugName: "sidebarOpen" }] : /* istanbul ignore next */ []));
764
+ scrollMode = input('page', ...(ngDevMode ? [{ debugName: "scrollMode" }] : /* istanbul ignore next */ []));
765
+ showToolbar = input(true, ...(ngDevMode ? [{ debugName: "showToolbar" }] : /* istanbul ignore next */ []));
766
+ downloadable = input(true, ...(ngDevMode ? [{ debugName: "downloadable" }] : /* istanbul ignore next */ []));
767
+ password = input(undefined, ...(ngDevMode ? [{ debugName: "password" }] : /* istanbul ignore next */ []));
768
+ httpHeaders = input(undefined, ...(ngDevMode ? [{ debugName: "httpHeaders" }] : /* istanbul ignore next */ []));
769
769
  // Theme variant — drives [data-theme] host attribute. Default 'dark'
770
770
  // preserves the original visual contract; 'light' flips token set via SCSS.
771
- theme = input('dark', ...(ngDevMode ? [{ debugName: "theme" }] : []));
771
+ theme = input('dark', ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
772
772
  // ==========================================
773
773
  // OUTPUTS
774
774
  // ==========================================
@@ -785,24 +785,24 @@ class SdPreviewPdf {
785
785
  // ==========================================
786
786
  // STATE (signals)
787
787
  // ==========================================
788
- #stage = signal('empty', ...(ngDevMode ? [{ debugName: "#stage" }] : []));
789
- #pdfDoc = signal(null, ...(ngDevMode ? [{ debugName: "#pdfDoc" }] : []));
790
- #meta = signal(null, ...(ngDevMode ? [{ debugName: "#meta" }] : []));
791
- #activePage = signal(1, ...(ngDevMode ? [{ debugName: "#activePage" }] : []));
792
- #zoom = signal(1, ...(ngDevMode ? [{ debugName: "#zoom" }] : []));
793
- #zoomMode = signal('page-fit', ...(ngDevMode ? [{ debugName: "#zoomMode" }] : []));
794
- #rotation = signal(0, ...(ngDevMode ? [{ debugName: "#rotation" }] : []));
795
- #sidebarOpenInternal = signal(true, ...(ngDevMode ? [{ debugName: "#sidebarOpenInternal" }] : []));
796
- #sidebarModeInternal = signal('thumbnails', ...(ngDevMode ? [{ debugName: "#sidebarModeInternal" }] : []));
797
- #scrollModeInternal = signal('page', ...(ngDevMode ? [{ debugName: "#scrollModeInternal" }] : []));
798
- #loadProgress = signal({ loaded: 0, total: 0 }, ...(ngDevMode ? [{ debugName: "#loadProgress" }] : []));
799
- #loadError = signal(null, ...(ngDevMode ? [{ debugName: "#loadError" }] : []));
800
- #isFullscreen = signal(false, ...(ngDevMode ? [{ debugName: "#isFullscreen" }] : []));
801
- #filename = signal('document.pdf', ...(ngDevMode ? [{ debugName: "#filename" }] : []));
802
- #fileSize = signal(0, ...(ngDevMode ? [{ debugName: "#fileSize" }] : []));
788
+ #stage = signal('empty', ...(ngDevMode ? [{ debugName: "#stage" }] : /* istanbul ignore next */ []));
789
+ #pdfDoc = signal(null, ...(ngDevMode ? [{ debugName: "#pdfDoc" }] : /* istanbul ignore next */ []));
790
+ #meta = signal(null, ...(ngDevMode ? [{ debugName: "#meta" }] : /* istanbul ignore next */ []));
791
+ #activePage = signal(1, ...(ngDevMode ? [{ debugName: "#activePage" }] : /* istanbul ignore next */ []));
792
+ #zoom = signal(1, ...(ngDevMode ? [{ debugName: "#zoom" }] : /* istanbul ignore next */ []));
793
+ #zoomMode = signal('page-fit', ...(ngDevMode ? [{ debugName: "#zoomMode" }] : /* istanbul ignore next */ []));
794
+ #rotation = signal(0, ...(ngDevMode ? [{ debugName: "#rotation" }] : /* istanbul ignore next */ []));
795
+ #sidebarOpenInternal = signal(true, ...(ngDevMode ? [{ debugName: "#sidebarOpenInternal" }] : /* istanbul ignore next */ []));
796
+ #sidebarModeInternal = signal('thumbnails', ...(ngDevMode ? [{ debugName: "#sidebarModeInternal" }] : /* istanbul ignore next */ []));
797
+ #scrollModeInternal = signal('page', ...(ngDevMode ? [{ debugName: "#scrollModeInternal" }] : /* istanbul ignore next */ []));
798
+ #loadProgress = signal({ loaded: 0, total: 0 }, ...(ngDevMode ? [{ debugName: "#loadProgress" }] : /* istanbul ignore next */ []));
799
+ #loadError = signal(null, ...(ngDevMode ? [{ debugName: "#loadError" }] : /* istanbul ignore next */ []));
800
+ #isFullscreen = signal(false, ...(ngDevMode ? [{ debugName: "#isFullscreen" }] : /* istanbul ignore next */ []));
801
+ #filename = signal('document.pdf', ...(ngDevMode ? [{ debugName: "#filename" }] : /* istanbul ignore next */ []));
802
+ #fileSize = signal(0, ...(ngDevMode ? [{ debugName: "#fileSize" }] : /* istanbul ignore next */ []));
803
803
  // Thumbnail cache: page number → data URL of mini-render. Lazy-populated as
804
804
  // the user opens the sidebar / scrolls thumbnails into view.
805
- #thumbCache = signal({}, ...(ngDevMode ? [{ debugName: "#thumbCache" }] : []));
805
+ #thumbCache = signal({}, ...(ngDevMode ? [{ debugName: "#thumbCache" }] : /* istanbul ignore next */ []));
806
806
  // ==========================================
807
807
  // SEARCH STATE
808
808
  // ==========================================
@@ -810,17 +810,17 @@ class SdPreviewPdf {
810
810
  // Ctrl+F, the sidebar tab, or `openSearch()` / `closeSearch()`. Independent
811
811
  // from the sidebar's `'search'` tab — the bar can stay open with the
812
812
  // sidebar closed (Ctrl+F flow), and the tab can be open without the bar.
813
- #searchBarOpen = signal(false, ...(ngDevMode ? [{ debugName: "#searchBarOpen" }] : []));
813
+ #searchBarOpen = signal(false, ...(ngDevMode ? [{ debugName: "#searchBarOpen" }] : /* istanbul ignore next */ []));
814
814
  // Persisted across `clearSearch()` so user toggles don't reset on each new
815
815
  // term — mirrors Acrobat / Chrome's "Find in page" behaviour.
816
- #searchCaseSensitive = signal(false, ...(ngDevMode ? [{ debugName: "#searchCaseSensitive" }] : []));
817
- #searchWholeWord = signal(false, ...(ngDevMode ? [{ debugName: "#searchWholeWord" }] : []));
818
- #searchTerm = signal('', ...(ngDevMode ? [{ debugName: "#searchTerm" }] : []));
819
- #searchResults = signal([], ...(ngDevMode ? [{ debugName: "#searchResults" }] : []));
816
+ #searchCaseSensitive = signal(false, ...(ngDevMode ? [{ debugName: "#searchCaseSensitive" }] : /* istanbul ignore next */ []));
817
+ #searchWholeWord = signal(false, ...(ngDevMode ? [{ debugName: "#searchWholeWord" }] : /* istanbul ignore next */ []));
818
+ #searchTerm = signal('', ...(ngDevMode ? [{ debugName: "#searchTerm" }] : /* istanbul ignore next */ []));
819
+ #searchResults = signal([], ...(ngDevMode ? [{ debugName: "#searchResults" }] : /* istanbul ignore next */ []));
820
820
  // -1 sentinel means "no result focused yet" (e.g. right after clearSearch
821
821
  // or before the first searchNext). Highlight rendering uses this to skip
822
822
  // the `--active` class altogether.
823
- #searchActiveIndex = signal(-1, ...(ngDevMode ? [{ debugName: "#searchActiveIndex" }] : []));
823
+ #searchActiveIndex = signal(-1, ...(ngDevMode ? [{ debugName: "#searchActiveIndex" }] : /* istanbul ignore next */ []));
824
824
  // Page-text cache: pageNum → fully-joined plain text. We pay the
825
825
  // `getTextContent()` cost once per page per document, then reuse across
826
826
  // re-runs (e.g. toggling case-sensitive). Cleared on every source change.
@@ -860,24 +860,24 @@ class SdPreviewPdf {
860
860
  fileSize = this.#fileSize.asReadonly();
861
861
  loadError$ = this.#loadError.asReadonly();
862
862
  thumbCache = this.#thumbCache.asReadonly();
863
- numPages = computed(() => this.#meta()?.numPages ?? 0, ...(ngDevMode ? [{ debugName: "numPages" }] : []));
864
- canPrev = computed(() => this.#activePage() > 1, ...(ngDevMode ? [{ debugName: "canPrev" }] : []));
863
+ numPages = computed(() => this.#meta()?.numPages ?? 0, ...(ngDevMode ? [{ debugName: "numPages" }] : /* istanbul ignore next */ []));
864
+ canPrev = computed(() => this.#activePage() > 1, ...(ngDevMode ? [{ debugName: "canPrev" }] : /* istanbul ignore next */ []));
865
865
  canNext = computed(() => {
866
866
  const n = this.numPages();
867
867
  return n > 0 && this.#activePage() < n;
868
- }, ...(ngDevMode ? [{ debugName: "canNext" }] : []));
869
- zoomPercent = computed(() => Math.round(this.#zoom() * 100), ...(ngDevMode ? [{ debugName: "zoomPercent" }] : []));
868
+ }, ...(ngDevMode ? [{ debugName: "canNext" }] : /* istanbul ignore next */ []));
869
+ zoomPercent = computed(() => Math.round(this.#zoom() * 100), ...(ngDevMode ? [{ debugName: "zoomPercent" }] : /* istanbul ignore next */ []));
870
870
  loadPercent = computed(() => {
871
871
  const p = this.#loadProgress();
872
872
  if (p.total <= 0)
873
873
  return 0;
874
874
  return Math.min(100, Math.round((p.loaded / p.total) * 100));
875
- }, ...(ngDevMode ? [{ debugName: "loadPercent" }] : []));
876
- isSidebarOpen = computed(() => this.#sidebarOpenInternal() && this.#sidebarModeInternal() !== 'none', ...(ngDevMode ? [{ debugName: "isSidebarOpen" }] : []));
875
+ }, ...(ngDevMode ? [{ debugName: "loadPercent" }] : /* istanbul ignore next */ []));
876
+ isSidebarOpen = computed(() => this.#sidebarOpenInternal() && this.#sidebarModeInternal() !== 'none', ...(ngDevMode ? [{ debugName: "isSidebarOpen" }] : /* istanbul ignore next */ []));
877
877
  pageList = computed(() => {
878
878
  const n = this.numPages();
879
879
  return n > 0 ? Array.from({ length: n }, (_, i) => i + 1) : [];
880
- }, ...(ngDevMode ? [{ debugName: "pageList" }] : []));
880
+ }, ...(ngDevMode ? [{ debugName: "pageList" }] : /* istanbul ignore next */ []));
881
881
  // Alias used by the template's thumbnail @for — keeps the JSX-y `pageNumbers`
882
882
  // name from the design handoff while reusing the same computed.
883
883
  pageNumbers = this.pageList;
@@ -889,20 +889,20 @@ class SdPreviewPdf {
889
889
  searchActiveIndex = this.#searchActiveIndex.asReadonly();
890
890
  searchCaseSensitive = this.#searchCaseSensitive.asReadonly();
891
891
  searchWholeWord = this.#searchWholeWord.asReadonly();
892
- searchTotal = computed(() => this.#searchResults().length, ...(ngDevMode ? [{ debugName: "searchTotal" }] : []));
892
+ searchTotal = computed(() => this.#searchResults().length, ...(ngDevMode ? [{ debugName: "searchTotal" }] : /* istanbul ignore next */ []));
893
893
  // 1-based "X of N" indicator for the search bar counter. Reads 0 when
894
894
  // there are no results so the template can hide / dim the counter.
895
895
  searchCurrent = computed(() => {
896
896
  const idx = this.#searchActiveIndex();
897
897
  return idx < 0 ? 0 : idx + 1;
898
- }, ...(ngDevMode ? [{ debugName: "searchCurrent" }] : []));
898
+ }, ...(ngDevMode ? [{ debugName: "searchCurrent" }] : /* istanbul ignore next */ []));
899
899
  // Currently-active hit (or null when nothing is focused) — drives the
900
900
  // in-page `<mark class="--active">` highlight + auto-scroll effect below.
901
901
  searchActiveResult = computed(() => {
902
902
  const idx = this.#searchActiveIndex();
903
903
  const results = this.#searchResults();
904
904
  return idx >= 0 && idx < results.length ? results[idx] : null;
905
- }, ...(ngDevMode ? [{ debugName: "searchActiveResult" }] : []));
905
+ }, ...(ngDevMode ? [{ debugName: "searchActiveResult" }] : /* istanbul ignore next */ []));
906
906
  // Snapshot of the full search state — handed to consumer via
907
907
  // `getSearchState()` for parity with `searchChange` event shape.
908
908
  searchState = computed(() => ({
@@ -911,7 +911,7 @@ class SdPreviewPdf {
911
911
  wholeWord: this.#searchWholeWord(),
912
912
  results: this.#searchResults(),
913
913
  activeIndex: this.#searchActiveIndex(),
914
- }), ...(ngDevMode ? [{ debugName: "searchState" }] : []));
914
+ }), ...(ngDevMode ? [{ debugName: "searchState" }] : /* istanbul ignore next */ []));
915
915
  // ==========================================
916
916
  // CONSTRUCTOR — declarative wiring
917
917
  // ==========================================
@@ -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.23", ngImport: i0, type: SdPreviewPdf, deps: [], target: i0.ɵɵFactoryTarget.Component });
1963
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.23", 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\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 <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 <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\">&nbsp;{{ 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 <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: "21.2.15", ngImport: i0, type: SdPreviewPdf, deps: [], target: i0.ɵɵFactoryTarget.Component });
1963
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", 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\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 <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 <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\">&nbsp;{{ 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 <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.23", ngImport: i0, type: SdPreviewPdf, decorators: [{
1966
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", 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',