@sdcorejs/angular 19.0.9 → 19.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +270 -140
- package/assets/STYLE-GUIDE.md +2 -2
- package/assets/scss/core/_inline-edit.scss +1 -1
- package/assets/scss/core/form.scss +1 -1
- package/assets/scss/core/utilities/_grid.scss +25 -19
- package/assets/scss/themes/default.scss +2 -2
- package/components/anchor/src/models/sd-anchor.model.d.ts +1 -1
- package/components/badge/src/badge.component.d.ts +3 -14
- package/components/button/src/button.component.d.ts +5 -3
- package/components/document-builder/src/document-builder.component.d.ts +2 -2
- package/components/document-builder/src/plugins/paste-handler/filters/parse.d.ts +1 -1
- package/components/editor/src/plugins/image-upload/utils/batch.utils.d.ts +3 -3
- package/components/form-generic/src/components/form-builder/components/attribute-expression/attribute-expression.component.d.ts +10 -6
- package/components/form-generic/src/components/form-builder/components/attribute-expression/form-expression-query-adapter.d.ts +6 -0
- package/components/form-generic/src/components/form-builder/components/attribute-parameter/attribute-parameter.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/attribute-selection/attribute-selection.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/attribute-selection/components/build-queries/build-queries.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/attribute-selection/components/build-variables/build-variables.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/attribute-table/attribute-table.component.d.ts +2 -4
- package/components/form-generic/src/components/form-builder/components/attribute-template/attribute-template.component.d.ts +2 -4
- package/components/form-generic/src/components/form-builder/components/checkbox/attribute/checkbox-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/chip-calendar/attribute/chip-calendar-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/chip-calendar/control/chip-calendar-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/chip-string/attribute/chip-string-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/chip-string/control/chip-string-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/configure-validation/configure-validation.component.d.ts +6 -7
- package/components/form-generic/src/components/form-builder/components/datetime/attribute/datetime-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/datetime/control/datetime-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/expression-builder/expression-builder.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/html/attribute/components/build-queries/build-queries.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/html/control/html-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/number/attribute/number-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/number/control/number-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/radio/attribute/radio-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/radio/control/radio-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/select/attribute/select-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/select/control/select-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/table/attribute/table-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/table/control/table-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/textarea/attribute/textarea-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/textarea/control/textarea-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/textfield/attribute/textfield-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/textfield/control/textfield-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/upload/attribute/upload-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/upload/control/upload-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/form-builder-layout.d.ts +22 -0
- package/components/form-generic/src/components/form-builder/form-builder.component.d.ts +24 -5
- package/components/form-generic/src/components/form-render/components/item/components/chip-calendar/chip-calendar.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/chip-string/chip-string.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/datetime/datetime.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/html/html.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/number/number.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/radio/radio.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/select/select.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/table/table.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/textarea/textarea.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/textfield/textfield.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/upload/upload.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/variable/variable.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/form-render.component.d.ts +4 -6
- package/components/form-generic/src/components/sd-feel-expression/sd-feel-expression.component.d.ts +2 -2
- package/components/form-generic/src/configurations/form.configuration.d.ts +1 -1
- package/components/form-generic/src/models/form-generic-component.model.d.ts +2 -2
- package/components/form-generic/src/services/form-generic.service.d.ts +1 -3
- package/components/import-excel/src/import-excel.model.d.ts +2 -2
- package/components/inform/src/inform.component.d.ts +2 -8
- package/components/mini-editor/src/mini-editor.component.d.ts +4 -4
- package/components/modal/src/modal.component.d.ts +1 -1
- package/components/query-builder/src/query-builder.component.d.ts +3 -3
- package/components/query-builder/src/query-builder.model.d.ts +4 -4
- package/components/splitter/src/splitter-state.service.d.ts +1 -1
- package/components/tab-router/src/models/tab-router.model.d.ts +2 -1
- package/components/tab-router/src/services/tab-router.service.d.ts +0 -1
- package/components/table/src/components/command/desktop-command.component.d.ts +7 -7
- package/components/table/src/components/command/pipes/command.pipe.d.ts +1 -12
- package/components/table/src/components/command/pipes/filter.pipe.d.ts +1 -8
- package/components/table/src/components/filter/column-filter/column-filter.component.d.ts +1 -0
- package/components/table/src/models/table-column.model.d.ts +3 -2
- package/components/table/src/models/table-command.model.d.ts +3 -3
- package/components/table/src/models/table-option-selector.model.d.ts +5 -5
- package/components/table/src/pipes/selection-disabled.pipe.d.ts +1 -1
- package/components/table/src/services/config.service.d.ts +4 -5
- package/components/tree/src/tree.model.d.ts +3 -2
- package/components/view/src/view.component.d.ts +1 -1
- package/configurations/src/sd-core.configuration.d.ts +2 -2
- package/fesm2022/sdcorejs-angular-components-anchor.mjs +20 -24
- package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +4 -5
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-avatar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-badge.mjs +14 -13
- package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-button.mjs +15 -17
- package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-chart.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-code-editor.mjs +5 -6
- package/fesm2022/sdcorejs-angular-components-code-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs +17 -26
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-editor.mjs +11 -7
- package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs +715 -436
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-history.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-history.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs +38 -23
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-inform.mjs +5 -16
- package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-mini-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +5 -6
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal.mjs +28 -18
- package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-operator.mjs +1 -1
- package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs +4 -5
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-preview.mjs +40 -37
- package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs +38 -55
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs +5 -7
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-quick-action.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-section.mjs +3 -5
- package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +6 -7
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-splitter.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-stepper.mjs +3 -4
- package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs +36 -37
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab.mjs +3 -4
- package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-table.mjs +79 -101
- package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tree.mjs +6 -8
- package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs +14 -15
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-view.mjs +3 -9
- package/fesm2022/sdcorejs-angular-components-view.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-configurations.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-directives.mjs +2 -7
- package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +5 -10
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +9 -11
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip.mjs +7 -9
- package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs +8 -12
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date.mjs +8 -12
- package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs +7 -13
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs +4 -5
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs +3 -3
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs +6 -8
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input.mjs +5 -7
- package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-label.mjs +4 -6
- package/fesm2022/sdcorejs-angular-forms-label.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-radio.mjs +12 -4
- package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-select.mjs +51 -22
- package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs +7 -9
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-handlers.mjs +3 -6
- package/fesm2022/sdcorejs-angular-handlers.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-i18n.mjs +11 -7
- package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-interceptors.mjs +0 -2
- package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-auth.mjs +14 -38
- package/fesm2022/sdcorejs-angular-modules-auth.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-authom.mjs +14 -14
- package/fesm2022/sdcorejs-angular-modules-authom.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-icon.mjs +523 -0
- package/fesm2022/sdcorejs-angular-modules-icon.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +22 -11
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-layout.mjs +53 -52
- package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-permission.mjs +5 -12
- package/fesm2022/sdcorejs-angular-modules-permission.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules.mjs +1 -0
- package/fesm2022/sdcorejs-angular-modules.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-pipes.mjs +71 -17
- package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-api.mjs +0 -2
- package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-cache.mjs +5 -11
- package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-confirm.mjs +19 -25
- package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-docx.mjs +2 -8
- package/fesm2022/sdcorejs-angular-services-docx.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-excel.mjs +24 -16
- package/fesm2022/sdcorejs-angular-services-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-license.mjs +5 -12
- package/fesm2022/sdcorejs-angular-services-license.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-notify.mjs +70 -87
- package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-storage.mjs +6 -15
- package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-utilities-data-state.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-utilities-extensions.mjs +47 -5
- package/fesm2022/sdcorejs-angular-utilities-extensions.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-utilities-models.mjs +21 -5
- package/fesm2022/sdcorejs-angular-utilities-models.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular.mjs.map +1 -1
- package/forms/chip/src/chip.component.d.ts +2 -2
- package/forms/chip-calendar/src/chip-calendar.component.d.ts +2 -2
- package/forms/input-color/src/input-color.component.d.ts +2 -1
- package/forms/select/src/select-footer-action.directive.d.ts +5 -1
- package/forms/select/src/select.component.d.ts +4 -0
- package/modules/auth/guards/auth.guard.d.ts +2 -4
- package/modules/auth/guards/portal.guard.d.ts +2 -4
- package/modules/auth/services/auth.service.d.ts +3 -4
- package/modules/icon/index.d.ts +1 -0
- package/modules/icon/src/icon.component.d.ts +101 -0
- package/modules/icon/src/icon.model.d.ts +59 -0
- package/modules/icon/src/icon.provider.d.ts +33 -0
- package/modules/icon/src/index.d.ts +3 -0
- package/modules/index.d.ts +1 -0
- package/modules/layout/modules/home/guards/home-redirect.guard.d.ts +3 -5
- package/modules/permission/src/configurations/permission.configuration.d.ts +3 -3
- package/modules/permission/src/guards/permission.guard.d.ts +2 -5
- package/package.json +11 -6
- package/pipes/index.d.ts +3 -0
- package/pipes/src/format-date.pipe.d.ts +8 -0
- package/pipes/src/format-datetime.pipe.d.ts +8 -0
- package/pipes/src/format-number.pipe.d.ts +1 -3
- package/pipes/src/view.pipe.d.ts +7 -0
- package/services/confirm/src/lib/components/dialog-confirm/dialog-confirm.component.d.ts +3 -3
- package/services/excel/src/lib/spreadsheet-formula-injection.util.d.ts +5 -0
- package/services/license/src/license.service.d.ts +2 -3
- package/services/notify/src/components/toast/toast.component.d.ts +9 -13
- package/services/notify/src/notify.service.d.ts +4 -5
- package/services/storage/src/storage.service.d.ts +3 -4
- package/utilities/extensions/index.d.ts +1 -0
- package/utilities/extensions/src/object.extension.d.ts +8 -0
- package/utilities/models/src/icon.model.d.ts +4 -2
- package/components/document-builder/src/plugins/paste-handler/filters/replacetabswithinprewithspaces.d.ts +0 -24
|
@@ -2,13 +2,12 @@ import * as i1 from '@angular/common';
|
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { InjectionToken, Injectable, inject, input, booleanAttribute, signal, computed, HostListener, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
5
|
-
import * as i3 from '@angular/material/
|
|
6
|
-
import { MatIconModule } from '@angular/material/icon';
|
|
7
|
-
import * as i4 from '@angular/material/tooltip';
|
|
5
|
+
import * as i3 from '@angular/material/tooltip';
|
|
8
6
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
9
7
|
import * as i2 from '@angular/forms';
|
|
10
8
|
import { FormsModule } from '@angular/forms';
|
|
11
9
|
import { Router } from '@angular/router';
|
|
10
|
+
import { SdIcon } from '@sdcorejs/angular/modules/icon';
|
|
12
11
|
|
|
13
12
|
/** Cau hinh global cho AutoId Inspector. `[config]` tren component co the override theo instance. */
|
|
14
13
|
const SD_AUTOID_INSPECTOR_CONFIGURATION = new InjectionToken('sd.autoid-inspector.configuration');
|
|
@@ -962,11 +961,11 @@ class SdAutoidInspector {
|
|
|
962
961
|
}, 1800);
|
|
963
962
|
}
|
|
964
963
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidInspector, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
965
|
-
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();\n@let _open = open();\n@if (_enabled && !dismissed()) {\n <div class=\"sd-autoid-inspector__fab-wrap\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__fab\"\n data-autoid=\"sd-autoid-inspector-fab\"\n [attr.data-opened]=\"dataOpened()\"\n [matTooltip]=\"_open ? '\u0110\u00F3ng AutoId Inspector' : 'M\u1EDF AutoId Inspector'\"\n matTooltipPosition=\"left\"\n (click)=\"togglePanel()\">\n <mat-icon>{{ _open ? 'close' : 'tag' }}</mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__fab-dismiss\"\n matTooltip=\"\u1EA8n t\u1EA1m \u2014 reload trang \u0111\u1EC3 hi\u1EC7n l\u1EA1i\"\n matTooltipPosition=\"left\"\n aria-label=\"\u1EA8n t\u1EA1m FAB\"\n (click)=\"dismissFab($event)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n}\n\n@if (_enabled && _open) {\n @let _segment = segment();\n <button type=\"button\" class=\"sd-autoid-inspector__backdrop\" aria-label=\"\u0110\u00F3ng AutoId Inspector\" (click)=\"closePanel()\"></button>\n <section\n class=\"sd-autoid-inspector__panel\"\n role=\"dialog\"\n aria-label=\"AutoId Inspector\"\n data-autoid=\"sd-autoid-inspector-panel\"\n [attr.data-segment]=\"dataSegment()\"\n [attr.data-highlight-on]=\"dataHighlightOn()\"\n [attr.data-element-count]=\"dataElementCount()\"\n [attr.data-missing-count]=\"dataMissingCount()\"\n [attr.data-duplicate-count]=\"dataDuplicateCount()\">\n <header class=\"sd-autoid-inspector__header\">\n <div class=\"sd-autoid-inspector__segments\">\n <button type=\"button\" [class.is-active]=\"_segment === 'audit'\" (click)=\"setSegment('audit')\">\n Audit\n @if (audit(); as a) {\n <span class=\"sd-autoid-inspector__badge\" [class.is-warn]=\"a.missingCount + a.duplicateCount > 0\">\n {{ a.missingCount + a.duplicateCount }}\n </span>\n }\n </button>\n <button type=\"button\" [class.is-active]=\"_segment === 'elements'\" (click)=\"setSegment('elements')\">\n Elements\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\n </button>\n <button type=\"button\" [class.is-active]=\"_segment === 'export'\" (click)=\"setSegment('export')\">Export</button>\n </div>\n <div class=\"sd-autoid-inspector__actions\">\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"Qu\u00E9t l\u1EA1i\" (click)=\"refresh()\">\n <mat-icon>refresh</mat-icon>\n </button>\n <button type=\"button\" class=\"sd-autoid-inspector__close-btn\" matTooltip=\"\u0110\u00F3ng\" aria-label=\"\u0110\u00F3ng panel\" (click)=\"closePanel()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </header>\n\n @if (copyOk()) {\n <div class=\"sd-autoid-inspector__toast\">\u0110\u00E3 copy \u2713</div>\n }\n\n <div class=\"sd-autoid-inspector__body\">\n @switch (_segment) {\n @case ('audit') {\n <ng-container *ngTemplateOutlet=\"auditTpl\"></ng-container>\n }\n @case ('elements') {\n <ng-container *ngTemplateOutlet=\"elementsTpl\"></ng-container>\n }\n @case ('export') {\n <ng-container *ngTemplateOutlet=\"exportTpl\"></ng-container>\n }\n }\n </div>\n </section>\n\n <ng-template #auditTpl>\n @if (audit(); as a) {\n @let _highlightOn = highlightOn();\n <div class=\"sd-autoid-inspector__audit-toolbar\">\n <button type=\"button\" class=\"sd-autoid-inspector__toggle\" [class.is-on]=\"_highlightOn\" (click)=\"toggleHighlight()\">\n <mat-icon>{{ _highlightOn ? 'visibility' : 'visibility_off' }}</mat-icon>\n <span>Highlight DOM</span>\n <span class=\"sd-autoid-inspector__toggle-state\">{{ _highlightOn ? 'ON' : 'OFF' }}</span>\n </button>\n </div>\n <div class=\"sd-autoid-inspector__summary\">\n <div class=\"sd-autoid-inspector__stat is-info\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.total }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">T\u1ED5ng autoid</div>\n </div>\n <div class=\"sd-autoid-inspector__stat\" [class.is-error]=\"a.duplicateCount > 0\" [class.is-success]=\"a.duplicateCount === 0\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.duplicateCount }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">Tr\u00F9ng</div>\n </div>\n <div class=\"sd-autoid-inspector__stat\" [class.is-warning]=\"a.missingCount > 0\" [class.is-success]=\"a.missingCount === 0\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.missingCount }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">Thi\u1EBFu</div>\n </div>\n </div>\n\n @if (a.duplicateCount > 0) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <mat-icon class=\"is-error\">error_outline</mat-icon>\n Autoid b\u1ECB tr\u00F9ng\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th>Autoid</th>\n <th>S\u1ED1 l\u1EA7n</th>\n </tr>\n </thead>\n <tbody>\n @for (entry of a.duplicates | keyvalue; track entry.key) {\n <tr class=\"is-error\">\n <td>\n <code>{{ entry.key }}</code>\n </td>\n <td>{{ entry.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (a.missingCount > 0) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <mat-icon class=\"is-warning\">warning_amber</mat-icon>\n Element thi\u1EBFu autoid\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th>Tag</th>\n <th>Name hint</th>\n <th>Selector</th>\n </tr>\n </thead>\n <tbody>\n @for (m of a.missing; track $index) {\n <tr class=\"is-warning\">\n <td>\n <code>{{ m.tag }}</code>\n </td>\n <td>{{ m.nameHint }}</td>\n <td>\n <code>{{ m.selector }}</code>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (a.duplicateCount === 0 && a.missingCount === 0) {\n <div class=\"sd-autoid-inspector__success-card\">\n <mat-icon>check_circle</mat-icon>\n <div>\n <strong>Kh\u00F4ng c\u00F3 element thi\u1EBFu ho\u1EB7c tr\u00F9ng autoid.</strong>\n <small>Trang \u0111\u00E3 \u0111\u1EA1t chu\u1EA9n convention autoid.</small>\n </div>\n </div>\n }\n }\n </ng-template>\n\n <ng-template #elementsTpl>\n @let _filter = filter();\n <div class=\"sd-autoid-inspector__filter\">\n <mat-icon>search</mat-icon>\n <input type=\"text\" placeholder=\"L\u1ECDc theo autoid / name / tag\" [ngModel]=\"_filter\" (ngModelChange)=\"filter.set($event)\" />\n @if (_filter) {\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"Xo\u00E1 filter\" (click)=\"filter.set('')\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\n\n <!-- Top-level elements (not inside any sd-table) -->\n <h4 class=\"sd-autoid-inspector__section-title\">\n Top-level elements\n <span class=\"sd-autoid-inspector__badge\">{{ topLevelElements().length }}</span>\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th class=\"is-num\">STT</th>\n <th>Name</th>\n <th>Autoid</th>\n <th>Tag</th>\n <th>State</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of topLevelElements(); track el.autoid + $index) {\n <tr [class.is-error]=\"el.duplicate\">\n <td class=\"is-num\">{{ el.stt }}</td>\n <td>{{ el.name || '\u2014' }}</td>\n <td>\n <div class=\"sd-autoid-inspector__autoid-cell\">\n <code>{{ el.autoid }}</code>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn is-primary\"\n matTooltip=\"Copy xpath\"\n (click)=\"copyXpath(el.autoid)\">\n <mat-icon>content_copy</mat-icon>\n </button>\n </div>\n </td>\n <td>\n <span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span>\n </td>\n <td class=\"sd-autoid-inspector__state-cell\">\n @if (el.state.disabled !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.disabled === 'true'\">\n disabled={{ el.state.disabled }}\n </span>\n }\n @if (el.state.loading !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.loading === 'true'\">\n loading={{ el.state.loading }}\n </span>\n }\n @if (el.state.empty !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.empty === 'true'\">\n empty={{ el.state.empty }}\n </span>\n }\n @if (el.state.invalid !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.invalid === 'true'\">\n invalid={{ el.state.invalid }}\n </span>\n }\n @if (el.state.opened !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.opened === 'true'\">\n opened={{ el.state.opened }}\n </span>\n }\n @if (el.state.count !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> count={{ el.state.count }} </span>\n }\n @if (el.state.required !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.required === 'true'\">\n required={{ el.state.required }}\n </span>\n }\n @if (el.state.maxlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> maxlength={{ el.state.maxlength }} </span>\n }\n @if (el.state.minlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> minlength={{ el.state.minlength }} </span>\n }\n @if (el.state.pattern !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> pattern={{ el.state.pattern }} </span>\n }\n @if (el.state.errorMessage !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-error\"> error: {{ el.state.errorMessage }} </span>\n }\n </td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\n {{ el.state.dataValue || el.text || '\u2014' }}\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"6\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <!-- One section per sd-table group -->\n @for (group of tableGroups(); track group.scope) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <mat-icon class=\"is-info\">table_chart</mat-icon>\n Inside <code>{{ group.scope }}</code>\n <span class=\"sd-autoid-inspector__badge\">{{ group.items.length }}</span>\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th class=\"is-num\">STT</th>\n <th>Name</th>\n <th>Autoid</th>\n <th>Tag</th>\n <th>State</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of group.items; track el.autoid + $index) {\n <tr [class.is-error]=\"el.duplicate\">\n <td class=\"is-num\">{{ el.stt }}</td>\n <td>{{ el.name || '\u2014' }}</td>\n <td>\n <div class=\"sd-autoid-inspector__autoid-cell\">\n <code>{{ el.autoid }}</code>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn is-primary\"\n matTooltip=\"Copy xpath\"\n (click)=\"copyXpath(el.autoid)\">\n <mat-icon>content_copy</mat-icon>\n </button>\n </div>\n </td>\n <td>\n <span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span>\n </td>\n <td class=\"sd-autoid-inspector__state-cell\">\n @if (el.state.disabled !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.disabled === 'true'\">\n disabled={{ el.state.disabled }}\n </span>\n }\n @if (el.state.loading !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.loading === 'true'\">\n loading={{ el.state.loading }}\n </span>\n }\n @if (el.state.empty !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.empty === 'true'\">\n empty={{ el.state.empty }}\n </span>\n }\n @if (el.state.invalid !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.invalid === 'true'\">\n invalid={{ el.state.invalid }}\n </span>\n }\n @if (el.state.opened !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.opened === 'true'\">\n opened={{ el.state.opened }}\n </span>\n }\n @if (el.state.count !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> count={{ el.state.count }} </span>\n }\n @if (el.state.required !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.required === 'true'\">\n required={{ el.state.required }}\n </span>\n }\n @if (el.state.maxlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> maxlength={{ el.state.maxlength }} </span>\n }\n @if (el.state.minlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> minlength={{ el.state.minlength }} </span>\n }\n @if (el.state.pattern !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> pattern={{ el.state.pattern }} </span>\n }\n @if (el.state.errorMessage !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-error\"> error: {{ el.state.errorMessage }} </span>\n }\n </td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\n {{ el.state.dataValue || el.text || '\u2014' }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </ng-template>\n\n <ng-template #exportTpl>\n <div class=\"sd-autoid-inspector__export-grid\">\n <button type=\"button\" matTooltip=\"Copy JSON v\u00E0o clipboard\" (click)=\"copyJson()\">\n <mat-icon>content_copy</mat-icon>\n <span>Copy JSON</span>\n <small>clipboard</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i file JSON\" (click)=\"exportJson()\">\n <mat-icon>download</mat-icon>\n <span>JSON</span>\n <small>.json</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i file CSV\" (click)=\"exportCsv()\">\n <mat-icon>table_view</mat-icon>\n <span>CSV</span>\n <small>.csv</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i MD POM skeleton \u2014 cho AI vi\u1EBFt auto-test\" (click)=\"exportMdPom()\">\n <mat-icon>code</mat-icon>\n <span>MD POM</span>\n <small>AI test</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i MD reference table \u2014 group theo tag sd-*\" (click)=\"exportMdTable()\">\n <mat-icon>view_list</mat-icon>\n <span>MD Table</span>\n <small>reference</small>\n </button>\n </div>\n\n @if (e2eGeneratorHost()) {\n @let _e2eExporting = e2eExporting();\n <div class=\"sd-autoid-inspector__export-section\">\n <h4 class=\"sd-autoid-inspector__section-title\">\n <mat-icon class=\"is-info\">auto_awesome</mat-icon>\n T\u1EA1o E2E test\n </h4>\n <div class=\"sd-autoid-inspector__export-grid is-e2e\">\n <button\n type=\"button\"\n matTooltip=\"T\u1EA1o b\u1ED9 test Playwright (.zip)\"\n [disabled]=\"_e2eExporting !== null\"\n (click)=\"exportE2eTest('playwright')\">\n <mat-icon>{{ _e2eExporting === 'playwright' ? 'hourglass_empty' : 'play_arrow' }}</mat-icon>\n <span>Playwright</span>\n <small>.zip</small>\n </button>\n <button\n type=\"button\"\n matTooltip=\"T\u1EA1o b\u1ED9 test Robot Framework (.zip)\"\n [disabled]=\"_e2eExporting !== null\"\n (click)=\"openRobotExportContext()\">\n <mat-icon>{{ _e2eExporting === 'robot' ? 'hourglass_empty' : 'smart_toy' }}</mat-icon>\n <span>Robot Framework</span>\n <small>.zip</small>\n </button>\n </div>\n\n @if (robotContextOpen()) {\n <div class=\"sd-autoid-inspector__context-backdrop\" role=\"presentation\" (click)=\"closeRobotExportContext()\"></div>\n <section\n class=\"sd-autoid-inspector__context-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"sd-autoid-robot-context-title\">\n <header class=\"sd-autoid-inspector__context-header\">\n <div>\n <h4 id=\"sd-autoid-robot-context-title\">Ng\u1EEF c\u1EA3nh QC cho Robot Framework</h4>\n <small>Requirement, test case, test data</small>\n </div>\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"\u0110\u00F3ng\" (click)=\"closeRobotExportContext()\">\n <mat-icon>close</mat-icon>\n </button>\n </header>\n\n <div class=\"sd-autoid-inspector__context-form\">\n <label>\n <span>Component</span>\n <input\n type=\"text\"\n placeholder=\"SP-Wallet\"\n [ngModel]=\"robotExportContext().component || ''\"\n (ngModelChange)=\"updateRobotExportContext('component', $event)\" />\n </label>\n <label>\n <span>Story / Trace</span>\n <input\n type=\"text\"\n placeholder=\"US-001, AC-01\"\n [ngModel]=\"robotExportContext().storyLinkages || ''\"\n (ngModelChange)=\"updateRobotExportContext('storyLinkages', $event)\" />\n </label>\n <label class=\"is-full\">\n <span>Requirement / AC / BR</span>\n <textarea\n rows=\"4\"\n placeholder=\"D\u00E1n requirement ho\u1EB7c acceptance criteria...\"\n [ngModel]=\"robotExportContext().requirement || ''\"\n (ngModelChange)=\"updateRobotExportContext('requirement', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Test case QC \u0111\u00E3 \u0111\u1ECBnh ngh\u0129a</span>\n <textarea\n rows=\"4\"\n placeholder=\"TC-001: ...\"\n [ngModel]=\"robotExportContext().testCases || ''\"\n (ngModelChange)=\"updateRobotExportContext('testCases', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Test data</span>\n <textarea\n rows=\"3\"\n placeholder=\"wallet=V\u00ED A, amount=100000...\"\n [ngModel]=\"robotExportContext().testData || ''\"\n (ngModelChange)=\"updateRobotExportContext('testData', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Precondition</span>\n <textarea\n rows=\"2\"\n placeholder=\"User \u0111\u00E3 \u0111\u0103ng nh\u1EADp, d\u1EEF li\u1EC7u v\u00ED \u0111\u00E3 t\u1ED3n t\u1EA1i...\"\n [ngModel]=\"robotExportContext().precondition || ''\"\n (ngModelChange)=\"updateRobotExportContext('precondition', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Ghi ch\u00FA format QC</span>\n <textarea\n rows=\"3\"\n placeholder=\"Smoke=Y, Auto=Y, \u01B0u ti\u00EAn happy path...\"\n [ngModel]=\"robotExportContext().qcNotes || ''\"\n (ngModelChange)=\"updateRobotExportContext('qcNotes', $event)\"></textarea>\n </label>\n </div>\n\n <footer class=\"sd-autoid-inspector__context-actions\">\n <button type=\"button\" class=\"is-secondary\" [disabled]=\"_e2eExporting !== null\" (click)=\"closeRobotExportContext()\">\n Hu\u1EF7\n </button>\n <button\n type=\"button\"\n class=\"is-primary\"\n [disabled]=\"_e2eExporting !== null || !hasRobotExportContext()\"\n (click)=\"confirmRobotExport()\">\n <mat-icon>{{ _e2eExporting === 'robot' ? 'hourglass_empty' : 'download' }}</mat-icon>\n <span>\u0110\u1ED3ng \u00FD xu\u1EA5t</span>\n </button>\n </footer>\n </section>\n }\n\n @if (e2eExportOk(); as targetLabel) {\n <div class=\"sd-autoid-inspector__export-message is-success\">\u0110\u00E3 t\u1EA3i b\u1ED9 test {{ targetLabel }}.</div>\n }\n @if (e2eExportError(); as error) {\n <div class=\"sd-autoid-inspector__export-message is-error\">\n {{ error }}\n </div>\n }\n </div>\n }\n </ng-template>\n}\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;padding:0;border:none;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(auto-fit,minmax(112px,1fr));gap:8px}.sd-autoid-inspector__export-grid.is-e2e{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}.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:disabled{cursor:wait;opacity:.68;transform:none}.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)}.sd-autoid-inspector__export-section{margin-top:14px;padding-top:12px;border-top:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-backdrop{position:fixed;inset:0;z-index:10001;background:#141c2652}.sd-autoid-inspector__context-dialog{position:fixed;z-index:10002;top:50%;left:50%;width:min(720px,100vw - 28px);max-height:min(720px,100vh - 28px);transform:translate(-50%,-50%);display:flex;flex-direction:column;border:1px solid var(--sd-black200, #e6e6e6);border-radius:8px;background:#fff;box-shadow:0 18px 48px #0f172a38;overflow:hidden}.sd-autoid-inspector__context-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:14px 16px;border-bottom:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-header h4{margin:0;font-size:15px;font-weight:700;line-height:1.3;color:var(--sd-black500, #212121)}.sd-autoid-inspector__context-header small{display:block;margin-top:2px;font-size:11px;color:var(--sd-black400, #757575);line-height:1.3}.sd-autoid-inspector__context-form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;padding:14px 16px;overflow:auto}.sd-autoid-inspector__context-form label{display:flex;flex-direction:column;gap:6px;min-width:0}.sd-autoid-inspector__context-form label.is-full{grid-column:1/-1}.sd-autoid-inspector__context-form span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__context-form input,.sd-autoid-inspector__context-form textarea{width:100%;min-width:0;border:1px solid var(--sd-black200, #e6e6e6);border-radius:6px;padding:8px 10px;color:var(--sd-black500, #212121);font:inherit;font-size:12px;line-height:1.4;outline:none;resize:vertical}.sd-autoid-inspector__context-form input:focus,.sd-autoid-inspector__context-form textarea:focus{border-color:var(--sd-primary, #2a66f4);box-shadow:0 0 0 2px #2a66f424}.sd-autoid-inspector__context-actions{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-actions button{min-height:34px;border-radius:6px;padding:0 12px;border:1px solid var(--sd-black200, #e6e6e6);background:#fff;color:var(--sd-black500, #212121);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:6px;font-size:12px;font-weight:600}.sd-autoid-inspector__context-actions button.is-primary{border-color:var(--sd-primary, #2a66f4);background:var(--sd-primary, #2a66f4);color:#fff}.sd-autoid-inspector__context-actions button:disabled{cursor:not-allowed;opacity:.62}.sd-autoid-inspector__context-actions button mat-icon{font-size:17px;width:17px;height:17px}.sd-autoid-inspector__export-message{margin-top:10px;border-radius:8px;padding:8px 10px;font-size:12px;line-height:1.35}.sd-autoid-inspector__export-message.is-success{background:var(--sd-success-light, #dbefdc);color:var(--sd-success-dark, #39833c);border:1px solid var(--sd-success, #4caf50)}.sd-autoid-inspector__export-message.is-error{background:var(--sd-error-light, #fed5d0);color:var(--sd-error-dark, #ba200e);border:1px solid var(--sd-error, #f82c13)}@media(max-width:560px){.sd-autoid-inspector__context-form{grid-template-columns:1fr}.sd-autoid-inspector__context-actions{flex-direction:column-reverse}.sd-autoid-inspector__context-actions button{width:100%}}\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 });
|
|
964
|
+
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();\n@let _open = open();\n@if (_enabled && !dismissed()) {\n <div class=\"sd-autoid-inspector__fab-wrap\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__fab\"\n data-autoid=\"sd-autoid-inspector-fab\"\n [attr.data-opened]=\"dataOpened()\"\n [matTooltip]=\"_open ? '\u0110\u00F3ng AutoId Inspector' : 'M\u1EDF AutoId Inspector'\"\n matTooltipPosition=\"left\"\n (click)=\"togglePanel()\">\n <sd-icon [name]=\"_open ? 'close' : 'tag'\"></sd-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__fab-dismiss\"\n matTooltip=\"\u1EA8n t\u1EA1m \u2014 reload trang \u0111\u1EC3 hi\u1EC7n l\u1EA1i\"\n matTooltipPosition=\"left\"\n aria-label=\"\u1EA8n t\u1EA1m FAB\"\n (click)=\"dismissFab($event)\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n </div>\n}\n\n@if (_enabled && _open) {\n @let _segment = segment();\n <button type=\"button\" class=\"sd-autoid-inspector__backdrop\" aria-label=\"\u0110\u00F3ng AutoId Inspector\" (click)=\"closePanel()\"></button>\n <section\n class=\"sd-autoid-inspector__panel\"\n role=\"dialog\"\n aria-label=\"AutoId Inspector\"\n data-autoid=\"sd-autoid-inspector-panel\"\n [attr.data-segment]=\"dataSegment()\"\n [attr.data-highlight-on]=\"dataHighlightOn()\"\n [attr.data-element-count]=\"dataElementCount()\"\n [attr.data-missing-count]=\"dataMissingCount()\"\n [attr.data-duplicate-count]=\"dataDuplicateCount()\">\n <header class=\"sd-autoid-inspector__header\">\n <div class=\"sd-autoid-inspector__segments\">\n <button type=\"button\" [class.is-active]=\"_segment === 'audit'\" (click)=\"setSegment('audit')\">\n Audit\n @if (audit(); as a) {\n <span class=\"sd-autoid-inspector__badge\" [class.is-warn]=\"a.missingCount + a.duplicateCount > 0\">\n {{ a.missingCount + a.duplicateCount }}\n </span>\n }\n </button>\n <button type=\"button\" [class.is-active]=\"_segment === 'elements'\" (click)=\"setSegment('elements')\">\n Elements\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\n </button>\n <button type=\"button\" [class.is-active]=\"_segment === 'export'\" (click)=\"setSegment('export')\">Export</button>\n </div>\n <div class=\"sd-autoid-inspector__actions\">\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"Qu\u00E9t l\u1EA1i\" (click)=\"refresh()\">\n <sd-icon name=\"refresh\"></sd-icon>\n </button>\n <button type=\"button\" class=\"sd-autoid-inspector__close-btn\" matTooltip=\"\u0110\u00F3ng\" aria-label=\"\u0110\u00F3ng panel\" (click)=\"closePanel()\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n </div>\n </header>\n\n @if (copyOk()) {\n <div class=\"sd-autoid-inspector__toast\">\u0110\u00E3 copy \u2713</div>\n }\n\n <div class=\"sd-autoid-inspector__body\">\n @switch (_segment) {\n @case ('audit') {\n <ng-container *ngTemplateOutlet=\"auditTpl\"></ng-container>\n }\n @case ('elements') {\n <ng-container *ngTemplateOutlet=\"elementsTpl\"></ng-container>\n }\n @case ('export') {\n <ng-container *ngTemplateOutlet=\"exportTpl\"></ng-container>\n }\n }\n </div>\n </section>\n\n <ng-template #auditTpl>\n @if (audit(); as a) {\n @let _highlightOn = highlightOn();\n <div class=\"sd-autoid-inspector__audit-toolbar\">\n <button type=\"button\" class=\"sd-autoid-inspector__toggle\" [class.is-on]=\"_highlightOn\" (click)=\"toggleHighlight()\">\n <sd-icon [name]=\"_highlightOn ? 'visibility' : 'visibility_off'\"></sd-icon>\n <span>Highlight DOM</span>\n <span class=\"sd-autoid-inspector__toggle-state\">{{ _highlightOn ? 'ON' : 'OFF' }}</span>\n </button>\n </div>\n <div class=\"sd-autoid-inspector__summary\">\n <div class=\"sd-autoid-inspector__stat is-info\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.total }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">T\u1ED5ng autoid</div>\n </div>\n <div class=\"sd-autoid-inspector__stat\" [class.is-error]=\"a.duplicateCount > 0\" [class.is-success]=\"a.duplicateCount === 0\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.duplicateCount }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">Tr\u00F9ng</div>\n </div>\n <div class=\"sd-autoid-inspector__stat\" [class.is-warning]=\"a.missingCount > 0\" [class.is-success]=\"a.missingCount === 0\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.missingCount }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">Thi\u1EBFu</div>\n </div>\n </div>\n\n @if (a.duplicateCount > 0) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <sd-icon class=\"is-error\" name=\"error\"></sd-icon>\n Autoid b\u1ECB tr\u00F9ng\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th>Autoid</th>\n <th>S\u1ED1 l\u1EA7n</th>\n </tr>\n </thead>\n <tbody>\n @for (entry of a.duplicates | keyvalue; track entry.key) {\n <tr class=\"is-error\">\n <td>\n <code>{{ entry.key }}</code>\n </td>\n <td>{{ entry.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (a.missingCount > 0) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <sd-icon class=\"is-warning\" name=\"warning_amber\"></sd-icon>\n Element thi\u1EBFu autoid\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th>Tag</th>\n <th>Name hint</th>\n <th>Selector</th>\n </tr>\n </thead>\n <tbody>\n @for (m of a.missing; track $index) {\n <tr class=\"is-warning\">\n <td>\n <code>{{ m.tag }}</code>\n </td>\n <td>{{ m.nameHint }}</td>\n <td>\n <code>{{ m.selector }}</code>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (a.duplicateCount === 0 && a.missingCount === 0) {\n <div class=\"sd-autoid-inspector__success-card\">\n <sd-icon name=\"check_circle\"></sd-icon>\n <div>\n <strong>Kh\u00F4ng c\u00F3 element thi\u1EBFu ho\u1EB7c tr\u00F9ng autoid.</strong>\n <small>Trang \u0111\u00E3 \u0111\u1EA1t chu\u1EA9n convention autoid.</small>\n </div>\n </div>\n }\n }\n </ng-template>\n\n <ng-template #elementsTpl>\n @let _filter = filter();\n <div class=\"sd-autoid-inspector__filter\">\n <sd-icon name=\"search\"></sd-icon>\n <input type=\"text\" placeholder=\"L\u1ECDc theo autoid / name / tag\" [ngModel]=\"_filter\" (ngModelChange)=\"filter.set($event)\" />\n @if (_filter) {\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"Xo\u00E1 filter\" (click)=\"filter.set('')\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n }\n </div>\n\n <!-- Top-level elements (not inside any sd-table) -->\n <h4 class=\"sd-autoid-inspector__section-title\">\n Top-level elements\n <span class=\"sd-autoid-inspector__badge\">{{ topLevelElements().length }}</span>\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th class=\"is-num\">STT</th>\n <th>Name</th>\n <th>Autoid</th>\n <th>Tag</th>\n <th>State</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of topLevelElements(); track el.autoid + $index) {\n <tr [class.is-error]=\"el.duplicate\">\n <td class=\"is-num\">{{ el.stt }}</td>\n <td>{{ el.name || '\u2014' }}</td>\n <td>\n <div class=\"sd-autoid-inspector__autoid-cell\">\n <code>{{ el.autoid }}</code>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn is-primary\"\n matTooltip=\"Copy xpath\"\n (click)=\"copyXpath(el.autoid)\">\n <sd-icon name=\"content_copy\"></sd-icon>\n </button>\n </div>\n </td>\n <td>\n <span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span>\n </td>\n <td class=\"sd-autoid-inspector__state-cell\">\n @if (el.state.disabled !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.disabled === 'true'\">\n disabled={{ el.state.disabled }}\n </span>\n }\n @if (el.state.loading !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.loading === 'true'\">\n loading={{ el.state.loading }}\n </span>\n }\n @if (el.state.empty !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.empty === 'true'\">\n empty={{ el.state.empty }}\n </span>\n }\n @if (el.state.invalid !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.invalid === 'true'\">\n invalid={{ el.state.invalid }}\n </span>\n }\n @if (el.state.opened !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.opened === 'true'\">\n opened={{ el.state.opened }}\n </span>\n }\n @if (el.state.count !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> count={{ el.state.count }} </span>\n }\n @if (el.state.required !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.required === 'true'\">\n required={{ el.state.required }}\n </span>\n }\n @if (el.state.maxlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> maxlength={{ el.state.maxlength }} </span>\n }\n @if (el.state.minlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> minlength={{ el.state.minlength }} </span>\n }\n @if (el.state.pattern !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> pattern={{ el.state.pattern }} </span>\n }\n @if (el.state.errorMessage !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-error\"> error: {{ el.state.errorMessage }} </span>\n }\n </td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\n {{ el.state.dataValue || el.text || '\u2014' }}\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"6\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <!-- One section per sd-table group -->\n @for (group of tableGroups(); track group.scope) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <sd-icon class=\"is-info\" name=\"table_chart\"></sd-icon>\n Inside <code>{{ group.scope }}</code>\n <span class=\"sd-autoid-inspector__badge\">{{ group.items.length }}</span>\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th class=\"is-num\">STT</th>\n <th>Name</th>\n <th>Autoid</th>\n <th>Tag</th>\n <th>State</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of group.items; track el.autoid + $index) {\n <tr [class.is-error]=\"el.duplicate\">\n <td class=\"is-num\">{{ el.stt }}</td>\n <td>{{ el.name || '\u2014' }}</td>\n <td>\n <div class=\"sd-autoid-inspector__autoid-cell\">\n <code>{{ el.autoid }}</code>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn is-primary\"\n matTooltip=\"Copy xpath\"\n (click)=\"copyXpath(el.autoid)\">\n <sd-icon name=\"content_copy\"></sd-icon>\n </button>\n </div>\n </td>\n <td>\n <span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span>\n </td>\n <td class=\"sd-autoid-inspector__state-cell\">\n @if (el.state.disabled !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.disabled === 'true'\">\n disabled={{ el.state.disabled }}\n </span>\n }\n @if (el.state.loading !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.loading === 'true'\">\n loading={{ el.state.loading }}\n </span>\n }\n @if (el.state.empty !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.empty === 'true'\">\n empty={{ el.state.empty }}\n </span>\n }\n @if (el.state.invalid !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.invalid === 'true'\">\n invalid={{ el.state.invalid }}\n </span>\n }\n @if (el.state.opened !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.opened === 'true'\">\n opened={{ el.state.opened }}\n </span>\n }\n @if (el.state.count !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> count={{ el.state.count }} </span>\n }\n @if (el.state.required !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.required === 'true'\">\n required={{ el.state.required }}\n </span>\n }\n @if (el.state.maxlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> maxlength={{ el.state.maxlength }} </span>\n }\n @if (el.state.minlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> minlength={{ el.state.minlength }} </span>\n }\n @if (el.state.pattern !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> pattern={{ el.state.pattern }} </span>\n }\n @if (el.state.errorMessage !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-error\"> error: {{ el.state.errorMessage }} </span>\n }\n </td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\n {{ el.state.dataValue || el.text || '\u2014' }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </ng-template>\n\n <ng-template #exportTpl>\n <div class=\"sd-autoid-inspector__export-grid\">\n <button type=\"button\" matTooltip=\"Copy JSON v\u00E0o clipboard\" (click)=\"copyJson()\">\n <sd-icon name=\"content_copy\"></sd-icon>\n <span>Copy JSON</span>\n <small>clipboard</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i file JSON\" (click)=\"exportJson()\">\n <sd-icon name=\"download\"></sd-icon>\n <span>JSON</span>\n <small>.json</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i file CSV\" (click)=\"exportCsv()\">\n <sd-icon name=\"table_view\"></sd-icon>\n <span>CSV</span>\n <small>.csv</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i MD POM skeleton \u2014 cho AI vi\u1EBFt auto-test\" (click)=\"exportMdPom()\">\n <sd-icon name=\"code\"></sd-icon>\n <span>MD POM</span>\n <small>AI test</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i MD reference table \u2014 group theo tag sd-*\" (click)=\"exportMdTable()\">\n <sd-icon name=\"view_list\"></sd-icon>\n <span>MD Table</span>\n <small>reference</small>\n </button>\n </div>\n\n @if (e2eGeneratorHost()) {\n @let _e2eExporting = e2eExporting();\n <div class=\"sd-autoid-inspector__export-section\">\n <h4 class=\"sd-autoid-inspector__section-title\">\n <sd-icon class=\"is-info\" name=\"auto_awesome\"></sd-icon>\n T\u1EA1o E2E test\n </h4>\n <div class=\"sd-autoid-inspector__export-grid is-e2e\">\n <button\n type=\"button\"\n matTooltip=\"T\u1EA1o b\u1ED9 test Playwright (.zip)\"\n [disabled]=\"_e2eExporting !== null\"\n (click)=\"exportE2eTest('playwright')\">\n <sd-icon [name]=\"_e2eExporting === 'playwright' ? 'hourglass_empty' : 'play_arrow'\"></sd-icon>\n <span>Playwright</span>\n <small>.zip</small>\n </button>\n <button\n type=\"button\"\n matTooltip=\"T\u1EA1o b\u1ED9 test Robot Framework (.zip)\"\n [disabled]=\"_e2eExporting !== null\"\n (click)=\"openRobotExportContext()\">\n <sd-icon [name]=\"_e2eExporting === 'robot' ? 'hourglass_empty' : 'smart_toy'\"></sd-icon>\n <span>Robot Framework</span>\n <small>.zip</small>\n </button>\n </div>\n\n @if (robotContextOpen()) {\n <div class=\"sd-autoid-inspector__context-backdrop\" role=\"presentation\" (click)=\"closeRobotExportContext()\"></div>\n <section\n class=\"sd-autoid-inspector__context-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"sd-autoid-robot-context-title\">\n <header class=\"sd-autoid-inspector__context-header\">\n <div>\n <h4 id=\"sd-autoid-robot-context-title\">Ng\u1EEF c\u1EA3nh QC cho Robot Framework</h4>\n <small>Requirement, test case, test data</small>\n </div>\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"\u0110\u00F3ng\" (click)=\"closeRobotExportContext()\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n </header>\n\n <div class=\"sd-autoid-inspector__context-form\">\n <label>\n <span>Component</span>\n <input\n type=\"text\"\n placeholder=\"SP-Wallet\"\n [ngModel]=\"robotExportContext().component || ''\"\n (ngModelChange)=\"updateRobotExportContext('component', $event)\" />\n </label>\n <label>\n <span>Story / Trace</span>\n <input\n type=\"text\"\n placeholder=\"US-001, AC-01\"\n [ngModel]=\"robotExportContext().storyLinkages || ''\"\n (ngModelChange)=\"updateRobotExportContext('storyLinkages', $event)\" />\n </label>\n <label class=\"is-full\">\n <span>Requirement / AC / BR</span>\n <textarea\n rows=\"4\"\n placeholder=\"D\u00E1n requirement ho\u1EB7c acceptance criteria...\"\n [ngModel]=\"robotExportContext().requirement || ''\"\n (ngModelChange)=\"updateRobotExportContext('requirement', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Test case QC \u0111\u00E3 \u0111\u1ECBnh ngh\u0129a</span>\n <textarea\n rows=\"4\"\n placeholder=\"TC-001: ...\"\n [ngModel]=\"robotExportContext().testCases || ''\"\n (ngModelChange)=\"updateRobotExportContext('testCases', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Test data</span>\n <textarea\n rows=\"3\"\n placeholder=\"wallet=V\u00ED A, amount=100000...\"\n [ngModel]=\"robotExportContext().testData || ''\"\n (ngModelChange)=\"updateRobotExportContext('testData', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Precondition</span>\n <textarea\n rows=\"2\"\n placeholder=\"User \u0111\u00E3 \u0111\u0103ng nh\u1EADp, d\u1EEF li\u1EC7u v\u00ED \u0111\u00E3 t\u1ED3n t\u1EA1i...\"\n [ngModel]=\"robotExportContext().precondition || ''\"\n (ngModelChange)=\"updateRobotExportContext('precondition', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Ghi ch\u00FA format QC</span>\n <textarea\n rows=\"3\"\n placeholder=\"Smoke=Y, Auto=Y, \u01B0u ti\u00EAn happy path...\"\n [ngModel]=\"robotExportContext().qcNotes || ''\"\n (ngModelChange)=\"updateRobotExportContext('qcNotes', $event)\"></textarea>\n </label>\n </div>\n\n <footer class=\"sd-autoid-inspector__context-actions\">\n <button type=\"button\" class=\"is-secondary\" [disabled]=\"_e2eExporting !== null\" (click)=\"closeRobotExportContext()\">\n Hu\u1EF7\n </button>\n <button\n type=\"button\"\n class=\"is-primary\"\n [disabled]=\"_e2eExporting !== null || !hasRobotExportContext()\"\n (click)=\"confirmRobotExport()\">\n <sd-icon [name]=\"_e2eExporting === 'robot' ? 'hourglass_empty' : 'download'\"></sd-icon>\n <span>\u0110\u1ED3ng \u00FD xu\u1EA5t</span>\n </button>\n </footer>\n </section>\n }\n\n @if (e2eExportOk(); as targetLabel) {\n <div class=\"sd-autoid-inspector__export-message is-success\">\u0110\u00E3 t\u1EA3i b\u1ED9 test {{ targetLabel }}.</div>\n }\n @if (e2eExportError(); as error) {\n <div class=\"sd-autoid-inspector__export-message is-error\">\n {{ error }}\n </div>\n }\n </div>\n }\n </ng-template>\n}\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 sd-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 sd-icon{font-size:12px;width:12px;height:12px;line-height:12px}.sd-autoid-inspector__backdrop{position:fixed;inset:0;padding:0;border:none;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 sd-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 sd-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 sd-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 sd-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__section-title sd-icon.is-error{color:var(--sd-error, #f82c13)}.sd-autoid-inspector__section-title sd-icon.is-warning{color:var(--sd-warning, #ff9600)}.sd-autoid-inspector__section-title sd-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 sd-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>sd-icon{font-size:18px;width:18px;height:18px;color:var(--sd-black400, #757575)}.sd-autoid-inspector__export-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(112px,1fr));gap:8px}.sd-autoid-inspector__export-grid.is-e2e{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}.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:disabled{cursor:wait;opacity:.68;transform:none}.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 sd-icon{font-size:22px;width:22px;height:22px;color:var(--sd-primary, #2a66f4)}.sd-autoid-inspector__export-section{margin-top:14px;padding-top:12px;border-top:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-backdrop{position:fixed;inset:0;z-index:10001;background:#141c2652}.sd-autoid-inspector__context-dialog{position:fixed;z-index:10002;top:50%;left:50%;width:min(720px,100vw - 28px);max-height:min(720px,100vh - 28px);transform:translate(-50%,-50%);display:flex;flex-direction:column;border:1px solid var(--sd-black200, #e6e6e6);border-radius:8px;background:#fff;box-shadow:0 18px 48px #0f172a38;overflow:hidden}.sd-autoid-inspector__context-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:14px 16px;border-bottom:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-header h4{margin:0;font-size:15px;font-weight:700;line-height:1.3;color:var(--sd-black500, #212121)}.sd-autoid-inspector__context-header small{display:block;margin-top:2px;font-size:11px;color:var(--sd-black400, #757575);line-height:1.3}.sd-autoid-inspector__context-form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;padding:14px 16px;overflow:auto}.sd-autoid-inspector__context-form label{display:flex;flex-direction:column;gap:6px;min-width:0}.sd-autoid-inspector__context-form label.is-full{grid-column:1/-1}.sd-autoid-inspector__context-form span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__context-form input,.sd-autoid-inspector__context-form textarea{width:100%;min-width:0;border:1px solid var(--sd-black200, #e6e6e6);border-radius:6px;padding:8px 10px;color:var(--sd-black500, #212121);font:inherit;font-size:12px;line-height:1.4;outline:none;resize:vertical}.sd-autoid-inspector__context-form input:focus,.sd-autoid-inspector__context-form textarea:focus{border-color:var(--sd-primary, #2a66f4);box-shadow:0 0 0 2px #2a66f424}.sd-autoid-inspector__context-actions{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-actions button{min-height:34px;border-radius:6px;padding:0 12px;border:1px solid var(--sd-black200, #e6e6e6);background:#fff;color:var(--sd-black500, #212121);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:6px;font-size:12px;font-weight:600}.sd-autoid-inspector__context-actions button.is-primary{border-color:var(--sd-primary, #2a66f4);background:var(--sd-primary, #2a66f4);color:#fff}.sd-autoid-inspector__context-actions button:disabled{cursor:not-allowed;opacity:.62}.sd-autoid-inspector__context-actions button sd-icon{font-size:17px;width:17px;height:17px}.sd-autoid-inspector__export-message{margin-top:10px;border-radius:8px;padding:8px 10px;font-size:12px;line-height:1.35}.sd-autoid-inspector__export-message.is-success{background:var(--sd-success-light, #dbefdc);color:var(--sd-success-dark, #39833c);border:1px solid var(--sd-success, #4caf50)}.sd-autoid-inspector__export-message.is-error{background:var(--sd-error-light, #fed5d0);color:var(--sd-error-dark, #ba200e);border:1px solid var(--sd-error, #f82c13)}@media(max-width:560px){.sd-autoid-inspector__context-form{grid-template-columns:1fr}.sd-autoid-inspector__context-actions{flex-direction:column-reverse}.sd-autoid-inspector__context-actions button{width:100%}}\n"], dependencies: [{ kind: "component", type: SdIcon, selector: "sd-icon", inputs: ["name", "fontIcon", "color", "set", "fontSet", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { 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: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
966
965
|
}
|
|
967
966
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidInspector, decorators: [{
|
|
968
967
|
type: Component,
|
|
969
|
-
args: [{ selector: 'sd-autoid-inspector', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, MatIconModule, MatTooltipModule], template: "@let _enabled = enabled();\n@let _open = open();\n@if (_enabled && !dismissed()) {\n <div class=\"sd-autoid-inspector__fab-wrap\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__fab\"\n data-autoid=\"sd-autoid-inspector-fab\"\n [attr.data-opened]=\"dataOpened()\"\n [matTooltip]=\"_open ? '\u0110\u00F3ng AutoId Inspector' : 'M\u1EDF AutoId Inspector'\"\n matTooltipPosition=\"left\"\n (click)=\"togglePanel()\">\n <mat-icon>{{ _open ? 'close' : 'tag' }}</mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__fab-dismiss\"\n matTooltip=\"\u1EA8n t\u1EA1m \u2014 reload trang \u0111\u1EC3 hi\u1EC7n l\u1EA1i\"\n matTooltipPosition=\"left\"\n aria-label=\"\u1EA8n t\u1EA1m FAB\"\n (click)=\"dismissFab($event)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n}\n\n@if (_enabled && _open) {\n @let _segment = segment();\n <button type=\"button\" class=\"sd-autoid-inspector__backdrop\" aria-label=\"\u0110\u00F3ng AutoId Inspector\" (click)=\"closePanel()\"></button>\n <section\n class=\"sd-autoid-inspector__panel\"\n role=\"dialog\"\n aria-label=\"AutoId Inspector\"\n data-autoid=\"sd-autoid-inspector-panel\"\n [attr.data-segment]=\"dataSegment()\"\n [attr.data-highlight-on]=\"dataHighlightOn()\"\n [attr.data-element-count]=\"dataElementCount()\"\n [attr.data-missing-count]=\"dataMissingCount()\"\n [attr.data-duplicate-count]=\"dataDuplicateCount()\">\n <header class=\"sd-autoid-inspector__header\">\n <div class=\"sd-autoid-inspector__segments\">\n <button type=\"button\" [class.is-active]=\"_segment === 'audit'\" (click)=\"setSegment('audit')\">\n Audit\n @if (audit(); as a) {\n <span class=\"sd-autoid-inspector__badge\" [class.is-warn]=\"a.missingCount + a.duplicateCount > 0\">\n {{ a.missingCount + a.duplicateCount }}\n </span>\n }\n </button>\n <button type=\"button\" [class.is-active]=\"_segment === 'elements'\" (click)=\"setSegment('elements')\">\n Elements\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\n </button>\n <button type=\"button\" [class.is-active]=\"_segment === 'export'\" (click)=\"setSegment('export')\">Export</button>\n </div>\n <div class=\"sd-autoid-inspector__actions\">\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"Qu\u00E9t l\u1EA1i\" (click)=\"refresh()\">\n <mat-icon>refresh</mat-icon>\n </button>\n <button type=\"button\" class=\"sd-autoid-inspector__close-btn\" matTooltip=\"\u0110\u00F3ng\" aria-label=\"\u0110\u00F3ng panel\" (click)=\"closePanel()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </header>\n\n @if (copyOk()) {\n <div class=\"sd-autoid-inspector__toast\">\u0110\u00E3 copy \u2713</div>\n }\n\n <div class=\"sd-autoid-inspector__body\">\n @switch (_segment) {\n @case ('audit') {\n <ng-container *ngTemplateOutlet=\"auditTpl\"></ng-container>\n }\n @case ('elements') {\n <ng-container *ngTemplateOutlet=\"elementsTpl\"></ng-container>\n }\n @case ('export') {\n <ng-container *ngTemplateOutlet=\"exportTpl\"></ng-container>\n }\n }\n </div>\n </section>\n\n <ng-template #auditTpl>\n @if (audit(); as a) {\n @let _highlightOn = highlightOn();\n <div class=\"sd-autoid-inspector__audit-toolbar\">\n <button type=\"button\" class=\"sd-autoid-inspector__toggle\" [class.is-on]=\"_highlightOn\" (click)=\"toggleHighlight()\">\n <mat-icon>{{ _highlightOn ? 'visibility' : 'visibility_off' }}</mat-icon>\n <span>Highlight DOM</span>\n <span class=\"sd-autoid-inspector__toggle-state\">{{ _highlightOn ? 'ON' : 'OFF' }}</span>\n </button>\n </div>\n <div class=\"sd-autoid-inspector__summary\">\n <div class=\"sd-autoid-inspector__stat is-info\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.total }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">T\u1ED5ng autoid</div>\n </div>\n <div class=\"sd-autoid-inspector__stat\" [class.is-error]=\"a.duplicateCount > 0\" [class.is-success]=\"a.duplicateCount === 0\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.duplicateCount }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">Tr\u00F9ng</div>\n </div>\n <div class=\"sd-autoid-inspector__stat\" [class.is-warning]=\"a.missingCount > 0\" [class.is-success]=\"a.missingCount === 0\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.missingCount }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">Thi\u1EBFu</div>\n </div>\n </div>\n\n @if (a.duplicateCount > 0) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <mat-icon class=\"is-error\">error_outline</mat-icon>\n Autoid b\u1ECB tr\u00F9ng\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th>Autoid</th>\n <th>S\u1ED1 l\u1EA7n</th>\n </tr>\n </thead>\n <tbody>\n @for (entry of a.duplicates | keyvalue; track entry.key) {\n <tr class=\"is-error\">\n <td>\n <code>{{ entry.key }}</code>\n </td>\n <td>{{ entry.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (a.missingCount > 0) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <mat-icon class=\"is-warning\">warning_amber</mat-icon>\n Element thi\u1EBFu autoid\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th>Tag</th>\n <th>Name hint</th>\n <th>Selector</th>\n </tr>\n </thead>\n <tbody>\n @for (m of a.missing; track $index) {\n <tr class=\"is-warning\">\n <td>\n <code>{{ m.tag }}</code>\n </td>\n <td>{{ m.nameHint }}</td>\n <td>\n <code>{{ m.selector }}</code>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (a.duplicateCount === 0 && a.missingCount === 0) {\n <div class=\"sd-autoid-inspector__success-card\">\n <mat-icon>check_circle</mat-icon>\n <div>\n <strong>Kh\u00F4ng c\u00F3 element thi\u1EBFu ho\u1EB7c tr\u00F9ng autoid.</strong>\n <small>Trang \u0111\u00E3 \u0111\u1EA1t chu\u1EA9n convention autoid.</small>\n </div>\n </div>\n }\n }\n </ng-template>\n\n <ng-template #elementsTpl>\n @let _filter = filter();\n <div class=\"sd-autoid-inspector__filter\">\n <mat-icon>search</mat-icon>\n <input type=\"text\" placeholder=\"L\u1ECDc theo autoid / name / tag\" [ngModel]=\"_filter\" (ngModelChange)=\"filter.set($event)\" />\n @if (_filter) {\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"Xo\u00E1 filter\" (click)=\"filter.set('')\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\n\n <!-- Top-level elements (not inside any sd-table) -->\n <h4 class=\"sd-autoid-inspector__section-title\">\n Top-level elements\n <span class=\"sd-autoid-inspector__badge\">{{ topLevelElements().length }}</span>\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th class=\"is-num\">STT</th>\n <th>Name</th>\n <th>Autoid</th>\n <th>Tag</th>\n <th>State</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of topLevelElements(); track el.autoid + $index) {\n <tr [class.is-error]=\"el.duplicate\">\n <td class=\"is-num\">{{ el.stt }}</td>\n <td>{{ el.name || '\u2014' }}</td>\n <td>\n <div class=\"sd-autoid-inspector__autoid-cell\">\n <code>{{ el.autoid }}</code>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn is-primary\"\n matTooltip=\"Copy xpath\"\n (click)=\"copyXpath(el.autoid)\">\n <mat-icon>content_copy</mat-icon>\n </button>\n </div>\n </td>\n <td>\n <span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span>\n </td>\n <td class=\"sd-autoid-inspector__state-cell\">\n @if (el.state.disabled !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.disabled === 'true'\">\n disabled={{ el.state.disabled }}\n </span>\n }\n @if (el.state.loading !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.loading === 'true'\">\n loading={{ el.state.loading }}\n </span>\n }\n @if (el.state.empty !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.empty === 'true'\">\n empty={{ el.state.empty }}\n </span>\n }\n @if (el.state.invalid !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.invalid === 'true'\">\n invalid={{ el.state.invalid }}\n </span>\n }\n @if (el.state.opened !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.opened === 'true'\">\n opened={{ el.state.opened }}\n </span>\n }\n @if (el.state.count !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> count={{ el.state.count }} </span>\n }\n @if (el.state.required !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.required === 'true'\">\n required={{ el.state.required }}\n </span>\n }\n @if (el.state.maxlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> maxlength={{ el.state.maxlength }} </span>\n }\n @if (el.state.minlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> minlength={{ el.state.minlength }} </span>\n }\n @if (el.state.pattern !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> pattern={{ el.state.pattern }} </span>\n }\n @if (el.state.errorMessage !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-error\"> error: {{ el.state.errorMessage }} </span>\n }\n </td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\n {{ el.state.dataValue || el.text || '\u2014' }}\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"6\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <!-- One section per sd-table group -->\n @for (group of tableGroups(); track group.scope) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <mat-icon class=\"is-info\">table_chart</mat-icon>\n Inside <code>{{ group.scope }}</code>\n <span class=\"sd-autoid-inspector__badge\">{{ group.items.length }}</span>\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th class=\"is-num\">STT</th>\n <th>Name</th>\n <th>Autoid</th>\n <th>Tag</th>\n <th>State</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of group.items; track el.autoid + $index) {\n <tr [class.is-error]=\"el.duplicate\">\n <td class=\"is-num\">{{ el.stt }}</td>\n <td>{{ el.name || '\u2014' }}</td>\n <td>\n <div class=\"sd-autoid-inspector__autoid-cell\">\n <code>{{ el.autoid }}</code>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn is-primary\"\n matTooltip=\"Copy xpath\"\n (click)=\"copyXpath(el.autoid)\">\n <mat-icon>content_copy</mat-icon>\n </button>\n </div>\n </td>\n <td>\n <span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span>\n </td>\n <td class=\"sd-autoid-inspector__state-cell\">\n @if (el.state.disabled !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.disabled === 'true'\">\n disabled={{ el.state.disabled }}\n </span>\n }\n @if (el.state.loading !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.loading === 'true'\">\n loading={{ el.state.loading }}\n </span>\n }\n @if (el.state.empty !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.empty === 'true'\">\n empty={{ el.state.empty }}\n </span>\n }\n @if (el.state.invalid !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.invalid === 'true'\">\n invalid={{ el.state.invalid }}\n </span>\n }\n @if (el.state.opened !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.opened === 'true'\">\n opened={{ el.state.opened }}\n </span>\n }\n @if (el.state.count !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> count={{ el.state.count }} </span>\n }\n @if (el.state.required !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.required === 'true'\">\n required={{ el.state.required }}\n </span>\n }\n @if (el.state.maxlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> maxlength={{ el.state.maxlength }} </span>\n }\n @if (el.state.minlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> minlength={{ el.state.minlength }} </span>\n }\n @if (el.state.pattern !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> pattern={{ el.state.pattern }} </span>\n }\n @if (el.state.errorMessage !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-error\"> error: {{ el.state.errorMessage }} </span>\n }\n </td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\n {{ el.state.dataValue || el.text || '\u2014' }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </ng-template>\n\n <ng-template #exportTpl>\n <div class=\"sd-autoid-inspector__export-grid\">\n <button type=\"button\" matTooltip=\"Copy JSON v\u00E0o clipboard\" (click)=\"copyJson()\">\n <mat-icon>content_copy</mat-icon>\n <span>Copy JSON</span>\n <small>clipboard</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i file JSON\" (click)=\"exportJson()\">\n <mat-icon>download</mat-icon>\n <span>JSON</span>\n <small>.json</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i file CSV\" (click)=\"exportCsv()\">\n <mat-icon>table_view</mat-icon>\n <span>CSV</span>\n <small>.csv</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i MD POM skeleton \u2014 cho AI vi\u1EBFt auto-test\" (click)=\"exportMdPom()\">\n <mat-icon>code</mat-icon>\n <span>MD POM</span>\n <small>AI test</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i MD reference table \u2014 group theo tag sd-*\" (click)=\"exportMdTable()\">\n <mat-icon>view_list</mat-icon>\n <span>MD Table</span>\n <small>reference</small>\n </button>\n </div>\n\n @if (e2eGeneratorHost()) {\n @let _e2eExporting = e2eExporting();\n <div class=\"sd-autoid-inspector__export-section\">\n <h4 class=\"sd-autoid-inspector__section-title\">\n <mat-icon class=\"is-info\">auto_awesome</mat-icon>\n T\u1EA1o E2E test\n </h4>\n <div class=\"sd-autoid-inspector__export-grid is-e2e\">\n <button\n type=\"button\"\n matTooltip=\"T\u1EA1o b\u1ED9 test Playwright (.zip)\"\n [disabled]=\"_e2eExporting !== null\"\n (click)=\"exportE2eTest('playwright')\">\n <mat-icon>{{ _e2eExporting === 'playwright' ? 'hourglass_empty' : 'play_arrow' }}</mat-icon>\n <span>Playwright</span>\n <small>.zip</small>\n </button>\n <button\n type=\"button\"\n matTooltip=\"T\u1EA1o b\u1ED9 test Robot Framework (.zip)\"\n [disabled]=\"_e2eExporting !== null\"\n (click)=\"openRobotExportContext()\">\n <mat-icon>{{ _e2eExporting === 'robot' ? 'hourglass_empty' : 'smart_toy' }}</mat-icon>\n <span>Robot Framework</span>\n <small>.zip</small>\n </button>\n </div>\n\n @if (robotContextOpen()) {\n <div class=\"sd-autoid-inspector__context-backdrop\" role=\"presentation\" (click)=\"closeRobotExportContext()\"></div>\n <section\n class=\"sd-autoid-inspector__context-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"sd-autoid-robot-context-title\">\n <header class=\"sd-autoid-inspector__context-header\">\n <div>\n <h4 id=\"sd-autoid-robot-context-title\">Ng\u1EEF c\u1EA3nh QC cho Robot Framework</h4>\n <small>Requirement, test case, test data</small>\n </div>\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"\u0110\u00F3ng\" (click)=\"closeRobotExportContext()\">\n <mat-icon>close</mat-icon>\n </button>\n </header>\n\n <div class=\"sd-autoid-inspector__context-form\">\n <label>\n <span>Component</span>\n <input\n type=\"text\"\n placeholder=\"SP-Wallet\"\n [ngModel]=\"robotExportContext().component || ''\"\n (ngModelChange)=\"updateRobotExportContext('component', $event)\" />\n </label>\n <label>\n <span>Story / Trace</span>\n <input\n type=\"text\"\n placeholder=\"US-001, AC-01\"\n [ngModel]=\"robotExportContext().storyLinkages || ''\"\n (ngModelChange)=\"updateRobotExportContext('storyLinkages', $event)\" />\n </label>\n <label class=\"is-full\">\n <span>Requirement / AC / BR</span>\n <textarea\n rows=\"4\"\n placeholder=\"D\u00E1n requirement ho\u1EB7c acceptance criteria...\"\n [ngModel]=\"robotExportContext().requirement || ''\"\n (ngModelChange)=\"updateRobotExportContext('requirement', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Test case QC \u0111\u00E3 \u0111\u1ECBnh ngh\u0129a</span>\n <textarea\n rows=\"4\"\n placeholder=\"TC-001: ...\"\n [ngModel]=\"robotExportContext().testCases || ''\"\n (ngModelChange)=\"updateRobotExportContext('testCases', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Test data</span>\n <textarea\n rows=\"3\"\n placeholder=\"wallet=V\u00ED A, amount=100000...\"\n [ngModel]=\"robotExportContext().testData || ''\"\n (ngModelChange)=\"updateRobotExportContext('testData', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Precondition</span>\n <textarea\n rows=\"2\"\n placeholder=\"User \u0111\u00E3 \u0111\u0103ng nh\u1EADp, d\u1EEF li\u1EC7u v\u00ED \u0111\u00E3 t\u1ED3n t\u1EA1i...\"\n [ngModel]=\"robotExportContext().precondition || ''\"\n (ngModelChange)=\"updateRobotExportContext('precondition', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Ghi ch\u00FA format QC</span>\n <textarea\n rows=\"3\"\n placeholder=\"Smoke=Y, Auto=Y, \u01B0u ti\u00EAn happy path...\"\n [ngModel]=\"robotExportContext().qcNotes || ''\"\n (ngModelChange)=\"updateRobotExportContext('qcNotes', $event)\"></textarea>\n </label>\n </div>\n\n <footer class=\"sd-autoid-inspector__context-actions\">\n <button type=\"button\" class=\"is-secondary\" [disabled]=\"_e2eExporting !== null\" (click)=\"closeRobotExportContext()\">\n Hu\u1EF7\n </button>\n <button\n type=\"button\"\n class=\"is-primary\"\n [disabled]=\"_e2eExporting !== null || !hasRobotExportContext()\"\n (click)=\"confirmRobotExport()\">\n <mat-icon>{{ _e2eExporting === 'robot' ? 'hourglass_empty' : 'download' }}</mat-icon>\n <span>\u0110\u1ED3ng \u00FD xu\u1EA5t</span>\n </button>\n </footer>\n </section>\n }\n\n @if (e2eExportOk(); as targetLabel) {\n <div class=\"sd-autoid-inspector__export-message is-success\">\u0110\u00E3 t\u1EA3i b\u1ED9 test {{ targetLabel }}.</div>\n }\n @if (e2eExportError(); as error) {\n <div class=\"sd-autoid-inspector__export-message is-error\">\n {{ error }}\n </div>\n }\n </div>\n }\n </ng-template>\n}\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;padding:0;border:none;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(auto-fit,minmax(112px,1fr));gap:8px}.sd-autoid-inspector__export-grid.is-e2e{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}.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:disabled{cursor:wait;opacity:.68;transform:none}.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)}.sd-autoid-inspector__export-section{margin-top:14px;padding-top:12px;border-top:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-backdrop{position:fixed;inset:0;z-index:10001;background:#141c2652}.sd-autoid-inspector__context-dialog{position:fixed;z-index:10002;top:50%;left:50%;width:min(720px,100vw - 28px);max-height:min(720px,100vh - 28px);transform:translate(-50%,-50%);display:flex;flex-direction:column;border:1px solid var(--sd-black200, #e6e6e6);border-radius:8px;background:#fff;box-shadow:0 18px 48px #0f172a38;overflow:hidden}.sd-autoid-inspector__context-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:14px 16px;border-bottom:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-header h4{margin:0;font-size:15px;font-weight:700;line-height:1.3;color:var(--sd-black500, #212121)}.sd-autoid-inspector__context-header small{display:block;margin-top:2px;font-size:11px;color:var(--sd-black400, #757575);line-height:1.3}.sd-autoid-inspector__context-form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;padding:14px 16px;overflow:auto}.sd-autoid-inspector__context-form label{display:flex;flex-direction:column;gap:6px;min-width:0}.sd-autoid-inspector__context-form label.is-full{grid-column:1/-1}.sd-autoid-inspector__context-form span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__context-form input,.sd-autoid-inspector__context-form textarea{width:100%;min-width:0;border:1px solid var(--sd-black200, #e6e6e6);border-radius:6px;padding:8px 10px;color:var(--sd-black500, #212121);font:inherit;font-size:12px;line-height:1.4;outline:none;resize:vertical}.sd-autoid-inspector__context-form input:focus,.sd-autoid-inspector__context-form textarea:focus{border-color:var(--sd-primary, #2a66f4);box-shadow:0 0 0 2px #2a66f424}.sd-autoid-inspector__context-actions{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-actions button{min-height:34px;border-radius:6px;padding:0 12px;border:1px solid var(--sd-black200, #e6e6e6);background:#fff;color:var(--sd-black500, #212121);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:6px;font-size:12px;font-weight:600}.sd-autoid-inspector__context-actions button.is-primary{border-color:var(--sd-primary, #2a66f4);background:var(--sd-primary, #2a66f4);color:#fff}.sd-autoid-inspector__context-actions button:disabled{cursor:not-allowed;opacity:.62}.sd-autoid-inspector__context-actions button mat-icon{font-size:17px;width:17px;height:17px}.sd-autoid-inspector__export-message{margin-top:10px;border-radius:8px;padding:8px 10px;font-size:12px;line-height:1.35}.sd-autoid-inspector__export-message.is-success{background:var(--sd-success-light, #dbefdc);color:var(--sd-success-dark, #39833c);border:1px solid var(--sd-success, #4caf50)}.sd-autoid-inspector__export-message.is-error{background:var(--sd-error-light, #fed5d0);color:var(--sd-error-dark, #ba200e);border:1px solid var(--sd-error, #f82c13)}@media(max-width:560px){.sd-autoid-inspector__context-form{grid-template-columns:1fr}.sd-autoid-inspector__context-actions{flex-direction:column-reverse}.sd-autoid-inspector__context-actions button{width:100%}}\n"] }]
|
|
968
|
+
args: [{ selector: 'sd-autoid-inspector', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [SdIcon, CommonModule, FormsModule, MatTooltipModule], template: "@let _enabled = enabled();\n@let _open = open();\n@if (_enabled && !dismissed()) {\n <div class=\"sd-autoid-inspector__fab-wrap\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__fab\"\n data-autoid=\"sd-autoid-inspector-fab\"\n [attr.data-opened]=\"dataOpened()\"\n [matTooltip]=\"_open ? '\u0110\u00F3ng AutoId Inspector' : 'M\u1EDF AutoId Inspector'\"\n matTooltipPosition=\"left\"\n (click)=\"togglePanel()\">\n <sd-icon [name]=\"_open ? 'close' : 'tag'\"></sd-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__fab-dismiss\"\n matTooltip=\"\u1EA8n t\u1EA1m \u2014 reload trang \u0111\u1EC3 hi\u1EC7n l\u1EA1i\"\n matTooltipPosition=\"left\"\n aria-label=\"\u1EA8n t\u1EA1m FAB\"\n (click)=\"dismissFab($event)\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n </div>\n}\n\n@if (_enabled && _open) {\n @let _segment = segment();\n <button type=\"button\" class=\"sd-autoid-inspector__backdrop\" aria-label=\"\u0110\u00F3ng AutoId Inspector\" (click)=\"closePanel()\"></button>\n <section\n class=\"sd-autoid-inspector__panel\"\n role=\"dialog\"\n aria-label=\"AutoId Inspector\"\n data-autoid=\"sd-autoid-inspector-panel\"\n [attr.data-segment]=\"dataSegment()\"\n [attr.data-highlight-on]=\"dataHighlightOn()\"\n [attr.data-element-count]=\"dataElementCount()\"\n [attr.data-missing-count]=\"dataMissingCount()\"\n [attr.data-duplicate-count]=\"dataDuplicateCount()\">\n <header class=\"sd-autoid-inspector__header\">\n <div class=\"sd-autoid-inspector__segments\">\n <button type=\"button\" [class.is-active]=\"_segment === 'audit'\" (click)=\"setSegment('audit')\">\n Audit\n @if (audit(); as a) {\n <span class=\"sd-autoid-inspector__badge\" [class.is-warn]=\"a.missingCount + a.duplicateCount > 0\">\n {{ a.missingCount + a.duplicateCount }}\n </span>\n }\n </button>\n <button type=\"button\" [class.is-active]=\"_segment === 'elements'\" (click)=\"setSegment('elements')\">\n Elements\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\n </button>\n <button type=\"button\" [class.is-active]=\"_segment === 'export'\" (click)=\"setSegment('export')\">Export</button>\n </div>\n <div class=\"sd-autoid-inspector__actions\">\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"Qu\u00E9t l\u1EA1i\" (click)=\"refresh()\">\n <sd-icon name=\"refresh\"></sd-icon>\n </button>\n <button type=\"button\" class=\"sd-autoid-inspector__close-btn\" matTooltip=\"\u0110\u00F3ng\" aria-label=\"\u0110\u00F3ng panel\" (click)=\"closePanel()\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n </div>\n </header>\n\n @if (copyOk()) {\n <div class=\"sd-autoid-inspector__toast\">\u0110\u00E3 copy \u2713</div>\n }\n\n <div class=\"sd-autoid-inspector__body\">\n @switch (_segment) {\n @case ('audit') {\n <ng-container *ngTemplateOutlet=\"auditTpl\"></ng-container>\n }\n @case ('elements') {\n <ng-container *ngTemplateOutlet=\"elementsTpl\"></ng-container>\n }\n @case ('export') {\n <ng-container *ngTemplateOutlet=\"exportTpl\"></ng-container>\n }\n }\n </div>\n </section>\n\n <ng-template #auditTpl>\n @if (audit(); as a) {\n @let _highlightOn = highlightOn();\n <div class=\"sd-autoid-inspector__audit-toolbar\">\n <button type=\"button\" class=\"sd-autoid-inspector__toggle\" [class.is-on]=\"_highlightOn\" (click)=\"toggleHighlight()\">\n <sd-icon [name]=\"_highlightOn ? 'visibility' : 'visibility_off'\"></sd-icon>\n <span>Highlight DOM</span>\n <span class=\"sd-autoid-inspector__toggle-state\">{{ _highlightOn ? 'ON' : 'OFF' }}</span>\n </button>\n </div>\n <div class=\"sd-autoid-inspector__summary\">\n <div class=\"sd-autoid-inspector__stat is-info\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.total }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">T\u1ED5ng autoid</div>\n </div>\n <div class=\"sd-autoid-inspector__stat\" [class.is-error]=\"a.duplicateCount > 0\" [class.is-success]=\"a.duplicateCount === 0\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.duplicateCount }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">Tr\u00F9ng</div>\n </div>\n <div class=\"sd-autoid-inspector__stat\" [class.is-warning]=\"a.missingCount > 0\" [class.is-success]=\"a.missingCount === 0\">\n <div class=\"sd-autoid-inspector__stat-value\">{{ a.missingCount }}</div>\n <div class=\"sd-autoid-inspector__stat-label\">Thi\u1EBFu</div>\n </div>\n </div>\n\n @if (a.duplicateCount > 0) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <sd-icon class=\"is-error\" name=\"error\"></sd-icon>\n Autoid b\u1ECB tr\u00F9ng\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th>Autoid</th>\n <th>S\u1ED1 l\u1EA7n</th>\n </tr>\n </thead>\n <tbody>\n @for (entry of a.duplicates | keyvalue; track entry.key) {\n <tr class=\"is-error\">\n <td>\n <code>{{ entry.key }}</code>\n </td>\n <td>{{ entry.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (a.missingCount > 0) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <sd-icon class=\"is-warning\" name=\"warning_amber\"></sd-icon>\n Element thi\u1EBFu autoid\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th>Tag</th>\n <th>Name hint</th>\n <th>Selector</th>\n </tr>\n </thead>\n <tbody>\n @for (m of a.missing; track $index) {\n <tr class=\"is-warning\">\n <td>\n <code>{{ m.tag }}</code>\n </td>\n <td>{{ m.nameHint }}</td>\n <td>\n <code>{{ m.selector }}</code>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n @if (a.duplicateCount === 0 && a.missingCount === 0) {\n <div class=\"sd-autoid-inspector__success-card\">\n <sd-icon name=\"check_circle\"></sd-icon>\n <div>\n <strong>Kh\u00F4ng c\u00F3 element thi\u1EBFu ho\u1EB7c tr\u00F9ng autoid.</strong>\n <small>Trang \u0111\u00E3 \u0111\u1EA1t chu\u1EA9n convention autoid.</small>\n </div>\n </div>\n }\n }\n </ng-template>\n\n <ng-template #elementsTpl>\n @let _filter = filter();\n <div class=\"sd-autoid-inspector__filter\">\n <sd-icon name=\"search\"></sd-icon>\n <input type=\"text\" placeholder=\"L\u1ECDc theo autoid / name / tag\" [ngModel]=\"_filter\" (ngModelChange)=\"filter.set($event)\" />\n @if (_filter) {\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"Xo\u00E1 filter\" (click)=\"filter.set('')\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n }\n </div>\n\n <!-- Top-level elements (not inside any sd-table) -->\n <h4 class=\"sd-autoid-inspector__section-title\">\n Top-level elements\n <span class=\"sd-autoid-inspector__badge\">{{ topLevelElements().length }}</span>\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th class=\"is-num\">STT</th>\n <th>Name</th>\n <th>Autoid</th>\n <th>Tag</th>\n <th>State</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of topLevelElements(); track el.autoid + $index) {\n <tr [class.is-error]=\"el.duplicate\">\n <td class=\"is-num\">{{ el.stt }}</td>\n <td>{{ el.name || '\u2014' }}</td>\n <td>\n <div class=\"sd-autoid-inspector__autoid-cell\">\n <code>{{ el.autoid }}</code>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn is-primary\"\n matTooltip=\"Copy xpath\"\n (click)=\"copyXpath(el.autoid)\">\n <sd-icon name=\"content_copy\"></sd-icon>\n </button>\n </div>\n </td>\n <td>\n <span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span>\n </td>\n <td class=\"sd-autoid-inspector__state-cell\">\n @if (el.state.disabled !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.disabled === 'true'\">\n disabled={{ el.state.disabled }}\n </span>\n }\n @if (el.state.loading !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.loading === 'true'\">\n loading={{ el.state.loading }}\n </span>\n }\n @if (el.state.empty !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.empty === 'true'\">\n empty={{ el.state.empty }}\n </span>\n }\n @if (el.state.invalid !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.invalid === 'true'\">\n invalid={{ el.state.invalid }}\n </span>\n }\n @if (el.state.opened !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.opened === 'true'\">\n opened={{ el.state.opened }}\n </span>\n }\n @if (el.state.count !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> count={{ el.state.count }} </span>\n }\n @if (el.state.required !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.required === 'true'\">\n required={{ el.state.required }}\n </span>\n }\n @if (el.state.maxlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> maxlength={{ el.state.maxlength }} </span>\n }\n @if (el.state.minlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> minlength={{ el.state.minlength }} </span>\n }\n @if (el.state.pattern !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> pattern={{ el.state.pattern }} </span>\n }\n @if (el.state.errorMessage !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-error\"> error: {{ el.state.errorMessage }} </span>\n }\n </td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\n {{ el.state.dataValue || el.text || '\u2014' }}\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"6\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <!-- One section per sd-table group -->\n @for (group of tableGroups(); track group.scope) {\n <h4 class=\"sd-autoid-inspector__section-title\">\n <sd-icon class=\"is-info\" name=\"table_chart\"></sd-icon>\n Inside <code>{{ group.scope }}</code>\n <span class=\"sd-autoid-inspector__badge\">{{ group.items.length }}</span>\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr>\n <th class=\"is-num\">STT</th>\n <th>Name</th>\n <th>Autoid</th>\n <th>Tag</th>\n <th>State</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of group.items; track el.autoid + $index) {\n <tr [class.is-error]=\"el.duplicate\">\n <td class=\"is-num\">{{ el.stt }}</td>\n <td>{{ el.name || '\u2014' }}</td>\n <td>\n <div class=\"sd-autoid-inspector__autoid-cell\">\n <code>{{ el.autoid }}</code>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn is-primary\"\n matTooltip=\"Copy xpath\"\n (click)=\"copyXpath(el.autoid)\">\n <sd-icon name=\"content_copy\"></sd-icon>\n </button>\n </div>\n </td>\n <td>\n <span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span>\n </td>\n <td class=\"sd-autoid-inspector__state-cell\">\n @if (el.state.disabled !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.disabled === 'true'\">\n disabled={{ el.state.disabled }}\n </span>\n }\n @if (el.state.loading !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.loading === 'true'\">\n loading={{ el.state.loading }}\n </span>\n }\n @if (el.state.empty !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.empty === 'true'\">\n empty={{ el.state.empty }}\n </span>\n }\n @if (el.state.invalid !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-error]=\"el.state.invalid === 'true'\">\n invalid={{ el.state.invalid }}\n </span>\n }\n @if (el.state.opened !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-info]=\"el.state.opened === 'true'\">\n opened={{ el.state.opened }}\n </span>\n }\n @if (el.state.count !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> count={{ el.state.count }} </span>\n }\n @if (el.state.required !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip\" [class.is-warning]=\"el.state.required === 'true'\">\n required={{ el.state.required }}\n </span>\n }\n @if (el.state.maxlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> maxlength={{ el.state.maxlength }} </span>\n }\n @if (el.state.minlength !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> minlength={{ el.state.minlength }} </span>\n }\n @if (el.state.pattern !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-info\"> pattern={{ el.state.pattern }} </span>\n }\n @if (el.state.errorMessage !== undefined) {\n <span class=\"sd-autoid-inspector__state-chip is-error\"> error: {{ el.state.errorMessage }} </span>\n }\n </td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.state.dataValue || el.text || ''\">\n {{ el.state.dataValue || el.text || '\u2014' }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </ng-template>\n\n <ng-template #exportTpl>\n <div class=\"sd-autoid-inspector__export-grid\">\n <button type=\"button\" matTooltip=\"Copy JSON v\u00E0o clipboard\" (click)=\"copyJson()\">\n <sd-icon name=\"content_copy\"></sd-icon>\n <span>Copy JSON</span>\n <small>clipboard</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i file JSON\" (click)=\"exportJson()\">\n <sd-icon name=\"download\"></sd-icon>\n <span>JSON</span>\n <small>.json</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i file CSV\" (click)=\"exportCsv()\">\n <sd-icon name=\"table_view\"></sd-icon>\n <span>CSV</span>\n <small>.csv</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i MD POM skeleton \u2014 cho AI vi\u1EBFt auto-test\" (click)=\"exportMdPom()\">\n <sd-icon name=\"code\"></sd-icon>\n <span>MD POM</span>\n <small>AI test</small>\n </button>\n <button type=\"button\" matTooltip=\"T\u1EA3i MD reference table \u2014 group theo tag sd-*\" (click)=\"exportMdTable()\">\n <sd-icon name=\"view_list\"></sd-icon>\n <span>MD Table</span>\n <small>reference</small>\n </button>\n </div>\n\n @if (e2eGeneratorHost()) {\n @let _e2eExporting = e2eExporting();\n <div class=\"sd-autoid-inspector__export-section\">\n <h4 class=\"sd-autoid-inspector__section-title\">\n <sd-icon class=\"is-info\" name=\"auto_awesome\"></sd-icon>\n T\u1EA1o E2E test\n </h4>\n <div class=\"sd-autoid-inspector__export-grid is-e2e\">\n <button\n type=\"button\"\n matTooltip=\"T\u1EA1o b\u1ED9 test Playwright (.zip)\"\n [disabled]=\"_e2eExporting !== null\"\n (click)=\"exportE2eTest('playwright')\">\n <sd-icon [name]=\"_e2eExporting === 'playwright' ? 'hourglass_empty' : 'play_arrow'\"></sd-icon>\n <span>Playwright</span>\n <small>.zip</small>\n </button>\n <button\n type=\"button\"\n matTooltip=\"T\u1EA1o b\u1ED9 test Robot Framework (.zip)\"\n [disabled]=\"_e2eExporting !== null\"\n (click)=\"openRobotExportContext()\">\n <sd-icon [name]=\"_e2eExporting === 'robot' ? 'hourglass_empty' : 'smart_toy'\"></sd-icon>\n <span>Robot Framework</span>\n <small>.zip</small>\n </button>\n </div>\n\n @if (robotContextOpen()) {\n <div class=\"sd-autoid-inspector__context-backdrop\" role=\"presentation\" (click)=\"closeRobotExportContext()\"></div>\n <section\n class=\"sd-autoid-inspector__context-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"sd-autoid-robot-context-title\">\n <header class=\"sd-autoid-inspector__context-header\">\n <div>\n <h4 id=\"sd-autoid-robot-context-title\">Ng\u1EEF c\u1EA3nh QC cho Robot Framework</h4>\n <small>Requirement, test case, test data</small>\n </div>\n <button type=\"button\" class=\"sd-autoid-inspector__icon-btn\" matTooltip=\"\u0110\u00F3ng\" (click)=\"closeRobotExportContext()\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n </header>\n\n <div class=\"sd-autoid-inspector__context-form\">\n <label>\n <span>Component</span>\n <input\n type=\"text\"\n placeholder=\"SP-Wallet\"\n [ngModel]=\"robotExportContext().component || ''\"\n (ngModelChange)=\"updateRobotExportContext('component', $event)\" />\n </label>\n <label>\n <span>Story / Trace</span>\n <input\n type=\"text\"\n placeholder=\"US-001, AC-01\"\n [ngModel]=\"robotExportContext().storyLinkages || ''\"\n (ngModelChange)=\"updateRobotExportContext('storyLinkages', $event)\" />\n </label>\n <label class=\"is-full\">\n <span>Requirement / AC / BR</span>\n <textarea\n rows=\"4\"\n placeholder=\"D\u00E1n requirement ho\u1EB7c acceptance criteria...\"\n [ngModel]=\"robotExportContext().requirement || ''\"\n (ngModelChange)=\"updateRobotExportContext('requirement', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Test case QC \u0111\u00E3 \u0111\u1ECBnh ngh\u0129a</span>\n <textarea\n rows=\"4\"\n placeholder=\"TC-001: ...\"\n [ngModel]=\"robotExportContext().testCases || ''\"\n (ngModelChange)=\"updateRobotExportContext('testCases', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Test data</span>\n <textarea\n rows=\"3\"\n placeholder=\"wallet=V\u00ED A, amount=100000...\"\n [ngModel]=\"robotExportContext().testData || ''\"\n (ngModelChange)=\"updateRobotExportContext('testData', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Precondition</span>\n <textarea\n rows=\"2\"\n placeholder=\"User \u0111\u00E3 \u0111\u0103ng nh\u1EADp, d\u1EEF li\u1EC7u v\u00ED \u0111\u00E3 t\u1ED3n t\u1EA1i...\"\n [ngModel]=\"robotExportContext().precondition || ''\"\n (ngModelChange)=\"updateRobotExportContext('precondition', $event)\"></textarea>\n </label>\n <label class=\"is-full\">\n <span>Ghi ch\u00FA format QC</span>\n <textarea\n rows=\"3\"\n placeholder=\"Smoke=Y, Auto=Y, \u01B0u ti\u00EAn happy path...\"\n [ngModel]=\"robotExportContext().qcNotes || ''\"\n (ngModelChange)=\"updateRobotExportContext('qcNotes', $event)\"></textarea>\n </label>\n </div>\n\n <footer class=\"sd-autoid-inspector__context-actions\">\n <button type=\"button\" class=\"is-secondary\" [disabled]=\"_e2eExporting !== null\" (click)=\"closeRobotExportContext()\">\n Hu\u1EF7\n </button>\n <button\n type=\"button\"\n class=\"is-primary\"\n [disabled]=\"_e2eExporting !== null || !hasRobotExportContext()\"\n (click)=\"confirmRobotExport()\">\n <sd-icon [name]=\"_e2eExporting === 'robot' ? 'hourglass_empty' : 'download'\"></sd-icon>\n <span>\u0110\u1ED3ng \u00FD xu\u1EA5t</span>\n </button>\n </footer>\n </section>\n }\n\n @if (e2eExportOk(); as targetLabel) {\n <div class=\"sd-autoid-inspector__export-message is-success\">\u0110\u00E3 t\u1EA3i b\u1ED9 test {{ targetLabel }}.</div>\n }\n @if (e2eExportError(); as error) {\n <div class=\"sd-autoid-inspector__export-message is-error\">\n {{ error }}\n </div>\n }\n </div>\n }\n </ng-template>\n}\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 sd-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 sd-icon{font-size:12px;width:12px;height:12px;line-height:12px}.sd-autoid-inspector__backdrop{position:fixed;inset:0;padding:0;border:none;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 sd-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 sd-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 sd-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 sd-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__section-title sd-icon.is-error{color:var(--sd-error, #f82c13)}.sd-autoid-inspector__section-title sd-icon.is-warning{color:var(--sd-warning, #ff9600)}.sd-autoid-inspector__section-title sd-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 sd-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>sd-icon{font-size:18px;width:18px;height:18px;color:var(--sd-black400, #757575)}.sd-autoid-inspector__export-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(112px,1fr));gap:8px}.sd-autoid-inspector__export-grid.is-e2e{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}.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:disabled{cursor:wait;opacity:.68;transform:none}.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 sd-icon{font-size:22px;width:22px;height:22px;color:var(--sd-primary, #2a66f4)}.sd-autoid-inspector__export-section{margin-top:14px;padding-top:12px;border-top:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-backdrop{position:fixed;inset:0;z-index:10001;background:#141c2652}.sd-autoid-inspector__context-dialog{position:fixed;z-index:10002;top:50%;left:50%;width:min(720px,100vw - 28px);max-height:min(720px,100vh - 28px);transform:translate(-50%,-50%);display:flex;flex-direction:column;border:1px solid var(--sd-black200, #e6e6e6);border-radius:8px;background:#fff;box-shadow:0 18px 48px #0f172a38;overflow:hidden}.sd-autoid-inspector__context-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:14px 16px;border-bottom:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-header h4{margin:0;font-size:15px;font-weight:700;line-height:1.3;color:var(--sd-black500, #212121)}.sd-autoid-inspector__context-header small{display:block;margin-top:2px;font-size:11px;color:var(--sd-black400, #757575);line-height:1.3}.sd-autoid-inspector__context-form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;padding:14px 16px;overflow:auto}.sd-autoid-inspector__context-form label{display:flex;flex-direction:column;gap:6px;min-width:0}.sd-autoid-inspector__context-form label.is-full{grid-column:1/-1}.sd-autoid-inspector__context-form span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__context-form input,.sd-autoid-inspector__context-form textarea{width:100%;min-width:0;border:1px solid var(--sd-black200, #e6e6e6);border-radius:6px;padding:8px 10px;color:var(--sd-black500, #212121);font:inherit;font-size:12px;line-height:1.4;outline:none;resize:vertical}.sd-autoid-inspector__context-form input:focus,.sd-autoid-inspector__context-form textarea:focus{border-color:var(--sd-primary, #2a66f4);box-shadow:0 0 0 2px #2a66f424}.sd-autoid-inspector__context-actions{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--sd-black200, #e6e6e6)}.sd-autoid-inspector__context-actions button{min-height:34px;border-radius:6px;padding:0 12px;border:1px solid var(--sd-black200, #e6e6e6);background:#fff;color:var(--sd-black500, #212121);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:6px;font-size:12px;font-weight:600}.sd-autoid-inspector__context-actions button.is-primary{border-color:var(--sd-primary, #2a66f4);background:var(--sd-primary, #2a66f4);color:#fff}.sd-autoid-inspector__context-actions button:disabled{cursor:not-allowed;opacity:.62}.sd-autoid-inspector__context-actions button sd-icon{font-size:17px;width:17px;height:17px}.sd-autoid-inspector__export-message{margin-top:10px;border-radius:8px;padding:8px 10px;font-size:12px;line-height:1.35}.sd-autoid-inspector__export-message.is-success{background:var(--sd-success-light, #dbefdc);color:var(--sd-success-dark, #39833c);border:1px solid var(--sd-success, #4caf50)}.sd-autoid-inspector__export-message.is-error{background:var(--sd-error-light, #fed5d0);color:var(--sd-error-dark, #ba200e);border:1px solid var(--sd-error, #f82c13)}@media(max-width:560px){.sd-autoid-inspector__context-form{grid-template-columns:1fr}.sd-autoid-inspector__context-actions{flex-direction:column-reverse}.sd-autoid-inspector__context-actions button{width:100%}}\n"] }]
|
|
970
969
|
}], propDecorators: { onEscape: [{
|
|
971
970
|
type: HostListener,
|
|
972
971
|
args: ['document:keydown.escape']
|