@sd-angular/core 19.0.0-beta.99 → 19.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/README.md +9 -11
  2. package/assets/images/coming-soon.svg +23 -0
  3. package/assets/images/data-empty.svg +21 -0
  4. package/assets/images/expired.svg +22 -0
  5. package/assets/images/file-error.svg +28 -0
  6. package/assets/images/filter-empty.svg +20 -0
  7. package/assets/images/filter-required.svg +21 -0
  8. package/assets/images/forbidden.svg +15 -0
  9. package/assets/images/image-error.svg +27 -0
  10. package/assets/images/maintenance.svg +23 -0
  11. package/assets/images/not-found.svg +20 -0
  12. package/assets/images/offline.svg +20 -0
  13. package/assets/images/submitted.svg +18 -0
  14. package/assets/images/success.svg +18 -0
  15. package/assets/images/unauthorized.svg +22 -0
  16. package/assets/images/unknown-error.svg +18 -0
  17. package/assets/scss/README.md +433 -353
  18. package/assets/scss/core/_inline-edit.scss +105 -0
  19. package/assets/scss/core/form.scss +58 -1
  20. package/assets/scss/core/image.scss +35 -0
  21. package/assets/scss/core/utilities/_base.scss +6 -6
  22. package/assets/scss/core/utilities/_grid.scss +4 -3
  23. package/assets/scss/core/utilities/_index.scss +1 -1
  24. package/assets/scss/core/utilities/_sizing.scss +2 -2
  25. package/assets/scss/sd-core.scss +1 -2
  26. package/components/autoid-inspector/src/autoid-inspector.component.d.ts +18 -0
  27. package/components/autoid-inspector/src/models/autoid-element.model.d.ts +45 -1
  28. package/components/autoid-inspector/src/models/autoid-export-format.model.d.ts +19 -0
  29. package/components/autoid-inspector/src/services/autoid-export.service.d.ts +10 -2
  30. package/components/autoid-inspector/src/services/autoid-scanner.service.d.ts +26 -3
  31. package/components/badge/src/badge.component.d.ts +20 -3
  32. package/components/button/src/button.component.d.ts +2 -1
  33. package/components/ckeditor-styles/index.d.ts +1 -0
  34. package/components/ckeditor-styles/src/ckeditor-styles.component.d.ts +25 -0
  35. package/components/form-generic/src/components/form-builder/form-builder.component.d.ts +12 -13
  36. package/components/form-generic/src/models/form-generic-component.model.d.ts +5 -6
  37. package/components/form-generic/src/models/form-generic-expression.model.d.ts +1 -1
  38. package/components/history/models/history.model.d.ts +2 -2
  39. package/components/index.d.ts +2 -0
  40. package/components/inform/index.d.ts +2 -0
  41. package/components/inform/src/inform-action.directive.d.ts +9 -0
  42. package/components/inform/src/inform.component.d.ts +59 -0
  43. package/components/modal/src/modal.component.d.ts +2 -1
  44. package/components/modal-resizable/index.d.ts +1 -0
  45. package/components/modal-resizable/src/modal-resizable.component.d.ts +29 -0
  46. package/components/operator/index.d.ts +1 -0
  47. package/components/operator/src/operator.component.d.ts +34 -0
  48. package/components/query-bar/index.d.ts +2 -0
  49. package/components/query-bar/src/components/actions-bar/actions-bar.component.d.ts +28 -0
  50. package/components/query-bar/src/components/build-chip/build-chip.component.d.ts +67 -0
  51. package/components/query-bar/src/components/chip-popover/chip-popover.component.d.ts +73 -0
  52. package/components/query-bar/src/components/field-picker/field-picker.component.d.ts +37 -0
  53. package/components/query-bar/src/components/inline-chip/inline-chip.component.d.ts +76 -0
  54. package/components/query-bar/src/components/inline-value-chip/inline-value-chip.component.d.ts +67 -0
  55. package/components/query-bar/src/components/popover-chip/popover-chip.component.d.ts +35 -0
  56. package/components/query-bar/src/components/saved-filters-menu/saved-filters-menu.component.d.ts +39 -0
  57. package/components/query-bar/src/query-bar.component.d.ts +137 -0
  58. package/components/query-bar/src/query-bar.model.d.ts +136 -0
  59. package/components/section/src/section.component.d.ts +2 -1
  60. package/components/stepper/index.d.ts +2 -0
  61. package/components/stepper/src/step.component.d.ts +17 -0
  62. package/components/stepper/src/stepper.component.d.ts +33 -0
  63. package/components/tab/index.d.ts +2 -0
  64. package/components/tab/src/tab-group.component.d.ts +37 -0
  65. package/components/tab/src/tab.component.d.ts +13 -0
  66. package/components/tab-router/src/decorators/tab.decorator.d.ts +2 -2
  67. package/components/tab-router/src/models/tab-router.model.d.ts +2 -2
  68. package/components/table/index.d.ts +1 -0
  69. package/components/table/src/components/column-title/column-title.component.d.ts +1 -1
  70. package/components/table/src/components/config/config.component.d.ts +3 -1
  71. package/components/table/src/components/desktop-cell/desktop-cell.component.d.ts +3 -3
  72. package/components/table/src/components/filter/column-filter/column-filter.component.d.ts +3 -7
  73. package/components/table/src/components/selector-action/selector-action.component.d.ts +3 -1
  74. package/components/table/src/configurations/table.configuration.d.ts +3 -3
  75. package/components/table/src/directives/index.d.ts +1 -0
  76. package/components/table/src/directives/sd-table-cell-def.directive.d.ts +12 -4
  77. package/components/table/src/directives/sd-table-column-filter-def.directive.d.ts +12 -4
  78. package/components/table/src/directives/sd-table-expand-def.directive.d.ts +10 -4
  79. package/components/table/src/directives/sd-table-filter-def.directive.d.ts +3 -3
  80. package/components/table/src/directives/sd-table-footer-def.directive.d.ts +12 -4
  81. package/components/table/src/directives/sd-table-group-def.directive.d.ts +44 -0
  82. package/components/table/src/directives/sd-table-title-def.directive.d.ts +10 -4
  83. package/components/table/src/models/index.d.ts +1 -0
  84. package/components/table/src/models/table-column.model.d.ts +13 -13
  85. package/components/table/src/models/table-command.model.d.ts +3 -2
  86. package/components/table/src/models/table-item.model.d.ts +19 -4
  87. package/components/table/src/models/table-option-export.model.d.ts +3 -3
  88. package/components/table/src/models/table-option-group.model.d.ts +19 -2
  89. package/components/table/src/models/table-option-selector.model.d.ts +17 -1
  90. package/components/table/src/models/table-option-tree.model.d.ts +96 -8
  91. package/components/table/src/models/table-option.model.d.ts +11 -2
  92. package/components/table/src/pipes/sd-group.pipe.d.ts +15 -1
  93. package/components/table/src/services/table-filter/table-filter.model.d.ts +9 -9
  94. package/components/table/src/services/table-filter/table-filter.service.d.ts +2 -2
  95. package/components/table/src/services/tree/tree.util.d.ts +43 -2
  96. package/components/table/src/table.component.d.ts +36 -11
  97. package/components/view/src/view.component.d.ts +35 -1
  98. package/directives/src/sd-desktop.directive.d.ts +2 -4
  99. package/directives/src/sd-mobile.directive.d.ts +2 -4
  100. package/fesm2022/sd-angular-core-components-anchor.mjs +75 -49
  101. package/fesm2022/sd-angular-core-components-anchor.mjs.map +1 -1
  102. package/fesm2022/sd-angular-core-components-autoid-inspector.mjs +254 -29
  103. package/fesm2022/sd-angular-core-components-autoid-inspector.mjs.map +1 -1
  104. package/fesm2022/sd-angular-core-components-avatar.mjs +2 -2
  105. package/fesm2022/sd-angular-core-components-avatar.mjs.map +1 -1
  106. package/fesm2022/sd-angular-core-components-badge.mjs +18 -3
  107. package/fesm2022/sd-angular-core-components-badge.mjs.map +1 -1
  108. package/fesm2022/sd-angular-core-components-button.mjs +2 -2
  109. package/fesm2022/sd-angular-core-components-button.mjs.map +1 -1
  110. package/fesm2022/sd-angular-core-components-ckeditor-styles.mjs +38 -0
  111. package/fesm2022/sd-angular-core-components-ckeditor-styles.mjs.map +1 -0
  112. package/fesm2022/sd-angular-core-components-document-builder.mjs +10 -8
  113. package/fesm2022/sd-angular-core-components-document-builder.mjs.map +1 -1
  114. package/fesm2022/sd-angular-core-components-editor.mjs +3 -2
  115. package/fesm2022/sd-angular-core-components-editor.mjs.map +1 -1
  116. package/fesm2022/sd-angular-core-components-form-generic.mjs +149 -235
  117. package/fesm2022/sd-angular-core-components-form-generic.mjs.map +1 -1
  118. package/fesm2022/sd-angular-core-components-history.mjs +3 -2
  119. package/fesm2022/sd-angular-core-components-history.mjs.map +1 -1
  120. package/fesm2022/sd-angular-core-components-inform.mjs +190 -0
  121. package/fesm2022/sd-angular-core-components-inform.mjs.map +1 -0
  122. package/fesm2022/sd-angular-core-components-mini-editor.mjs +4 -3
  123. package/fesm2022/sd-angular-core-components-mini-editor.mjs.map +1 -1
  124. package/fesm2022/sd-angular-core-components-modal-resizable.mjs +158 -0
  125. package/fesm2022/sd-angular-core-components-modal-resizable.mjs.map +1 -0
  126. package/fesm2022/sd-angular-core-components-modal.mjs +2 -2
  127. package/fesm2022/sd-angular-core-components-modal.mjs.map +1 -1
  128. package/fesm2022/sd-angular-core-components-operator.mjs +77 -0
  129. package/fesm2022/sd-angular-core-components-operator.mjs.map +1 -0
  130. package/fesm2022/sd-angular-core-components-preview.mjs +4 -4
  131. package/fesm2022/sd-angular-core-components-preview.mjs.map +1 -1
  132. package/fesm2022/sd-angular-core-components-query-bar.mjs +1384 -0
  133. package/fesm2022/sd-angular-core-components-query-bar.mjs.map +1 -0
  134. package/fesm2022/sd-angular-core-components-quick-action.mjs +2 -2
  135. package/fesm2022/sd-angular-core-components-quick-action.mjs.map +1 -1
  136. package/fesm2022/sd-angular-core-components-section.mjs.map +1 -1
  137. package/fesm2022/sd-angular-core-components-side-drawer.mjs +2 -2
  138. package/fesm2022/sd-angular-core-components-side-drawer.mjs.map +1 -1
  139. package/fesm2022/sd-angular-core-components-splitter.mjs +5 -2
  140. package/fesm2022/sd-angular-core-components-splitter.mjs.map +1 -1
  141. package/fesm2022/sd-angular-core-components-stepper.mjs +140 -0
  142. package/fesm2022/sd-angular-core-components-stepper.mjs.map +1 -0
  143. package/fesm2022/sd-angular-core-components-tab-router.mjs +3 -3
  144. package/fesm2022/sd-angular-core-components-tab-router.mjs.map +1 -1
  145. package/fesm2022/sd-angular-core-components-tab.mjs +145 -0
  146. package/fesm2022/sd-angular-core-components-tab.mjs.map +1 -0
  147. package/fesm2022/sd-angular-core-components-table.mjs +576 -222
  148. package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
  149. package/fesm2022/sd-angular-core-components-upload-file.mjs +23 -23
  150. package/fesm2022/sd-angular-core-components-upload-file.mjs.map +1 -1
  151. package/fesm2022/sd-angular-core-components-view.mjs +44 -9
  152. package/fesm2022/sd-angular-core-components-view.mjs.map +1 -1
  153. package/fesm2022/sd-angular-core-components.mjs +2 -0
  154. package/fesm2022/sd-angular-core-components.mjs.map +1 -1
  155. package/fesm2022/sd-angular-core-directives.mjs +19 -21
  156. package/fesm2022/sd-angular-core-directives.mjs.map +1 -1
  157. package/fesm2022/sd-angular-core-forms-autocomplete.mjs +38 -14
  158. package/fesm2022/sd-angular-core-forms-autocomplete.mjs.map +1 -1
  159. package/fesm2022/sd-angular-core-forms-checkbox.mjs +97 -87
  160. package/fesm2022/sd-angular-core-forms-checkbox.mjs.map +1 -1
  161. package/fesm2022/sd-angular-core-forms-chip-calendar.mjs +92 -61
  162. package/fesm2022/sd-angular-core-forms-chip-calendar.mjs.map +1 -1
  163. package/fesm2022/sd-angular-core-forms-chip.mjs +89 -52
  164. package/fesm2022/sd-angular-core-forms-chip.mjs.map +1 -1
  165. package/fesm2022/sd-angular-core-forms-date-range.mjs +63 -10
  166. package/fesm2022/sd-angular-core-forms-date-range.mjs.map +1 -1
  167. package/fesm2022/sd-angular-core-forms-date.mjs +39 -15
  168. package/fesm2022/sd-angular-core-forms-date.mjs.map +1 -1
  169. package/fesm2022/sd-angular-core-forms-datetime.mjs +33 -14
  170. package/fesm2022/sd-angular-core-forms-datetime.mjs.map +1 -1
  171. package/fesm2022/sd-angular-core-forms-directives.mjs +18 -24
  172. package/fesm2022/sd-angular-core-forms-directives.mjs.map +1 -1
  173. package/fesm2022/sd-angular-core-forms-inline-text.mjs +167 -0
  174. package/fesm2022/sd-angular-core-forms-inline-text.mjs.map +1 -0
  175. package/fesm2022/sd-angular-core-forms-input-color.mjs +119 -0
  176. package/fesm2022/sd-angular-core-forms-input-color.mjs.map +1 -0
  177. package/fesm2022/sd-angular-core-forms-input-number.mjs +66 -14
  178. package/fesm2022/sd-angular-core-forms-input-number.mjs.map +1 -1
  179. package/fesm2022/sd-angular-core-forms-input.mjs +86 -29
  180. package/fesm2022/sd-angular-core-forms-input.mjs.map +1 -1
  181. package/fesm2022/sd-angular-core-forms-models.mjs +44 -2
  182. package/fesm2022/sd-angular-core-forms-models.mjs.map +1 -1
  183. package/fesm2022/sd-angular-core-forms-radio.mjs +130 -175
  184. package/fesm2022/sd-angular-core-forms-radio.mjs.map +1 -1
  185. package/fesm2022/sd-angular-core-forms-select.mjs +66 -23
  186. package/fesm2022/sd-angular-core-forms-select.mjs.map +1 -1
  187. package/fesm2022/sd-angular-core-forms-switch.mjs +95 -98
  188. package/fesm2022/sd-angular-core-forms-switch.mjs.map +1 -1
  189. package/fesm2022/sd-angular-core-forms-textarea.mjs +33 -12
  190. package/fesm2022/sd-angular-core-forms-textarea.mjs.map +1 -1
  191. package/fesm2022/sd-angular-core-i18n.mjs +65 -0
  192. package/fesm2022/sd-angular-core-i18n.mjs.map +1 -1
  193. package/fesm2022/sd-angular-core-modules-auth.mjs +4 -4
  194. package/fesm2022/sd-angular-core-modules-auth.mjs.map +1 -1
  195. package/fesm2022/sd-angular-core-modules-authom.mjs +1 -1
  196. package/fesm2022/sd-angular-core-modules-authom.mjs.map +1 -1
  197. package/fesm2022/sd-angular-core-modules-layout.mjs +23 -23
  198. package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
  199. package/fesm2022/sd-angular-core-modules-permission.mjs +3 -3
  200. package/fesm2022/sd-angular-core-modules-permission.mjs.map +1 -1
  201. package/fesm2022/sd-angular-core-pipes.mjs +2 -2
  202. package/fesm2022/sd-angular-core-pipes.mjs.map +1 -1
  203. package/fesm2022/sd-angular-core-services-api.mjs +3 -3
  204. package/fesm2022/sd-angular-core-services-api.mjs.map +1 -1
  205. package/fesm2022/sd-angular-core-services-cache.mjs +3 -2
  206. package/fesm2022/sd-angular-core-services-cache.mjs.map +1 -1
  207. package/fesm2022/sd-angular-core-services-confirm.mjs +1 -1
  208. package/fesm2022/sd-angular-core-services-confirm.mjs.map +1 -1
  209. package/fesm2022/sd-angular-core-services-excel.mjs +6 -5
  210. package/fesm2022/sd-angular-core-services-excel.mjs.map +1 -1
  211. package/fesm2022/sd-angular-core-services-notify.mjs +18 -5
  212. package/fesm2022/sd-angular-core-services-notify.mjs.map +1 -1
  213. package/fesm2022/sd-angular-core-services-storage.mjs +2 -2
  214. package/fesm2022/sd-angular-core-services-storage.mjs.map +1 -1
  215. package/fesm2022/sd-angular-core-utilities-models.mjs.map +1 -1
  216. package/forms/autocomplete/src/autocomplete.component.d.ts +24 -10
  217. package/forms/checkbox/src/checkbox.component.d.ts +21 -20
  218. package/forms/chip/src/chip.component.d.ts +25 -20
  219. package/forms/chip-calendar/src/chip-calendar.component.d.ts +27 -22
  220. package/forms/date/src/date.component.d.ts +23 -9
  221. package/forms/date-range/src/date-range.component.d.ts +28 -5
  222. package/forms/datetime/src/datetime.component.d.ts +21 -8
  223. package/forms/directives/src/item-def.directive.d.ts +10 -5
  224. package/forms/directives/src/label-def.directive.d.ts +3 -2
  225. package/forms/directives/src/suffix-def.directive.d.ts +3 -2
  226. package/forms/directives/src/view-def.directive.d.ts +9 -9
  227. package/forms/inline-text/index.d.ts +1 -0
  228. package/forms/inline-text/src/inline-text.component.d.ts +76 -0
  229. package/forms/input/src/input.component.d.ts +31 -13
  230. package/forms/input-color/index.d.ts +1 -0
  231. package/forms/input-color/src/input-color.component.d.ts +34 -0
  232. package/forms/input-number/src/input-number.component.d.ts +25 -9
  233. package/forms/models/index.d.ts +1 -0
  234. package/forms/models/src/sd-custom-validator.model.d.ts +13 -1
  235. package/forms/models/src/sd-viewed.d.ts +38 -0
  236. package/forms/radio/src/radio.component.d.ts +37 -38
  237. package/forms/select/src/select.component.d.ts +36 -14
  238. package/forms/switch/src/switch.component.d.ts +22 -23
  239. package/forms/textarea/src/textarea.component.d.ts +18 -8
  240. package/i18n/src/en.d.ts +11 -0
  241. package/modules/auth/configurations/auth.configuration.d.ts +4 -4
  242. package/modules/layout/configurations/layout.configuration.d.ts +3 -3
  243. package/modules/permission/src/configurations/permission.configuration.d.ts +3 -3
  244. package/package.json +92 -56
  245. package/sd-angular-core-19.0.3.tgz +0 -0
  246. package/services/confirm/src/lib/components/dialog-confirm/dialog-confirm.component.d.ts +3 -3
  247. package/services/confirm/src/lib/confirm.service.d.ts +9 -9
  248. package/services/notify/src/components/toast/toast.component.d.ts +4 -0
  249. package/utilities/models/src/icon.model.d.ts +1 -1
  250. package/assets/scss/bootstrap-4.6.2/_alert.scss +0 -52
  251. package/assets/scss/bootstrap-4.6.2/_badge.scss +0 -54
  252. package/assets/scss/bootstrap-4.6.2/_breadcrumb.scss +0 -42
  253. package/assets/scss/bootstrap-4.6.2/_button-group.scss +0 -163
  254. package/assets/scss/bootstrap-4.6.2/_buttons.scss +0 -142
  255. package/assets/scss/bootstrap-4.6.2/_card.scss +0 -286
  256. package/assets/scss/bootstrap-4.6.2/_carousel.scss +0 -200
  257. package/assets/scss/bootstrap-4.6.2/_close.scss +0 -40
  258. package/assets/scss/bootstrap-4.6.2/_code.scss +0 -48
  259. package/assets/scss/bootstrap-4.6.2/_custom-forms.scss +0 -526
  260. package/assets/scss/bootstrap-4.6.2/_dropdown.scss +0 -192
  261. package/assets/scss/bootstrap-4.6.2/_forms.scss +0 -347
  262. package/assets/scss/bootstrap-4.6.2/_functions.scss +0 -190
  263. package/assets/scss/bootstrap-4.6.2/_grid.scss +0 -73
  264. package/assets/scss/bootstrap-4.6.2/_images.scss +0 -42
  265. package/assets/scss/bootstrap-4.6.2/_input-group.scss +0 -211
  266. package/assets/scss/bootstrap-4.6.2/_jumbotron.scss +0 -17
  267. package/assets/scss/bootstrap-4.6.2/_list-group.scss +0 -154
  268. package/assets/scss/bootstrap-4.6.2/_media.scss +0 -8
  269. package/assets/scss/bootstrap-4.6.2/_mixins.scss +0 -47
  270. package/assets/scss/bootstrap-4.6.2/_modal.scss +0 -240
  271. package/assets/scss/bootstrap-4.6.2/_nav.scss +0 -125
  272. package/assets/scss/bootstrap-4.6.2/_navbar.scss +0 -332
  273. package/assets/scss/bootstrap-4.6.2/_pagination.scss +0 -74
  274. package/assets/scss/bootstrap-4.6.2/_popover.scss +0 -170
  275. package/assets/scss/bootstrap-4.6.2/_print.scss +0 -132
  276. package/assets/scss/bootstrap-4.6.2/_progress.scss +0 -47
  277. package/assets/scss/bootstrap-4.6.2/_reboot.scss +0 -484
  278. package/assets/scss/bootstrap-4.6.2/_root.scss +0 -19
  279. package/assets/scss/bootstrap-4.6.2/_spinners.scss +0 -65
  280. package/assets/scss/bootstrap-4.6.2/_tables.scss +0 -185
  281. package/assets/scss/bootstrap-4.6.2/_toasts.scss +0 -46
  282. package/assets/scss/bootstrap-4.6.2/_tooltip.scss +0 -115
  283. package/assets/scss/bootstrap-4.6.2/_transitions.scss +0 -26
  284. package/assets/scss/bootstrap-4.6.2/_type.scss +0 -125
  285. package/assets/scss/bootstrap-4.6.2/_utilities.scss +0 -18
  286. package/assets/scss/bootstrap-4.6.2/_variables.scss +0 -1150
  287. package/assets/scss/bootstrap-4.6.2/bootstrap-grid.scss +0 -30
  288. package/assets/scss/bootstrap-4.6.2/bootstrap-reboot.scss +0 -12
  289. package/assets/scss/bootstrap-4.6.2/bootstrap.scss +0 -44
  290. package/assets/scss/bootstrap-4.6.2/mixins/_alert.scss +0 -13
  291. package/assets/scss/bootstrap-4.6.2/mixins/_background-variant.scss +0 -23
  292. package/assets/scss/bootstrap-4.6.2/mixins/_badge.scss +0 -17
  293. package/assets/scss/bootstrap-4.6.2/mixins/_border-radius.scss +0 -76
  294. package/assets/scss/bootstrap-4.6.2/mixins/_box-shadow.scss +0 -20
  295. package/assets/scss/bootstrap-4.6.2/mixins/_breakpoints.scss +0 -123
  296. package/assets/scss/bootstrap-4.6.2/mixins/_buttons.scss +0 -110
  297. package/assets/scss/bootstrap-4.6.2/mixins/_caret.scss +0 -62
  298. package/assets/scss/bootstrap-4.6.2/mixins/_clearfix.scss +0 -7
  299. package/assets/scss/bootstrap-4.6.2/mixins/_deprecate.scss +0 -10
  300. package/assets/scss/bootstrap-4.6.2/mixins/_float.scss +0 -14
  301. package/assets/scss/bootstrap-4.6.2/mixins/_forms.scss +0 -195
  302. package/assets/scss/bootstrap-4.6.2/mixins/_gradients.scss +0 -45
  303. package/assets/scss/bootstrap-4.6.2/mixins/_grid-framework.scss +0 -80
  304. package/assets/scss/bootstrap-4.6.2/mixins/_grid.scss +0 -69
  305. package/assets/scss/bootstrap-4.6.2/mixins/_hover.scss +0 -37
  306. package/assets/scss/bootstrap-4.6.2/mixins/_image.scss +0 -36
  307. package/assets/scss/bootstrap-4.6.2/mixins/_list-group.scss +0 -21
  308. package/assets/scss/bootstrap-4.6.2/mixins/_lists.scss +0 -7
  309. package/assets/scss/bootstrap-4.6.2/mixins/_nav-divider.scss +0 -11
  310. package/assets/scss/bootstrap-4.6.2/mixins/_pagination.scss +0 -22
  311. package/assets/scss/bootstrap-4.6.2/mixins/_reset-text.scss +0 -17
  312. package/assets/scss/bootstrap-4.6.2/mixins/_resize.scss +0 -6
  313. package/assets/scss/bootstrap-4.6.2/mixins/_screen-reader.scss +0 -34
  314. package/assets/scss/bootstrap-4.6.2/mixins/_size.scss +0 -7
  315. package/assets/scss/bootstrap-4.6.2/mixins/_table-row.scss +0 -39
  316. package/assets/scss/bootstrap-4.6.2/mixins/_text-emphasis.scss +0 -17
  317. package/assets/scss/bootstrap-4.6.2/mixins/_text-hide.scss +0 -11
  318. package/assets/scss/bootstrap-4.6.2/mixins/_text-truncate.scss +0 -8
  319. package/assets/scss/bootstrap-4.6.2/mixins/_transition.scss +0 -26
  320. package/assets/scss/bootstrap-4.6.2/mixins/_visibility.scss +0 -8
  321. package/assets/scss/bootstrap-4.6.2/utilities/_align.scss +0 -8
  322. package/assets/scss/bootstrap-4.6.2/utilities/_background.scss +0 -19
  323. package/assets/scss/bootstrap-4.6.2/utilities/_borders.scss +0 -75
  324. package/assets/scss/bootstrap-4.6.2/utilities/_clearfix.scss +0 -3
  325. package/assets/scss/bootstrap-4.6.2/utilities/_display.scss +0 -26
  326. package/assets/scss/bootstrap-4.6.2/utilities/_embed.scss +0 -39
  327. package/assets/scss/bootstrap-4.6.2/utilities/_flex.scss +0 -51
  328. package/assets/scss/bootstrap-4.6.2/utilities/_float.scss +0 -11
  329. package/assets/scss/bootstrap-4.6.2/utilities/_interactions.scss +0 -5
  330. package/assets/scss/bootstrap-4.6.2/utilities/_overflow.scss +0 -5
  331. package/assets/scss/bootstrap-4.6.2/utilities/_position.scss +0 -32
  332. package/assets/scss/bootstrap-4.6.2/utilities/_screenreaders.scss +0 -11
  333. package/assets/scss/bootstrap-4.6.2/utilities/_shadows.scss +0 -6
  334. package/assets/scss/bootstrap-4.6.2/utilities/_sizing.scss +0 -20
  335. package/assets/scss/bootstrap-4.6.2/utilities/_spacing.scss +0 -73
  336. package/assets/scss/bootstrap-4.6.2/utilities/_stretched-link.scss +0 -19
  337. package/assets/scss/bootstrap-4.6.2/utilities/_text.scss +0 -72
  338. package/assets/scss/bootstrap-4.6.2/utilities/_visibility.scss +0 -13
  339. package/assets/scss/bootstrap-4.6.2/vendor/_rfs.scss +0 -228
  340. package/assets/scss/core/bootstrap.scss +0 -13
  341. package/components/table/index.d.ts.map +0 -1
  342. package/components/table/sd-angular-core-components-table.d.ts.map +0 -1
  343. package/components/table/src/components/column-title/column-title.component.d.ts.map +0 -1
  344. package/components/table/src/components/command/desktop-command.component.d.ts.map +0 -1
  345. package/components/table/src/components/command/pipes/command.pipe.d.ts.map +0 -1
  346. package/components/table/src/components/command/pipes/filter.pipe.d.ts.map +0 -1
  347. package/components/table/src/components/config/config.component.d.ts.map +0 -1
  348. package/components/table/src/components/desktop-cell/desktop-cell.component.d.ts.map +0 -1
  349. package/components/table/src/components/desktop-cell/view/view.component.d.ts.map +0 -1
  350. package/components/table/src/components/filter/column-filter/column-filter.component.d.ts.map +0 -1
  351. package/components/table/src/components/filter/external-filter/external-filter.component.d.ts.map +0 -1
  352. package/components/table/src/components/filter/index.d.ts.map +0 -1
  353. package/components/table/src/components/filter/mobile-filter/mobile-filter.component.d.ts.map +0 -1
  354. package/components/table/src/components/index.d.ts.map +0 -1
  355. package/components/table/src/components/popup-export/popup-export.component.d.ts.map +0 -1
  356. package/components/table/src/components/selector-action/action-filter.pipe.d.ts.map +0 -1
  357. package/components/table/src/components/selector-action/selector-action.component.d.ts.map +0 -1
  358. package/components/table/src/configurations/index.d.ts.map +0 -1
  359. package/components/table/src/configurations/table.configuration.d.ts.map +0 -1
  360. package/components/table/src/directives/index.d.ts.map +0 -1
  361. package/components/table/src/directives/sd-column-resize.directive.d.ts.map +0 -1
  362. package/components/table/src/directives/sd-table-cell-def.directive.d.ts.map +0 -1
  363. package/components/table/src/directives/sd-table-column-filter-def.directive.d.ts.map +0 -1
  364. package/components/table/src/directives/sd-table-expand-def.directive.d.ts.map +0 -1
  365. package/components/table/src/directives/sd-table-filter-def.directive.d.ts.map +0 -1
  366. package/components/table/src/directives/sd-table-footer-def.directive.d.ts.map +0 -1
  367. package/components/table/src/directives/sd-table-title-def.directive.d.ts.map +0 -1
  368. package/components/table/src/directives/sticky-shadow.directive.d.ts.map +0 -1
  369. package/components/table/src/models/index.d.ts.map +0 -1
  370. package/components/table/src/models/table-column.model.d.ts.map +0 -1
  371. package/components/table/src/models/table-command.model.d.ts.map +0 -1
  372. package/components/table/src/models/table-item.model.d.ts.map +0 -1
  373. package/components/table/src/models/table-option-config.model.d.ts.map +0 -1
  374. package/components/table/src/models/table-option-expand.model.d.ts.map +0 -1
  375. package/components/table/src/models/table-option-export.model.d.ts.map +0 -1
  376. package/components/table/src/models/table-option-group.model.d.ts.map +0 -1
  377. package/components/table/src/models/table-option-paginate.model.d.ts.map +0 -1
  378. package/components/table/src/models/table-option-reload.model.d.ts.map +0 -1
  379. package/components/table/src/models/table-option-selector.model.d.ts.map +0 -1
  380. package/components/table/src/models/table-option-sort.model.d.ts.map +0 -1
  381. package/components/table/src/models/table-option-style.model.d.ts.map +0 -1
  382. package/components/table/src/models/table-option-tree.model.d.ts.map +0 -1
  383. package/components/table/src/models/table-option.model.d.ts.map +0 -1
  384. package/components/table/src/pipes/filter-values.pipe.d.ts.map +0 -1
  385. package/components/table/src/pipes/index.d.ts.map +0 -1
  386. package/components/table/src/pipes/sd-group.pipe.d.ts.map +0 -1
  387. package/components/table/src/pipes/sd-tree.pipe.d.ts.map +0 -1
  388. package/components/table/src/pipes/selection-disabled.pipe.d.ts.map +0 -1
  389. package/components/table/src/pipes/selection-visible-select-all.pipe.d.ts.map +0 -1
  390. package/components/table/src/pipes/selection-visible.pipe.d.ts.map +0 -1
  391. package/components/table/src/services/column-width.util.d.ts.map +0 -1
  392. package/components/table/src/services/config.service.d.ts.map +0 -1
  393. package/components/table/src/services/index.d.ts.map +0 -1
  394. package/components/table/src/services/table-export/table-export.service.d.ts.map +0 -1
  395. package/components/table/src/services/table-filter/table-filter.model.d.ts.map +0 -1
  396. package/components/table/src/services/table-filter/table-filter.service.d.ts.map +0 -1
  397. package/components/table/src/services/table-format/table-format.service.d.ts.map +0 -1
  398. package/components/table/src/services/tree/tree.util.d.ts.map +0 -1
  399. package/components/table/src/table.component.d.ts.map +0 -1
  400. package/sd-angular-core-19.0.0-beta.99.tgz +0 -0
@@ -8,6 +8,7 @@ import * as i4 from '@angular/material/tooltip';
8
8
  import { MatTooltipModule } from '@angular/material/tooltip';
9
9
  import * as i2 from '@angular/forms';
10
10
  import { FormsModule } from '@angular/forms';
11
+ import { Router } from '@angular/router';
11
12
 
12
13
  /** Selector mặc định coi là phải có data-autoid. */
13
14
  const SD_AUTOID_DEFAULT_REQUIRE_SELECTORS = [
@@ -28,8 +29,14 @@ const SD_AUTOID_DEFAULT_REQUIRE_SELECTORS = [
28
29
  ];
29
30
 
30
31
  class SdAutoidScannerService {
31
- /** Quét toàn bộ element có [data-autoid] trong root, gắn thông tin name/tag/value/xpath. */
32
- scan(root = document.body) {
32
+ /**
33
+ * Quét element có [data-autoid] trong root, gắn name/tag/value/xpath.
34
+ * Khi truyền `requireSelectors` (vd các sd-* form/button), những node khớp selector
35
+ * mà KHÔNG có data-autoid (self lẫn con) sẽ được thêm vào dưới dạng phần tử fallback
36
+ * (`autoid: ''`, xpath theo vị trí thẻ + cờ `missingAutoid` + warning) — để JSON xuất ra
37
+ * vẫn dùng được và dev biết chỗ cần bổ sung autoid.
38
+ */
39
+ scan(root = document.body, requireSelectors = []) {
33
40
  const nodes = root.querySelectorAll('[data-autoid]');
34
41
  const dupCount = {};
35
42
  nodes.forEach(n => {
@@ -44,18 +51,61 @@ class SdAutoidScannerService {
44
51
  const autoid = node.getAttribute('data-autoid');
45
52
  if (!autoid)
46
53
  return;
54
+ const state = this.readState(node);
55
+ const tableScope = this.resolveTableScope(node);
47
56
  result.push({
48
57
  stt: stt++,
49
58
  name: this.resolveName(node),
50
59
  autoid,
51
60
  tag: this.resolveSdTag(node),
52
- value: this.resolveValue(node),
61
+ text: this.resolveText(node),
53
62
  xpath: `//*[@data-autoid="${autoid}"]`,
54
63
  duplicate: dupCount[autoid] > 1,
64
+ state,
65
+ tableScope,
55
66
  });
56
67
  });
68
+ if (requireSelectors.length) {
69
+ stt = this.appendMissing(root, requireSelectors, result, stt);
70
+ }
57
71
  return result;
58
72
  }
73
+ /**
74
+ * Tìm các node khớp `requireSelectors` nhưng thiếu data-autoid (self + mọi descendant),
75
+ * thêm vào `result` dưới dạng phần tử fallback. Trả về `stt` kế tiếp.
76
+ */
77
+ appendMissing(root, requireSelectors, result, startStt) {
78
+ let stt = startStt;
79
+ const joined = requireSelectors.join(',');
80
+ root.querySelectorAll(joined).forEach(node => {
81
+ // Cùng quy ước với audit: bỏ qua khi self hoặc con đã có data-autoid.
82
+ if (node.hasAttribute('data-autoid'))
83
+ return;
84
+ if (node.querySelector('[data-autoid]'))
85
+ return;
86
+ const tag = node.tagName.toLowerCase();
87
+ result.push({
88
+ stt: stt++,
89
+ name: this.resolveName(node),
90
+ autoid: '',
91
+ tag,
92
+ text: this.resolveText(node),
93
+ xpath: this.fallbackXpath(node, tag),
94
+ duplicate: false,
95
+ state: this.readState(node),
96
+ tableScope: this.resolveTableScope(node),
97
+ missingAutoid: true,
98
+ warning: 'Thiếu data-autoid — dùng xpath fallback theo tag (dev nên bổ sung autoid)',
99
+ });
100
+ });
101
+ return stt;
102
+ }
103
+ /** XPath theo vị trí thẻ trong document, vd `(//sd-button)[2]`, khi không có autoid. */
104
+ fallbackXpath(node, tag) {
105
+ const all = Array.from(document.querySelectorAll(tag));
106
+ const idx = all.indexOf(node);
107
+ return `(//${tag})[${idx >= 0 ? idx + 1 : 1}]`;
108
+ }
59
109
  /** Group element theo autoid để consumer lấy duplicate map. */
60
110
  groupByAutoid(elements) {
61
111
  const map = {};
@@ -64,6 +114,46 @@ class SdAutoidScannerService {
64
114
  }
65
115
  return map;
66
116
  }
117
+ /**
118
+ * Read the optional `data-*` E2E state attributes off the same node.
119
+ * Only includes fields actually present on the DOM (skipped fields stay undefined).
120
+ */
121
+ readState(node) {
122
+ const get = (n) => {
123
+ const v = node.getAttribute(n);
124
+ return v === null ? undefined : v;
125
+ };
126
+ return {
127
+ disabled: get('data-disabled'),
128
+ loading: get('data-loading'),
129
+ empty: get('data-empty'),
130
+ invalid: get('data-invalid'),
131
+ opened: get('data-opened'),
132
+ count: get('data-count'),
133
+ dataValue: get('data-value'),
134
+ required: get('data-required'),
135
+ maxlength: get('data-maxlength'),
136
+ minlength: get('data-minlength'),
137
+ pattern: get('data-pattern'),
138
+ errorMessage: get('data-error-message'),
139
+ type: get('data-type'),
140
+ title: get('data-title'),
141
+ message: get('data-message'),
142
+ };
143
+ }
144
+ /**
145
+ * If the node is inside an `<sd-table>` element, return that table's `data-autoid`.
146
+ * Walks up via closest('sd-table') — skips the node itself if it IS the table.
147
+ */
148
+ resolveTableScope(node) {
149
+ // Skip self if the node itself is the sd-table host.
150
+ const start = node.tagName.toLowerCase() === 'sd-table' ? node.parentElement : node;
151
+ const table = start?.closest('sd-table');
152
+ if (!table || table === node)
153
+ return undefined;
154
+ const id = table.getAttribute('data-autoid');
155
+ return id ?? undefined;
156
+ }
67
157
  resolveName(node) {
68
158
  if (node.id) {
69
159
  // CSS.escape phòng id chứa ký tự đặc biệt làm vỡ selector.
@@ -88,7 +178,7 @@ class SdAutoidScannerService {
88
178
  }
89
179
  return node.tagName.toLowerCase();
90
180
  }
91
- resolveValue(node) {
181
+ resolveText(node) {
92
182
  const input = node;
93
183
  if (typeof input.value === 'string' && input.value)
94
184
  return input.value;
@@ -293,12 +383,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
293
383
  }] });
294
384
 
295
385
  class SdAutoidExportService {
296
- toJson(elements) {
386
+ /**
387
+ * Có `meta` → bọc `{ meta, elements }` (kèm url/queryParams) để consumer biết trang/route.
388
+ * Không `meta` → giữ mảng thuần (back-compat cho caller cũ chỉ cần elements).
389
+ */
390
+ toJson(elements, meta) {
391
+ if (meta)
392
+ return JSON.stringify({ meta, elements }, null, 2);
297
393
  return JSON.stringify(elements, null, 2);
298
394
  }
395
+ /** Parse a `location.search` string into a flat key/value map (last value wins). */
396
+ parseQueryParams(search) {
397
+ const out = {};
398
+ new URLSearchParams(search || '').forEach((v, k) => {
399
+ out[k] = v;
400
+ });
401
+ return out;
402
+ }
299
403
  toCsv(elements) {
300
- const header = 'STT,name,autoid,tag,value,xpath';
301
- const rows = elements.map(el => [el.stt, this.q(el.name), this.q(el.autoid), this.q(el.tag), this.q(el.value), this.q(el.xpath)].join(','));
404
+ const header = 'STT,name,autoid,tag,table-scope,disabled,loading,empty,invalid,opened,count,data-value,text,xpath';
405
+ const rows = elements.map(el => [
406
+ el.stt,
407
+ this.q(el.name),
408
+ this.q(el.autoid),
409
+ this.q(el.tag),
410
+ this.q(el.tableScope ?? ''),
411
+ this.q(el.state.disabled ?? ''),
412
+ this.q(el.state.loading ?? ''),
413
+ this.q(el.state.empty ?? ''),
414
+ this.q(el.state.invalid ?? ''),
415
+ this.q(el.state.opened ?? ''),
416
+ this.q(el.state.count ?? ''),
417
+ this.q(el.state.dataValue ?? ''),
418
+ this.q(el.text),
419
+ this.q(el.xpath),
420
+ ].join(','));
302
421
  return [header, ...rows].join('\n') + '\n';
303
422
  }
304
423
  /** POM TypeScript skeleton — copy ngay vào file Playwright/Cypress. */
@@ -313,9 +432,12 @@ class SdAutoidExportService {
313
432
  lines.push('```ts');
314
433
  lines.push(`export class ${className} {`);
315
434
  for (const el of elements) {
316
- const propName = this.toCamel(el.autoid);
435
+ // autoid rỗng (phần tử fallback thiếu autoid) → đặt tên prop theo tag + stt.
436
+ const propName = el.autoid ? this.toCamel(el.autoid) : this.toCamel(`${el.tag}-${el.stt}`);
317
437
  const nameHint = el.name ? ` ${el.name} —` : '';
318
- lines.push(` /** ${el.tag}${nameHint} */`);
438
+ const stateSummary = this.buildStateSummary(el.state);
439
+ const stateStr = stateSummary ? ` — ${stateSummary}` : '';
440
+ lines.push(` /** ${el.tag}${nameHint}${stateStr} */`);
319
441
  lines.push(` readonly ${propName} = '${el.xpath}';`);
320
442
  }
321
443
  lines.push('}');
@@ -323,7 +445,7 @@ class SdAutoidExportService {
323
445
  lines.push('');
324
446
  return lines.join('\n');
325
447
  }
326
- /** Markdown reference table, group theo tag sd-*. */
448
+ /** Markdown reference table, group FIRST by tableScope (top-level first, then per table), then by tag. */
327
449
  toMarkdownTable(elements, meta) {
328
450
  const lines = [];
329
451
  lines.push('# AutoId Reference');
@@ -331,24 +453,54 @@ class SdAutoidExportService {
331
453
  lines.push(`- Page: \`${meta.pageUrl}\``);
332
454
  lines.push(`- Generated: \`${meta.timestamp}\``);
333
455
  lines.push('');
334
- const groups = new Map();
456
+ // Partition into top-level and per-table buckets.
457
+ const topLevel = elements.filter(el => !el.tableScope);
458
+ // Collect unique table scopes in insertion order (preserves DOM order).
459
+ const tableScopes = [];
335
460
  for (const el of elements) {
336
- const key = el.tag || '(no-tag)';
337
- if (!groups.has(key))
338
- groups.set(key, []);
339
- groups.get(key).push(el);
461
+ if (el.tableScope && !tableScopes.includes(el.tableScope)) {
462
+ tableScopes.push(el.tableScope);
463
+ }
340
464
  }
341
- const sortedTags = [...groups.keys()].sort();
342
- for (const tag of sortedTags) {
343
- lines.push(`## ${tag}`);
344
- lines.push('');
345
- lines.push('| name | autoid | xpath | duplicate |');
346
- lines.push('|------|--------|-------|-----------|');
347
- for (const el of groups.get(tag)) {
348
- lines.push(`| ${this.mdCell(el.name)} | \`${el.autoid}\` | \`${el.xpath}\` | ${el.duplicate ? '⚠️' : ''} |`);
465
+ tableScopes.sort();
466
+ const renderTagGroup = (items) => {
467
+ const groups = new Map();
468
+ for (const el of items) {
469
+ const key = el.tag || '(no-tag)';
470
+ if (!groups.has(key))
471
+ groups.set(key, []);
472
+ groups.get(key).push(el);
473
+ }
474
+ const sortedTags = [...groups.keys()].sort();
475
+ for (const tag of sortedTags) {
476
+ lines.push(`### ${tag}`);
477
+ lines.push('');
478
+ lines.push('| name | autoid | xpath | state | duplicate |');
479
+ lines.push('|------|--------|-------|-------|-----------|');
480
+ for (const el of groups.get(tag)) {
481
+ const stateSummary = this.buildStateSummary(el.state);
482
+ lines.push(`| ${this.mdCell(el.name)} | \`${el.autoid}\` | \`${el.xpath}\` | ${this.mdCell(stateSummary)} | ${el.duplicate ? '⚠️' : ''} |`);
483
+ }
484
+ lines.push('');
349
485
  }
486
+ };
487
+ // Top-level section.
488
+ lines.push('## Top-level');
489
+ lines.push('');
490
+ if (topLevel.length > 0) {
491
+ renderTagGroup(topLevel);
492
+ }
493
+ else {
494
+ lines.push('_(no top-level elements)_');
350
495
  lines.push('');
351
496
  }
497
+ // Per-table sections.
498
+ for (const scope of tableScopes) {
499
+ lines.push(`## Inside table \`${scope}\``);
500
+ lines.push('');
501
+ const scopeItems = elements.filter(el => el.tableScope === scope);
502
+ renderTagGroup(scopeItems);
503
+ }
352
504
  return lines.join('\n');
353
505
  }
354
506
  download(content, filename, mime) {
@@ -377,6 +529,25 @@ class SdAutoidExportService {
377
529
  document.execCommand('copy');
378
530
  document.body.removeChild(ta);
379
531
  }
532
+ /** Build a compact state summary string from defined state keys, e.g. "disabled=false; empty=true". */
533
+ buildStateSummary(state) {
534
+ const parts = [];
535
+ if (state.disabled !== undefined)
536
+ parts.push(`disabled=${state.disabled}`);
537
+ if (state.loading !== undefined)
538
+ parts.push(`loading=${state.loading}`);
539
+ if (state.empty !== undefined)
540
+ parts.push(`empty=${state.empty}`);
541
+ if (state.invalid !== undefined)
542
+ parts.push(`invalid=${state.invalid}`);
543
+ if (state.opened !== undefined)
544
+ parts.push(`opened=${state.opened}`);
545
+ if (state.count !== undefined)
546
+ parts.push(`count=${state.count}`);
547
+ if (state.dataValue !== undefined)
548
+ parts.push(`data-value=${state.dataValue}`);
549
+ return parts.join('; ');
550
+ }
380
551
  q(v) {
381
552
  const s = String(v ?? '').replace(/"/g, '""');
382
553
  return `"${s}"`;
@@ -431,6 +602,37 @@ class SdAutoidInspector {
431
602
  el.name.toLowerCase().includes(q) ||
432
603
  el.tag.toLowerCase().includes(q));
433
604
  });
605
+ /**
606
+ * Elements not inside any sd-table — rendered in the main "Top-level" section.
607
+ */
608
+ topLevelElements = computed(() => this.filteredElements().filter(el => !el.tableScope));
609
+ /**
610
+ * Map of `sd-table` autoid → its inner autoid elements. Tables themselves
611
+ * stay in `topLevelElements` (the table's own autoid is top-level).
612
+ */
613
+ tableGroups = computed(() => {
614
+ const groups = new Map();
615
+ for (const el of this.filteredElements()) {
616
+ if (!el.tableScope)
617
+ continue;
618
+ if (!groups.has(el.tableScope))
619
+ groups.set(el.tableScope, []);
620
+ groups.get(el.tableScope).push(el);
621
+ }
622
+ // Return a sorted array for stable rendering.
623
+ return [...groups.entries()]
624
+ .sort(([a], [b]) => a.localeCompare(b))
625
+ .map(([scope, items]) => ({ scope, items }));
626
+ });
627
+ // ==========================================
628
+ // DATA-* ATTRIBUTE COMPUTEDS (for E2E selectors)
629
+ // ==========================================
630
+ dataOpened = computed(() => (this.open() ? 'true' : 'false'));
631
+ dataHighlightOn = computed(() => (this.highlightOn() ? 'true' : 'false'));
632
+ dataSegment = computed(() => this.segment());
633
+ dataElementCount = computed(() => String(this.elements().length));
634
+ dataMissingCount = computed(() => String(this.audit()?.missingCount ?? 0));
635
+ dataDuplicateCount = computed(() => String(this.audit()?.duplicateCount ?? 0));
434
636
  // ==========================================
435
637
  // SERVICES
436
638
  // ==========================================
@@ -438,6 +640,8 @@ class SdAutoidInspector {
438
640
  #auditSvc = inject(SdAutoidAuditService);
439
641
  #highlight = inject(SdAutoidHighlightService);
440
642
  #export = inject(SdAutoidExportService);
643
+ // Optional — chỉ có khi app dùng RouterModule; dùng để lấy route params cho meta.
644
+ #router = inject(Router, { optional: true });
441
645
  // ==========================================
442
646
  // LIFECYCLE
443
647
  // ==========================================
@@ -468,7 +672,7 @@ class SdAutoidInspector {
468
672
  };
469
673
  refresh = () => {
470
674
  const root = this.#root();
471
- const elements = this.#scanner.scan(root);
675
+ const elements = this.#scanner.scan(root, this.#requireSelectors());
472
676
  const result = this.#auditSvc.audit(elements, {
473
677
  root,
474
678
  requireSelectors: this.#requireSelectors(),
@@ -495,7 +699,7 @@ class SdAutoidInspector {
495
699
  };
496
700
  setSegment = (seg) => this.segment.set(seg);
497
701
  copyJson = async () => {
498
- await this.#export.copyToClipboard(this.#export.toJson(this.elements()));
702
+ await this.#export.copyToClipboard(this.#export.toJson(this.elements(), this.#meta()));
499
703
  this.#flashCopyOk();
500
704
  };
501
705
  copyXpath = async (autoid) => {
@@ -506,7 +710,7 @@ class SdAutoidInspector {
506
710
  this.#export.download(this.#export.toCsv(this.elements()), this.#filename('csv'), 'text/csv;charset=utf-8');
507
711
  };
508
712
  exportJson = () => {
509
- this.#export.download(this.#export.toJson(this.elements()), this.#filename('json'), 'application/json');
713
+ this.#export.download(this.#export.toJson(this.elements(), this.#meta()), this.#filename('json'), 'application/json');
510
714
  };
511
715
  exportMdPom = () => {
512
716
  this.#export.download(this.#export.toMarkdownPom(this.elements(), this.#meta()), this.#filename('pom.md'), 'text/markdown');
@@ -549,12 +753,33 @@ class SdAutoidInspector {
549
753
  this.#highlightMissing(result);
550
754
  }
551
755
  #meta() {
756
+ const loc = window.location;
552
757
  return {
553
- pageUrl: window.location.pathname + window.location.search,
758
+ pageUrl: loc.pathname + loc.search,
554
759
  pageTitle: document.title || 'Page',
555
760
  timestamp: new Date().toISOString(),
761
+ url: loc.href,
762
+ pathname: loc.pathname,
763
+ search: loc.search,
764
+ queryParams: this.#export.parseQueryParams(loc.search),
765
+ params: this.#routeParams(),
556
766
  };
557
767
  }
768
+ /**
769
+ * Route path params gộp dọc cây ActivatedRoute (nếu có Router). Trả về undefined khi
770
+ * không có Router hoặc không có param nào — để `meta.params` được bỏ qua khỏi JSON.
771
+ */
772
+ #routeParams() {
773
+ if (!this.#router)
774
+ return undefined;
775
+ const params = {};
776
+ let route = this.#router.routerState.snapshot.root;
777
+ while (route) {
778
+ Object.assign(params, route.params);
779
+ route = route.firstChild;
780
+ }
781
+ return Object.keys(params).length ? params : undefined;
782
+ }
558
783
  #filename(ext) {
559
784
  const slug = (document.title || 'autoid')
560
785
  .toLowerCase()
@@ -567,11 +792,11 @@ class SdAutoidInspector {
567
792
  setTimeout(() => this.copyOk.set(false), 1200);
568
793
  }
569
794
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidInspector, deps: [], target: i0.ɵɵFactoryTarget.Component });
570
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SdAutoidInspector, isStandalone: true, selector: "sd-autoid-inspector", inputs: { enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, ngImport: i0, template: "@if (enabled() && !dismissed()) {\r\n <div class=\"sd-autoid-inspector__fab-wrap\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__fab\"\r\n data-autoid=\"sd-autoid-inspector-fab\"\r\n [matTooltip]=\"open() ? '\u0110\u00F3ng AutoId Inspector' : 'M\u1EDF AutoId Inspector'\"\r\n matTooltipPosition=\"left\"\r\n (click)=\"togglePanel()\">\r\n <mat-icon>{{ open() ? 'close' : 'tag' }}</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__fab-dismiss\"\r\n matTooltip=\"\u1EA8n t\u1EA1m \u2014 reload trang \u0111\u1EC3 hi\u1EC7n l\u1EA1i\"\r\n matTooltipPosition=\"left\"\r\n aria-label=\"\u1EA8n t\u1EA1m FAB\"\r\n (click)=\"dismissFab($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n}\r\n\r\n@if (enabled() && open()) {\r\n <div class=\"sd-autoid-inspector__backdrop\" (click)=\"closePanel()\"></div>\r\n <section class=\"sd-autoid-inspector__panel\" role=\"dialog\" aria-label=\"AutoId Inspector\">\r\n <header class=\"sd-autoid-inspector__header\">\r\n <div class=\"sd-autoid-inspector__segments\">\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"segment() === 'audit'\"\r\n (click)=\"setSegment('audit')\">\r\n Audit\r\n @if (audit(); as a) {\r\n <span class=\"sd-autoid-inspector__badge\" [class.is-warn]=\"a.missingCount + a.duplicateCount > 0\">\r\n {{ a.missingCount + a.duplicateCount }}\r\n </span>\r\n }\r\n </button>\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"segment() === 'elements'\"\r\n (click)=\"setSegment('elements')\">\r\n Elements\r\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\r\n </button>\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"segment() === 'export'\"\r\n (click)=\"setSegment('export')\">\r\n Export\r\n </button>\r\n </div>\r\n <div class=\"sd-autoid-inspector__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn\"\r\n matTooltip=\"Qu\u00E9t l\u1EA1i\"\r\n (click)=\"refresh()\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__close-btn\"\r\n matTooltip=\"\u0110\u00F3ng\"\r\n aria-label=\"\u0110\u00F3ng panel\"\r\n (click)=\"closePanel()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </header>\r\n\r\n @if (copyOk()) {\r\n <div class=\"sd-autoid-inspector__toast\">\u0110\u00E3 copy \u2713</div>\r\n }\r\n\r\n <div class=\"sd-autoid-inspector__body\">\r\n @switch (segment()) {\r\n @case ('audit') {\r\n <ng-container *ngTemplateOutlet=\"auditTpl\"></ng-container>\r\n }\r\n @case ('elements') {\r\n <ng-container *ngTemplateOutlet=\"elementsTpl\"></ng-container>\r\n }\r\n @case ('export') {\r\n <ng-container *ngTemplateOutlet=\"exportTpl\"></ng-container>\r\n }\r\n }\r\n </div>\r\n </section>\r\n\r\n <ng-template #auditTpl>\r\n @if (audit(); as a) {\r\n <div class=\"sd-autoid-inspector__audit-toolbar\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__toggle\"\r\n [class.is-on]=\"highlightOn()\"\r\n (click)=\"toggleHighlight()\">\r\n <mat-icon>{{ highlightOn() ? 'visibility' : 'visibility_off' }}</mat-icon>\r\n <span>Highlight DOM</span>\r\n <span class=\"sd-autoid-inspector__toggle-state\">{{ highlightOn() ? 'ON' : 'OFF' }}</span>\r\n </button>\r\n </div>\r\n <div class=\"sd-autoid-inspector__summary\">\r\n <div class=\"sd-autoid-inspector__stat is-info\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.total }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">T\u1ED5ng autoid</div>\r\n </div>\r\n <div class=\"sd-autoid-inspector__stat\" [class.is-error]=\"a.duplicateCount > 0\" [class.is-success]=\"a.duplicateCount === 0\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.duplicateCount }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">Tr\u00F9ng</div>\r\n </div>\r\n <div class=\"sd-autoid-inspector__stat\" [class.is-warning]=\"a.missingCount > 0\" [class.is-success]=\"a.missingCount === 0\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.missingCount }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">Thi\u1EBFu</div>\r\n </div>\r\n </div>\r\n\r\n @if (a.duplicateCount > 0) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-error\">error_outline</mat-icon>\r\n Autoid b\u1ECB tr\u00F9ng\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr><th>Autoid</th><th>S\u1ED1 l\u1EA7n</th></tr>\r\n </thead>\r\n <tbody>\r\n @for (entry of a.duplicates | keyvalue; track entry.key) {\r\n <tr class=\"is-error\">\r\n <td><code>{{ entry.key }}</code></td>\r\n <td>{{ entry.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n\r\n @if (a.missingCount > 0) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-warning\">warning_amber</mat-icon>\r\n Element thi\u1EBFu autoid\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr><th>Tag</th><th>Name hint</th><th>Selector</th></tr>\r\n </thead>\r\n <tbody>\r\n @for (m of a.missing; track $index) {\r\n <tr class=\"is-warning\">\r\n <td><code>{{ m.tag }}</code></td>\r\n <td>{{ m.nameHint }}</td>\r\n <td><code>{{ m.selector }}</code></td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n\r\n @if (a.duplicateCount === 0 && a.missingCount === 0) {\r\n <div class=\"sd-autoid-inspector__success-card\">\r\n <mat-icon>check_circle</mat-icon>\r\n <div>\r\n <strong>Kh\u00F4ng c\u00F3 element thi\u1EBFu ho\u1EB7c tr\u00F9ng autoid.</strong>\r\n <small>Trang \u0111\u00E3 \u0111\u1EA1t chu\u1EA9n convention autoid.</small>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-template>\r\n\r\n <ng-template #elementsTpl>\r\n <div class=\"sd-autoid-inspector__filter\">\r\n <mat-icon>search</mat-icon>\r\n <input\r\n type=\"text\"\r\n placeholder=\"L\u1ECDc theo autoid / name / tag\"\r\n [ngModel]=\"filter()\"\r\n (ngModelChange)=\"filter.set($event)\"/>\r\n @if (filter()) {\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn\"\r\n matTooltip=\"Xo\u00E1 filter\"\r\n (click)=\"filter.set('')\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr>\r\n <th class=\"is-num\">STT</th>\r\n <th>Name</th>\r\n <th>Autoid</th>\r\n <th>Tag</th>\r\n <th>Value</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (el of filteredElements(); track el.autoid + $index) {\r\n <tr [class.is-error]=\"el.duplicate\">\r\n <td class=\"is-num\">{{ el.stt }}</td>\r\n <td>{{ el.name || '\u2014' }}</td>\r\n <td>\r\n <div class=\"sd-autoid-inspector__autoid-cell\">\r\n <code>{{ el.autoid }}</code>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn is-primary\"\r\n matTooltip=\"Copy xpath\"\r\n (click)=\"copyXpath(el.autoid)\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n </div>\r\n </td>\r\n <td><span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span></td>\r\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.value || ''\">\r\n {{ el.value || '\u2014' }}\r\n </td>\r\n </tr>\r\n } @empty {\r\n <tr><td colspan=\"5\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td></tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #exportTpl>\r\n <div class=\"sd-autoid-inspector__export-grid\">\r\n <button type=\"button\" matTooltip=\"Copy JSON v\u00E0o clipboard\" (click)=\"copyJson()\">\r\n <mat-icon>content_copy</mat-icon>\r\n <span>Copy JSON</span>\r\n <small>clipboard</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i file JSON\" (click)=\"exportJson()\">\r\n <mat-icon>download</mat-icon>\r\n <span>JSON</span>\r\n <small>.json</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i file CSV\" (click)=\"exportCsv()\">\r\n <mat-icon>table_view</mat-icon>\r\n <span>CSV</span>\r\n <small>.csv</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i MD POM skeleton \u2014 cho AI vi\u1EBFt auto-test\" (click)=\"exportMdPom()\">\r\n <mat-icon>code</mat-icon>\r\n <span>MD POM</span>\r\n <small>AI test</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i MD reference table \u2014 group theo tag sd-*\" (click)=\"exportMdTable()\">\r\n <mat-icon>view_list</mat-icon>\r\n <span>MD Table</span>\r\n <small>reference</small>\r\n </button>\r\n </div>\r\n </ng-template>\r\n}\r\n", styles: [":host{position:fixed;inset:auto 0 0 auto;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__fab-wrap{position:fixed;right:16px;bottom:16px;z-index:100000}.sd-autoid-inspector__fab-wrap:hover .sd-autoid-inspector__fab-dismiss{opacity:1;transform:scale(1);pointer-events:auto}.sd-autoid-inspector__fab{width:36px;height:36px;border-radius:50%;border:none;background:var(--sd-primary, #2A66F4);color:#fff;cursor:pointer;box-shadow:0 3px 10px #00000038;display:inline-flex;align-items:center;justify-content:center;transition:transform .15s ease,background .15s ease,box-shadow .15s ease}.sd-autoid-inspector__fab:hover{background:var(--sd-primary-dark, #1C4AD9);transform:scale(1.08);box-shadow:0 5px 14px #00000047}.sd-autoid-inspector__fab mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__fab-dismiss{position:absolute;top:-6px;right:-6px;width:18px;height:18px;border-radius:50%;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;color:var(--sd-black400, #757575);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;opacity:0;transform:scale(.7);pointer-events:none;transition:opacity .12s ease,transform .12s ease,color .12s ease,background .12s ease;box-shadow:0 1px 4px #00000026}.sd-autoid-inspector__fab-dismiss:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__fab-dismiss mat-icon{font-size:12px;width:12px;height:12px;line-height:12px}.sd-autoid-inspector__backdrop{position:fixed;inset:0;background:#00000052;z-index:100001;backdrop-filter:blur(2px)}.sd-autoid-inspector__panel{position:fixed;right:20px;bottom:80px;width:min(860px,100vw - 40px);max-height:calc(100vh - 110px);background:#fff;border-radius:12px;box-shadow:0 16px 48px #00000038;display:flex;flex-direction:column;z-index:100002;overflow:hidden;border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__header{display:flex;align-items:center;gap:8px;padding:8px 10px;border-bottom:1px solid var(--sd-black200, #E6E6E6);background:var(--sd-black100, #F2F2F2);flex-shrink:0}.sd-autoid-inspector__segments{display:inline-flex;border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;background:#fff;overflow:hidden}.sd-autoid-inspector__segments button{border:none;background:transparent;padding:5px 12px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;gap:6px;border-right:1px solid var(--sd-black200, #E6E6E6);transition:background .12s ease,color .12s ease}.sd-autoid-inspector__segments button:last-child{border-right:none}.sd-autoid-inspector__segments button:hover:not(.is-active){background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__segments button.is-active{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__badge{background:var(--sd-black200, #E6E6E6);color:var(--sd-black500, #212121);border-radius:10px;padding:0 7px;font-size:11px;font-weight:600;line-height:16px}.is-active .sd-autoid-inspector__badge{background:#ffffff40;color:#fff}.sd-autoid-inspector__badge.is-warn{background:var(--sd-error, #F82C13);color:#fff}.sd-autoid-inspector__actions{display:inline-flex;gap:4px;margin-left:auto}.sd-autoid-inspector__icon-btn{border:none;background:transparent;cursor:pointer;padding:4px;border-radius:6px;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__icon-btn:hover{background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__icon-btn.is-primary{color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__icon-btn.is-primary:hover{background:var(--sd-primary-light, #EAF1FF);color:var(--sd-primary-dark, #1C4AD9)}.sd-autoid-inspector__icon-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__close-btn{border:none;cursor:pointer;padding:4px;border-radius:50%;width:28px;height:28px;background:transparent;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__close-btn:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__close-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__body{padding:14px;overflow:auto;flex:1;background:#fff}.sd-autoid-inspector__toast{position:absolute;top:56px;right:14px;background:var(--sd-success, #4CAF50);color:#fff;padding:6px 12px;border-radius:6px;font-size:12px;z-index:2;box-shadow:0 4px 12px #0000002e}.sd-autoid-inspector__audit-toolbar{display:flex;justify-content:flex-end;margin-bottom:12px}.sd-autoid-inspector__toggle{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:999px;padding:5px 12px 5px 10px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);transition:all .15s ease}.sd-autoid-inspector__toggle:hover{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__toggle.is-on{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__toggle mat-icon{font-size:16px;width:16px;height:16px}.sd-autoid-inspector__toggle-state{font-size:10px;font-weight:700;padding:1px 7px;border-radius:999px;background:var(--sd-black200, #E6E6E6);color:var(--sd-black400, #757575)}.is-on .sd-autoid-inspector__toggle-state{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__summary{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px}.sd-autoid-inspector__stat{background:var(--sd-black100, #F2F2F2);border-radius:10px;padding:12px;text-align:center;border:1px solid transparent}.sd-autoid-inspector__stat.is-info{background:var(--sd-info-light, #E7E9FF);border-color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-info .sd-autoid-inspector__stat-value{color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-success{background:var(--sd-success-light, #DBEFDC);border-color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__stat.is-success .sd-autoid-inspector__stat-value{color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__stat.is-warning{background:var(--sd-warning-light, #FFEACC);border-color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__stat.is-warning .sd-autoid-inspector__stat-value{color:var(--sd-warning-dark, #BF7000)}.sd-autoid-inspector__stat.is-error{background:var(--sd-error-light, #FED5D0);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__stat.is-error .sd-autoid-inspector__stat-value{color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__stat-value{font-size:22px;font-weight:700;line-height:1;margin-bottom:4px}.sd-autoid-inspector__stat-label{font-size:11px;color:var(--sd-black400, #757575);text-transform:uppercase;letter-spacing:.4px;font-weight:600}.sd-autoid-inspector__section-title{display:flex;align-items:center;gap:6px;margin:14px 0 8px;font-size:13px;font-weight:600;color:var(--sd-black500, #212121)}.sd-autoid-inspector__section-title mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__section-title mat-icon.is-error{color:var(--sd-error, #F82C13)}.sd-autoid-inspector__section-title mat-icon.is-warning{color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__success-card{display:flex;align-items:center;gap:12px;padding:14px 16px;background:var(--sd-success-light, #DBEFDC);border:1px solid var(--sd-success, #4CAF50);border-radius:10px;color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__success-card mat-icon{font-size:28px;width:28px;height:28px;color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__success-card strong{display:block;font-size:13px;margin-bottom:2px}.sd-autoid-inspector__success-card small{font-size:11px;opacity:.85}.sd-autoid-inspector__table-wrap{border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;overflow:auto;max-height:60vh;background:#fff}.sd-autoid-inspector__table{width:100%;border-collapse:separate;border-spacing:0;font-size:12px}.sd-autoid-inspector__table th,.sd-autoid-inspector__table td{padding:8px 10px;text-align:left;vertical-align:middle;border-bottom:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__table thead th{position:sticky;top:0;z-index:1;background:var(--sd-black100, #F2F2F2);font-weight:600;color:var(--sd-black500, #212121);text-transform:none;font-size:11px;letter-spacing:.3px;border-bottom:none;box-shadow:inset 0 -1px 0 var(--sd-black200, #E6E6E6),0 2px 4px #0000000a;white-space:nowrap}.sd-autoid-inspector__table thead th.is-num{text-align:right;width:50px}.sd-autoid-inspector__table tbody tr{transition:background .1s ease}.sd-autoid-inspector__table tbody tr:hover{background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__table tbody tr:last-child td{border-bottom:none}.sd-autoid-inspector__table tbody tr.is-error{background:var(--sd-error-light, #FED5D0)}.sd-autoid-inspector__table tbody tr.is-error:hover{background:var(--sd-error-light, #FED5D0);filter:brightness(.98)}.sd-autoid-inspector__table tbody tr.is-warning{background:var(--sd-warning-light, #FFEACC)}.sd-autoid-inspector__table tbody tr.is-warning:hover{background:var(--sd-warning-light, #FFEACC);filter:brightness(.98)}.sd-autoid-inspector__table td.is-num{text-align:right;color:var(--sd-black400, #757575);font-variant-numeric:tabular-nums}.sd-autoid-inspector__table code{font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-black100, #F2F2F2);padding:2px 6px;border-radius:4px;color:var(--sd-primary-dark, #1C4AD9);border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__autoid-cell{display:inline-flex;align-items:center;gap:6px}.sd-autoid-inspector__tag-chip{display:inline-block;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-info-light, #E7E9FF);color:var(--sd-info, #2962FF);border:1px solid var(--sd-info, #2962FF);padding:1px 8px;border-radius:999px;font-weight:500}.sd-autoid-inspector__value{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sd-black400, #757575);font-style:italic}.sd-autoid-inspector__empty{text-align:center;color:var(--sd-black400, #757575);padding:24px;font-style:italic}.sd-autoid-inspector__filter{display:flex;align-items:center;gap:6px;background:var(--sd-black100, #F2F2F2);border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;padding:6px 10px;margin-bottom:12px;transition:border-color .15s ease}.sd-autoid-inspector__filter:focus-within{border-color:var(--sd-primary, #2A66F4);background:#fff}.sd-autoid-inspector__filter input{flex:1;border:none;background:transparent;outline:none;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__filter input::placeholder{color:var(--sd-black300, #BFBFBF)}.sd-autoid-inspector__filter>mat-icon{font-size:18px;width:18px;height:18px;color:var(--sd-black400, #757575)}.sd-autoid-inspector__export-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:8px}.sd-autoid-inspector__export-grid button{border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:10px;padding:12px 10px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;min-width:0;transition:border-color .15s ease,background .15s ease,transform .12s ease;text-align:center}.sd-autoid-inspector__export-grid button:hover{border-color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF);transform:translateY(-1px)}.sd-autoid-inspector__export-grid button span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__export-grid button small{font-size:10px;color:var(--sd-black400, #757575);line-height:1.2}.sd-autoid-inspector__export-grid button mat-icon{font-size:22px;width:22px;height:22px;color:var(--sd-primary, #2A66F4)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
795
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SdAutoidInspector, isStandalone: true, selector: "sd-autoid-inspector", inputs: { enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, ngImport: i0, template: "@let _enabled = enabled();\r\n@let _open = open();\r\n@if (_enabled && !dismissed()) {\r\n <div class=\"sd-autoid-inspector__fab-wrap\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__fab\"\r\n data-autoid=\"sd-autoid-inspector-fab\"\r\n [attr.data-opened]=\"dataOpened()\"\r\n [matTooltip]=\"_open ? '\u0110\u00F3ng AutoId Inspector' : 'M\u1EDF AutoId Inspector'\"\r\n matTooltipPosition=\"left\"\r\n (click)=\"togglePanel()\">\r\n <mat-icon>{{ _open ? 'close' : 'tag' }}</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__fab-dismiss\"\r\n matTooltip=\"\u1EA8n t\u1EA1m \u2014 reload trang \u0111\u1EC3 hi\u1EC7n l\u1EA1i\"\r\n matTooltipPosition=\"left\"\r\n aria-label=\"\u1EA8n t\u1EA1m FAB\"\r\n (click)=\"dismissFab($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n}\r\n\r\n@if (_enabled && _open) {\r\n @let _segment = segment();\r\n <div class=\"sd-autoid-inspector__backdrop\" (click)=\"closePanel()\"></div>\r\n <section class=\"sd-autoid-inspector__panel\"\r\n role=\"dialog\"\r\n aria-label=\"AutoId Inspector\"\r\n data-autoid=\"sd-autoid-inspector-panel\"\r\n [attr.data-segment]=\"dataSegment()\"\r\n [attr.data-highlight-on]=\"dataHighlightOn()\"\r\n [attr.data-element-count]=\"dataElementCount()\"\r\n [attr.data-missing-count]=\"dataMissingCount()\"\r\n [attr.data-duplicate-count]=\"dataDuplicateCount()\">\r\n <header class=\"sd-autoid-inspector__header\">\r\n <div class=\"sd-autoid-inspector__segments\">\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"_segment === 'audit'\"\r\n (click)=\"setSegment('audit')\">\r\n Audit\r\n @if (audit(); as a) {\r\n <span class=\"sd-autoid-inspector__badge\" [class.is-warn]=\"a.missingCount + a.duplicateCount > 0\">\r\n {{ a.missingCount + a.duplicateCount }}\r\n </span>\r\n }\r\n </button>\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"_segment === 'elements'\"\r\n (click)=\"setSegment('elements')\">\r\n Elements\r\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\r\n </button>\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"_segment === 'export'\"\r\n (click)=\"setSegment('export')\">\r\n Export\r\n </button>\r\n </div>\r\n <div class=\"sd-autoid-inspector__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn\"\r\n matTooltip=\"Qu\u00E9t l\u1EA1i\"\r\n (click)=\"refresh()\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__close-btn\"\r\n matTooltip=\"\u0110\u00F3ng\"\r\n aria-label=\"\u0110\u00F3ng panel\"\r\n (click)=\"closePanel()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </header>\r\n\r\n @if (copyOk()) {\r\n <div class=\"sd-autoid-inspector__toast\">\u0110\u00E3 copy \u2713</div>\r\n }\r\n\r\n <div class=\"sd-autoid-inspector__body\">\r\n @switch (_segment) {\r\n @case ('audit') {\r\n <ng-container *ngTemplateOutlet=\"auditTpl\"></ng-container>\r\n }\r\n @case ('elements') {\r\n <ng-container *ngTemplateOutlet=\"elementsTpl\"></ng-container>\r\n }\r\n @case ('export') {\r\n <ng-container *ngTemplateOutlet=\"exportTpl\"></ng-container>\r\n }\r\n }\r\n </div>\r\n </section>\r\n\r\n <ng-template #auditTpl>\r\n @if (audit(); as a) {\r\n @let _highlightOn = highlightOn();\r\n <div class=\"sd-autoid-inspector__audit-toolbar\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__toggle\"\r\n [class.is-on]=\"_highlightOn\"\r\n (click)=\"toggleHighlight()\">\r\n <mat-icon>{{ _highlightOn ? 'visibility' : 'visibility_off' }}</mat-icon>\r\n <span>Highlight DOM</span>\r\n <span class=\"sd-autoid-inspector__toggle-state\">{{ _highlightOn ? 'ON' : 'OFF' }}</span>\r\n </button>\r\n </div>\r\n <div class=\"sd-autoid-inspector__summary\">\r\n <div class=\"sd-autoid-inspector__stat is-info\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.total }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">T\u1ED5ng autoid</div>\r\n </div>\r\n <div class=\"sd-autoid-inspector__stat\" [class.is-error]=\"a.duplicateCount > 0\" [class.is-success]=\"a.duplicateCount === 0\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.duplicateCount }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">Tr\u00F9ng</div>\r\n </div>\r\n <div class=\"sd-autoid-inspector__stat\" [class.is-warning]=\"a.missingCount > 0\" [class.is-success]=\"a.missingCount === 0\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.missingCount }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">Thi\u1EBFu</div>\r\n </div>\r\n </div>\r\n\r\n @if (a.duplicateCount > 0) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-error\">error_outline</mat-icon>\r\n Autoid b\u1ECB tr\u00F9ng\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr><th>Autoid</th><th>S\u1ED1 l\u1EA7n</th></tr>\r\n </thead>\r\n <tbody>\r\n @for (entry of a.duplicates | keyvalue; track entry.key) {\r\n <tr class=\"is-error\">\r\n <td><code>{{ entry.key }}</code></td>\r\n <td>{{ entry.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n\r\n @if (a.missingCount > 0) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-warning\">warning_amber</mat-icon>\r\n Element thi\u1EBFu autoid\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr><th>Tag</th><th>Name hint</th><th>Selector</th></tr>\r\n </thead>\r\n <tbody>\r\n @for (m of a.missing; track $index) {\r\n <tr class=\"is-warning\">\r\n <td><code>{{ m.tag }}</code></td>\r\n <td>{{ m.nameHint }}</td>\r\n <td><code>{{ m.selector }}</code></td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n\r\n @if (a.duplicateCount === 0 && a.missingCount === 0) {\r\n <div class=\"sd-autoid-inspector__success-card\">\r\n <mat-icon>check_circle</mat-icon>\r\n <div>\r\n <strong>Kh\u00F4ng c\u00F3 element thi\u1EBFu ho\u1EB7c tr\u00F9ng autoid.</strong>\r\n <small>Trang \u0111\u00E3 \u0111\u1EA1t chu\u1EA9n convention autoid.</small>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-template>\r\n\r\n <ng-template #elementsTpl>\r\n @let _filter = filter();\r\n <div class=\"sd-autoid-inspector__filter\">\r\n <mat-icon>search</mat-icon>\r\n <input\r\n type=\"text\"\r\n placeholder=\"L\u1ECDc theo autoid / name / tag\"\r\n [ngModel]=\"_filter\"\r\n (ngModelChange)=\"filter.set($event)\"/>\r\n @if (_filter) {\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn\"\r\n matTooltip=\"Xo\u00E1 filter\"\r\n (click)=\"filter.set('')\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Top-level elements (not inside any sd-table) -->\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n Top-level elements\r\n <span class=\"sd-autoid-inspector__badge\">{{ topLevelElements().length }}</span>\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr>\r\n <th class=\"is-num\">STT</th>\r\n <th>Name</th>\r\n <th>Autoid</th>\r\n <th>Tag</th>\r\n <th>State</th>\r\n <th>Value</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (el of topLevelElements(); track el.autoid + $index) {\r\n <tr [class.is-error]=\"el.duplicate\">\r\n <td class=\"is-num\">{{ el.stt }}</td>\r\n <td>{{ el.name || '\u2014' }}</td>\r\n <td>\r\n <div class=\"sd-autoid-inspector__autoid-cell\">\r\n <code>{{ el.autoid }}</code>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn is-primary\"\r\n matTooltip=\"Copy xpath\"\r\n (click)=\"copyXpath(el.autoid)\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n </div>\r\n </td>\r\n <td><span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span></td>\r\n <td class=\"sd-autoid-inspector__state-cell\">\r\n @if (el.state.disabled !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-error]=\"el.state.disabled === 'true'\">\r\n disabled={{ el.state.disabled }}\r\n </span>\r\n }\r\n @if (el.state.loading !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-warning]=\"el.state.loading === 'true'\">\r\n loading={{ el.state.loading }}\r\n </span>\r\n }\r\n @if (el.state.empty !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-info]=\"el.state.empty === 'true'\">\r\n empty={{ el.state.empty }}\r\n </span>\r\n }\r\n @if (el.state.invalid !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-error]=\"el.state.invalid === 'true'\">\r\n invalid={{ el.state.invalid }}\r\n </span>\r\n }\r\n @if (el.state.opened !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-info]=\"el.state.opened === 'true'\">\r\n opened={{ el.state.opened }}\r\n </span>\r\n }\r\n @if (el.state.count !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n count={{ el.state.count }}\r\n </span>\r\n }\r\n @if (el.state.required !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-warning]=\"el.state.required === 'true'\">\r\n required={{ el.state.required }}\r\n </span>\r\n }\r\n @if (el.state.maxlength !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n maxlength={{ el.state.maxlength }}\r\n </span>\r\n }\r\n @if (el.state.minlength !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n minlength={{ el.state.minlength }}\r\n </span>\r\n }\r\n @if (el.state.pattern !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n pattern={{ el.state.pattern }}\r\n </span>\r\n }\r\n @if (el.state.errorMessage !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-error\">\r\n error: {{ el.state.errorMessage }}\r\n </span>\r\n }\r\n </td>\r\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\r\n {{ el.state.dataValue || el.text || '\u2014' }}\r\n </td>\r\n </tr>\r\n } @empty {\r\n <tr><td colspan=\"6\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td></tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <!-- One section per sd-table group -->\r\n @for (group of tableGroups(); track group.scope) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-info\">table_chart</mat-icon>\r\n Inside <code>{{ group.scope }}</code>\r\n <span class=\"sd-autoid-inspector__badge\">{{ group.items.length }}</span>\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr>\r\n <th class=\"is-num\">STT</th>\r\n <th>Name</th>\r\n <th>Autoid</th>\r\n <th>Tag</th>\r\n <th>State</th>\r\n <th>Value</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (el of group.items; track el.autoid + $index) {\r\n <tr [class.is-error]=\"el.duplicate\">\r\n <td class=\"is-num\">{{ el.stt }}</td>\r\n <td>{{ el.name || '\u2014' }}</td>\r\n <td>\r\n <div class=\"sd-autoid-inspector__autoid-cell\">\r\n <code>{{ el.autoid }}</code>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn is-primary\"\r\n matTooltip=\"Copy xpath\"\r\n (click)=\"copyXpath(el.autoid)\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n </div>\r\n </td>\r\n <td><span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span></td>\r\n <td class=\"sd-autoid-inspector__state-cell\">\r\n @if (el.state.disabled !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-error]=\"el.state.disabled === 'true'\">\r\n disabled={{ el.state.disabled }}\r\n </span>\r\n }\r\n @if (el.state.loading !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-warning]=\"el.state.loading === 'true'\">\r\n loading={{ el.state.loading }}\r\n </span>\r\n }\r\n @if (el.state.empty !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-info]=\"el.state.empty === 'true'\">\r\n empty={{ el.state.empty }}\r\n </span>\r\n }\r\n @if (el.state.invalid !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-error]=\"el.state.invalid === 'true'\">\r\n invalid={{ el.state.invalid }}\r\n </span>\r\n }\r\n @if (el.state.opened !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-info]=\"el.state.opened === 'true'\">\r\n opened={{ el.state.opened }}\r\n </span>\r\n }\r\n @if (el.state.count !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n count={{ el.state.count }}\r\n </span>\r\n }\r\n @if (el.state.required !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-warning]=\"el.state.required === 'true'\">\r\n required={{ el.state.required }}\r\n </span>\r\n }\r\n @if (el.state.maxlength !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n maxlength={{ el.state.maxlength }}\r\n </span>\r\n }\r\n @if (el.state.minlength !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n minlength={{ el.state.minlength }}\r\n </span>\r\n }\r\n @if (el.state.pattern !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n pattern={{ el.state.pattern }}\r\n </span>\r\n }\r\n @if (el.state.errorMessage !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-error\">\r\n error: {{ el.state.errorMessage }}\r\n </span>\r\n }\r\n </td>\r\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\r\n {{ el.state.dataValue || el.text || '\u2014' }}\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n <ng-template #exportTpl>\r\n <div class=\"sd-autoid-inspector__export-grid\">\r\n <button type=\"button\" matTooltip=\"Copy JSON v\u00E0o clipboard\" (click)=\"copyJson()\">\r\n <mat-icon>content_copy</mat-icon>\r\n <span>Copy JSON</span>\r\n <small>clipboard</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i file JSON\" (click)=\"exportJson()\">\r\n <mat-icon>download</mat-icon>\r\n <span>JSON</span>\r\n <small>.json</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i file CSV\" (click)=\"exportCsv()\">\r\n <mat-icon>table_view</mat-icon>\r\n <span>CSV</span>\r\n <small>.csv</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i MD POM skeleton \u2014 cho AI vi\u1EBFt auto-test\" (click)=\"exportMdPom()\">\r\n <mat-icon>code</mat-icon>\r\n <span>MD POM</span>\r\n <small>AI test</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i MD reference table \u2014 group theo tag sd-*\" (click)=\"exportMdTable()\">\r\n <mat-icon>view_list</mat-icon>\r\n <span>MD Table</span>\r\n <small>reference</small>\r\n </button>\r\n </div>\r\n </ng-template>\r\n}\r\n", styles: [":host{position:fixed;inset:auto 0 0 auto;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__fab-wrap{position:fixed;right:16px;bottom:16px;z-index:100000}.sd-autoid-inspector__fab-wrap:hover .sd-autoid-inspector__fab-dismiss{opacity:1;transform:scale(1);pointer-events:auto}.sd-autoid-inspector__fab{width:36px;height:36px;border-radius:50%;border:none;background:var(--sd-primary, #2A66F4);color:#fff;cursor:pointer;box-shadow:0 3px 10px #00000038;display:inline-flex;align-items:center;justify-content:center;transition:transform .15s ease,background .15s ease,box-shadow .15s ease}.sd-autoid-inspector__fab:hover{background:var(--sd-primary-dark, #1C4AD9);transform:scale(1.08);box-shadow:0 5px 14px #00000047}.sd-autoid-inspector__fab mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__fab-dismiss{position:absolute;top:-6px;right:-6px;width:18px;height:18px;border-radius:50%;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;color:var(--sd-black400, #757575);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;opacity:0;transform:scale(.7);pointer-events:none;transition:opacity .12s ease,transform .12s ease,color .12s ease,background .12s ease;box-shadow:0 1px 4px #00000026}.sd-autoid-inspector__fab-dismiss:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__fab-dismiss mat-icon{font-size:12px;width:12px;height:12px;line-height:12px}.sd-autoid-inspector__backdrop{position:fixed;inset:0;background:#00000052;z-index:100001;backdrop-filter:blur(2px)}.sd-autoid-inspector__panel{position:fixed;right:20px;bottom:80px;width:min(860px,100vw - 40px);max-height:calc(100vh - 110px);background:#fff;border-radius:12px;box-shadow:0 16px 48px #00000038;display:flex;flex-direction:column;z-index:100002;overflow:hidden;border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__header{display:flex;align-items:center;gap:8px;padding:8px 10px;border-bottom:1px solid var(--sd-black200, #E6E6E6);background:var(--sd-black100, #F2F2F2);flex-shrink:0}.sd-autoid-inspector__segments{display:inline-flex;border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;background:#fff;overflow:hidden}.sd-autoid-inspector__segments button{border:none;background:transparent;padding:5px 12px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;gap:6px;border-right:1px solid var(--sd-black200, #E6E6E6);transition:background .12s ease,color .12s ease}.sd-autoid-inspector__segments button:last-child{border-right:none}.sd-autoid-inspector__segments button:hover:not(.is-active){background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__segments button.is-active{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__badge{background:var(--sd-black200, #E6E6E6);color:var(--sd-black500, #212121);border-radius:10px;padding:0 7px;font-size:11px;font-weight:600;line-height:16px}.is-active .sd-autoid-inspector__badge{background:#ffffff40;color:#fff}.sd-autoid-inspector__badge.is-warn{background:var(--sd-error, #F82C13);color:#fff}.sd-autoid-inspector__actions{display:inline-flex;gap:4px;margin-left:auto}.sd-autoid-inspector__icon-btn{border:none;background:transparent;cursor:pointer;padding:4px;border-radius:6px;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__icon-btn:hover{background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__icon-btn.is-primary{color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__icon-btn.is-primary:hover{background:var(--sd-primary-light, #EAF1FF);color:var(--sd-primary-dark, #1C4AD9)}.sd-autoid-inspector__icon-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__close-btn{border:none;cursor:pointer;padding:4px;border-radius:50%;width:28px;height:28px;background:transparent;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__close-btn:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__close-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__body{padding:14px;overflow:auto;flex:1;background:#fff}.sd-autoid-inspector__toast{position:absolute;top:56px;right:14px;background:var(--sd-success, #4CAF50);color:#fff;padding:6px 12px;border-radius:6px;font-size:12px;z-index:2;box-shadow:0 4px 12px #0000002e}.sd-autoid-inspector__audit-toolbar{display:flex;justify-content:flex-end;margin-bottom:12px}.sd-autoid-inspector__toggle{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:999px;padding:5px 12px 5px 10px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);transition:all .15s ease}.sd-autoid-inspector__toggle:hover{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__toggle.is-on{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__toggle mat-icon{font-size:16px;width:16px;height:16px}.sd-autoid-inspector__toggle-state{font-size:10px;font-weight:700;padding:1px 7px;border-radius:999px;background:var(--sd-black200, #E6E6E6);color:var(--sd-black400, #757575)}.is-on .sd-autoid-inspector__toggle-state{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__summary{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px}.sd-autoid-inspector__stat{background:var(--sd-black100, #F2F2F2);border-radius:10px;padding:12px;text-align:center;border:1px solid transparent}.sd-autoid-inspector__stat.is-info{background:var(--sd-info-light, #E7E9FF);border-color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-info .sd-autoid-inspector__stat-value{color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-success{background:var(--sd-success-light, #DBEFDC);border-color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__stat.is-success .sd-autoid-inspector__stat-value{color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__stat.is-warning{background:var(--sd-warning-light, #FFEACC);border-color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__stat.is-warning .sd-autoid-inspector__stat-value{color:var(--sd-warning-dark, #BF7000)}.sd-autoid-inspector__stat.is-error{background:var(--sd-error-light, #FED5D0);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__stat.is-error .sd-autoid-inspector__stat-value{color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__stat-value{font-size:22px;font-weight:700;line-height:1;margin-bottom:4px}.sd-autoid-inspector__stat-label{font-size:11px;color:var(--sd-black400, #757575);text-transform:uppercase;letter-spacing:.4px;font-weight:600}.sd-autoid-inspector__section-title{display:flex;align-items:center;gap:6px;margin:14px 0 8px;font-size:13px;font-weight:600;color:var(--sd-black500, #212121)}.sd-autoid-inspector__section-title mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__section-title mat-icon.is-error{color:var(--sd-error, #F82C13)}.sd-autoid-inspector__section-title mat-icon.is-warning{color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__section-title mat-icon.is-info{color:var(--sd-info, #2962FF)}.sd-autoid-inspector__success-card{display:flex;align-items:center;gap:12px;padding:14px 16px;background:var(--sd-success-light, #DBEFDC);border:1px solid var(--sd-success, #4CAF50);border-radius:10px;color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__success-card mat-icon{font-size:28px;width:28px;height:28px;color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__success-card strong{display:block;font-size:13px;margin-bottom:2px}.sd-autoid-inspector__success-card small{font-size:11px;opacity:.85}.sd-autoid-inspector__table-wrap{border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;overflow:auto;max-height:60vh;background:#fff}.sd-autoid-inspector__table{width:100%;border-collapse:separate;border-spacing:0;font-size:12px}.sd-autoid-inspector__table th,.sd-autoid-inspector__table td{padding:8px 10px;text-align:left;vertical-align:middle;border-bottom:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__table thead th{position:sticky;top:0;z-index:1;background:var(--sd-black100, #F2F2F2);font-weight:600;color:var(--sd-black500, #212121);text-transform:none;font-size:11px;letter-spacing:.3px;border-bottom:none;box-shadow:inset 0 -1px 0 var(--sd-black200, #E6E6E6),0 2px 4px #0000000a;white-space:nowrap}.sd-autoid-inspector__table thead th.is-num{text-align:right;width:50px}.sd-autoid-inspector__table tbody tr{transition:background .1s ease}.sd-autoid-inspector__table tbody tr:hover{background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__table tbody tr:last-child td{border-bottom:none}.sd-autoid-inspector__table tbody tr.is-error{background:var(--sd-error-light, #FED5D0)}.sd-autoid-inspector__table tbody tr.is-error:hover{background:var(--sd-error-light, #FED5D0);filter:brightness(.98)}.sd-autoid-inspector__table tbody tr.is-warning{background:var(--sd-warning-light, #FFEACC)}.sd-autoid-inspector__table tbody tr.is-warning:hover{background:var(--sd-warning-light, #FFEACC);filter:brightness(.98)}.sd-autoid-inspector__table td.is-num{text-align:right;color:var(--sd-black400, #757575);font-variant-numeric:tabular-nums}.sd-autoid-inspector__table code{font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-black100, #F2F2F2);padding:2px 6px;border-radius:4px;color:var(--sd-primary-dark, #1C4AD9);border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__autoid-cell{display:inline-flex;align-items:center;gap:6px}.sd-autoid-inspector__tag-chip{display:inline-block;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-info-light, #E7E9FF);color:var(--sd-info, #2962FF);border:1px solid var(--sd-info, #2962FF);padding:1px 8px;border-radius:999px;font-weight:500}.sd-autoid-inspector__value{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sd-black400, #757575);font-style:italic}.sd-autoid-inspector__state-cell{display:flex;flex-wrap:wrap;gap:4px;align-items:center;min-width:0}.sd-autoid-inspector__state-chip{display:inline-block;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:10px;background:var(--sd-black100, #F2F2F2);color:var(--sd-black400, #757575);border:1px solid var(--sd-black200, #E6E6E6);padding:1px 6px;border-radius:999px;font-weight:500;white-space:nowrap}.sd-autoid-inspector__state-chip.is-error{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__state-chip.is-warning{background:var(--sd-warning-light, #FFEACC);color:var(--sd-warning-dark, #BF7000);border-color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__state-chip.is-info{background:var(--sd-info-light, #E7E9FF);color:var(--sd-info, #2962FF);border-color:var(--sd-info, #2962FF)}.sd-autoid-inspector__empty{text-align:center;color:var(--sd-black400, #757575);padding:24px;font-style:italic}.sd-autoid-inspector__filter{display:flex;align-items:center;gap:6px;background:var(--sd-black100, #F2F2F2);border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;padding:6px 10px;margin-bottom:12px;transition:border-color .15s ease}.sd-autoid-inspector__filter:focus-within{border-color:var(--sd-primary, #2A66F4);background:#fff}.sd-autoid-inspector__filter input{flex:1;border:none;background:transparent;outline:none;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__filter input::placeholder{color:var(--sd-black300, #BFBFBF)}.sd-autoid-inspector__filter>mat-icon{font-size:18px;width:18px;height:18px;color:var(--sd-black400, #757575)}.sd-autoid-inspector__export-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:8px}.sd-autoid-inspector__export-grid button{border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:10px;padding:12px 10px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;min-width:0;transition:border-color .15s ease,background .15s ease,transform .12s ease;text-align:center}.sd-autoid-inspector__export-grid button:hover{border-color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF);transform:translateY(-1px)}.sd-autoid-inspector__export-grid button span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__export-grid button small{font-size:10px;color:var(--sd-black400, #757575);line-height:1.2}.sd-autoid-inspector__export-grid button mat-icon{font-size:22px;width:22px;height:22px;color:var(--sd-primary, #2A66F4)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
571
796
  }
572
797
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidInspector, decorators: [{
573
798
  type: Component,
574
- args: [{ selector: 'sd-autoid-inspector', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, MatIconModule, MatTooltipModule], template: "@if (enabled() && !dismissed()) {\r\n <div class=\"sd-autoid-inspector__fab-wrap\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__fab\"\r\n data-autoid=\"sd-autoid-inspector-fab\"\r\n [matTooltip]=\"open() ? '\u0110\u00F3ng AutoId Inspector' : 'M\u1EDF AutoId Inspector'\"\r\n matTooltipPosition=\"left\"\r\n (click)=\"togglePanel()\">\r\n <mat-icon>{{ open() ? 'close' : 'tag' }}</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__fab-dismiss\"\r\n matTooltip=\"\u1EA8n t\u1EA1m \u2014 reload trang \u0111\u1EC3 hi\u1EC7n l\u1EA1i\"\r\n matTooltipPosition=\"left\"\r\n aria-label=\"\u1EA8n t\u1EA1m FAB\"\r\n (click)=\"dismissFab($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n}\r\n\r\n@if (enabled() && open()) {\r\n <div class=\"sd-autoid-inspector__backdrop\" (click)=\"closePanel()\"></div>\r\n <section class=\"sd-autoid-inspector__panel\" role=\"dialog\" aria-label=\"AutoId Inspector\">\r\n <header class=\"sd-autoid-inspector__header\">\r\n <div class=\"sd-autoid-inspector__segments\">\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"segment() === 'audit'\"\r\n (click)=\"setSegment('audit')\">\r\n Audit\r\n @if (audit(); as a) {\r\n <span class=\"sd-autoid-inspector__badge\" [class.is-warn]=\"a.missingCount + a.duplicateCount > 0\">\r\n {{ a.missingCount + a.duplicateCount }}\r\n </span>\r\n }\r\n </button>\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"segment() === 'elements'\"\r\n (click)=\"setSegment('elements')\">\r\n Elements\r\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\r\n </button>\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"segment() === 'export'\"\r\n (click)=\"setSegment('export')\">\r\n Export\r\n </button>\r\n </div>\r\n <div class=\"sd-autoid-inspector__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn\"\r\n matTooltip=\"Qu\u00E9t l\u1EA1i\"\r\n (click)=\"refresh()\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__close-btn\"\r\n matTooltip=\"\u0110\u00F3ng\"\r\n aria-label=\"\u0110\u00F3ng panel\"\r\n (click)=\"closePanel()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </header>\r\n\r\n @if (copyOk()) {\r\n <div class=\"sd-autoid-inspector__toast\">\u0110\u00E3 copy \u2713</div>\r\n }\r\n\r\n <div class=\"sd-autoid-inspector__body\">\r\n @switch (segment()) {\r\n @case ('audit') {\r\n <ng-container *ngTemplateOutlet=\"auditTpl\"></ng-container>\r\n }\r\n @case ('elements') {\r\n <ng-container *ngTemplateOutlet=\"elementsTpl\"></ng-container>\r\n }\r\n @case ('export') {\r\n <ng-container *ngTemplateOutlet=\"exportTpl\"></ng-container>\r\n }\r\n }\r\n </div>\r\n </section>\r\n\r\n <ng-template #auditTpl>\r\n @if (audit(); as a) {\r\n <div class=\"sd-autoid-inspector__audit-toolbar\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__toggle\"\r\n [class.is-on]=\"highlightOn()\"\r\n (click)=\"toggleHighlight()\">\r\n <mat-icon>{{ highlightOn() ? 'visibility' : 'visibility_off' }}</mat-icon>\r\n <span>Highlight DOM</span>\r\n <span class=\"sd-autoid-inspector__toggle-state\">{{ highlightOn() ? 'ON' : 'OFF' }}</span>\r\n </button>\r\n </div>\r\n <div class=\"sd-autoid-inspector__summary\">\r\n <div class=\"sd-autoid-inspector__stat is-info\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.total }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">T\u1ED5ng autoid</div>\r\n </div>\r\n <div class=\"sd-autoid-inspector__stat\" [class.is-error]=\"a.duplicateCount > 0\" [class.is-success]=\"a.duplicateCount === 0\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.duplicateCount }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">Tr\u00F9ng</div>\r\n </div>\r\n <div class=\"sd-autoid-inspector__stat\" [class.is-warning]=\"a.missingCount > 0\" [class.is-success]=\"a.missingCount === 0\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.missingCount }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">Thi\u1EBFu</div>\r\n </div>\r\n </div>\r\n\r\n @if (a.duplicateCount > 0) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-error\">error_outline</mat-icon>\r\n Autoid b\u1ECB tr\u00F9ng\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr><th>Autoid</th><th>S\u1ED1 l\u1EA7n</th></tr>\r\n </thead>\r\n <tbody>\r\n @for (entry of a.duplicates | keyvalue; track entry.key) {\r\n <tr class=\"is-error\">\r\n <td><code>{{ entry.key }}</code></td>\r\n <td>{{ entry.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n\r\n @if (a.missingCount > 0) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-warning\">warning_amber</mat-icon>\r\n Element thi\u1EBFu autoid\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr><th>Tag</th><th>Name hint</th><th>Selector</th></tr>\r\n </thead>\r\n <tbody>\r\n @for (m of a.missing; track $index) {\r\n <tr class=\"is-warning\">\r\n <td><code>{{ m.tag }}</code></td>\r\n <td>{{ m.nameHint }}</td>\r\n <td><code>{{ m.selector }}</code></td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n\r\n @if (a.duplicateCount === 0 && a.missingCount === 0) {\r\n <div class=\"sd-autoid-inspector__success-card\">\r\n <mat-icon>check_circle</mat-icon>\r\n <div>\r\n <strong>Kh\u00F4ng c\u00F3 element thi\u1EBFu ho\u1EB7c tr\u00F9ng autoid.</strong>\r\n <small>Trang \u0111\u00E3 \u0111\u1EA1t chu\u1EA9n convention autoid.</small>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-template>\r\n\r\n <ng-template #elementsTpl>\r\n <div class=\"sd-autoid-inspector__filter\">\r\n <mat-icon>search</mat-icon>\r\n <input\r\n type=\"text\"\r\n placeholder=\"L\u1ECDc theo autoid / name / tag\"\r\n [ngModel]=\"filter()\"\r\n (ngModelChange)=\"filter.set($event)\"/>\r\n @if (filter()) {\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn\"\r\n matTooltip=\"Xo\u00E1 filter\"\r\n (click)=\"filter.set('')\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr>\r\n <th class=\"is-num\">STT</th>\r\n <th>Name</th>\r\n <th>Autoid</th>\r\n <th>Tag</th>\r\n <th>Value</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (el of filteredElements(); track el.autoid + $index) {\r\n <tr [class.is-error]=\"el.duplicate\">\r\n <td class=\"is-num\">{{ el.stt }}</td>\r\n <td>{{ el.name || '\u2014' }}</td>\r\n <td>\r\n <div class=\"sd-autoid-inspector__autoid-cell\">\r\n <code>{{ el.autoid }}</code>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn is-primary\"\r\n matTooltip=\"Copy xpath\"\r\n (click)=\"copyXpath(el.autoid)\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n </div>\r\n </td>\r\n <td><span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span></td>\r\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.value || ''\">\r\n {{ el.value || '\u2014' }}\r\n </td>\r\n </tr>\r\n } @empty {\r\n <tr><td colspan=\"5\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td></tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #exportTpl>\r\n <div class=\"sd-autoid-inspector__export-grid\">\r\n <button type=\"button\" matTooltip=\"Copy JSON v\u00E0o clipboard\" (click)=\"copyJson()\">\r\n <mat-icon>content_copy</mat-icon>\r\n <span>Copy JSON</span>\r\n <small>clipboard</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i file JSON\" (click)=\"exportJson()\">\r\n <mat-icon>download</mat-icon>\r\n <span>JSON</span>\r\n <small>.json</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i file CSV\" (click)=\"exportCsv()\">\r\n <mat-icon>table_view</mat-icon>\r\n <span>CSV</span>\r\n <small>.csv</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i MD POM skeleton \u2014 cho AI vi\u1EBFt auto-test\" (click)=\"exportMdPom()\">\r\n <mat-icon>code</mat-icon>\r\n <span>MD POM</span>\r\n <small>AI test</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i MD reference table \u2014 group theo tag sd-*\" (click)=\"exportMdTable()\">\r\n <mat-icon>view_list</mat-icon>\r\n <span>MD Table</span>\r\n <small>reference</small>\r\n </button>\r\n </div>\r\n </ng-template>\r\n}\r\n", styles: [":host{position:fixed;inset:auto 0 0 auto;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__fab-wrap{position:fixed;right:16px;bottom:16px;z-index:100000}.sd-autoid-inspector__fab-wrap:hover .sd-autoid-inspector__fab-dismiss{opacity:1;transform:scale(1);pointer-events:auto}.sd-autoid-inspector__fab{width:36px;height:36px;border-radius:50%;border:none;background:var(--sd-primary, #2A66F4);color:#fff;cursor:pointer;box-shadow:0 3px 10px #00000038;display:inline-flex;align-items:center;justify-content:center;transition:transform .15s ease,background .15s ease,box-shadow .15s ease}.sd-autoid-inspector__fab:hover{background:var(--sd-primary-dark, #1C4AD9);transform:scale(1.08);box-shadow:0 5px 14px #00000047}.sd-autoid-inspector__fab mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__fab-dismiss{position:absolute;top:-6px;right:-6px;width:18px;height:18px;border-radius:50%;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;color:var(--sd-black400, #757575);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;opacity:0;transform:scale(.7);pointer-events:none;transition:opacity .12s ease,transform .12s ease,color .12s ease,background .12s ease;box-shadow:0 1px 4px #00000026}.sd-autoid-inspector__fab-dismiss:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__fab-dismiss mat-icon{font-size:12px;width:12px;height:12px;line-height:12px}.sd-autoid-inspector__backdrop{position:fixed;inset:0;background:#00000052;z-index:100001;backdrop-filter:blur(2px)}.sd-autoid-inspector__panel{position:fixed;right:20px;bottom:80px;width:min(860px,100vw - 40px);max-height:calc(100vh - 110px);background:#fff;border-radius:12px;box-shadow:0 16px 48px #00000038;display:flex;flex-direction:column;z-index:100002;overflow:hidden;border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__header{display:flex;align-items:center;gap:8px;padding:8px 10px;border-bottom:1px solid var(--sd-black200, #E6E6E6);background:var(--sd-black100, #F2F2F2);flex-shrink:0}.sd-autoid-inspector__segments{display:inline-flex;border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;background:#fff;overflow:hidden}.sd-autoid-inspector__segments button{border:none;background:transparent;padding:5px 12px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;gap:6px;border-right:1px solid var(--sd-black200, #E6E6E6);transition:background .12s ease,color .12s ease}.sd-autoid-inspector__segments button:last-child{border-right:none}.sd-autoid-inspector__segments button:hover:not(.is-active){background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__segments button.is-active{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__badge{background:var(--sd-black200, #E6E6E6);color:var(--sd-black500, #212121);border-radius:10px;padding:0 7px;font-size:11px;font-weight:600;line-height:16px}.is-active .sd-autoid-inspector__badge{background:#ffffff40;color:#fff}.sd-autoid-inspector__badge.is-warn{background:var(--sd-error, #F82C13);color:#fff}.sd-autoid-inspector__actions{display:inline-flex;gap:4px;margin-left:auto}.sd-autoid-inspector__icon-btn{border:none;background:transparent;cursor:pointer;padding:4px;border-radius:6px;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__icon-btn:hover{background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__icon-btn.is-primary{color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__icon-btn.is-primary:hover{background:var(--sd-primary-light, #EAF1FF);color:var(--sd-primary-dark, #1C4AD9)}.sd-autoid-inspector__icon-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__close-btn{border:none;cursor:pointer;padding:4px;border-radius:50%;width:28px;height:28px;background:transparent;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__close-btn:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__close-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__body{padding:14px;overflow:auto;flex:1;background:#fff}.sd-autoid-inspector__toast{position:absolute;top:56px;right:14px;background:var(--sd-success, #4CAF50);color:#fff;padding:6px 12px;border-radius:6px;font-size:12px;z-index:2;box-shadow:0 4px 12px #0000002e}.sd-autoid-inspector__audit-toolbar{display:flex;justify-content:flex-end;margin-bottom:12px}.sd-autoid-inspector__toggle{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:999px;padding:5px 12px 5px 10px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);transition:all .15s ease}.sd-autoid-inspector__toggle:hover{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__toggle.is-on{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__toggle mat-icon{font-size:16px;width:16px;height:16px}.sd-autoid-inspector__toggle-state{font-size:10px;font-weight:700;padding:1px 7px;border-radius:999px;background:var(--sd-black200, #E6E6E6);color:var(--sd-black400, #757575)}.is-on .sd-autoid-inspector__toggle-state{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__summary{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px}.sd-autoid-inspector__stat{background:var(--sd-black100, #F2F2F2);border-radius:10px;padding:12px;text-align:center;border:1px solid transparent}.sd-autoid-inspector__stat.is-info{background:var(--sd-info-light, #E7E9FF);border-color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-info .sd-autoid-inspector__stat-value{color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-success{background:var(--sd-success-light, #DBEFDC);border-color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__stat.is-success .sd-autoid-inspector__stat-value{color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__stat.is-warning{background:var(--sd-warning-light, #FFEACC);border-color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__stat.is-warning .sd-autoid-inspector__stat-value{color:var(--sd-warning-dark, #BF7000)}.sd-autoid-inspector__stat.is-error{background:var(--sd-error-light, #FED5D0);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__stat.is-error .sd-autoid-inspector__stat-value{color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__stat-value{font-size:22px;font-weight:700;line-height:1;margin-bottom:4px}.sd-autoid-inspector__stat-label{font-size:11px;color:var(--sd-black400, #757575);text-transform:uppercase;letter-spacing:.4px;font-weight:600}.sd-autoid-inspector__section-title{display:flex;align-items:center;gap:6px;margin:14px 0 8px;font-size:13px;font-weight:600;color:var(--sd-black500, #212121)}.sd-autoid-inspector__section-title mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__section-title mat-icon.is-error{color:var(--sd-error, #F82C13)}.sd-autoid-inspector__section-title mat-icon.is-warning{color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__success-card{display:flex;align-items:center;gap:12px;padding:14px 16px;background:var(--sd-success-light, #DBEFDC);border:1px solid var(--sd-success, #4CAF50);border-radius:10px;color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__success-card mat-icon{font-size:28px;width:28px;height:28px;color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__success-card strong{display:block;font-size:13px;margin-bottom:2px}.sd-autoid-inspector__success-card small{font-size:11px;opacity:.85}.sd-autoid-inspector__table-wrap{border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;overflow:auto;max-height:60vh;background:#fff}.sd-autoid-inspector__table{width:100%;border-collapse:separate;border-spacing:0;font-size:12px}.sd-autoid-inspector__table th,.sd-autoid-inspector__table td{padding:8px 10px;text-align:left;vertical-align:middle;border-bottom:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__table thead th{position:sticky;top:0;z-index:1;background:var(--sd-black100, #F2F2F2);font-weight:600;color:var(--sd-black500, #212121);text-transform:none;font-size:11px;letter-spacing:.3px;border-bottom:none;box-shadow:inset 0 -1px 0 var(--sd-black200, #E6E6E6),0 2px 4px #0000000a;white-space:nowrap}.sd-autoid-inspector__table thead th.is-num{text-align:right;width:50px}.sd-autoid-inspector__table tbody tr{transition:background .1s ease}.sd-autoid-inspector__table tbody tr:hover{background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__table tbody tr:last-child td{border-bottom:none}.sd-autoid-inspector__table tbody tr.is-error{background:var(--sd-error-light, #FED5D0)}.sd-autoid-inspector__table tbody tr.is-error:hover{background:var(--sd-error-light, #FED5D0);filter:brightness(.98)}.sd-autoid-inspector__table tbody tr.is-warning{background:var(--sd-warning-light, #FFEACC)}.sd-autoid-inspector__table tbody tr.is-warning:hover{background:var(--sd-warning-light, #FFEACC);filter:brightness(.98)}.sd-autoid-inspector__table td.is-num{text-align:right;color:var(--sd-black400, #757575);font-variant-numeric:tabular-nums}.sd-autoid-inspector__table code{font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-black100, #F2F2F2);padding:2px 6px;border-radius:4px;color:var(--sd-primary-dark, #1C4AD9);border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__autoid-cell{display:inline-flex;align-items:center;gap:6px}.sd-autoid-inspector__tag-chip{display:inline-block;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-info-light, #E7E9FF);color:var(--sd-info, #2962FF);border:1px solid var(--sd-info, #2962FF);padding:1px 8px;border-radius:999px;font-weight:500}.sd-autoid-inspector__value{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sd-black400, #757575);font-style:italic}.sd-autoid-inspector__empty{text-align:center;color:var(--sd-black400, #757575);padding:24px;font-style:italic}.sd-autoid-inspector__filter{display:flex;align-items:center;gap:6px;background:var(--sd-black100, #F2F2F2);border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;padding:6px 10px;margin-bottom:12px;transition:border-color .15s ease}.sd-autoid-inspector__filter:focus-within{border-color:var(--sd-primary, #2A66F4);background:#fff}.sd-autoid-inspector__filter input{flex:1;border:none;background:transparent;outline:none;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__filter input::placeholder{color:var(--sd-black300, #BFBFBF)}.sd-autoid-inspector__filter>mat-icon{font-size:18px;width:18px;height:18px;color:var(--sd-black400, #757575)}.sd-autoid-inspector__export-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:8px}.sd-autoid-inspector__export-grid button{border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:10px;padding:12px 10px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;min-width:0;transition:border-color .15s ease,background .15s ease,transform .12s ease;text-align:center}.sd-autoid-inspector__export-grid button:hover{border-color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF);transform:translateY(-1px)}.sd-autoid-inspector__export-grid button span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__export-grid button small{font-size:10px;color:var(--sd-black400, #757575);line-height:1.2}.sd-autoid-inspector__export-grid button mat-icon{font-size:22px;width:22px;height:22px;color:var(--sd-primary, #2A66F4)}\n"] }]
799
+ args: [{ selector: 'sd-autoid-inspector', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, MatIconModule, MatTooltipModule], template: "@let _enabled = enabled();\r\n@let _open = open();\r\n@if (_enabled && !dismissed()) {\r\n <div class=\"sd-autoid-inspector__fab-wrap\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__fab\"\r\n data-autoid=\"sd-autoid-inspector-fab\"\r\n [attr.data-opened]=\"dataOpened()\"\r\n [matTooltip]=\"_open ? '\u0110\u00F3ng AutoId Inspector' : 'M\u1EDF AutoId Inspector'\"\r\n matTooltipPosition=\"left\"\r\n (click)=\"togglePanel()\">\r\n <mat-icon>{{ _open ? 'close' : 'tag' }}</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__fab-dismiss\"\r\n matTooltip=\"\u1EA8n t\u1EA1m \u2014 reload trang \u0111\u1EC3 hi\u1EC7n l\u1EA1i\"\r\n matTooltipPosition=\"left\"\r\n aria-label=\"\u1EA8n t\u1EA1m FAB\"\r\n (click)=\"dismissFab($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n}\r\n\r\n@if (_enabled && _open) {\r\n @let _segment = segment();\r\n <div class=\"sd-autoid-inspector__backdrop\" (click)=\"closePanel()\"></div>\r\n <section class=\"sd-autoid-inspector__panel\"\r\n role=\"dialog\"\r\n aria-label=\"AutoId Inspector\"\r\n data-autoid=\"sd-autoid-inspector-panel\"\r\n [attr.data-segment]=\"dataSegment()\"\r\n [attr.data-highlight-on]=\"dataHighlightOn()\"\r\n [attr.data-element-count]=\"dataElementCount()\"\r\n [attr.data-missing-count]=\"dataMissingCount()\"\r\n [attr.data-duplicate-count]=\"dataDuplicateCount()\">\r\n <header class=\"sd-autoid-inspector__header\">\r\n <div class=\"sd-autoid-inspector__segments\">\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"_segment === 'audit'\"\r\n (click)=\"setSegment('audit')\">\r\n Audit\r\n @if (audit(); as a) {\r\n <span class=\"sd-autoid-inspector__badge\" [class.is-warn]=\"a.missingCount + a.duplicateCount > 0\">\r\n {{ a.missingCount + a.duplicateCount }}\r\n </span>\r\n }\r\n </button>\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"_segment === 'elements'\"\r\n (click)=\"setSegment('elements')\">\r\n Elements\r\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\r\n </button>\r\n <button\r\n type=\"button\"\r\n [class.is-active]=\"_segment === 'export'\"\r\n (click)=\"setSegment('export')\">\r\n Export\r\n </button>\r\n </div>\r\n <div class=\"sd-autoid-inspector__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn\"\r\n matTooltip=\"Qu\u00E9t l\u1EA1i\"\r\n (click)=\"refresh()\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__close-btn\"\r\n matTooltip=\"\u0110\u00F3ng\"\r\n aria-label=\"\u0110\u00F3ng panel\"\r\n (click)=\"closePanel()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </header>\r\n\r\n @if (copyOk()) {\r\n <div class=\"sd-autoid-inspector__toast\">\u0110\u00E3 copy \u2713</div>\r\n }\r\n\r\n <div class=\"sd-autoid-inspector__body\">\r\n @switch (_segment) {\r\n @case ('audit') {\r\n <ng-container *ngTemplateOutlet=\"auditTpl\"></ng-container>\r\n }\r\n @case ('elements') {\r\n <ng-container *ngTemplateOutlet=\"elementsTpl\"></ng-container>\r\n }\r\n @case ('export') {\r\n <ng-container *ngTemplateOutlet=\"exportTpl\"></ng-container>\r\n }\r\n }\r\n </div>\r\n </section>\r\n\r\n <ng-template #auditTpl>\r\n @if (audit(); as a) {\r\n @let _highlightOn = highlightOn();\r\n <div class=\"sd-autoid-inspector__audit-toolbar\">\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__toggle\"\r\n [class.is-on]=\"_highlightOn\"\r\n (click)=\"toggleHighlight()\">\r\n <mat-icon>{{ _highlightOn ? 'visibility' : 'visibility_off' }}</mat-icon>\r\n <span>Highlight DOM</span>\r\n <span class=\"sd-autoid-inspector__toggle-state\">{{ _highlightOn ? 'ON' : 'OFF' }}</span>\r\n </button>\r\n </div>\r\n <div class=\"sd-autoid-inspector__summary\">\r\n <div class=\"sd-autoid-inspector__stat is-info\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.total }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">T\u1ED5ng autoid</div>\r\n </div>\r\n <div class=\"sd-autoid-inspector__stat\" [class.is-error]=\"a.duplicateCount > 0\" [class.is-success]=\"a.duplicateCount === 0\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.duplicateCount }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">Tr\u00F9ng</div>\r\n </div>\r\n <div class=\"sd-autoid-inspector__stat\" [class.is-warning]=\"a.missingCount > 0\" [class.is-success]=\"a.missingCount === 0\">\r\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.missingCount }}</div>\r\n <div class=\"sd-autoid-inspector__stat-label\">Thi\u1EBFu</div>\r\n </div>\r\n </div>\r\n\r\n @if (a.duplicateCount > 0) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-error\">error_outline</mat-icon>\r\n Autoid b\u1ECB tr\u00F9ng\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr><th>Autoid</th><th>S\u1ED1 l\u1EA7n</th></tr>\r\n </thead>\r\n <tbody>\r\n @for (entry of a.duplicates | keyvalue; track entry.key) {\r\n <tr class=\"is-error\">\r\n <td><code>{{ entry.key }}</code></td>\r\n <td>{{ entry.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n\r\n @if (a.missingCount > 0) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-warning\">warning_amber</mat-icon>\r\n Element thi\u1EBFu autoid\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr><th>Tag</th><th>Name hint</th><th>Selector</th></tr>\r\n </thead>\r\n <tbody>\r\n @for (m of a.missing; track $index) {\r\n <tr class=\"is-warning\">\r\n <td><code>{{ m.tag }}</code></td>\r\n <td>{{ m.nameHint }}</td>\r\n <td><code>{{ m.selector }}</code></td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n\r\n @if (a.duplicateCount === 0 && a.missingCount === 0) {\r\n <div class=\"sd-autoid-inspector__success-card\">\r\n <mat-icon>check_circle</mat-icon>\r\n <div>\r\n <strong>Kh\u00F4ng c\u00F3 element thi\u1EBFu ho\u1EB7c tr\u00F9ng autoid.</strong>\r\n <small>Trang \u0111\u00E3 \u0111\u1EA1t chu\u1EA9n convention autoid.</small>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-template>\r\n\r\n <ng-template #elementsTpl>\r\n @let _filter = filter();\r\n <div class=\"sd-autoid-inspector__filter\">\r\n <mat-icon>search</mat-icon>\r\n <input\r\n type=\"text\"\r\n placeholder=\"L\u1ECDc theo autoid / name / tag\"\r\n [ngModel]=\"_filter\"\r\n (ngModelChange)=\"filter.set($event)\"/>\r\n @if (_filter) {\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn\"\r\n matTooltip=\"Xo\u00E1 filter\"\r\n (click)=\"filter.set('')\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Top-level elements (not inside any sd-table) -->\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n Top-level elements\r\n <span class=\"sd-autoid-inspector__badge\">{{ topLevelElements().length }}</span>\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr>\r\n <th class=\"is-num\">STT</th>\r\n <th>Name</th>\r\n <th>Autoid</th>\r\n <th>Tag</th>\r\n <th>State</th>\r\n <th>Value</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (el of topLevelElements(); track el.autoid + $index) {\r\n <tr [class.is-error]=\"el.duplicate\">\r\n <td class=\"is-num\">{{ el.stt }}</td>\r\n <td>{{ el.name || '\u2014' }}</td>\r\n <td>\r\n <div class=\"sd-autoid-inspector__autoid-cell\">\r\n <code>{{ el.autoid }}</code>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn is-primary\"\r\n matTooltip=\"Copy xpath\"\r\n (click)=\"copyXpath(el.autoid)\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n </div>\r\n </td>\r\n <td><span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span></td>\r\n <td class=\"sd-autoid-inspector__state-cell\">\r\n @if (el.state.disabled !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-error]=\"el.state.disabled === 'true'\">\r\n disabled={{ el.state.disabled }}\r\n </span>\r\n }\r\n @if (el.state.loading !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-warning]=\"el.state.loading === 'true'\">\r\n loading={{ el.state.loading }}\r\n </span>\r\n }\r\n @if (el.state.empty !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-info]=\"el.state.empty === 'true'\">\r\n empty={{ el.state.empty }}\r\n </span>\r\n }\r\n @if (el.state.invalid !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-error]=\"el.state.invalid === 'true'\">\r\n invalid={{ el.state.invalid }}\r\n </span>\r\n }\r\n @if (el.state.opened !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-info]=\"el.state.opened === 'true'\">\r\n opened={{ el.state.opened }}\r\n </span>\r\n }\r\n @if (el.state.count !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n count={{ el.state.count }}\r\n </span>\r\n }\r\n @if (el.state.required !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-warning]=\"el.state.required === 'true'\">\r\n required={{ el.state.required }}\r\n </span>\r\n }\r\n @if (el.state.maxlength !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n maxlength={{ el.state.maxlength }}\r\n </span>\r\n }\r\n @if (el.state.minlength !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n minlength={{ el.state.minlength }}\r\n </span>\r\n }\r\n @if (el.state.pattern !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n pattern={{ el.state.pattern }}\r\n </span>\r\n }\r\n @if (el.state.errorMessage !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-error\">\r\n error: {{ el.state.errorMessage }}\r\n </span>\r\n }\r\n </td>\r\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\r\n {{ el.state.dataValue || el.text || '\u2014' }}\r\n </td>\r\n </tr>\r\n } @empty {\r\n <tr><td colspan=\"6\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td></tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <!-- One section per sd-table group -->\r\n @for (group of tableGroups(); track group.scope) {\r\n <h4 class=\"sd-autoid-inspector__section-title\">\r\n <mat-icon class=\"is-info\">table_chart</mat-icon>\r\n Inside <code>{{ group.scope }}</code>\r\n <span class=\"sd-autoid-inspector__badge\">{{ group.items.length }}</span>\r\n </h4>\r\n <div class=\"sd-autoid-inspector__table-wrap\">\r\n <table class=\"sd-autoid-inspector__table\">\r\n <thead>\r\n <tr>\r\n <th class=\"is-num\">STT</th>\r\n <th>Name</th>\r\n <th>Autoid</th>\r\n <th>Tag</th>\r\n <th>State</th>\r\n <th>Value</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (el of group.items; track el.autoid + $index) {\r\n <tr [class.is-error]=\"el.duplicate\">\r\n <td class=\"is-num\">{{ el.stt }}</td>\r\n <td>{{ el.name || '\u2014' }}</td>\r\n <td>\r\n <div class=\"sd-autoid-inspector__autoid-cell\">\r\n <code>{{ el.autoid }}</code>\r\n <button\r\n type=\"button\"\r\n class=\"sd-autoid-inspector__icon-btn is-primary\"\r\n matTooltip=\"Copy xpath\"\r\n (click)=\"copyXpath(el.autoid)\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n </div>\r\n </td>\r\n <td><span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span></td>\r\n <td class=\"sd-autoid-inspector__state-cell\">\r\n @if (el.state.disabled !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-error]=\"el.state.disabled === 'true'\">\r\n disabled={{ el.state.disabled }}\r\n </span>\r\n }\r\n @if (el.state.loading !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-warning]=\"el.state.loading === 'true'\">\r\n loading={{ el.state.loading }}\r\n </span>\r\n }\r\n @if (el.state.empty !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-info]=\"el.state.empty === 'true'\">\r\n empty={{ el.state.empty }}\r\n </span>\r\n }\r\n @if (el.state.invalid !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-error]=\"el.state.invalid === 'true'\">\r\n invalid={{ el.state.invalid }}\r\n </span>\r\n }\r\n @if (el.state.opened !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-info]=\"el.state.opened === 'true'\">\r\n opened={{ el.state.opened }}\r\n </span>\r\n }\r\n @if (el.state.count !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n count={{ el.state.count }}\r\n </span>\r\n }\r\n @if (el.state.required !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip\"\r\n [class.is-warning]=\"el.state.required === 'true'\">\r\n required={{ el.state.required }}\r\n </span>\r\n }\r\n @if (el.state.maxlength !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n maxlength={{ el.state.maxlength }}\r\n </span>\r\n }\r\n @if (el.state.minlength !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n minlength={{ el.state.minlength }}\r\n </span>\r\n }\r\n @if (el.state.pattern !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-info\">\r\n pattern={{ el.state.pattern }}\r\n </span>\r\n }\r\n @if (el.state.errorMessage !== undefined) {\r\n <span class=\"sd-autoid-inspector__state-chip is-error\">\r\n error: {{ el.state.errorMessage }}\r\n </span>\r\n }\r\n </td>\r\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\r\n {{ el.state.dataValue || el.text || '\u2014' }}\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n </ng-template>\r\n\r\n <ng-template #exportTpl>\r\n <div class=\"sd-autoid-inspector__export-grid\">\r\n <button type=\"button\" matTooltip=\"Copy JSON v\u00E0o clipboard\" (click)=\"copyJson()\">\r\n <mat-icon>content_copy</mat-icon>\r\n <span>Copy JSON</span>\r\n <small>clipboard</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i file JSON\" (click)=\"exportJson()\">\r\n <mat-icon>download</mat-icon>\r\n <span>JSON</span>\r\n <small>.json</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i file CSV\" (click)=\"exportCsv()\">\r\n <mat-icon>table_view</mat-icon>\r\n <span>CSV</span>\r\n <small>.csv</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i MD POM skeleton \u2014 cho AI vi\u1EBFt auto-test\" (click)=\"exportMdPom()\">\r\n <mat-icon>code</mat-icon>\r\n <span>MD POM</span>\r\n <small>AI test</small>\r\n </button>\r\n <button type=\"button\" matTooltip=\"T\u1EA3i MD reference table \u2014 group theo tag sd-*\" (click)=\"exportMdTable()\">\r\n <mat-icon>view_list</mat-icon>\r\n <span>MD Table</span>\r\n <small>reference</small>\r\n </button>\r\n </div>\r\n </ng-template>\r\n}\r\n", styles: [":host{position:fixed;inset:auto 0 0 auto;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__fab-wrap{position:fixed;right:16px;bottom:16px;z-index:100000}.sd-autoid-inspector__fab-wrap:hover .sd-autoid-inspector__fab-dismiss{opacity:1;transform:scale(1);pointer-events:auto}.sd-autoid-inspector__fab{width:36px;height:36px;border-radius:50%;border:none;background:var(--sd-primary, #2A66F4);color:#fff;cursor:pointer;box-shadow:0 3px 10px #00000038;display:inline-flex;align-items:center;justify-content:center;transition:transform .15s ease,background .15s ease,box-shadow .15s ease}.sd-autoid-inspector__fab:hover{background:var(--sd-primary-dark, #1C4AD9);transform:scale(1.08);box-shadow:0 5px 14px #00000047}.sd-autoid-inspector__fab mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__fab-dismiss{position:absolute;top:-6px;right:-6px;width:18px;height:18px;border-radius:50%;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;color:var(--sd-black400, #757575);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;opacity:0;transform:scale(.7);pointer-events:none;transition:opacity .12s ease,transform .12s ease,color .12s ease,background .12s ease;box-shadow:0 1px 4px #00000026}.sd-autoid-inspector__fab-dismiss:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__fab-dismiss mat-icon{font-size:12px;width:12px;height:12px;line-height:12px}.sd-autoid-inspector__backdrop{position:fixed;inset:0;background:#00000052;z-index:100001;backdrop-filter:blur(2px)}.sd-autoid-inspector__panel{position:fixed;right:20px;bottom:80px;width:min(860px,100vw - 40px);max-height:calc(100vh - 110px);background:#fff;border-radius:12px;box-shadow:0 16px 48px #00000038;display:flex;flex-direction:column;z-index:100002;overflow:hidden;border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__header{display:flex;align-items:center;gap:8px;padding:8px 10px;border-bottom:1px solid var(--sd-black200, #E6E6E6);background:var(--sd-black100, #F2F2F2);flex-shrink:0}.sd-autoid-inspector__segments{display:inline-flex;border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;background:#fff;overflow:hidden}.sd-autoid-inspector__segments button{border:none;background:transparent;padding:5px 12px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;gap:6px;border-right:1px solid var(--sd-black200, #E6E6E6);transition:background .12s ease,color .12s ease}.sd-autoid-inspector__segments button:last-child{border-right:none}.sd-autoid-inspector__segments button:hover:not(.is-active){background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__segments button.is-active{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__badge{background:var(--sd-black200, #E6E6E6);color:var(--sd-black500, #212121);border-radius:10px;padding:0 7px;font-size:11px;font-weight:600;line-height:16px}.is-active .sd-autoid-inspector__badge{background:#ffffff40;color:#fff}.sd-autoid-inspector__badge.is-warn{background:var(--sd-error, #F82C13);color:#fff}.sd-autoid-inspector__actions{display:inline-flex;gap:4px;margin-left:auto}.sd-autoid-inspector__icon-btn{border:none;background:transparent;cursor:pointer;padding:4px;border-radius:6px;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__icon-btn:hover{background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__icon-btn.is-primary{color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__icon-btn.is-primary:hover{background:var(--sd-primary-light, #EAF1FF);color:var(--sd-primary-dark, #1C4AD9)}.sd-autoid-inspector__icon-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__close-btn{border:none;cursor:pointer;padding:4px;border-radius:50%;width:28px;height:28px;background:transparent;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__close-btn:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__close-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__body{padding:14px;overflow:auto;flex:1;background:#fff}.sd-autoid-inspector__toast{position:absolute;top:56px;right:14px;background:var(--sd-success, #4CAF50);color:#fff;padding:6px 12px;border-radius:6px;font-size:12px;z-index:2;box-shadow:0 4px 12px #0000002e}.sd-autoid-inspector__audit-toolbar{display:flex;justify-content:flex-end;margin-bottom:12px}.sd-autoid-inspector__toggle{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:999px;padding:5px 12px 5px 10px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);transition:all .15s ease}.sd-autoid-inspector__toggle:hover{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__toggle.is-on{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__toggle mat-icon{font-size:16px;width:16px;height:16px}.sd-autoid-inspector__toggle-state{font-size:10px;font-weight:700;padding:1px 7px;border-radius:999px;background:var(--sd-black200, #E6E6E6);color:var(--sd-black400, #757575)}.is-on .sd-autoid-inspector__toggle-state{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__summary{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px}.sd-autoid-inspector__stat{background:var(--sd-black100, #F2F2F2);border-radius:10px;padding:12px;text-align:center;border:1px solid transparent}.sd-autoid-inspector__stat.is-info{background:var(--sd-info-light, #E7E9FF);border-color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-info .sd-autoid-inspector__stat-value{color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-success{background:var(--sd-success-light, #DBEFDC);border-color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__stat.is-success .sd-autoid-inspector__stat-value{color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__stat.is-warning{background:var(--sd-warning-light, #FFEACC);border-color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__stat.is-warning .sd-autoid-inspector__stat-value{color:var(--sd-warning-dark, #BF7000)}.sd-autoid-inspector__stat.is-error{background:var(--sd-error-light, #FED5D0);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__stat.is-error .sd-autoid-inspector__stat-value{color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__stat-value{font-size:22px;font-weight:700;line-height:1;margin-bottom:4px}.sd-autoid-inspector__stat-label{font-size:11px;color:var(--sd-black400, #757575);text-transform:uppercase;letter-spacing:.4px;font-weight:600}.sd-autoid-inspector__section-title{display:flex;align-items:center;gap:6px;margin:14px 0 8px;font-size:13px;font-weight:600;color:var(--sd-black500, #212121)}.sd-autoid-inspector__section-title mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__section-title mat-icon.is-error{color:var(--sd-error, #F82C13)}.sd-autoid-inspector__section-title mat-icon.is-warning{color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__section-title mat-icon.is-info{color:var(--sd-info, #2962FF)}.sd-autoid-inspector__success-card{display:flex;align-items:center;gap:12px;padding:14px 16px;background:var(--sd-success-light, #DBEFDC);border:1px solid var(--sd-success, #4CAF50);border-radius:10px;color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__success-card mat-icon{font-size:28px;width:28px;height:28px;color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__success-card strong{display:block;font-size:13px;margin-bottom:2px}.sd-autoid-inspector__success-card small{font-size:11px;opacity:.85}.sd-autoid-inspector__table-wrap{border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;overflow:auto;max-height:60vh;background:#fff}.sd-autoid-inspector__table{width:100%;border-collapse:separate;border-spacing:0;font-size:12px}.sd-autoid-inspector__table th,.sd-autoid-inspector__table td{padding:8px 10px;text-align:left;vertical-align:middle;border-bottom:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__table thead th{position:sticky;top:0;z-index:1;background:var(--sd-black100, #F2F2F2);font-weight:600;color:var(--sd-black500, #212121);text-transform:none;font-size:11px;letter-spacing:.3px;border-bottom:none;box-shadow:inset 0 -1px 0 var(--sd-black200, #E6E6E6),0 2px 4px #0000000a;white-space:nowrap}.sd-autoid-inspector__table thead th.is-num{text-align:right;width:50px}.sd-autoid-inspector__table tbody tr{transition:background .1s ease}.sd-autoid-inspector__table tbody tr:hover{background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__table tbody tr:last-child td{border-bottom:none}.sd-autoid-inspector__table tbody tr.is-error{background:var(--sd-error-light, #FED5D0)}.sd-autoid-inspector__table tbody tr.is-error:hover{background:var(--sd-error-light, #FED5D0);filter:brightness(.98)}.sd-autoid-inspector__table tbody tr.is-warning{background:var(--sd-warning-light, #FFEACC)}.sd-autoid-inspector__table tbody tr.is-warning:hover{background:var(--sd-warning-light, #FFEACC);filter:brightness(.98)}.sd-autoid-inspector__table td.is-num{text-align:right;color:var(--sd-black400, #757575);font-variant-numeric:tabular-nums}.sd-autoid-inspector__table code{font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-black100, #F2F2F2);padding:2px 6px;border-radius:4px;color:var(--sd-primary-dark, #1C4AD9);border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__autoid-cell{display:inline-flex;align-items:center;gap:6px}.sd-autoid-inspector__tag-chip{display:inline-block;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-info-light, #E7E9FF);color:var(--sd-info, #2962FF);border:1px solid var(--sd-info, #2962FF);padding:1px 8px;border-radius:999px;font-weight:500}.sd-autoid-inspector__value{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sd-black400, #757575);font-style:italic}.sd-autoid-inspector__state-cell{display:flex;flex-wrap:wrap;gap:4px;align-items:center;min-width:0}.sd-autoid-inspector__state-chip{display:inline-block;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:10px;background:var(--sd-black100, #F2F2F2);color:var(--sd-black400, #757575);border:1px solid var(--sd-black200, #E6E6E6);padding:1px 6px;border-radius:999px;font-weight:500;white-space:nowrap}.sd-autoid-inspector__state-chip.is-error{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__state-chip.is-warning{background:var(--sd-warning-light, #FFEACC);color:var(--sd-warning-dark, #BF7000);border-color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__state-chip.is-info{background:var(--sd-info-light, #E7E9FF);color:var(--sd-info, #2962FF);border-color:var(--sd-info, #2962FF)}.sd-autoid-inspector__empty{text-align:center;color:var(--sd-black400, #757575);padding:24px;font-style:italic}.sd-autoid-inspector__filter{display:flex;align-items:center;gap:6px;background:var(--sd-black100, #F2F2F2);border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;padding:6px 10px;margin-bottom:12px;transition:border-color .15s ease}.sd-autoid-inspector__filter:focus-within{border-color:var(--sd-primary, #2A66F4);background:#fff}.sd-autoid-inspector__filter input{flex:1;border:none;background:transparent;outline:none;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__filter input::placeholder{color:var(--sd-black300, #BFBFBF)}.sd-autoid-inspector__filter>mat-icon{font-size:18px;width:18px;height:18px;color:var(--sd-black400, #757575)}.sd-autoid-inspector__export-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:8px}.sd-autoid-inspector__export-grid button{border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:10px;padding:12px 10px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;min-width:0;transition:border-color .15s ease,background .15s ease,transform .12s ease;text-align:center}.sd-autoid-inspector__export-grid button:hover{border-color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF);transform:translateY(-1px)}.sd-autoid-inspector__export-grid button span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__export-grid button small{font-size:10px;color:var(--sd-black400, #757575);line-height:1.2}.sd-autoid-inspector__export-grid button mat-icon{font-size:22px;width:22px;height:22px;color:var(--sd-primary, #2A66F4)}\n"] }]
575
800
  }], propDecorators: { onEscape: [{
576
801
  type: HostListener,
577
802
  args: ['document:keydown.escape']