@sd-angular/core 19.0.0-beta.97 → 19.0.0-beta.98
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/components/autoid-inspector/index.d.ts +8 -0
- package/components/autoid-inspector/src/autoid-inspector.component.d.ts +37 -0
- package/components/autoid-inspector/src/models/autoid-element.model.d.ts +22 -0
- package/components/autoid-inspector/src/models/autoid-export-format.model.d.ts +6 -0
- package/components/autoid-inspector/src/models/autoid-inspector-config.model.d.ts +8 -0
- package/components/autoid-inspector/src/services/autoid-audit.service.d.ts +19 -0
- package/components/autoid-inspector/src/services/autoid-export.service.d.ts +19 -0
- package/components/autoid-inspector/src/services/autoid-highlight.service.d.ts +12 -0
- package/components/autoid-inspector/src/services/autoid-scanner.service.d.ts +13 -0
- package/components/index.d.ts +1 -0
- package/fesm2022/sd-angular-core-components-autoid-inspector.mjs +585 -0
- package/fesm2022/sd-angular-core-components-autoid-inspector.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components.mjs +1 -0
- package/fesm2022/sd-angular-core-components.mjs.map +1 -1
- package/package.json +48 -44
- package/sd-angular-core-19.0.0-beta.98.tgz +0 -0
- package/sd-angular-core-19.0.0-beta.97.tgz +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './src/autoid-inspector.component';
|
|
2
|
+
export * from './src/models/autoid-element.model';
|
|
3
|
+
export * from './src/models/autoid-inspector-config.model';
|
|
4
|
+
export * from './src/models/autoid-export-format.model';
|
|
5
|
+
export * from './src/services/autoid-scanner.service';
|
|
6
|
+
export * from './src/services/autoid-audit.service';
|
|
7
|
+
export * from './src/services/autoid-highlight.service';
|
|
8
|
+
export * from './src/services/autoid-export.service';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { OnDestroy } from '@angular/core';
|
|
2
|
+
import { SdAutoidElement, SdAutoidAuditResult } from './models/autoid-element.model';
|
|
3
|
+
import { SdAutoidInspectorConfig } from './models/autoid-inspector-config.model';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
type Segment = 'audit' | 'elements' | 'export';
|
|
6
|
+
export declare class SdAutoidInspector implements OnDestroy {
|
|
7
|
+
#private;
|
|
8
|
+
enabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
9
|
+
config: import("@angular/core").InputSignal<SdAutoidInspectorConfig | undefined>;
|
|
10
|
+
open: import("@angular/core").WritableSignal<boolean>;
|
|
11
|
+
segment: import("@angular/core").WritableSignal<Segment>;
|
|
12
|
+
filter: import("@angular/core").WritableSignal<string>;
|
|
13
|
+
elements: import("@angular/core").WritableSignal<SdAutoidElement[]>;
|
|
14
|
+
audit: import("@angular/core").WritableSignal<SdAutoidAuditResult | null>;
|
|
15
|
+
copyOk: import("@angular/core").WritableSignal<boolean>;
|
|
16
|
+
highlightOn: import("@angular/core").WritableSignal<boolean>;
|
|
17
|
+
dismissed: import("@angular/core").WritableSignal<boolean>;
|
|
18
|
+
filteredElements: import("@angular/core").Signal<SdAutoidElement[]>;
|
|
19
|
+
ngOnDestroy(): void;
|
|
20
|
+
togglePanel: () => void;
|
|
21
|
+
openPanel: () => void;
|
|
22
|
+
closePanel: () => void;
|
|
23
|
+
refresh: () => void;
|
|
24
|
+
dismissFab: (event: Event) => void;
|
|
25
|
+
toggleHighlight: () => void;
|
|
26
|
+
setSegment: (seg: Segment) => void;
|
|
27
|
+
copyJson: () => Promise<void>;
|
|
28
|
+
copyXpath: (autoid: string) => Promise<void>;
|
|
29
|
+
exportCsv: () => void;
|
|
30
|
+
exportJson: () => void;
|
|
31
|
+
exportMdPom: () => void;
|
|
32
|
+
exportMdTable: () => void;
|
|
33
|
+
onEscape(): void;
|
|
34
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SdAutoidInspector, never>;
|
|
35
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SdAutoidInspector, "sd-autoid-inspector", never, { "enabled": { "alias": "enabled"; "required": false; "isSignal": true; }; "config": { "alias": "config"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface SdAutoidElement {
|
|
2
|
+
stt: number;
|
|
3
|
+
name: string;
|
|
4
|
+
autoid: string;
|
|
5
|
+
tag: string;
|
|
6
|
+
value: string;
|
|
7
|
+
xpath: string;
|
|
8
|
+
duplicate: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface SdAutoidMissing {
|
|
11
|
+
tag: string;
|
|
12
|
+
selector: string;
|
|
13
|
+
outerHtmlPreview: string;
|
|
14
|
+
nameHint: string;
|
|
15
|
+
}
|
|
16
|
+
export interface SdAutoidAuditResult {
|
|
17
|
+
total: number;
|
|
18
|
+
duplicates: Record<string, number>;
|
|
19
|
+
duplicateCount: number;
|
|
20
|
+
missing: SdAutoidMissing[];
|
|
21
|
+
missingCount: number;
|
|
22
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface SdAutoidInspectorConfig {
|
|
2
|
+
/** Selector phụ thêm cần audit (mặc định component đã cover sd-* form + sd-button). */
|
|
3
|
+
extraRequireSelectors?: string[];
|
|
4
|
+
/** Root scan, mặc định document.body. */
|
|
5
|
+
root?: HTMLElement;
|
|
6
|
+
}
|
|
7
|
+
/** Selector mặc định coi là phải có data-autoid. */
|
|
8
|
+
export declare const SD_AUTOID_DEFAULT_REQUIRE_SELECTORS: ReadonlyArray<string>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SdAutoidElement, SdAutoidAuditResult } from '../models/autoid-element.model';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class SdAutoidAuditService {
|
|
4
|
+
/**
|
|
5
|
+
* Audit kết quả scan + DOM:
|
|
6
|
+
* - duplicates: map autoid → count khi count > 1
|
|
7
|
+
* - missing: element khớp selector yêu cầu nhưng KHÔNG có [data-autoid]
|
|
8
|
+
*/
|
|
9
|
+
audit(elements: SdAutoidElement[], options?: {
|
|
10
|
+
requireSelectors?: ReadonlyArray<string>;
|
|
11
|
+
root?: HTMLElement;
|
|
12
|
+
}): SdAutoidAuditResult;
|
|
13
|
+
private findMissing;
|
|
14
|
+
private buildSelectorPath;
|
|
15
|
+
private shortHtml;
|
|
16
|
+
private resolveNameHint;
|
|
17
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SdAutoidAuditService, never>;
|
|
18
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SdAutoidAuditService>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SdAutoidElement } from '../models/autoid-element.model';
|
|
2
|
+
import { SdAutoidExportMeta } from '../models/autoid-export-format.model';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class SdAutoidExportService {
|
|
5
|
+
toJson(elements: SdAutoidElement[]): string;
|
|
6
|
+
toCsv(elements: SdAutoidElement[]): string;
|
|
7
|
+
/** POM TypeScript skeleton — copy ngay vào file Playwright/Cypress. */
|
|
8
|
+
toMarkdownPom(elements: SdAutoidElement[], meta: SdAutoidExportMeta): string;
|
|
9
|
+
/** Markdown reference table, group theo tag sd-*. */
|
|
10
|
+
toMarkdownTable(elements: SdAutoidElement[], meta: SdAutoidExportMeta): string;
|
|
11
|
+
download(content: string, filename: string, mime: string): void;
|
|
12
|
+
copyToClipboard(content: string): Promise<void>;
|
|
13
|
+
private q;
|
|
14
|
+
private mdCell;
|
|
15
|
+
private toCamel;
|
|
16
|
+
private toPascal;
|
|
17
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SdAutoidExportService, never>;
|
|
18
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SdAutoidExportService>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
export declare class SdAutoidHighlightService {
|
|
3
|
+
#private;
|
|
4
|
+
/** Apply outline cho mọi [data-autoid]: xanh nếu unique, đỏ nếu duplicate. Idempotent. */
|
|
5
|
+
apply(root?: HTMLElement): void;
|
|
6
|
+
/** Highlight tập element không có autoid (missing) bằng outline cam dashed. */
|
|
7
|
+
applyMissing(nodes: HTMLElement[]): void;
|
|
8
|
+
/** Restore inline style như trước khi apply. */
|
|
9
|
+
clear(root?: HTMLElement): void;
|
|
10
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SdAutoidHighlightService, never>;
|
|
11
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SdAutoidHighlightService>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SdAutoidElement } from '../models/autoid-element.model';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class SdAutoidScannerService {
|
|
4
|
+
/** Quét toàn bộ element có [data-autoid] trong root, gắn thông tin name/tag/value/xpath. */
|
|
5
|
+
scan(root?: HTMLElement): SdAutoidElement[];
|
|
6
|
+
/** Group element theo autoid để consumer lấy duplicate map. */
|
|
7
|
+
groupByAutoid(elements: SdAutoidElement[]): Record<string, SdAutoidElement[]>;
|
|
8
|
+
private resolveName;
|
|
9
|
+
private resolveSdTag;
|
|
10
|
+
private resolveValue;
|
|
11
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SdAutoidScannerService, never>;
|
|
12
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SdAutoidScannerService>;
|
|
13
|
+
}
|
package/components/index.d.ts
CHANGED
|
@@ -19,3 +19,4 @@ export * from '@sd-angular/core/components/chart';
|
|
|
19
19
|
export * from '@sd-angular/core/components/editor';
|
|
20
20
|
export * from '@sd-angular/core/components/splitter';
|
|
21
21
|
export * from '@sd-angular/core/components/preview';
|
|
22
|
+
export * from '@sd-angular/core/components/autoid-inspector';
|
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
import * as i1 from '@angular/common';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { Injectable, input, booleanAttribute, signal, computed, inject, HostListener, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
5
|
+
import * as i3 from '@angular/material/icon';
|
|
6
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
7
|
+
import * as i4 from '@angular/material/tooltip';
|
|
8
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
9
|
+
import * as i2 from '@angular/forms';
|
|
10
|
+
import { FormsModule } from '@angular/forms';
|
|
11
|
+
|
|
12
|
+
/** Selector mặc định coi là phải có data-autoid. */
|
|
13
|
+
const SD_AUTOID_DEFAULT_REQUIRE_SELECTORS = [
|
|
14
|
+
'sd-input',
|
|
15
|
+
'sd-input-number',
|
|
16
|
+
'sd-textarea',
|
|
17
|
+
'sd-select',
|
|
18
|
+
'sd-autocomplete',
|
|
19
|
+
'sd-checkbox',
|
|
20
|
+
'sd-radio',
|
|
21
|
+
'sd-switch',
|
|
22
|
+
'sd-date',
|
|
23
|
+
'sd-datetime',
|
|
24
|
+
'sd-date-range',
|
|
25
|
+
'sd-chip',
|
|
26
|
+
'sd-chip-calendar',
|
|
27
|
+
'sd-button',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
class SdAutoidScannerService {
|
|
31
|
+
/** Quét toàn bộ element có [data-autoid] trong root, gắn thông tin name/tag/value/xpath. */
|
|
32
|
+
scan(root = document.body) {
|
|
33
|
+
const nodes = root.querySelectorAll('[data-autoid]');
|
|
34
|
+
const dupCount = {};
|
|
35
|
+
nodes.forEach(n => {
|
|
36
|
+
const id = n.getAttribute('data-autoid');
|
|
37
|
+
if (!id)
|
|
38
|
+
return;
|
|
39
|
+
dupCount[id] = (dupCount[id] ?? 0) + 1;
|
|
40
|
+
});
|
|
41
|
+
const result = [];
|
|
42
|
+
let stt = 1;
|
|
43
|
+
nodes.forEach(node => {
|
|
44
|
+
const autoid = node.getAttribute('data-autoid');
|
|
45
|
+
if (!autoid)
|
|
46
|
+
return;
|
|
47
|
+
result.push({
|
|
48
|
+
stt: stt++,
|
|
49
|
+
name: this.resolveName(node),
|
|
50
|
+
autoid,
|
|
51
|
+
tag: this.resolveSdTag(node),
|
|
52
|
+
value: this.resolveValue(node),
|
|
53
|
+
xpath: `//*[@data-autoid="${autoid}"]`,
|
|
54
|
+
duplicate: dupCount[autoid] > 1,
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
/** Group element theo autoid để consumer lấy duplicate map. */
|
|
60
|
+
groupByAutoid(elements) {
|
|
61
|
+
const map = {};
|
|
62
|
+
for (const el of elements) {
|
|
63
|
+
(map[el.autoid] ??= []).push(el);
|
|
64
|
+
}
|
|
65
|
+
return map;
|
|
66
|
+
}
|
|
67
|
+
resolveName(node) {
|
|
68
|
+
if (node.id) {
|
|
69
|
+
// CSS.escape phòng id chứa ký tự đặc biệt làm vỡ selector.
|
|
70
|
+
const sel = typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(node.id) : node.id;
|
|
71
|
+
const label = document.querySelector(`label[for="${sel}"]`);
|
|
72
|
+
const text = label?.textContent?.trim();
|
|
73
|
+
if (text)
|
|
74
|
+
return text;
|
|
75
|
+
}
|
|
76
|
+
return node.getAttribute('aria-label')?.trim()
|
|
77
|
+
?? node.getAttribute('placeholder')?.trim()
|
|
78
|
+
?? node.getAttribute('title')?.trim()
|
|
79
|
+
?? '';
|
|
80
|
+
}
|
|
81
|
+
resolveSdTag(node) {
|
|
82
|
+
let cur = node;
|
|
83
|
+
while (cur) {
|
|
84
|
+
const tag = cur.tagName.toLowerCase();
|
|
85
|
+
if (tag.startsWith('sd-'))
|
|
86
|
+
return tag;
|
|
87
|
+
cur = cur.parentElement;
|
|
88
|
+
}
|
|
89
|
+
return node.tagName.toLowerCase();
|
|
90
|
+
}
|
|
91
|
+
resolveValue(node) {
|
|
92
|
+
const input = node;
|
|
93
|
+
if (typeof input.value === 'string' && input.value)
|
|
94
|
+
return input.value;
|
|
95
|
+
return (node.textContent ?? '').trim().slice(0, 80);
|
|
96
|
+
}
|
|
97
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidScannerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
98
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidScannerService, providedIn: 'root' });
|
|
99
|
+
}
|
|
100
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidScannerService, decorators: [{
|
|
101
|
+
type: Injectable,
|
|
102
|
+
args: [{ providedIn: 'root' }]
|
|
103
|
+
}] });
|
|
104
|
+
|
|
105
|
+
class SdAutoidAuditService {
|
|
106
|
+
/**
|
|
107
|
+
* Audit kết quả scan + DOM:
|
|
108
|
+
* - duplicates: map autoid → count khi count > 1
|
|
109
|
+
* - missing: element khớp selector yêu cầu nhưng KHÔNG có [data-autoid]
|
|
110
|
+
*/
|
|
111
|
+
audit(elements, options = {}) {
|
|
112
|
+
const requireSelectors = options.requireSelectors ?? SD_AUTOID_DEFAULT_REQUIRE_SELECTORS;
|
|
113
|
+
const root = options.root ?? document.body;
|
|
114
|
+
const duplicates = {};
|
|
115
|
+
for (const el of elements) {
|
|
116
|
+
if (el.duplicate) {
|
|
117
|
+
duplicates[el.autoid] = (duplicates[el.autoid] ?? 0) + 1;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const missing = this.findMissing(root, requireSelectors);
|
|
121
|
+
return {
|
|
122
|
+
total: elements.length,
|
|
123
|
+
duplicates,
|
|
124
|
+
duplicateCount: Object.keys(duplicates).length,
|
|
125
|
+
missing,
|
|
126
|
+
missingCount: missing.length,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
findMissing(root, selectors) {
|
|
130
|
+
if (!selectors.length)
|
|
131
|
+
return [];
|
|
132
|
+
const joined = selectors.join(',');
|
|
133
|
+
const nodes = root.querySelectorAll(joined);
|
|
134
|
+
const missing = [];
|
|
135
|
+
nodes.forEach(node => {
|
|
136
|
+
// Coi là missing khi element + mọi descendant đều không có data-autoid.
|
|
137
|
+
// Lý do: sd-button render thành <button data-autoid="..."> bên trong host
|
|
138
|
+
// <sd-button>. Nếu chỉ check chính host sẽ false-positive cho mọi sd-button.
|
|
139
|
+
if (node.hasAttribute('data-autoid'))
|
|
140
|
+
return;
|
|
141
|
+
if (node.querySelector('[data-autoid]'))
|
|
142
|
+
return;
|
|
143
|
+
missing.push({
|
|
144
|
+
tag: node.tagName.toLowerCase(),
|
|
145
|
+
selector: this.buildSelectorPath(node),
|
|
146
|
+
outerHtmlPreview: this.shortHtml(node),
|
|
147
|
+
nameHint: this.resolveNameHint(node),
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
return missing;
|
|
151
|
+
}
|
|
152
|
+
buildSelectorPath(node) {
|
|
153
|
+
const parts = [];
|
|
154
|
+
let cur = node;
|
|
155
|
+
let depth = 0;
|
|
156
|
+
while (cur && depth < 4) {
|
|
157
|
+
let part = cur.tagName.toLowerCase();
|
|
158
|
+
if (cur.id) {
|
|
159
|
+
part += `#${cur.id}`;
|
|
160
|
+
parts.unshift(part);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
const cls = (cur.getAttribute('class') ?? '').trim().split(/\s+/).filter(Boolean).slice(0, 2);
|
|
164
|
+
if (cls.length)
|
|
165
|
+
part += `.${cls.join('.')}`;
|
|
166
|
+
parts.unshift(part);
|
|
167
|
+
cur = cur.parentElement;
|
|
168
|
+
depth++;
|
|
169
|
+
}
|
|
170
|
+
return parts.join(' > ');
|
|
171
|
+
}
|
|
172
|
+
shortHtml(node) {
|
|
173
|
+
const html = node.outerHTML.replace(/\s+/g, ' ');
|
|
174
|
+
return html.length > 160 ? html.slice(0, 157) + '...' : html;
|
|
175
|
+
}
|
|
176
|
+
resolveNameHint(node) {
|
|
177
|
+
return node.getAttribute('label')
|
|
178
|
+
?? node.getAttribute('placeholder')
|
|
179
|
+
?? node.getAttribute('aria-label')
|
|
180
|
+
?? node.getAttribute('title')
|
|
181
|
+
?? '';
|
|
182
|
+
}
|
|
183
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidAuditService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
184
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidAuditService, providedIn: 'root' });
|
|
185
|
+
}
|
|
186
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidAuditService, decorators: [{
|
|
187
|
+
type: Injectable,
|
|
188
|
+
args: [{ providedIn: 'root' }]
|
|
189
|
+
}] });
|
|
190
|
+
|
|
191
|
+
const ATTR = 'data-sd-autoid-highlight';
|
|
192
|
+
const SAVED_OUTLINE = 'data-sd-autoid-prev-outline';
|
|
193
|
+
const SAVED_OUTLINE_OFFSET = 'data-sd-autoid-prev-outline-offset';
|
|
194
|
+
const SAVED_BG = 'data-sd-autoid-prev-bg';
|
|
195
|
+
const SAVED_BORDER_RADIUS = 'data-sd-autoid-prev-radius';
|
|
196
|
+
// Token màu lấy từ @sd-angular/core theme (--sd-*). Fallback hex áp dụng khi
|
|
197
|
+
// consumer chưa import sd-core.scss. Dùng cùng bộ var với scss component để
|
|
198
|
+
// nhất quán visual giữa highlight ok / duplicate / missing.
|
|
199
|
+
const COLOR_OK = 'var(--sd-success, #4CAF50)';
|
|
200
|
+
const COLOR_OK_BG = 'var(--sd-success-light, rgba(76, 175, 80, 0.12))';
|
|
201
|
+
const COLOR_DUP = 'var(--sd-error, #F82C13)';
|
|
202
|
+
const COLOR_DUP_BG = 'var(--sd-error-light, rgba(248, 44, 19, 0.12))';
|
|
203
|
+
const COLOR_MISSING = 'var(--sd-warning, #FF9600)';
|
|
204
|
+
const COLOR_MISSING_BG = 'var(--sd-warning-light, rgba(255, 150, 0, 0.12))';
|
|
205
|
+
class SdAutoidHighlightService {
|
|
206
|
+
/** Apply outline cho mọi [data-autoid]: xanh nếu unique, đỏ nếu duplicate. Idempotent. */
|
|
207
|
+
apply(root = document.body) {
|
|
208
|
+
this.clear(root);
|
|
209
|
+
const nodes = root.querySelectorAll('[data-autoid]');
|
|
210
|
+
const count = {};
|
|
211
|
+
nodes.forEach(n => {
|
|
212
|
+
const id = n.getAttribute('data-autoid');
|
|
213
|
+
if (!id)
|
|
214
|
+
return;
|
|
215
|
+
count[id] = (count[id] ?? 0) + 1;
|
|
216
|
+
});
|
|
217
|
+
// Để tránh apply 2 lần lên cùng 1 target khi nhiều [data-autoid] cùng
|
|
218
|
+
// chia sẻ 1 sd-* host (vd 2 input lồng trong 1 sd-date-range).
|
|
219
|
+
const visited = new Set();
|
|
220
|
+
nodes.forEach(node => {
|
|
221
|
+
const id = node.getAttribute('data-autoid');
|
|
222
|
+
if (!id)
|
|
223
|
+
return;
|
|
224
|
+
// Highlight HOST sd-* (giống applyMissing) — outline ôm trọn card,
|
|
225
|
+
// không hiển thị lệch trên input con / label fragment. Fallback về
|
|
226
|
+
// chính node khi không tìm thấy sd-* ancestor (vd native button).
|
|
227
|
+
const target = this.#resolveTarget(node);
|
|
228
|
+
if (visited.has(target))
|
|
229
|
+
return;
|
|
230
|
+
visited.add(target);
|
|
231
|
+
const isDup = count[id] > 1;
|
|
232
|
+
this.#paint(target, isDup ? COLOR_DUP : COLOR_OK, isDup ? COLOR_DUP_BG : COLOR_OK_BG, 'solid', isDup ? 'duplicate' : 'ok');
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/** Highlight tập element không có autoid (missing) bằng outline cam dashed. */
|
|
236
|
+
applyMissing(nodes) {
|
|
237
|
+
nodes.forEach(node => {
|
|
238
|
+
if (node.hasAttribute(ATTR))
|
|
239
|
+
return;
|
|
240
|
+
this.#paint(node, COLOR_MISSING, COLOR_MISSING_BG, 'dashed', 'missing');
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/** Restore inline style như trước khi apply. */
|
|
244
|
+
clear(root = document.body) {
|
|
245
|
+
const nodes = root.querySelectorAll(`[${ATTR}]`);
|
|
246
|
+
nodes.forEach(node => {
|
|
247
|
+
node.style.outline = node.getAttribute(SAVED_OUTLINE) ?? '';
|
|
248
|
+
node.style.outlineOffset = node.getAttribute(SAVED_OUTLINE_OFFSET) ?? '';
|
|
249
|
+
node.style.backgroundColor = node.getAttribute(SAVED_BG) ?? '';
|
|
250
|
+
node.style.borderRadius = node.getAttribute(SAVED_BORDER_RADIUS) ?? '';
|
|
251
|
+
node.removeAttribute(SAVED_OUTLINE);
|
|
252
|
+
node.removeAttribute(SAVED_OUTLINE_OFFSET);
|
|
253
|
+
node.removeAttribute(SAVED_BG);
|
|
254
|
+
node.removeAttribute(SAVED_BORDER_RADIUS);
|
|
255
|
+
node.removeAttribute(ATTR);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
// ==========================================
|
|
259
|
+
// HELPERS
|
|
260
|
+
// ==========================================
|
|
261
|
+
#resolveTarget(node) {
|
|
262
|
+
let cur = node;
|
|
263
|
+
while (cur) {
|
|
264
|
+
if (cur.tagName.toLowerCase().startsWith('sd-'))
|
|
265
|
+
return cur;
|
|
266
|
+
cur = cur.parentElement;
|
|
267
|
+
}
|
|
268
|
+
return node;
|
|
269
|
+
}
|
|
270
|
+
#paint(node, color, bg, style, marker) {
|
|
271
|
+
// Backup full style cần restore để clear() đưa về nguyên trạng.
|
|
272
|
+
node.setAttribute(SAVED_OUTLINE, node.style.outline ?? '');
|
|
273
|
+
node.setAttribute(SAVED_OUTLINE_OFFSET, node.style.outlineOffset ?? '');
|
|
274
|
+
node.setAttribute(SAVED_BG, node.style.backgroundColor ?? '');
|
|
275
|
+
node.setAttribute(SAVED_BORDER_RADIUS, node.style.borderRadius ?? '');
|
|
276
|
+
node.style.outline = `2px ${style} ${color}`;
|
|
277
|
+
// outline-offset 2px tránh đè lên border của host (mat-form-field, button)
|
|
278
|
+
// → highlight nằm gọn ngoài card thay vì cắt vào nội dung.
|
|
279
|
+
node.style.outlineOffset = '2px';
|
|
280
|
+
node.style.backgroundColor = bg;
|
|
281
|
+
// Bo nhẹ để outline trông sạch trên host bo góc sẵn.
|
|
282
|
+
if (!node.style.borderRadius) {
|
|
283
|
+
node.style.borderRadius = '6px';
|
|
284
|
+
}
|
|
285
|
+
node.setAttribute(ATTR, marker);
|
|
286
|
+
}
|
|
287
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidHighlightService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
288
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidHighlightService, providedIn: 'root' });
|
|
289
|
+
}
|
|
290
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidHighlightService, decorators: [{
|
|
291
|
+
type: Injectable,
|
|
292
|
+
args: [{ providedIn: 'root' }]
|
|
293
|
+
}] });
|
|
294
|
+
|
|
295
|
+
class SdAutoidExportService {
|
|
296
|
+
toJson(elements) {
|
|
297
|
+
return JSON.stringify(elements, null, 2);
|
|
298
|
+
}
|
|
299
|
+
toCsv(elements) {
|
|
300
|
+
const header = 'STT,name,autoid,tag,value,xpath';
|
|
301
|
+
const rows = elements.map(el => [el.stt, this.q(el.name), this.q(el.autoid), this.q(el.tag), this.q(el.value), this.q(el.xpath)].join(','));
|
|
302
|
+
return [header, ...rows].join('\n') + '\n';
|
|
303
|
+
}
|
|
304
|
+
/** POM TypeScript skeleton — copy ngay vào file Playwright/Cypress. */
|
|
305
|
+
toMarkdownPom(elements, meta) {
|
|
306
|
+
const className = this.toPascal(meta.pageTitle || 'AutoGenerated') + 'Page';
|
|
307
|
+
const lines = [];
|
|
308
|
+
lines.push(`# ${className}`);
|
|
309
|
+
lines.push('');
|
|
310
|
+
lines.push(`- Page: \`${meta.pageUrl}\``);
|
|
311
|
+
lines.push(`- Generated: \`${meta.timestamp}\``);
|
|
312
|
+
lines.push('');
|
|
313
|
+
lines.push('```ts');
|
|
314
|
+
lines.push(`export class ${className} {`);
|
|
315
|
+
for (const el of elements) {
|
|
316
|
+
const propName = this.toCamel(el.autoid);
|
|
317
|
+
const nameHint = el.name ? ` ${el.name} —` : '';
|
|
318
|
+
lines.push(` /** ${el.tag}${nameHint} */`);
|
|
319
|
+
lines.push(` readonly ${propName} = '${el.xpath}';`);
|
|
320
|
+
}
|
|
321
|
+
lines.push('}');
|
|
322
|
+
lines.push('```');
|
|
323
|
+
lines.push('');
|
|
324
|
+
return lines.join('\n');
|
|
325
|
+
}
|
|
326
|
+
/** Markdown reference table, group theo tag sd-*. */
|
|
327
|
+
toMarkdownTable(elements, meta) {
|
|
328
|
+
const lines = [];
|
|
329
|
+
lines.push('# AutoId Reference');
|
|
330
|
+
lines.push('');
|
|
331
|
+
lines.push(`- Page: \`${meta.pageUrl}\``);
|
|
332
|
+
lines.push(`- Generated: \`${meta.timestamp}\``);
|
|
333
|
+
lines.push('');
|
|
334
|
+
const groups = new Map();
|
|
335
|
+
for (const el of elements) {
|
|
336
|
+
const key = el.tag || '(no-tag)';
|
|
337
|
+
if (!groups.has(key))
|
|
338
|
+
groups.set(key, []);
|
|
339
|
+
groups.get(key).push(el);
|
|
340
|
+
}
|
|
341
|
+
const sortedTags = [...groups.keys()].sort();
|
|
342
|
+
for (const tag of sortedTags) {
|
|
343
|
+
lines.push(`## ${tag}`);
|
|
344
|
+
lines.push('');
|
|
345
|
+
lines.push('| name | autoid | xpath | duplicate |');
|
|
346
|
+
lines.push('|------|--------|-------|-----------|');
|
|
347
|
+
for (const el of groups.get(tag)) {
|
|
348
|
+
lines.push(`| ${this.mdCell(el.name)} | \`${el.autoid}\` | \`${el.xpath}\` | ${el.duplicate ? '⚠️' : ''} |`);
|
|
349
|
+
}
|
|
350
|
+
lines.push('');
|
|
351
|
+
}
|
|
352
|
+
return lines.join('\n');
|
|
353
|
+
}
|
|
354
|
+
download(content, filename, mime) {
|
|
355
|
+
const blob = new Blob([content], { type: mime });
|
|
356
|
+
const url = URL.createObjectURL(blob);
|
|
357
|
+
const link = document.createElement('a');
|
|
358
|
+
link.href = url;
|
|
359
|
+
link.download = filename;
|
|
360
|
+
document.body.appendChild(link);
|
|
361
|
+
link.click();
|
|
362
|
+
document.body.removeChild(link);
|
|
363
|
+
URL.revokeObjectURL(url);
|
|
364
|
+
}
|
|
365
|
+
async copyToClipboard(content) {
|
|
366
|
+
if (navigator.clipboard?.writeText) {
|
|
367
|
+
await navigator.clipboard.writeText(content);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
// Fallback cho browser cũ / context không có clipboard API.
|
|
371
|
+
const ta = document.createElement('textarea');
|
|
372
|
+
ta.value = content;
|
|
373
|
+
ta.style.position = 'fixed';
|
|
374
|
+
ta.style.opacity = '0';
|
|
375
|
+
document.body.appendChild(ta);
|
|
376
|
+
ta.select();
|
|
377
|
+
document.execCommand('copy');
|
|
378
|
+
document.body.removeChild(ta);
|
|
379
|
+
}
|
|
380
|
+
q(v) {
|
|
381
|
+
const s = String(v ?? '').replace(/"/g, '""');
|
|
382
|
+
return `"${s}"`;
|
|
383
|
+
}
|
|
384
|
+
mdCell(s) {
|
|
385
|
+
return (s || '').replace(/\|/g, '\\|').replace(/\n/g, ' ');
|
|
386
|
+
}
|
|
387
|
+
toCamel(autoid) {
|
|
388
|
+
const parts = autoid.split(/[-_]/).filter(Boolean);
|
|
389
|
+
return parts.map((p, i) => (i === 0 ? p : p[0].toUpperCase() + p.slice(1))).join('');
|
|
390
|
+
}
|
|
391
|
+
toPascal(title) {
|
|
392
|
+
return title
|
|
393
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
394
|
+
.filter(Boolean)
|
|
395
|
+
.map(p => p[0].toUpperCase() + p.slice(1))
|
|
396
|
+
.join('');
|
|
397
|
+
}
|
|
398
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidExportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
399
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidExportService, providedIn: 'root' });
|
|
400
|
+
}
|
|
401
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidExportService, decorators: [{
|
|
402
|
+
type: Injectable,
|
|
403
|
+
args: [{ providedIn: 'root' }]
|
|
404
|
+
}] });
|
|
405
|
+
|
|
406
|
+
class SdAutoidInspector {
|
|
407
|
+
// ==========================================
|
|
408
|
+
// INPUTS
|
|
409
|
+
// ==========================================
|
|
410
|
+
enabled = input(true, { transform: booleanAttribute });
|
|
411
|
+
config = input(undefined);
|
|
412
|
+
// ==========================================
|
|
413
|
+
// STATE
|
|
414
|
+
// ==========================================
|
|
415
|
+
open = signal(false);
|
|
416
|
+
segment = signal('audit');
|
|
417
|
+
filter = signal('');
|
|
418
|
+
elements = signal([]);
|
|
419
|
+
audit = signal(null);
|
|
420
|
+
copyOk = signal(false);
|
|
421
|
+
// Default true để mở panel lần đầu là có highlight ngay. Đóng panel KHÔNG
|
|
422
|
+
// tự tắt — user toggle qua nút trong tab Audit khi muốn nhìn DOM gốc.
|
|
423
|
+
highlightOn = signal(true);
|
|
424
|
+
// Ẩn tạm FAB — chỉ in-memory, reload trang sẽ hiện lại (theo thiết kế).
|
|
425
|
+
dismissed = signal(false);
|
|
426
|
+
filteredElements = computed(() => {
|
|
427
|
+
const q = this.filter().trim().toLowerCase();
|
|
428
|
+
if (!q)
|
|
429
|
+
return this.elements();
|
|
430
|
+
return this.elements().filter(el => el.autoid.toLowerCase().includes(q) ||
|
|
431
|
+
el.name.toLowerCase().includes(q) ||
|
|
432
|
+
el.tag.toLowerCase().includes(q));
|
|
433
|
+
});
|
|
434
|
+
// ==========================================
|
|
435
|
+
// SERVICES
|
|
436
|
+
// ==========================================
|
|
437
|
+
#scanner = inject(SdAutoidScannerService);
|
|
438
|
+
#auditSvc = inject(SdAutoidAuditService);
|
|
439
|
+
#highlight = inject(SdAutoidHighlightService);
|
|
440
|
+
#export = inject(SdAutoidExportService);
|
|
441
|
+
// ==========================================
|
|
442
|
+
// LIFECYCLE
|
|
443
|
+
// ==========================================
|
|
444
|
+
ngOnDestroy() {
|
|
445
|
+
this.#highlight.clear(this.#root());
|
|
446
|
+
}
|
|
447
|
+
// ==========================================
|
|
448
|
+
// ACTIONS
|
|
449
|
+
// ==========================================
|
|
450
|
+
togglePanel = () => {
|
|
451
|
+
if (this.open()) {
|
|
452
|
+
this.closePanel();
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
this.openPanel();
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
openPanel = () => {
|
|
459
|
+
if (!this.enabled())
|
|
460
|
+
return;
|
|
461
|
+
this.refresh();
|
|
462
|
+
this.open.set(true);
|
|
463
|
+
};
|
|
464
|
+
closePanel = () => {
|
|
465
|
+
this.open.set(false);
|
|
466
|
+
// Highlight được giữ lại để user vẫn thấy outline khi panel ẩn —
|
|
467
|
+
// toggleHighlight trong tab Audit là cách duy nhất để clear.
|
|
468
|
+
};
|
|
469
|
+
refresh = () => {
|
|
470
|
+
const root = this.#root();
|
|
471
|
+
const elements = this.#scanner.scan(root);
|
|
472
|
+
const result = this.#auditSvc.audit(elements, {
|
|
473
|
+
root,
|
|
474
|
+
requireSelectors: this.#requireSelectors(),
|
|
475
|
+
});
|
|
476
|
+
this.elements.set(elements);
|
|
477
|
+
this.audit.set(result);
|
|
478
|
+
this.#applyHighlightIfOn(result);
|
|
479
|
+
};
|
|
480
|
+
dismissFab = (event) => {
|
|
481
|
+
event.stopPropagation();
|
|
482
|
+
this.dismissed.set(true);
|
|
483
|
+
if (this.open())
|
|
484
|
+
this.closePanel();
|
|
485
|
+
};
|
|
486
|
+
toggleHighlight = () => {
|
|
487
|
+
const next = !this.highlightOn();
|
|
488
|
+
this.highlightOn.set(next);
|
|
489
|
+
if (next) {
|
|
490
|
+
this.#applyHighlightIfOn(this.audit());
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
this.#highlight.clear(this.#root());
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
setSegment = (seg) => this.segment.set(seg);
|
|
497
|
+
copyJson = async () => {
|
|
498
|
+
await this.#export.copyToClipboard(this.#export.toJson(this.elements()));
|
|
499
|
+
this.#flashCopyOk();
|
|
500
|
+
};
|
|
501
|
+
copyXpath = async (autoid) => {
|
|
502
|
+
await this.#export.copyToClipboard(`//*[@data-autoid="${autoid}"]`);
|
|
503
|
+
this.#flashCopyOk();
|
|
504
|
+
};
|
|
505
|
+
exportCsv = () => {
|
|
506
|
+
this.#export.download(this.#export.toCsv(this.elements()), this.#filename('csv'), 'text/csv;charset=utf-8');
|
|
507
|
+
};
|
|
508
|
+
exportJson = () => {
|
|
509
|
+
this.#export.download(this.#export.toJson(this.elements()), this.#filename('json'), 'application/json');
|
|
510
|
+
};
|
|
511
|
+
exportMdPom = () => {
|
|
512
|
+
this.#export.download(this.#export.toMarkdownPom(this.elements(), this.#meta()), this.#filename('pom.md'), 'text/markdown');
|
|
513
|
+
};
|
|
514
|
+
exportMdTable = () => {
|
|
515
|
+
this.#export.download(this.#export.toMarkdownTable(this.elements(), this.#meta()), this.#filename('reference.md'), 'text/markdown');
|
|
516
|
+
};
|
|
517
|
+
// ==========================================
|
|
518
|
+
// KEYBOARD: Esc đóng panel
|
|
519
|
+
// ==========================================
|
|
520
|
+
onEscape() {
|
|
521
|
+
if (this.open())
|
|
522
|
+
this.closePanel();
|
|
523
|
+
}
|
|
524
|
+
// ==========================================
|
|
525
|
+
// HELPERS
|
|
526
|
+
// ==========================================
|
|
527
|
+
#root() {
|
|
528
|
+
return this.config()?.root ?? document.body;
|
|
529
|
+
}
|
|
530
|
+
#requireSelectors() {
|
|
531
|
+
const extra = this.config()?.extraRequireSelectors ?? [];
|
|
532
|
+
return [...SD_AUTOID_DEFAULT_REQUIRE_SELECTORS, ...extra];
|
|
533
|
+
}
|
|
534
|
+
#highlightMissing(result) {
|
|
535
|
+
if (!result.missing.length)
|
|
536
|
+
return;
|
|
537
|
+
const root = this.#root();
|
|
538
|
+
const selector = this.#requireSelectors().join(',');
|
|
539
|
+
const all = Array.from(root.querySelectorAll(selector));
|
|
540
|
+
const missingNodes = all.filter(n => !n.hasAttribute('data-autoid') && !n.querySelector('[data-autoid]'));
|
|
541
|
+
this.#highlight.applyMissing(missingNodes);
|
|
542
|
+
}
|
|
543
|
+
#applyHighlightIfOn(result) {
|
|
544
|
+
if (!this.highlightOn())
|
|
545
|
+
return;
|
|
546
|
+
const root = this.#root();
|
|
547
|
+
this.#highlight.apply(root);
|
|
548
|
+
if (result)
|
|
549
|
+
this.#highlightMissing(result);
|
|
550
|
+
}
|
|
551
|
+
#meta() {
|
|
552
|
+
return {
|
|
553
|
+
pageUrl: window.location.pathname + window.location.search,
|
|
554
|
+
pageTitle: document.title || 'Page',
|
|
555
|
+
timestamp: new Date().toISOString(),
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
#filename(ext) {
|
|
559
|
+
const slug = (document.title || 'autoid')
|
|
560
|
+
.toLowerCase()
|
|
561
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
562
|
+
.replace(/^-|-$/g, '');
|
|
563
|
+
return `${slug || 'autoid'}-${Date.now()}.${ext}`;
|
|
564
|
+
}
|
|
565
|
+
#flashCopyOk() {
|
|
566
|
+
this.copyOk.set(true);
|
|
567
|
+
setTimeout(() => this.copyOk.set(false), 1200);
|
|
568
|
+
}
|
|
569
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidInspector, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
570
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SdAutoidInspector, isStandalone: true, selector: "sd-autoid-inspector", inputs: { enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, ngImport: i0, template: "@if (enabled() && !dismissed()) {\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 [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\n@if (enabled() && open()) {\n <div class=\"sd-autoid-inspector__backdrop\" (click)=\"closePanel()\"></div>\n <section class=\"sd-autoid-inspector__panel\" role=\"dialog\" aria-label=\"AutoId Inspector\">\n <header class=\"sd-autoid-inspector__header\">\n <div class=\"sd-autoid-inspector__segments\">\n <button\n type=\"button\"\n [class.is-active]=\"segment() === 'audit'\"\n (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\n type=\"button\"\n [class.is-active]=\"segment() === 'elements'\"\n (click)=\"setSegment('elements')\">\n Elements\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\n </button>\n <button\n type=\"button\"\n [class.is-active]=\"segment() === 'export'\"\n (click)=\"setSegment('export')\">\n Export\n </button>\n </div>\n <div class=\"sd-autoid-inspector__actions\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn\"\n matTooltip=\"Qu\u00E9t l\u1EA1i\"\n (click)=\"refresh()\">\n <mat-icon>refresh</mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__close-btn\"\n matTooltip=\"\u0110\u00F3ng\"\n aria-label=\"\u0110\u00F3ng panel\"\n (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 <div class=\"sd-autoid-inspector__audit-toolbar\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__toggle\"\n [class.is-on]=\"highlightOn()\"\n (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><th>Autoid</th><th>S\u1ED1 l\u1EA7n</th></tr>\n </thead>\n <tbody>\n @for (entry of a.duplicates | keyvalue; track entry.key) {\n <tr class=\"is-error\">\n <td><code>{{ entry.key }}</code></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><th>Tag</th><th>Name hint</th><th>Selector</th></tr>\n </thead>\n <tbody>\n @for (m of a.missing; track $index) {\n <tr class=\"is-warning\">\n <td><code>{{ m.tag }}</code></td>\n <td>{{ m.nameHint }}</td>\n <td><code>{{ m.selector }}</code></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 <div class=\"sd-autoid-inspector__filter\">\n <mat-icon>search</mat-icon>\n <input\n type=\"text\"\n placeholder=\"L\u1ECDc theo autoid / name / tag\"\n [ngModel]=\"filter()\"\n (ngModelChange)=\"filter.set($event)\"/>\n @if (filter()) {\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn\"\n matTooltip=\"Xo\u00E1 filter\"\n (click)=\"filter.set('')\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\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>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of filteredElements(); 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><span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span></td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.value || ''\">\n {{ el.value || '\u2014' }}\n </td>\n </tr>\n } @empty {\n <tr><td colspan=\"5\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td></tr>\n }\n </tbody>\n </table>\n </div>\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 </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;background:#00000052;z-index:100001;backdrop-filter:blur(2px)}.sd-autoid-inspector__panel{position:fixed;right:20px;bottom:80px;width:min(860px,100vw - 40px);max-height:calc(100vh - 110px);background:#fff;border-radius:12px;box-shadow:0 16px 48px #00000038;display:flex;flex-direction:column;z-index:100002;overflow:hidden;border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__header{display:flex;align-items:center;gap:8px;padding:8px 10px;border-bottom:1px solid var(--sd-black200, #E6E6E6);background:var(--sd-black100, #F2F2F2);flex-shrink:0}.sd-autoid-inspector__segments{display:inline-flex;border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;background:#fff;overflow:hidden}.sd-autoid-inspector__segments button{border:none;background:transparent;padding:5px 12px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;gap:6px;border-right:1px solid var(--sd-black200, #E6E6E6);transition:background .12s ease,color .12s ease}.sd-autoid-inspector__segments button:last-child{border-right:none}.sd-autoid-inspector__segments button:hover:not(.is-active){background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__segments button.is-active{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__badge{background:var(--sd-black200, #E6E6E6);color:var(--sd-black500, #212121);border-radius:10px;padding:0 7px;font-size:11px;font-weight:600;line-height:16px}.is-active .sd-autoid-inspector__badge{background:#ffffff40;color:#fff}.sd-autoid-inspector__badge.is-warn{background:var(--sd-error, #F82C13);color:#fff}.sd-autoid-inspector__actions{display:inline-flex;gap:4px;margin-left:auto}.sd-autoid-inspector__icon-btn{border:none;background:transparent;cursor:pointer;padding:4px;border-radius:6px;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__icon-btn:hover{background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__icon-btn.is-primary{color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__icon-btn.is-primary:hover{background:var(--sd-primary-light, #EAF1FF);color:var(--sd-primary-dark, #1C4AD9)}.sd-autoid-inspector__icon-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__close-btn{border:none;cursor:pointer;padding:4px;border-radius:50%;width:28px;height:28px;background:transparent;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__close-btn:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__close-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__body{padding:14px;overflow:auto;flex:1;background:#fff}.sd-autoid-inspector__toast{position:absolute;top:56px;right:14px;background:var(--sd-success, #4CAF50);color:#fff;padding:6px 12px;border-radius:6px;font-size:12px;z-index:2;box-shadow:0 4px 12px #0000002e}.sd-autoid-inspector__audit-toolbar{display:flex;justify-content:flex-end;margin-bottom:12px}.sd-autoid-inspector__toggle{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:999px;padding:5px 12px 5px 10px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);transition:all .15s ease}.sd-autoid-inspector__toggle:hover{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__toggle.is-on{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__toggle mat-icon{font-size:16px;width:16px;height:16px}.sd-autoid-inspector__toggle-state{font-size:10px;font-weight:700;padding:1px 7px;border-radius:999px;background:var(--sd-black200, #E6E6E6);color:var(--sd-black400, #757575)}.is-on .sd-autoid-inspector__toggle-state{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__summary{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px}.sd-autoid-inspector__stat{background:var(--sd-black100, #F2F2F2);border-radius:10px;padding:12px;text-align:center;border:1px solid transparent}.sd-autoid-inspector__stat.is-info{background:var(--sd-info-light, #E7E9FF);border-color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-info .sd-autoid-inspector__stat-value{color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-success{background:var(--sd-success-light, #DBEFDC);border-color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__stat.is-success .sd-autoid-inspector__stat-value{color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__stat.is-warning{background:var(--sd-warning-light, #FFEACC);border-color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__stat.is-warning .sd-autoid-inspector__stat-value{color:var(--sd-warning-dark, #BF7000)}.sd-autoid-inspector__stat.is-error{background:var(--sd-error-light, #FED5D0);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__stat.is-error .sd-autoid-inspector__stat-value{color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__stat-value{font-size:22px;font-weight:700;line-height:1;margin-bottom:4px}.sd-autoid-inspector__stat-label{font-size:11px;color:var(--sd-black400, #757575);text-transform:uppercase;letter-spacing:.4px;font-weight:600}.sd-autoid-inspector__section-title{display:flex;align-items:center;gap:6px;margin:14px 0 8px;font-size:13px;font-weight:600;color:var(--sd-black500, #212121)}.sd-autoid-inspector__section-title mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__section-title mat-icon.is-error{color:var(--sd-error, #F82C13)}.sd-autoid-inspector__section-title mat-icon.is-warning{color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__success-card{display:flex;align-items:center;gap:12px;padding:14px 16px;background:var(--sd-success-light, #DBEFDC);border:1px solid var(--sd-success, #4CAF50);border-radius:10px;color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__success-card mat-icon{font-size:28px;width:28px;height:28px;color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__success-card strong{display:block;font-size:13px;margin-bottom:2px}.sd-autoid-inspector__success-card small{font-size:11px;opacity:.85}.sd-autoid-inspector__table-wrap{border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;overflow:auto;max-height:60vh;background:#fff}.sd-autoid-inspector__table{width:100%;border-collapse:separate;border-spacing:0;font-size:12px}.sd-autoid-inspector__table th,.sd-autoid-inspector__table td{padding:8px 10px;text-align:left;vertical-align:middle;border-bottom:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__table thead th{position:sticky;top:0;z-index:1;background:var(--sd-black100, #F2F2F2);font-weight:600;color:var(--sd-black500, #212121);text-transform:none;font-size:11px;letter-spacing:.3px;border-bottom:none;box-shadow:inset 0 -1px 0 var(--sd-black200, #E6E6E6),0 2px 4px #0000000a;white-space:nowrap}.sd-autoid-inspector__table thead th.is-num{text-align:right;width:50px}.sd-autoid-inspector__table tbody tr{transition:background .1s ease}.sd-autoid-inspector__table tbody tr:hover{background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__table tbody tr:last-child td{border-bottom:none}.sd-autoid-inspector__table tbody tr.is-error{background:var(--sd-error-light, #FED5D0)}.sd-autoid-inspector__table tbody tr.is-error:hover{background:var(--sd-error-light, #FED5D0);filter:brightness(.98)}.sd-autoid-inspector__table tbody tr.is-warning{background:var(--sd-warning-light, #FFEACC)}.sd-autoid-inspector__table tbody tr.is-warning:hover{background:var(--sd-warning-light, #FFEACC);filter:brightness(.98)}.sd-autoid-inspector__table td.is-num{text-align:right;color:var(--sd-black400, #757575);font-variant-numeric:tabular-nums}.sd-autoid-inspector__table code{font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-black100, #F2F2F2);padding:2px 6px;border-radius:4px;color:var(--sd-primary-dark, #1C4AD9);border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__autoid-cell{display:inline-flex;align-items:center;gap:6px}.sd-autoid-inspector__tag-chip{display:inline-block;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-info-light, #E7E9FF);color:var(--sd-info, #2962FF);border:1px solid var(--sd-info, #2962FF);padding:1px 8px;border-radius:999px;font-weight:500}.sd-autoid-inspector__value{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sd-black400, #757575);font-style:italic}.sd-autoid-inspector__empty{text-align:center;color:var(--sd-black400, #757575);padding:24px;font-style:italic}.sd-autoid-inspector__filter{display:flex;align-items:center;gap:6px;background:var(--sd-black100, #F2F2F2);border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;padding:6px 10px;margin-bottom:12px;transition:border-color .15s ease}.sd-autoid-inspector__filter:focus-within{border-color:var(--sd-primary, #2A66F4);background:#fff}.sd-autoid-inspector__filter input{flex:1;border:none;background:transparent;outline:none;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__filter input::placeholder{color:var(--sd-black300, #BFBFBF)}.sd-autoid-inspector__filter>mat-icon{font-size:18px;width:18px;height:18px;color:var(--sd-black400, #757575)}.sd-autoid-inspector__export-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:8px}.sd-autoid-inspector__export-grid button{border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:10px;padding:12px 10px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;min-width:0;transition:border-color .15s ease,background .15s ease,transform .12s ease;text-align:center}.sd-autoid-inspector__export-grid button:hover{border-color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF);transform:translateY(-1px)}.sd-autoid-inspector__export-grid button span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__export-grid button small{font-size:10px;color:var(--sd-black400, #757575);line-height:1.2}.sd-autoid-inspector__export-grid button mat-icon{font-size:22px;width:22px;height:22px;color:var(--sd-primary, #2A66F4)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
571
|
+
}
|
|
572
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdAutoidInspector, decorators: [{
|
|
573
|
+
type: Component,
|
|
574
|
+
args: [{ selector: 'sd-autoid-inspector', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, MatIconModule, MatTooltipModule], template: "@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 [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\n@if (enabled() && open()) {\n <div class=\"sd-autoid-inspector__backdrop\" (click)=\"closePanel()\"></div>\n <section class=\"sd-autoid-inspector__panel\" role=\"dialog\" aria-label=\"AutoId Inspector\">\n <header class=\"sd-autoid-inspector__header\">\n <div class=\"sd-autoid-inspector__segments\">\n <button\n type=\"button\"\n [class.is-active]=\"segment() === 'audit'\"\n (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\n type=\"button\"\n [class.is-active]=\"segment() === 'elements'\"\n (click)=\"setSegment('elements')\">\n Elements\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\n </button>\n <button\n type=\"button\"\n [class.is-active]=\"segment() === 'export'\"\n (click)=\"setSegment('export')\">\n Export\n </button>\n </div>\n <div class=\"sd-autoid-inspector__actions\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn\"\n matTooltip=\"Qu\u00E9t l\u1EA1i\"\n (click)=\"refresh()\">\n <mat-icon>refresh</mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__close-btn\"\n matTooltip=\"\u0110\u00F3ng\"\n aria-label=\"\u0110\u00F3ng panel\"\n (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 <div class=\"sd-autoid-inspector__audit-toolbar\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__toggle\"\n [class.is-on]=\"highlightOn()\"\n (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><th>Autoid</th><th>S\u1ED1 l\u1EA7n</th></tr>\n </thead>\n <tbody>\n @for (entry of a.duplicates | keyvalue; track entry.key) {\n <tr class=\"is-error\">\n <td><code>{{ entry.key }}</code></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><th>Tag</th><th>Name hint</th><th>Selector</th></tr>\n </thead>\n <tbody>\n @for (m of a.missing; track $index) {\n <tr class=\"is-warning\">\n <td><code>{{ m.tag }}</code></td>\n <td>{{ m.nameHint }}</td>\n <td><code>{{ m.selector }}</code></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 <div class=\"sd-autoid-inspector__filter\">\n <mat-icon>search</mat-icon>\n <input\n type=\"text\"\n placeholder=\"L\u1ECDc theo autoid / name / tag\"\n [ngModel]=\"filter()\"\n (ngModelChange)=\"filter.set($event)\"/>\n @if (filter()) {\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn\"\n matTooltip=\"Xo\u00E1 filter\"\n (click)=\"filter.set('')\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\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>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of filteredElements(); 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><span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span></td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.value || ''\">\n {{ el.value || '\u2014' }}\n </td>\n </tr>\n } @empty {\n <tr><td colspan=\"5\" class=\"sd-autoid-inspector__empty\">Kh\u00F4ng c\u00F3 k\u1EBFt qu\u1EA3.</td></tr>\n }\n </tbody>\n </table>\n </div>\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 </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;background:#00000052;z-index:100001;backdrop-filter:blur(2px)}.sd-autoid-inspector__panel{position:fixed;right:20px;bottom:80px;width:min(860px,100vw - 40px);max-height:calc(100vh - 110px);background:#fff;border-radius:12px;box-shadow:0 16px 48px #00000038;display:flex;flex-direction:column;z-index:100002;overflow:hidden;border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__header{display:flex;align-items:center;gap:8px;padding:8px 10px;border-bottom:1px solid var(--sd-black200, #E6E6E6);background:var(--sd-black100, #F2F2F2);flex-shrink:0}.sd-autoid-inspector__segments{display:inline-flex;border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;background:#fff;overflow:hidden}.sd-autoid-inspector__segments button{border:none;background:transparent;padding:5px 12px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;gap:6px;border-right:1px solid var(--sd-black200, #E6E6E6);transition:background .12s ease,color .12s ease}.sd-autoid-inspector__segments button:last-child{border-right:none}.sd-autoid-inspector__segments button:hover:not(.is-active){background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__segments button.is-active{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__badge{background:var(--sd-black200, #E6E6E6);color:var(--sd-black500, #212121);border-radius:10px;padding:0 7px;font-size:11px;font-weight:600;line-height:16px}.is-active .sd-autoid-inspector__badge{background:#ffffff40;color:#fff}.sd-autoid-inspector__badge.is-warn{background:var(--sd-error, #F82C13);color:#fff}.sd-autoid-inspector__actions{display:inline-flex;gap:4px;margin-left:auto}.sd-autoid-inspector__icon-btn{border:none;background:transparent;cursor:pointer;padding:4px;border-radius:6px;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__icon-btn:hover{background:var(--sd-black100, #F2F2F2);color:var(--sd-black500, #212121)}.sd-autoid-inspector__icon-btn.is-primary{color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__icon-btn.is-primary:hover{background:var(--sd-primary-light, #EAF1FF);color:var(--sd-primary-dark, #1C4AD9)}.sd-autoid-inspector__icon-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__close-btn{border:none;cursor:pointer;padding:4px;border-radius:50%;width:28px;height:28px;background:transparent;color:var(--sd-black400, #757575);display:inline-flex;align-items:center;justify-content:center;transition:background .12s ease,color .12s ease}.sd-autoid-inspector__close-btn:hover{background:var(--sd-error-light, #FED5D0);color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__close-btn mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__body{padding:14px;overflow:auto;flex:1;background:#fff}.sd-autoid-inspector__toast{position:absolute;top:56px;right:14px;background:var(--sd-success, #4CAF50);color:#fff;padding:6px 12px;border-radius:6px;font-size:12px;z-index:2;box-shadow:0 4px 12px #0000002e}.sd-autoid-inspector__audit-toolbar{display:flex;justify-content:flex-end;margin-bottom:12px}.sd-autoid-inspector__toggle{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:999px;padding:5px 12px 5px 10px;cursor:pointer;font-size:12px;font-weight:500;color:var(--sd-black400, #757575);transition:all .15s ease}.sd-autoid-inspector__toggle:hover{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4)}.sd-autoid-inspector__toggle.is-on{border-color:var(--sd-primary, #2A66F4);color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__toggle mat-icon{font-size:16px;width:16px;height:16px}.sd-autoid-inspector__toggle-state{font-size:10px;font-weight:700;padding:1px 7px;border-radius:999px;background:var(--sd-black200, #E6E6E6);color:var(--sd-black400, #757575)}.is-on .sd-autoid-inspector__toggle-state{background:var(--sd-primary, #2A66F4);color:#fff}.sd-autoid-inspector__summary{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px}.sd-autoid-inspector__stat{background:var(--sd-black100, #F2F2F2);border-radius:10px;padding:12px;text-align:center;border:1px solid transparent}.sd-autoid-inspector__stat.is-info{background:var(--sd-info-light, #E7E9FF);border-color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-info .sd-autoid-inspector__stat-value{color:var(--sd-info, #2962FF)}.sd-autoid-inspector__stat.is-success{background:var(--sd-success-light, #DBEFDC);border-color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__stat.is-success .sd-autoid-inspector__stat-value{color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__stat.is-warning{background:var(--sd-warning-light, #FFEACC);border-color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__stat.is-warning .sd-autoid-inspector__stat-value{color:var(--sd-warning-dark, #BF7000)}.sd-autoid-inspector__stat.is-error{background:var(--sd-error-light, #FED5D0);border-color:var(--sd-error, #F82C13)}.sd-autoid-inspector__stat.is-error .sd-autoid-inspector__stat-value{color:var(--sd-error-dark, #BA200E)}.sd-autoid-inspector__stat-value{font-size:22px;font-weight:700;line-height:1;margin-bottom:4px}.sd-autoid-inspector__stat-label{font-size:11px;color:var(--sd-black400, #757575);text-transform:uppercase;letter-spacing:.4px;font-weight:600}.sd-autoid-inspector__section-title{display:flex;align-items:center;gap:6px;margin:14px 0 8px;font-size:13px;font-weight:600;color:var(--sd-black500, #212121)}.sd-autoid-inspector__section-title mat-icon{font-size:18px;width:18px;height:18px}.sd-autoid-inspector__section-title mat-icon.is-error{color:var(--sd-error, #F82C13)}.sd-autoid-inspector__section-title mat-icon.is-warning{color:var(--sd-warning, #FF9600)}.sd-autoid-inspector__success-card{display:flex;align-items:center;gap:12px;padding:14px 16px;background:var(--sd-success-light, #DBEFDC);border:1px solid var(--sd-success, #4CAF50);border-radius:10px;color:var(--sd-success-dark, #39833C)}.sd-autoid-inspector__success-card mat-icon{font-size:28px;width:28px;height:28px;color:var(--sd-success, #4CAF50)}.sd-autoid-inspector__success-card strong{display:block;font-size:13px;margin-bottom:2px}.sd-autoid-inspector__success-card small{font-size:11px;opacity:.85}.sd-autoid-inspector__table-wrap{border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;overflow:auto;max-height:60vh;background:#fff}.sd-autoid-inspector__table{width:100%;border-collapse:separate;border-spacing:0;font-size:12px}.sd-autoid-inspector__table th,.sd-autoid-inspector__table td{padding:8px 10px;text-align:left;vertical-align:middle;border-bottom:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__table thead th{position:sticky;top:0;z-index:1;background:var(--sd-black100, #F2F2F2);font-weight:600;color:var(--sd-black500, #212121);text-transform:none;font-size:11px;letter-spacing:.3px;border-bottom:none;box-shadow:inset 0 -1px 0 var(--sd-black200, #E6E6E6),0 2px 4px #0000000a;white-space:nowrap}.sd-autoid-inspector__table thead th.is-num{text-align:right;width:50px}.sd-autoid-inspector__table tbody tr{transition:background .1s ease}.sd-autoid-inspector__table tbody tr:hover{background:var(--sd-primary-light, #EAF1FF)}.sd-autoid-inspector__table tbody tr:last-child td{border-bottom:none}.sd-autoid-inspector__table tbody tr.is-error{background:var(--sd-error-light, #FED5D0)}.sd-autoid-inspector__table tbody tr.is-error:hover{background:var(--sd-error-light, #FED5D0);filter:brightness(.98)}.sd-autoid-inspector__table tbody tr.is-warning{background:var(--sd-warning-light, #FFEACC)}.sd-autoid-inspector__table tbody tr.is-warning:hover{background:var(--sd-warning-light, #FFEACC);filter:brightness(.98)}.sd-autoid-inspector__table td.is-num{text-align:right;color:var(--sd-black400, #757575);font-variant-numeric:tabular-nums}.sd-autoid-inspector__table code{font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-black100, #F2F2F2);padding:2px 6px;border-radius:4px;color:var(--sd-primary-dark, #1C4AD9);border:1px solid var(--sd-black200, #E6E6E6)}.sd-autoid-inspector__autoid-cell{display:inline-flex;align-items:center;gap:6px}.sd-autoid-inspector__tag-chip{display:inline-block;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;background:var(--sd-info-light, #E7E9FF);color:var(--sd-info, #2962FF);border:1px solid var(--sd-info, #2962FF);padding:1px 8px;border-radius:999px;font-weight:500}.sd-autoid-inspector__value{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sd-black400, #757575);font-style:italic}.sd-autoid-inspector__empty{text-align:center;color:var(--sd-black400, #757575);padding:24px;font-style:italic}.sd-autoid-inspector__filter{display:flex;align-items:center;gap:6px;background:var(--sd-black100, #F2F2F2);border:1px solid var(--sd-black200, #E6E6E6);border-radius:8px;padding:6px 10px;margin-bottom:12px;transition:border-color .15s ease}.sd-autoid-inspector__filter:focus-within{border-color:var(--sd-primary, #2A66F4);background:#fff}.sd-autoid-inspector__filter input{flex:1;border:none;background:transparent;outline:none;font-size:13px;color:var(--sd-black500, #212121)}.sd-autoid-inspector__filter input::placeholder{color:var(--sd-black300, #BFBFBF)}.sd-autoid-inspector__filter>mat-icon{font-size:18px;width:18px;height:18px;color:var(--sd-black400, #757575)}.sd-autoid-inspector__export-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:8px}.sd-autoid-inspector__export-grid button{border:1px solid var(--sd-black200, #E6E6E6);background:#fff;border-radius:10px;padding:12px 10px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;min-width:0;transition:border-color .15s ease,background .15s ease,transform .12s ease;text-align:center}.sd-autoid-inspector__export-grid button:hover{border-color:var(--sd-primary, #2A66F4);background:var(--sd-primary-light, #EAF1FF);transform:translateY(-1px)}.sd-autoid-inspector__export-grid button span{font-size:12px;font-weight:600;color:var(--sd-black500, #212121);line-height:1.25}.sd-autoid-inspector__export-grid button small{font-size:10px;color:var(--sd-black400, #757575);line-height:1.2}.sd-autoid-inspector__export-grid button mat-icon{font-size:22px;width:22px;height:22px;color:var(--sd-primary, #2A66F4)}\n"] }]
|
|
575
|
+
}], propDecorators: { onEscape: [{
|
|
576
|
+
type: HostListener,
|
|
577
|
+
args: ['document:keydown.escape']
|
|
578
|
+
}] } });
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Generated bundle index. Do not edit.
|
|
582
|
+
*/
|
|
583
|
+
|
|
584
|
+
export { SD_AUTOID_DEFAULT_REQUIRE_SELECTORS, SdAutoidAuditService, SdAutoidExportService, SdAutoidHighlightService, SdAutoidInspector, SdAutoidScannerService };
|
|
585
|
+
//# sourceMappingURL=sd-angular-core-components-autoid-inspector.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sd-angular-core-components-autoid-inspector.mjs","sources":["../../../projects/sd-angular/components/autoid-inspector/src/models/autoid-inspector-config.model.ts","../../../projects/sd-angular/components/autoid-inspector/src/services/autoid-scanner.service.ts","../../../projects/sd-angular/components/autoid-inspector/src/services/autoid-audit.service.ts","../../../projects/sd-angular/components/autoid-inspector/src/services/autoid-highlight.service.ts","../../../projects/sd-angular/components/autoid-inspector/src/services/autoid-export.service.ts","../../../projects/sd-angular/components/autoid-inspector/src/autoid-inspector.component.ts","../../../projects/sd-angular/components/autoid-inspector/src/autoid-inspector.component.html","../../../projects/sd-angular/components/autoid-inspector/sd-angular-core-components-autoid-inspector.ts"],"sourcesContent":["export interface SdAutoidInspectorConfig {\n /** Selector phụ thêm cần audit (mặc định component đã cover sd-* form + sd-button). */\n extraRequireSelectors?: string[];\n /** Root scan, mặc định document.body. */\n root?: HTMLElement;\n}\n\n/** Selector mặc định coi là phải có data-autoid. */\nexport const SD_AUTOID_DEFAULT_REQUIRE_SELECTORS: ReadonlyArray<string> = [\n 'sd-input',\n 'sd-input-number',\n 'sd-textarea',\n 'sd-select',\n 'sd-autocomplete',\n 'sd-checkbox',\n 'sd-radio',\n 'sd-switch',\n 'sd-date',\n 'sd-datetime',\n 'sd-date-range',\n 'sd-chip',\n 'sd-chip-calendar',\n 'sd-button',\n];\n","import { Injectable } from '@angular/core';\nimport { SdAutoidElement } from '../models/autoid-element.model';\n\n@Injectable({ providedIn: 'root' })\nexport class SdAutoidScannerService {\n /** Quét toàn bộ element có [data-autoid] trong root, gắn thông tin name/tag/value/xpath. */\n scan(root: HTMLElement = document.body): SdAutoidElement[] {\n const nodes = root.querySelectorAll<HTMLElement>('[data-autoid]');\n const dupCount: Record<string, number> = {};\n nodes.forEach(n => {\n const id = n.getAttribute('data-autoid');\n if (!id) return;\n dupCount[id] = (dupCount[id] ?? 0) + 1;\n });\n\n const result: SdAutoidElement[] = [];\n let stt = 1;\n nodes.forEach(node => {\n const autoid = node.getAttribute('data-autoid');\n if (!autoid) return;\n result.push({\n stt: stt++,\n name: this.resolveName(node),\n autoid,\n tag: this.resolveSdTag(node),\n value: this.resolveValue(node),\n xpath: `//*[@data-autoid=\"${autoid}\"]`,\n duplicate: dupCount[autoid] > 1,\n });\n });\n return result;\n }\n\n /** Group element theo autoid để consumer lấy duplicate map. */\n groupByAutoid(elements: SdAutoidElement[]): Record<string, SdAutoidElement[]> {\n const map: Record<string, SdAutoidElement[]> = {};\n for (const el of elements) {\n (map[el.autoid] ??= []).push(el);\n }\n return map;\n }\n\n private resolveName(node: HTMLElement): string {\n if (node.id) {\n // CSS.escape phòng id chứa ký tự đặc biệt làm vỡ selector.\n const sel = typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(node.id) : node.id;\n const label = document.querySelector(`label[for=\"${sel}\"]`);\n const text = label?.textContent?.trim();\n if (text) return text;\n }\n return node.getAttribute('aria-label')?.trim()\n ?? node.getAttribute('placeholder')?.trim()\n ?? node.getAttribute('title')?.trim()\n ?? '';\n }\n\n private resolveSdTag(node: HTMLElement): string {\n let cur: HTMLElement | null = node;\n while (cur) {\n const tag = cur.tagName.toLowerCase();\n if (tag.startsWith('sd-')) return tag;\n cur = cur.parentElement;\n }\n return node.tagName.toLowerCase();\n }\n\n private resolveValue(node: HTMLElement): string {\n const input = node as HTMLInputElement;\n if (typeof input.value === 'string' && input.value) return input.value;\n return (node.textContent ?? '').trim().slice(0, 80);\n }\n}\n","import { Injectable } from '@angular/core';\nimport { SdAutoidElement, SdAutoidAuditResult, SdAutoidMissing } from '../models/autoid-element.model';\nimport { SD_AUTOID_DEFAULT_REQUIRE_SELECTORS } from '../models/autoid-inspector-config.model';\n\n@Injectable({ providedIn: 'root' })\nexport class SdAutoidAuditService {\n /**\n * Audit kết quả scan + DOM:\n * - duplicates: map autoid → count khi count > 1\n * - missing: element khớp selector yêu cầu nhưng KHÔNG có [data-autoid]\n */\n audit(\n elements: SdAutoidElement[],\n options: { requireSelectors?: ReadonlyArray<string>; root?: HTMLElement } = {}\n ): SdAutoidAuditResult {\n const requireSelectors = options.requireSelectors ?? SD_AUTOID_DEFAULT_REQUIRE_SELECTORS;\n const root = options.root ?? document.body;\n\n const duplicates: Record<string, number> = {};\n for (const el of elements) {\n if (el.duplicate) {\n duplicates[el.autoid] = (duplicates[el.autoid] ?? 0) + 1;\n }\n }\n\n const missing = this.findMissing(root, requireSelectors);\n\n return {\n total: elements.length,\n duplicates,\n duplicateCount: Object.keys(duplicates).length,\n missing,\n missingCount: missing.length,\n };\n }\n\n private findMissing(root: HTMLElement, selectors: ReadonlyArray<string>): SdAutoidMissing[] {\n if (!selectors.length) return [];\n const joined = selectors.join(',');\n const nodes = root.querySelectorAll<HTMLElement>(joined);\n const missing: SdAutoidMissing[] = [];\n\n nodes.forEach(node => {\n // Coi là missing khi element + mọi descendant đều không có data-autoid.\n // Lý do: sd-button render thành <button data-autoid=\"...\"> bên trong host\n // <sd-button>. Nếu chỉ check chính host sẽ false-positive cho mọi sd-button.\n if (node.hasAttribute('data-autoid')) return;\n if (node.querySelector('[data-autoid]')) return;\n\n missing.push({\n tag: node.tagName.toLowerCase(),\n selector: this.buildSelectorPath(node),\n outerHtmlPreview: this.shortHtml(node),\n nameHint: this.resolveNameHint(node),\n });\n });\n\n return missing;\n }\n\n private buildSelectorPath(node: HTMLElement): string {\n const parts: string[] = [];\n let cur: HTMLElement | null = node;\n let depth = 0;\n while (cur && depth < 4) {\n let part = cur.tagName.toLowerCase();\n if (cur.id) {\n part += `#${cur.id}`;\n parts.unshift(part);\n break;\n }\n const cls = (cur.getAttribute('class') ?? '').trim().split(/\\s+/).filter(Boolean).slice(0, 2);\n if (cls.length) part += `.${cls.join('.')}`;\n parts.unshift(part);\n cur = cur.parentElement;\n depth++;\n }\n return parts.join(' > ');\n }\n\n private shortHtml(node: HTMLElement): string {\n const html = node.outerHTML.replace(/\\s+/g, ' ');\n return html.length > 160 ? html.slice(0, 157) + '...' : html;\n }\n\n private resolveNameHint(node: HTMLElement): string {\n return node.getAttribute('label')\n ?? node.getAttribute('placeholder')\n ?? node.getAttribute('aria-label')\n ?? node.getAttribute('title')\n ?? '';\n }\n}\n","import { Injectable } from '@angular/core';\n\nconst ATTR = 'data-sd-autoid-highlight';\nconst SAVED_OUTLINE = 'data-sd-autoid-prev-outline';\nconst SAVED_OUTLINE_OFFSET = 'data-sd-autoid-prev-outline-offset';\nconst SAVED_BG = 'data-sd-autoid-prev-bg';\nconst SAVED_BORDER_RADIUS = 'data-sd-autoid-prev-radius';\n\n// Token màu lấy từ @sd-angular/core theme (--sd-*). Fallback hex áp dụng khi\n// consumer chưa import sd-core.scss. Dùng cùng bộ var với scss component để\n// nhất quán visual giữa highlight ok / duplicate / missing.\nconst COLOR_OK = 'var(--sd-success, #4CAF50)';\nconst COLOR_OK_BG = 'var(--sd-success-light, rgba(76, 175, 80, 0.12))';\nconst COLOR_DUP = 'var(--sd-error, #F82C13)';\nconst COLOR_DUP_BG = 'var(--sd-error-light, rgba(248, 44, 19, 0.12))';\nconst COLOR_MISSING = 'var(--sd-warning, #FF9600)';\nconst COLOR_MISSING_BG = 'var(--sd-warning-light, rgba(255, 150, 0, 0.12))';\n\n@Injectable({ providedIn: 'root' })\nexport class SdAutoidHighlightService {\n /** Apply outline cho mọi [data-autoid]: xanh nếu unique, đỏ nếu duplicate. Idempotent. */\n apply(root: HTMLElement = document.body): void {\n this.clear(root);\n const nodes = root.querySelectorAll<HTMLElement>('[data-autoid]');\n const count: Record<string, number> = {};\n nodes.forEach(n => {\n const id = n.getAttribute('data-autoid');\n if (!id) return;\n count[id] = (count[id] ?? 0) + 1;\n });\n\n // Để tránh apply 2 lần lên cùng 1 target khi nhiều [data-autoid] cùng\n // chia sẻ 1 sd-* host (vd 2 input lồng trong 1 sd-date-range).\n const visited = new Set<HTMLElement>();\n\n nodes.forEach(node => {\n const id = node.getAttribute('data-autoid');\n if (!id) return;\n\n // Highlight HOST sd-* (giống applyMissing) — outline ôm trọn card,\n // không hiển thị lệch trên input con / label fragment. Fallback về\n // chính node khi không tìm thấy sd-* ancestor (vd native button).\n const target = this.#resolveTarget(node);\n if (visited.has(target)) return;\n visited.add(target);\n\n const isDup = count[id] > 1;\n this.#paint(\n target,\n isDup ? COLOR_DUP : COLOR_OK,\n isDup ? COLOR_DUP_BG : COLOR_OK_BG,\n 'solid',\n isDup ? 'duplicate' : 'ok'\n );\n });\n }\n\n /** Highlight tập element không có autoid (missing) bằng outline cam dashed. */\n applyMissing(nodes: HTMLElement[]): void {\n nodes.forEach(node => {\n if (node.hasAttribute(ATTR)) return;\n this.#paint(node, COLOR_MISSING, COLOR_MISSING_BG, 'dashed', 'missing');\n });\n }\n\n /** Restore inline style như trước khi apply. */\n clear(root: HTMLElement = document.body): void {\n const nodes = root.querySelectorAll<HTMLElement>(`[${ATTR}]`);\n nodes.forEach(node => {\n node.style.outline = node.getAttribute(SAVED_OUTLINE) ?? '';\n node.style.outlineOffset = node.getAttribute(SAVED_OUTLINE_OFFSET) ?? '';\n node.style.backgroundColor = node.getAttribute(SAVED_BG) ?? '';\n node.style.borderRadius = node.getAttribute(SAVED_BORDER_RADIUS) ?? '';\n node.removeAttribute(SAVED_OUTLINE);\n node.removeAttribute(SAVED_OUTLINE_OFFSET);\n node.removeAttribute(SAVED_BG);\n node.removeAttribute(SAVED_BORDER_RADIUS);\n node.removeAttribute(ATTR);\n });\n }\n\n // ==========================================\n // HELPERS\n // ==========================================\n #resolveTarget(node: HTMLElement): HTMLElement {\n let cur: HTMLElement | null = node;\n while (cur) {\n if (cur.tagName.toLowerCase().startsWith('sd-')) return cur;\n cur = cur.parentElement;\n }\n return node;\n }\n\n #paint(\n node: HTMLElement,\n color: string,\n bg: string,\n style: 'solid' | 'dashed',\n marker: 'ok' | 'duplicate' | 'missing'\n ): void {\n // Backup full style cần restore để clear() đưa về nguyên trạng.\n node.setAttribute(SAVED_OUTLINE, node.style.outline ?? '');\n node.setAttribute(SAVED_OUTLINE_OFFSET, node.style.outlineOffset ?? '');\n node.setAttribute(SAVED_BG, node.style.backgroundColor ?? '');\n node.setAttribute(SAVED_BORDER_RADIUS, node.style.borderRadius ?? '');\n\n node.style.outline = `2px ${style} ${color}`;\n // outline-offset 2px tránh đè lên border của host (mat-form-field, button)\n // → highlight nằm gọn ngoài card thay vì cắt vào nội dung.\n node.style.outlineOffset = '2px';\n node.style.backgroundColor = bg;\n // Bo nhẹ để outline trông sạch trên host bo góc sẵn.\n if (!node.style.borderRadius) {\n node.style.borderRadius = '6px';\n }\n node.setAttribute(ATTR, marker);\n }\n}\n","import { Injectable } from '@angular/core';\nimport { SdAutoidElement } from '../models/autoid-element.model';\nimport { SdAutoidExportMeta } from '../models/autoid-export-format.model';\n\n@Injectable({ providedIn: 'root' })\nexport class SdAutoidExportService {\n toJson(elements: SdAutoidElement[]): string {\n return JSON.stringify(elements, null, 2);\n }\n\n toCsv(elements: SdAutoidElement[]): string {\n const header = 'STT,name,autoid,tag,value,xpath';\n const rows = elements.map(el =>\n [el.stt, this.q(el.name), this.q(el.autoid), this.q(el.tag), this.q(el.value), this.q(el.xpath)].join(',')\n );\n return [header, ...rows].join('\\n') + '\\n';\n }\n\n /** POM TypeScript skeleton — copy ngay vào file Playwright/Cypress. */\n toMarkdownPom(elements: SdAutoidElement[], meta: SdAutoidExportMeta): string {\n const className = this.toPascal(meta.pageTitle || 'AutoGenerated') + 'Page';\n const lines: string[] = [];\n lines.push(`# ${className}`);\n lines.push('');\n lines.push(`- Page: \\`${meta.pageUrl}\\``);\n lines.push(`- Generated: \\`${meta.timestamp}\\``);\n lines.push('');\n lines.push('```ts');\n lines.push(`export class ${className} {`);\n for (const el of elements) {\n const propName = this.toCamel(el.autoid);\n const nameHint = el.name ? ` ${el.name} —` : '';\n lines.push(` /** ${el.tag}${nameHint} */`);\n lines.push(` readonly ${propName} = '${el.xpath}';`);\n }\n lines.push('}');\n lines.push('```');\n lines.push('');\n return lines.join('\\n');\n }\n\n /** Markdown reference table, group theo tag sd-*. */\n toMarkdownTable(elements: SdAutoidElement[], meta: SdAutoidExportMeta): string {\n const lines: string[] = [];\n lines.push('# AutoId Reference');\n lines.push('');\n lines.push(`- Page: \\`${meta.pageUrl}\\``);\n lines.push(`- Generated: \\`${meta.timestamp}\\``);\n lines.push('');\n\n const groups = new Map<string, SdAutoidElement[]>();\n for (const el of elements) {\n const key = el.tag || '(no-tag)';\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(el);\n }\n\n const sortedTags = [...groups.keys()].sort();\n for (const tag of sortedTags) {\n lines.push(`## ${tag}`);\n lines.push('');\n lines.push('| name | autoid | xpath | duplicate |');\n lines.push('|------|--------|-------|-----------|');\n for (const el of groups.get(tag)!) {\n lines.push(`| ${this.mdCell(el.name)} | \\`${el.autoid}\\` | \\`${el.xpath}\\` | ${el.duplicate ? '⚠️' : ''} |`);\n }\n lines.push('');\n }\n return lines.join('\\n');\n }\n\n download(content: string, filename: string, mime: string): void {\n const blob = new Blob([content], { type: mime });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n\n async copyToClipboard(content: string): Promise<void> {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(content);\n return;\n }\n // Fallback cho browser cũ / context không có clipboard API.\n const ta = document.createElement('textarea');\n ta.value = content;\n ta.style.position = 'fixed';\n ta.style.opacity = '0';\n document.body.appendChild(ta);\n ta.select();\n document.execCommand('copy');\n document.body.removeChild(ta);\n }\n\n private q(v: string | number): string {\n const s = String(v ?? '').replace(/\"/g, '\"\"');\n return `\"${s}\"`;\n }\n\n private mdCell(s: string): string {\n return (s || '').replace(/\\|/g, '\\\\|').replace(/\\n/g, ' ');\n }\n\n private toCamel(autoid: string): string {\n const parts = autoid.split(/[-_]/).filter(Boolean);\n return parts.map((p, i) => (i === 0 ? p : p[0].toUpperCase() + p.slice(1))).join('');\n }\n\n private toPascal(title: string): string {\n return title\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map(p => p[0].toUpperCase() + p.slice(1))\n .join('');\n }\n}\n","import { CommonModule } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n HostListener,\n inject,\n input,\n OnDestroy,\n signal,\n} from '@angular/core';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatTooltipModule } from '@angular/material/tooltip';\nimport { FormsModule } from '@angular/forms';\n\nimport { SdAutoidElement, SdAutoidAuditResult } from './models/autoid-element.model';\nimport {\n SdAutoidInspectorConfig,\n SD_AUTOID_DEFAULT_REQUIRE_SELECTORS,\n} from './models/autoid-inspector-config.model';\nimport { SdAutoidExportMeta } from './models/autoid-export-format.model';\nimport { SdAutoidScannerService } from './services/autoid-scanner.service';\nimport { SdAutoidAuditService } from './services/autoid-audit.service';\nimport { SdAutoidHighlightService } from './services/autoid-highlight.service';\nimport { SdAutoidExportService } from './services/autoid-export.service';\n\ntype Segment = 'audit' | 'elements' | 'export';\n\n@Component({\n selector: 'sd-autoid-inspector',\n templateUrl: './autoid-inspector.component.html',\n styleUrls: ['./autoid-inspector.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n imports: [CommonModule, FormsModule, MatIconModule, MatTooltipModule],\n})\nexport class SdAutoidInspector implements OnDestroy {\n // ==========================================\n // INPUTS\n // ==========================================\n enabled = input(true, { transform: booleanAttribute });\n config = input<SdAutoidInspectorConfig | undefined>(undefined);\n\n // ==========================================\n // STATE\n // ==========================================\n open = signal(false);\n segment = signal<Segment>('audit');\n filter = signal('');\n elements = signal<SdAutoidElement[]>([]);\n audit = signal<SdAutoidAuditResult | null>(null);\n copyOk = signal(false);\n // Default true để mở panel lần đầu là có highlight ngay. Đóng panel KHÔNG\n // tự tắt — user toggle qua nút trong tab Audit khi muốn nhìn DOM gốc.\n highlightOn = signal(true);\n // Ẩn tạm FAB — chỉ in-memory, reload trang sẽ hiện lại (theo thiết kế).\n dismissed = signal(false);\n\n filteredElements = computed(() => {\n const q = this.filter().trim().toLowerCase();\n if (!q) return this.elements();\n return this.elements().filter(\n el =>\n el.autoid.toLowerCase().includes(q) ||\n el.name.toLowerCase().includes(q) ||\n el.tag.toLowerCase().includes(q)\n );\n });\n\n // ==========================================\n // SERVICES\n // ==========================================\n #scanner = inject(SdAutoidScannerService);\n #auditSvc = inject(SdAutoidAuditService);\n #highlight = inject(SdAutoidHighlightService);\n #export = inject(SdAutoidExportService);\n\n // ==========================================\n // LIFECYCLE\n // ==========================================\n ngOnDestroy(): void {\n this.#highlight.clear(this.#root());\n }\n\n // ==========================================\n // ACTIONS\n // ==========================================\n togglePanel = (): void => {\n if (this.open()) {\n this.closePanel();\n } else {\n this.openPanel();\n }\n };\n\n openPanel = (): void => {\n if (!this.enabled()) return;\n this.refresh();\n this.open.set(true);\n };\n\n closePanel = (): void => {\n this.open.set(false);\n // Highlight được giữ lại để user vẫn thấy outline khi panel ẩn —\n // toggleHighlight trong tab Audit là cách duy nhất để clear.\n };\n\n refresh = (): void => {\n const root = this.#root();\n const elements = this.#scanner.scan(root);\n const result = this.#auditSvc.audit(elements, {\n root,\n requireSelectors: this.#requireSelectors(),\n });\n this.elements.set(elements);\n this.audit.set(result);\n this.#applyHighlightIfOn(result);\n };\n\n dismissFab = (event: Event): void => {\n event.stopPropagation();\n this.dismissed.set(true);\n if (this.open()) this.closePanel();\n };\n\n toggleHighlight = (): void => {\n const next = !this.highlightOn();\n this.highlightOn.set(next);\n if (next) {\n this.#applyHighlightIfOn(this.audit());\n } else {\n this.#highlight.clear(this.#root());\n }\n };\n\n setSegment = (seg: Segment): void => this.segment.set(seg);\n\n copyJson = async (): Promise<void> => {\n await this.#export.copyToClipboard(this.#export.toJson(this.elements()));\n this.#flashCopyOk();\n };\n\n copyXpath = async (autoid: string): Promise<void> => {\n await this.#export.copyToClipboard(`//*[@data-autoid=\"${autoid}\"]`);\n this.#flashCopyOk();\n };\n\n exportCsv = (): void => {\n this.#export.download(\n this.#export.toCsv(this.elements()),\n this.#filename('csv'),\n 'text/csv;charset=utf-8'\n );\n };\n\n exportJson = (): void => {\n this.#export.download(\n this.#export.toJson(this.elements()),\n this.#filename('json'),\n 'application/json'\n );\n };\n\n exportMdPom = (): void => {\n this.#export.download(\n this.#export.toMarkdownPom(this.elements(), this.#meta()),\n this.#filename('pom.md'),\n 'text/markdown'\n );\n };\n\n exportMdTable = (): void => {\n this.#export.download(\n this.#export.toMarkdownTable(this.elements(), this.#meta()),\n this.#filename('reference.md'),\n 'text/markdown'\n );\n };\n\n // ==========================================\n // KEYBOARD: Esc đóng panel\n // ==========================================\n @HostListener('document:keydown.escape')\n onEscape(): void {\n if (this.open()) this.closePanel();\n }\n\n // ==========================================\n // HELPERS\n // ==========================================\n #root(): HTMLElement {\n return this.config()?.root ?? document.body;\n }\n\n #requireSelectors(): ReadonlyArray<string> {\n const extra = this.config()?.extraRequireSelectors ?? [];\n return [...SD_AUTOID_DEFAULT_REQUIRE_SELECTORS, ...extra];\n }\n\n #highlightMissing(result: SdAutoidAuditResult): void {\n if (!result.missing.length) return;\n const root = this.#root();\n const selector = this.#requireSelectors().join(',');\n const all = Array.from(root.querySelectorAll<HTMLElement>(selector));\n const missingNodes = all.filter(\n n => !n.hasAttribute('data-autoid') && !n.querySelector('[data-autoid]')\n );\n this.#highlight.applyMissing(missingNodes);\n }\n\n #applyHighlightIfOn(result: SdAutoidAuditResult | null): void {\n if (!this.highlightOn()) return;\n const root = this.#root();\n this.#highlight.apply(root);\n if (result) this.#highlightMissing(result);\n }\n\n #meta(): SdAutoidExportMeta {\n return {\n pageUrl: window.location.pathname + window.location.search,\n pageTitle: document.title || 'Page',\n timestamp: new Date().toISOString(),\n };\n }\n\n #filename(ext: string): string {\n const slug = (document.title || 'autoid')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n return `${slug || 'autoid'}-${Date.now()}.${ext}`;\n }\n\n #flashCopyOk(): void {\n this.copyOk.set(true);\n setTimeout(() => this.copyOk.set(false), 1200);\n }\n}\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 [matTooltip]=\"open() ? 'Đóng AutoId Inspector' : 'Mở 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=\"Ẩn tạm — reload trang để hiện lại\"\n matTooltipPosition=\"left\"\n aria-label=\"Ẩn tạm FAB\"\n (click)=\"dismissFab($event)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n}\n\n@if (enabled() && open()) {\n <div class=\"sd-autoid-inspector__backdrop\" (click)=\"closePanel()\"></div>\n <section class=\"sd-autoid-inspector__panel\" role=\"dialog\" aria-label=\"AutoId Inspector\">\n <header class=\"sd-autoid-inspector__header\">\n <div class=\"sd-autoid-inspector__segments\">\n <button\n type=\"button\"\n [class.is-active]=\"segment() === 'audit'\"\n (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\n type=\"button\"\n [class.is-active]=\"segment() === 'elements'\"\n (click)=\"setSegment('elements')\">\n Elements\n <span class=\"sd-autoid-inspector__badge\">{{ elements().length }}</span>\n </button>\n <button\n type=\"button\"\n [class.is-active]=\"segment() === 'export'\"\n (click)=\"setSegment('export')\">\n Export\n </button>\n </div>\n <div class=\"sd-autoid-inspector__actions\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn\"\n matTooltip=\"Quét lại\"\n (click)=\"refresh()\">\n <mat-icon>refresh</mat-icon>\n </button>\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__close-btn\"\n matTooltip=\"Đóng\"\n aria-label=\"Đóng panel\"\n (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\">Đã copy ✓</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 <div class=\"sd-autoid-inspector__audit-toolbar\">\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__toggle\"\n [class.is-on]=\"highlightOn()\"\n (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ổng 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ùng</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ếu</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ị trùng\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr><th>Autoid</th><th>Số lần</th></tr>\n </thead>\n <tbody>\n @for (entry of a.duplicates | keyvalue; track entry.key) {\n <tr class=\"is-error\">\n <td><code>{{ entry.key }}</code></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ếu autoid\n </h4>\n <div class=\"sd-autoid-inspector__table-wrap\">\n <table class=\"sd-autoid-inspector__table\">\n <thead>\n <tr><th>Tag</th><th>Name hint</th><th>Selector</th></tr>\n </thead>\n <tbody>\n @for (m of a.missing; track $index) {\n <tr class=\"is-warning\">\n <td><code>{{ m.tag }}</code></td>\n <td>{{ m.nameHint }}</td>\n <td><code>{{ m.selector }}</code></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ông có element thiếu hoặc trùng autoid.</strong>\n <small>Trang đã đạt chuẩn convention autoid.</small>\n </div>\n </div>\n }\n }\n </ng-template>\n\n <ng-template #elementsTpl>\n <div class=\"sd-autoid-inspector__filter\">\n <mat-icon>search</mat-icon>\n <input\n type=\"text\"\n placeholder=\"Lọc theo autoid / name / tag\"\n [ngModel]=\"filter()\"\n (ngModelChange)=\"filter.set($event)\"/>\n @if (filter()) {\n <button\n type=\"button\"\n class=\"sd-autoid-inspector__icon-btn\"\n matTooltip=\"Xoá filter\"\n (click)=\"filter.set('')\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\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>Value</th>\n </tr>\n </thead>\n <tbody>\n @for (el of filteredElements(); track el.autoid + $index) {\n <tr [class.is-error]=\"el.duplicate\">\n <td class=\"is-num\">{{ el.stt }}</td>\n <td>{{ el.name || '—' }}</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><span class=\"sd-autoid-inspector__tag-chip\">{{ el.tag }}</span></td>\n <td class=\"sd-autoid-inspector__value\" [matTooltip]=\"el.value || ''\">\n {{ el.value || '—' }}\n </td>\n </tr>\n } @empty {\n <tr><td colspan=\"5\" class=\"sd-autoid-inspector__empty\">Không có kết quả.</td></tr>\n }\n </tbody>\n </table>\n </div>\n </ng-template>\n\n <ng-template #exportTpl>\n <div class=\"sd-autoid-inspector__export-grid\">\n <button type=\"button\" matTooltip=\"Copy JSON vào 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ải 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ải 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ải MD POM skeleton — cho AI viết 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ải MD reference table — 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 </ng-template>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;;AAOA;AACO,MAAM,mCAAmC,GAA0B;IACxE,UAAU;IACV,iBAAiB;IACjB,aAAa;IACb,WAAW;IACX,iBAAiB;IACjB,aAAa;IACb,UAAU;IACV,WAAW;IACX,SAAS;IACT,aAAa;IACb,eAAe;IACf,SAAS;IACT,kBAAkB;IAClB,WAAW;;;MClBA,sBAAsB,CAAA;;AAEjC,IAAA,IAAI,CAAC,IAAA,GAAoB,QAAQ,CAAC,IAAI,EAAA;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAc,eAAe,CAAC;QACjE,MAAM,QAAQ,GAA2B,EAAE;AAC3C,QAAA,KAAK,CAAC,OAAO,CAAC,CAAC,IAAG;YAChB,MAAM,EAAE,GAAG,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC;AACxC,YAAA,IAAI,CAAC,EAAE;gBAAE;AACT,YAAA,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;AACxC,QAAA,CAAC,CAAC;QAEF,MAAM,MAAM,GAAsB,EAAE;QACpC,IAAI,GAAG,GAAG,CAAC;AACX,QAAA,KAAK,CAAC,OAAO,CAAC,IAAI,IAAG;YACnB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC;AAC/C,YAAA,IAAI,CAAC,MAAM;gBAAE;YACb,MAAM,CAAC,IAAI,CAAC;gBACV,GAAG,EAAE,GAAG,EAAE;AACV,gBAAA,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;gBAC5B,MAAM;AACN,gBAAA,GAAG,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;AAC5B,gBAAA,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;gBAC9B,KAAK,EAAE,CAAA,kBAAA,EAAqB,MAAM,CAAA,EAAA,CAAI;AACtC,gBAAA,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC;AAChC,aAAA,CAAC;AACJ,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,MAAM;IACf;;AAGA,IAAA,aAAa,CAAC,QAA2B,EAAA;QACvC,MAAM,GAAG,GAAsC,EAAE;AACjD,QAAA,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE;AACzB,YAAA,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;QAClC;AACA,QAAA,OAAO,GAAG;IACZ;AAEQ,IAAA,WAAW,CAAC,IAAiB,EAAA;AACnC,QAAA,IAAI,IAAI,CAAC,EAAE,EAAE;;YAEX,MAAM,GAAG,GAAG,OAAO,GAAG,KAAK,WAAW,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE;YACpF,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAA,WAAA,EAAc,GAAG,CAAA,EAAA,CAAI,CAAC;YAC3D,MAAM,IAAI,GAAG,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE;AACvC,YAAA,IAAI,IAAI;AAAE,gBAAA,OAAO,IAAI;QACvB;QACA,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,IAAI;AACvC,eAAA,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE,IAAI;AACtC,eAAA,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,IAAI;AAChC,eAAA,EAAE;IACT;AAEQ,IAAA,YAAY,CAAC,IAAiB,EAAA;QACpC,IAAI,GAAG,GAAuB,IAAI;QAClC,OAAO,GAAG,EAAE;YACV,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE;AACrC,YAAA,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;AAAE,gBAAA,OAAO,GAAG;AACrC,YAAA,GAAG,GAAG,GAAG,CAAC,aAAa;QACzB;AACA,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;IACnC;AAEQ,IAAA,YAAY,CAAC,IAAiB,EAAA;QACpC,MAAM,KAAK,GAAG,IAAwB;QACtC,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC,KAAK;AACtE,QAAA,OAAO,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;IACrD;wGAlEW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cADT,MAAM,EAAA,CAAA;;4FACnB,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBADlC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MCErB,oBAAoB,CAAA;AAC/B;;;;AAIG;AACH,IAAA,KAAK,CACH,QAA2B,EAC3B,OAAA,GAA4E,EAAE,EAAA;AAE9E,QAAA,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,mCAAmC;QACxF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI;QAE1C,MAAM,UAAU,GAA2B,EAAE;AAC7C,QAAA,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE;AACzB,YAAA,IAAI,EAAE,CAAC,SAAS,EAAE;AAChB,gBAAA,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;YAC1D;QACF;QAEA,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,gBAAgB,CAAC;QAExD,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,MAAM;YACtB,UAAU;YACV,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM;YAC9C,OAAO;YACP,YAAY,EAAE,OAAO,CAAC,MAAM;SAC7B;IACH;IAEQ,WAAW,CAAC,IAAiB,EAAE,SAAgC,EAAA;QACrE,IAAI,CAAC,SAAS,CAAC,MAAM;AAAE,YAAA,OAAO,EAAE;QAChC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAc,MAAM,CAAC;QACxD,MAAM,OAAO,GAAsB,EAAE;AAErC,QAAA,KAAK,CAAC,OAAO,CAAC,IAAI,IAAG;;;;AAInB,YAAA,IAAI,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC;gBAAE;AACtC,YAAA,IAAI,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC;gBAAE;YAEzC,OAAO,CAAC,IAAI,CAAC;AACX,gBAAA,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;AAC/B,gBAAA,QAAQ,EAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;AACtC,gBAAA,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;AACtC,gBAAA,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;AACrC,aAAA,CAAC;AACJ,QAAA,CAAC,CAAC;AAEF,QAAA,OAAO,OAAO;IAChB;AAEQ,IAAA,iBAAiB,CAAC,IAAiB,EAAA;QACzC,MAAM,KAAK,GAAa,EAAE;QAC1B,IAAI,GAAG,GAAuB,IAAI;QAClC,IAAI,KAAK,GAAG,CAAC;AACb,QAAA,OAAO,GAAG,IAAI,KAAK,GAAG,CAAC,EAAE;YACvB,IAAI,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE;AACpC,YAAA,IAAI,GAAG,CAAC,EAAE,EAAE;AACV,gBAAA,IAAI,IAAI,CAAA,CAAA,EAAI,GAAG,CAAC,EAAE,EAAE;AACpB,gBAAA,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBACnB;YACF;AACA,YAAA,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YAC7F,IAAI,GAAG,CAAC,MAAM;gBAAE,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA,CAAE;AAC3C,YAAA,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;AACnB,YAAA,GAAG,GAAG,GAAG,CAAC,aAAa;AACvB,YAAA,KAAK,EAAE;QACT;AACA,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;IAC1B;AAEQ,IAAA,SAAS,CAAC,IAAiB,EAAA;AACjC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;QAChD,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,GAAG,IAAI;IAC9D;AAEQ,IAAA,eAAe,CAAC,IAAiB,EAAA;AACvC,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO;AAC3B,eAAA,IAAI,CAAC,YAAY,CAAC,aAAa;AAC/B,eAAA,IAAI,CAAC,YAAY,CAAC,YAAY;AAC9B,eAAA,IAAI,CAAC,YAAY,CAAC,OAAO;AACzB,eAAA,EAAE;IACT;wGAtFW,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAApB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,oBAAoB,cADP,MAAM,EAAA,CAAA;;4FACnB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBADhC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACFlC,MAAM,IAAI,GAAG,0BAA0B;AACvC,MAAM,aAAa,GAAG,6BAA6B;AACnD,MAAM,oBAAoB,GAAG,oCAAoC;AACjE,MAAM,QAAQ,GAAG,wBAAwB;AACzC,MAAM,mBAAmB,GAAG,4BAA4B;AAExD;AACA;AACA;AACA,MAAM,QAAQ,GAAG,4BAA4B;AAC7C,MAAM,WAAW,GAAG,kDAAkD;AACtE,MAAM,SAAS,GAAG,0BAA0B;AAC5C,MAAM,YAAY,GAAG,gDAAgD;AACrE,MAAM,aAAa,GAAG,4BAA4B;AAClD,MAAM,gBAAgB,GAAG,kDAAkD;MAG9D,wBAAwB,CAAA;;AAEnC,IAAA,KAAK,CAAC,IAAA,GAAoB,QAAQ,CAAC,IAAI,EAAA;AACrC,QAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAc,eAAe,CAAC;QACjE,MAAM,KAAK,GAA2B,EAAE;AACxC,QAAA,KAAK,CAAC,OAAO,CAAC,CAAC,IAAG;YAChB,MAAM,EAAE,GAAG,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC;AACxC,YAAA,IAAI,CAAC,EAAE;gBAAE;AACT,YAAA,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;AAClC,QAAA,CAAC,CAAC;;;AAIF,QAAA,MAAM,OAAO,GAAG,IAAI,GAAG,EAAe;AAEtC,QAAA,KAAK,CAAC,OAAO,CAAC,IAAI,IAAG;YACnB,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC;AAC3C,YAAA,IAAI,CAAC,EAAE;gBAAE;;;;YAKT,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;AACxC,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE;AACzB,YAAA,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YAEnB,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC;AAC3B,YAAA,IAAI,CAAC,MAAM,CACT,MAAM,EACN,KAAK,GAAG,SAAS,GAAG,QAAQ,EAC5B,KAAK,GAAG,YAAY,GAAG,WAAW,EAClC,OAAO,EACP,KAAK,GAAG,WAAW,GAAG,IAAI,CAC3B;AACH,QAAA,CAAC,CAAC;IACJ;;AAGA,IAAA,YAAY,CAAC,KAAoB,EAAA;AAC/B,QAAA,KAAK,CAAC,OAAO,CAAC,IAAI,IAAG;AACnB,YAAA,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;gBAAE;AAC7B,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,CAAC;AACzE,QAAA,CAAC,CAAC;IACJ;;AAGA,IAAA,KAAK,CAAC,IAAA,GAAoB,QAAQ,CAAC,IAAI,EAAA;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAc,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,CAAG,CAAC;AAC7D,QAAA,KAAK,CAAC,OAAO,CAAC,IAAI,IAAG;AACnB,YAAA,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE;AAC3D,YAAA,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,oBAAoB,CAAC,IAAI,EAAE;AACxE,YAAA,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC9D,YAAA,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,IAAI,EAAE;AACtE,YAAA,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC;AACnC,YAAA,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC;AAC1C,YAAA,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC;AAC9B,YAAA,IAAI,CAAC,eAAe,CAAC,mBAAmB,CAAC;AACzC,YAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;AAC5B,QAAA,CAAC,CAAC;IACJ;;;;AAKA,IAAA,cAAc,CAAC,IAAiB,EAAA;QAC9B,IAAI,GAAG,GAAuB,IAAI;QAClC,OAAO,GAAG,EAAE;YACV,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;AAAE,gBAAA,OAAO,GAAG;AAC3D,YAAA,GAAG,GAAG,GAAG,CAAC,aAAa;QACzB;AACA,QAAA,OAAO,IAAI;IACb;IAEA,MAAM,CACJ,IAAiB,EACjB,KAAa,EACb,EAAU,EACV,KAAyB,EACzB,MAAsC,EAAA;;AAGtC,QAAA,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;AAC1D,QAAA,IAAI,CAAC,YAAY,CAAC,oBAAoB,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC;AACvE,QAAA,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,IAAI,EAAE,CAAC;AAC7D,QAAA,IAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC;QAErE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE;;;AAG5C,QAAA,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,KAAK;AAChC,QAAA,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,EAAE;;AAE/B,QAAA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE;AAC5B,YAAA,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,KAAK;QACjC;AACA,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC;IACjC;wGAjGW,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAxB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,wBAAwB,cADX,MAAM,EAAA,CAAA;;4FACnB,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBADpC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MCbrB,qBAAqB,CAAA;AAChC,IAAA,MAAM,CAAC,QAA2B,EAAA;QAChC,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C;AAEA,IAAA,KAAK,CAAC,QAA2B,EAAA;QAC/B,MAAM,MAAM,GAAG,iCAAiC;AAChD,QAAA,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,IAC1B,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAC3G;AACD,QAAA,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI;IAC5C;;IAGA,aAAa,CAAC,QAA2B,EAAE,IAAwB,EAAA;AACjE,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,IAAI,eAAe,CAAC,GAAG,MAAM;QAC3E,MAAM,KAAK,GAAa,EAAE;AAC1B,QAAA,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAA,CAAE,CAAC;AAC5B,QAAA,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,OAAO,CAAA,EAAA,CAAI,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,CAAA,eAAA,EAAkB,IAAI,CAAC,SAAS,CAAA,EAAA,CAAI,CAAC;AAChD,QAAA,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AACd,QAAA,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;AACnB,QAAA,KAAK,CAAC,IAAI,CAAC,gBAAgB,SAAS,CAAA,EAAA,CAAI,CAAC;AACzC,QAAA,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC;AACxC,YAAA,MAAM,QAAQ,GAAG,EAAE,CAAC,IAAI,GAAG,CAAA,CAAA,EAAI,EAAE,CAAC,IAAI,CAAA,EAAA,CAAI,GAAG,EAAE;YAC/C,KAAK,CAAC,IAAI,CAAC,CAAA,MAAA,EAAS,EAAE,CAAC,GAAG,CAAA,EAAG,QAAQ,CAAA,GAAA,CAAK,CAAC;YAC3C,KAAK,CAAC,IAAI,CAAC,CAAA,WAAA,EAAc,QAAQ,CAAA,IAAA,EAAO,EAAE,CAAC,KAAK,CAAA,EAAA,CAAI,CAAC;QACvD;AACA,QAAA,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AACf,QAAA,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AACjB,QAAA,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AACd,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IACzB;;IAGA,eAAe,CAAC,QAA2B,EAAE,IAAwB,EAAA;QACnE,MAAM,KAAK,GAAa,EAAE;AAC1B,QAAA,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC;AAChC,QAAA,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,OAAO,CAAA,EAAA,CAAI,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,CAAA,eAAA,EAAkB,IAAI,CAAC,SAAS,CAAA,EAAA,CAAI,CAAC;AAChD,QAAA,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AAEd,QAAA,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6B;AACnD,QAAA,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE;AACzB,YAAA,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,UAAU;AAChC,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;AAAE,gBAAA,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC;YACzC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B;AAEA,QAAA,MAAM,UAAU,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;AAC5C,QAAA,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE;AAC5B,YAAA,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAA,CAAE,CAAC;AACvB,YAAA,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AACd,YAAA,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC;AACnD,YAAA,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC;YACnD,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAE,EAAE;AACjC,gBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,EAAA,EAAK,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA,KAAA,EAAQ,EAAE,CAAC,MAAM,CAAA,OAAA,EAAU,EAAE,CAAC,KAAK,CAAA,KAAA,EAAQ,EAAE,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA,EAAA,CAAI,CAAC;YAC9G;AACA,YAAA,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAChB;AACA,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IACzB;AAEA,IAAA,QAAQ,CAAC,OAAe,EAAE,QAAgB,EAAE,IAAY,EAAA;AACtD,QAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAChD,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC;QACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC;AACxC,QAAA,IAAI,CAAC,IAAI,GAAG,GAAG;AACf,QAAA,IAAI,CAAC,QAAQ,GAAG,QAAQ;AACxB,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAC/B,IAAI,CAAC,KAAK,EAAE;AACZ,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AAC/B,QAAA,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC;IAC1B;IAEA,MAAM,eAAe,CAAC,OAAe,EAAA;AACnC,QAAA,IAAI,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE;YAClC,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC;YAC5C;QACF;;QAEA,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC;AAC7C,QAAA,EAAE,CAAC,KAAK,GAAG,OAAO;AAClB,QAAA,EAAE,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO;AAC3B,QAAA,EAAE,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG;AACtB,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,EAAE,CAAC,MAAM,EAAE;AACX,QAAA,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC;AAC5B,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;IAC/B;AAEQ,IAAA,CAAC,CAAC,CAAkB,EAAA;AAC1B,QAAA,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC;QAC7C,OAAO,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAG;IACjB;AAEQ,IAAA,MAAM,CAAC,CAAS,EAAA;AACtB,QAAA,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;IAC5D;AAEQ,IAAA,OAAO,CAAC,MAAc,EAAA;AAC5B,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AAClD,QAAA,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IACtF;AAEQ,IAAA,QAAQ,CAAC,KAAa,EAAA;AAC5B,QAAA,OAAO;aACJ,KAAK,CAAC,eAAe;aACrB,MAAM,CAAC,OAAO;AACd,aAAA,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;aACxC,IAAI,CAAC,EAAE,CAAC;IACb;wGAlHW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAArB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,qBAAqB,cADR,MAAM,EAAA,CAAA;;4FACnB,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBADjC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MCiCrB,iBAAiB,CAAA;;;;IAI5B,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC;AACtD,IAAA,MAAM,GAAG,KAAK,CAAsC,SAAS,CAAC;;;;AAK9D,IAAA,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;AACpB,IAAA,OAAO,GAAG,MAAM,CAAU,OAAO,CAAC;AAClC,IAAA,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AACnB,IAAA,QAAQ,GAAG,MAAM,CAAoB,EAAE,CAAC;AACxC,IAAA,KAAK,GAAG,MAAM,CAA6B,IAAI,CAAC;AAChD,IAAA,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;;;AAGtB,IAAA,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC;;AAE1B,IAAA,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC;AAEzB,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAK;AAC/B,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;AAC5C,QAAA,IAAI,CAAC,CAAC;AAAE,YAAA,OAAO,IAAI,CAAC,QAAQ,EAAE;QAC9B,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,CAC3B,EAAE,IACA,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YACnC,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YACjC,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CACnC;AACH,IAAA,CAAC,CAAC;;;;AAKF,IAAA,QAAQ,GAAG,MAAM,CAAC,sBAAsB,CAAC;AACzC,IAAA,SAAS,GAAG,MAAM,CAAC,oBAAoB,CAAC;AACxC,IAAA,UAAU,GAAG,MAAM,CAAC,wBAAwB,CAAC;AAC7C,IAAA,OAAO,GAAG,MAAM,CAAC,qBAAqB,CAAC;;;;IAKvC,WAAW,GAAA;QACT,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACrC;;;;IAKA,WAAW,GAAG,MAAW;AACvB,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE;YACf,IAAI,CAAC,UAAU,EAAE;QACnB;aAAO;YACL,IAAI,CAAC,SAAS,EAAE;QAClB;AACF,IAAA,CAAC;IAED,SAAS,GAAG,MAAW;AACrB,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YAAE;QACrB,IAAI,CAAC,OAAO,EAAE;AACd,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,IAAA,CAAC;IAED,UAAU,GAAG,MAAW;AACtB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;;;AAGtB,IAAA,CAAC;IAED,OAAO,GAAG,MAAW;AACnB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE;YAC5C,IAAI;AACJ,YAAA,gBAAgB,EAAE,IAAI,CAAC,iBAAiB,EAAE;AAC3C,SAAA,CAAC;AACF,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC3B,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AACtB,QAAA,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC;AAClC,IAAA,CAAC;AAED,IAAA,UAAU,GAAG,CAAC,KAAY,KAAU;QAClC,KAAK,CAAC,eAAe,EAAE;AACvB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;QACxB,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,UAAU,EAAE;AACpC,IAAA,CAAC;IAED,eAAe,GAAG,MAAW;AAC3B,QAAA,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE;AAChC,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QAC1B,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACxC;aAAO;YACL,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACrC;AACF,IAAA,CAAC;AAED,IAAA,UAAU,GAAG,CAAC,GAAY,KAAW,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;IAE1D,QAAQ,GAAG,YAA0B;AACnC,QAAA,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,YAAY,EAAE;AACrB,IAAA,CAAC;AAED,IAAA,SAAS,GAAG,OAAO,MAAc,KAAmB;QAClD,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA,kBAAA,EAAqB,MAAM,CAAA,EAAA,CAAI,CAAC;QACnE,IAAI,CAAC,YAAY,EAAE;AACrB,IAAA,CAAC;IAED,SAAS,GAAG,MAAW;QACrB,IAAI,CAAC,OAAO,CAAC,QAAQ,CACnB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EACnC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EACrB,wBAAwB,CACzB;AACH,IAAA,CAAC;IAED,UAAU,GAAG,MAAW;QACtB,IAAI,CAAC,OAAO,CAAC,QAAQ,CACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EACpC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EACtB,kBAAkB,CACnB;AACH,IAAA,CAAC;IAED,WAAW,GAAG,MAAW;AACvB,QAAA,IAAI,CAAC,OAAO,CAAC,QAAQ,CACnB,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,EACzD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EACxB,eAAe,CAChB;AACH,IAAA,CAAC;IAED,aAAa,GAAG,MAAW;AACzB,QAAA,IAAI,CAAC,OAAO,CAAC,QAAQ,CACnB,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,EAC3D,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,EAC9B,eAAe,CAChB;AACH,IAAA,CAAC;;;;IAMD,QAAQ,GAAA;QACN,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,UAAU,EAAE;IACpC;;;;IAKA,KAAK,GAAA;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI,QAAQ,CAAC,IAAI;IAC7C;IAEA,iBAAiB,GAAA;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,qBAAqB,IAAI,EAAE;AACxD,QAAA,OAAO,CAAC,GAAG,mCAAmC,EAAE,GAAG,KAAK,CAAC;IAC3D;AAEA,IAAA,iBAAiB,CAAC,MAA2B,EAAA;AAC3C,QAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM;YAAE;AAC5B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;AACnD,QAAA,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAc,QAAQ,CAAC,CAAC;QACpE,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAC7B,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,eAAe,CAAC,CACzE;AACD,QAAA,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,YAAY,CAAC;IAC5C;AAEA,IAAA,mBAAmB,CAAC,MAAkC,EAAA;AACpD,QAAA,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YAAE;AACzB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE;AACzB,QAAA,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;AAC3B,QAAA,IAAI,MAAM;AAAE,YAAA,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;IAC5C;IAEA,KAAK,GAAA;QACH,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM;AAC1D,YAAA,SAAS,EAAE,QAAQ,CAAC,KAAK,IAAI,MAAM;AACnC,YAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC;IACH;AAEA,IAAA,SAAS,CAAC,GAAW,EAAA;QACnB,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,QAAQ;AACrC,aAAA,WAAW;AACX,aAAA,OAAO,CAAC,aAAa,EAAE,GAAG;AAC1B,aAAA,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;AACxB,QAAA,OAAO,CAAA,EAAG,IAAI,IAAI,QAAQ,CAAA,CAAA,EAAI,IAAI,CAAC,GAAG,EAAE,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE;IACnD;IAEA,YAAY,GAAA;AACV,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,QAAA,UAAU,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;IAChD;wGAxMW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;4FAAjB,iBAAiB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,yBAAA,EAAA,YAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECrC9B,yxUA0QA,EAAA,MAAA,EAAA,CAAA,y5XAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDvOY,YAAY,gQAAE,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,SAAA,EAAA,SAAA,EAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,gBAAgB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,UAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,oBAAA,EAAA,4BAAA,EAAA,oBAAA,EAAA,qBAAA,EAAA,qBAAA,EAAA,yBAAA,EAAA,YAAA,EAAA,iBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,YAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;4FAEzD,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAR7B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,EAAA,eAAA,EAGd,uBAAuB,CAAC,MAAM,cACnC,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,CAAC,EAAA,QAAA,EAAA,yxUAAA,EAAA,MAAA,EAAA,CAAA,y5XAAA,CAAA,EAAA;8BAqJrE,QAAQ,EAAA,CAAA;sBADP,YAAY;uBAAC,yBAAyB;;;AEvLzC;;AAEG;;;;"}
|
|
@@ -19,6 +19,7 @@ export * from '@sd-angular/core/components/chart';
|
|
|
19
19
|
export * from '@sd-angular/core/components/editor';
|
|
20
20
|
export * from '@sd-angular/core/components/splitter';
|
|
21
21
|
export * from '@sd-angular/core/components/preview';
|
|
22
|
+
export * from '@sd-angular/core/components/autoid-inspector';
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Generated bundle index. Do not edit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sd-angular-core-components.mjs","sources":["../../../projects/sd-angular/components/sd-angular-core-components.ts"],"sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sd-angular-core-components.mjs","sources":["../../../projects/sd-angular/components/sd-angular-core-components.ts"],"sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;;AAEG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sd-angular/core",
|
|
3
|
-
"version": "19.0.0-beta.
|
|
3
|
+
"version": "19.0.0-beta.98",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/common": "^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
6
6
|
"@angular/core": "^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
@@ -36,26 +36,26 @@
|
|
|
36
36
|
"types": "./components/index.d.ts",
|
|
37
37
|
"default": "./fesm2022/sd-angular-core-components.mjs"
|
|
38
38
|
},
|
|
39
|
-
"./directives": {
|
|
40
|
-
"types": "./directives/index.d.ts",
|
|
41
|
-
"default": "./fesm2022/sd-angular-core-directives.mjs"
|
|
42
|
-
},
|
|
43
39
|
"./configurations": {
|
|
44
40
|
"types": "./configurations/index.d.ts",
|
|
45
41
|
"default": "./fesm2022/sd-angular-core-configurations.mjs"
|
|
46
42
|
},
|
|
43
|
+
"./directives": {
|
|
44
|
+
"types": "./directives/index.d.ts",
|
|
45
|
+
"default": "./fesm2022/sd-angular-core-directives.mjs"
|
|
46
|
+
},
|
|
47
47
|
"./forms": {
|
|
48
48
|
"types": "./forms/index.d.ts",
|
|
49
49
|
"default": "./fesm2022/sd-angular-core-forms.mjs"
|
|
50
50
|
},
|
|
51
|
-
"./i18n": {
|
|
52
|
-
"types": "./i18n/index.d.ts",
|
|
53
|
-
"default": "./fesm2022/sd-angular-core-i18n.mjs"
|
|
54
|
-
},
|
|
55
51
|
"./handlers": {
|
|
56
52
|
"types": "./handlers/index.d.ts",
|
|
57
53
|
"default": "./fesm2022/sd-angular-core-handlers.mjs"
|
|
58
54
|
},
|
|
55
|
+
"./i18n": {
|
|
56
|
+
"types": "./i18n/index.d.ts",
|
|
57
|
+
"default": "./fesm2022/sd-angular-core-i18n.mjs"
|
|
58
|
+
},
|
|
59
59
|
"./interceptors": {
|
|
60
60
|
"types": "./interceptors/index.d.ts",
|
|
61
61
|
"default": "./fesm2022/sd-angular-core-interceptors.mjs"
|
|
@@ -84,10 +84,18 @@
|
|
|
84
84
|
"types": "./components/anchor/index.d.ts",
|
|
85
85
|
"default": "./fesm2022/sd-angular-core-components-anchor.mjs"
|
|
86
86
|
},
|
|
87
|
+
"./components/autoid-inspector": {
|
|
88
|
+
"types": "./components/autoid-inspector/index.d.ts",
|
|
89
|
+
"default": "./fesm2022/sd-angular-core-components-autoid-inspector.mjs"
|
|
90
|
+
},
|
|
87
91
|
"./components/avatar": {
|
|
88
92
|
"types": "./components/avatar/index.d.ts",
|
|
89
93
|
"default": "./fesm2022/sd-angular-core-components-avatar.mjs"
|
|
90
94
|
},
|
|
95
|
+
"./components/badge": {
|
|
96
|
+
"types": "./components/badge/index.d.ts",
|
|
97
|
+
"default": "./fesm2022/sd-angular-core-components-badge.mjs"
|
|
98
|
+
},
|
|
91
99
|
"./components/base": {
|
|
92
100
|
"types": "./components/base/index.d.ts",
|
|
93
101
|
"default": "./fesm2022/sd-angular-core-components-base.mjs"
|
|
@@ -96,10 +104,6 @@
|
|
|
96
104
|
"types": "./components/button/index.d.ts",
|
|
97
105
|
"default": "./fesm2022/sd-angular-core-components-button.mjs"
|
|
98
106
|
},
|
|
99
|
-
"./components/badge": {
|
|
100
|
-
"types": "./components/badge/index.d.ts",
|
|
101
|
-
"default": "./fesm2022/sd-angular-core-components-badge.mjs"
|
|
102
|
-
},
|
|
103
107
|
"./components/chart": {
|
|
104
108
|
"types": "./components/chart/index.d.ts",
|
|
105
109
|
"default": "./fesm2022/sd-angular-core-components-chart.mjs"
|
|
@@ -132,10 +136,6 @@
|
|
|
132
136
|
"types": "./components/mini-editor/index.d.ts",
|
|
133
137
|
"default": "./fesm2022/sd-angular-core-components-mini-editor.mjs"
|
|
134
138
|
},
|
|
135
|
-
"./components/preview": {
|
|
136
|
-
"types": "./components/preview/index.d.ts",
|
|
137
|
-
"default": "./fesm2022/sd-angular-core-components-preview.mjs"
|
|
138
|
-
},
|
|
139
139
|
"./components/modal": {
|
|
140
140
|
"types": "./components/modal/index.d.ts",
|
|
141
141
|
"default": "./fesm2022/sd-angular-core-components-modal.mjs"
|
|
@@ -144,6 +144,10 @@
|
|
|
144
144
|
"types": "./components/query-builder/index.d.ts",
|
|
145
145
|
"default": "./fesm2022/sd-angular-core-components-query-builder.mjs"
|
|
146
146
|
},
|
|
147
|
+
"./components/preview": {
|
|
148
|
+
"types": "./components/preview/index.d.ts",
|
|
149
|
+
"default": "./fesm2022/sd-angular-core-components-preview.mjs"
|
|
150
|
+
},
|
|
147
151
|
"./components/quick-action": {
|
|
148
152
|
"types": "./components/quick-action/index.d.ts",
|
|
149
153
|
"default": "./fesm2022/sd-angular-core-components-quick-action.mjs"
|
|
@@ -152,14 +156,18 @@
|
|
|
152
156
|
"types": "./components/section/index.d.ts",
|
|
153
157
|
"default": "./fesm2022/sd-angular-core-components-section.mjs"
|
|
154
158
|
},
|
|
155
|
-
"./components/
|
|
156
|
-
"types": "./components/
|
|
157
|
-
"default": "./fesm2022/sd-angular-core-components-
|
|
159
|
+
"./components/splitter": {
|
|
160
|
+
"types": "./components/splitter/index.d.ts",
|
|
161
|
+
"default": "./fesm2022/sd-angular-core-components-splitter.mjs"
|
|
158
162
|
},
|
|
159
163
|
"./components/tab-router": {
|
|
160
164
|
"types": "./components/tab-router/index.d.ts",
|
|
161
165
|
"default": "./fesm2022/sd-angular-core-components-tab-router.mjs"
|
|
162
166
|
},
|
|
167
|
+
"./components/table": {
|
|
168
|
+
"types": "./components/table/index.d.ts",
|
|
169
|
+
"default": "./fesm2022/sd-angular-core-components-table.mjs"
|
|
170
|
+
},
|
|
163
171
|
"./components/upload-file": {
|
|
164
172
|
"types": "./components/upload-file/index.d.ts",
|
|
165
173
|
"default": "./fesm2022/sd-angular-core-components-upload-file.mjs"
|
|
@@ -168,14 +176,14 @@
|
|
|
168
176
|
"types": "./components/view/index.d.ts",
|
|
169
177
|
"default": "./fesm2022/sd-angular-core-components-view.mjs"
|
|
170
178
|
},
|
|
171
|
-
"./components/table": {
|
|
172
|
-
"types": "./components/table/index.d.ts",
|
|
173
|
-
"default": "./fesm2022/sd-angular-core-components-table.mjs"
|
|
174
|
-
},
|
|
175
179
|
"./forms/autocomplete": {
|
|
176
180
|
"types": "./forms/autocomplete/index.d.ts",
|
|
177
181
|
"default": "./fesm2022/sd-angular-core-forms-autocomplete.mjs"
|
|
178
182
|
},
|
|
183
|
+
"./forms/checkbox": {
|
|
184
|
+
"types": "./forms/checkbox/index.d.ts",
|
|
185
|
+
"default": "./fesm2022/sd-angular-core-forms-checkbox.mjs"
|
|
186
|
+
},
|
|
179
187
|
"./forms/chip": {
|
|
180
188
|
"types": "./forms/chip/index.d.ts",
|
|
181
189
|
"default": "./fesm2022/sd-angular-core-forms-chip.mjs"
|
|
@@ -184,10 +192,6 @@
|
|
|
184
192
|
"types": "./forms/chip-calendar/index.d.ts",
|
|
185
193
|
"default": "./fesm2022/sd-angular-core-forms-chip-calendar.mjs"
|
|
186
194
|
},
|
|
187
|
-
"./forms/checkbox": {
|
|
188
|
-
"types": "./forms/checkbox/index.d.ts",
|
|
189
|
-
"default": "./fesm2022/sd-angular-core-forms-checkbox.mjs"
|
|
190
|
-
},
|
|
191
195
|
"./forms/date": {
|
|
192
196
|
"types": "./forms/date/index.d.ts",
|
|
193
197
|
"default": "./fesm2022/sd-angular-core-forms-date.mjs"
|
|
@@ -212,10 +216,6 @@
|
|
|
212
216
|
"types": "./forms/input-number/index.d.ts",
|
|
213
217
|
"default": "./fesm2022/sd-angular-core-forms-input-number.mjs"
|
|
214
218
|
},
|
|
215
|
-
"./forms/models": {
|
|
216
|
-
"types": "./forms/models/index.d.ts",
|
|
217
|
-
"default": "./fesm2022/sd-angular-core-forms-models.mjs"
|
|
218
|
-
},
|
|
219
219
|
"./forms/label": {
|
|
220
220
|
"types": "./forms/label/index.d.ts",
|
|
221
221
|
"default": "./fesm2022/sd-angular-core-forms-label.mjs"
|
|
@@ -224,6 +224,10 @@
|
|
|
224
224
|
"types": "./forms/radio/index.d.ts",
|
|
225
225
|
"default": "./fesm2022/sd-angular-core-forms-radio.mjs"
|
|
226
226
|
},
|
|
227
|
+
"./forms/models": {
|
|
228
|
+
"types": "./forms/models/index.d.ts",
|
|
229
|
+
"default": "./fesm2022/sd-angular-core-forms-models.mjs"
|
|
230
|
+
},
|
|
227
231
|
"./forms/select": {
|
|
228
232
|
"types": "./forms/select/index.d.ts",
|
|
229
233
|
"default": "./fesm2022/sd-angular-core-forms-select.mjs"
|
|
@@ -236,14 +240,14 @@
|
|
|
236
240
|
"types": "./forms/textarea/index.d.ts",
|
|
237
241
|
"default": "./fesm2022/sd-angular-core-forms-textarea.mjs"
|
|
238
242
|
},
|
|
239
|
-
"./modules/auth": {
|
|
240
|
-
"types": "./modules/auth/index.d.ts",
|
|
241
|
-
"default": "./fesm2022/sd-angular-core-modules-auth.mjs"
|
|
242
|
-
},
|
|
243
243
|
"./modules/authom": {
|
|
244
244
|
"types": "./modules/authom/index.d.ts",
|
|
245
245
|
"default": "./fesm2022/sd-angular-core-modules-authom.mjs"
|
|
246
246
|
},
|
|
247
|
+
"./modules/auth": {
|
|
248
|
+
"types": "./modules/auth/index.d.ts",
|
|
249
|
+
"default": "./fesm2022/sd-angular-core-modules-auth.mjs"
|
|
250
|
+
},
|
|
247
251
|
"./modules/keycloak": {
|
|
248
252
|
"types": "./modules/keycloak/index.d.ts",
|
|
249
253
|
"default": "./fesm2022/sd-angular-core-modules-keycloak.mjs"
|
|
@@ -256,6 +260,10 @@
|
|
|
256
260
|
"types": "./modules/permission/index.d.ts",
|
|
257
261
|
"default": "./fesm2022/sd-angular-core-modules-permission.mjs"
|
|
258
262
|
},
|
|
263
|
+
"./components/side-drawer": {
|
|
264
|
+
"types": "./components/side-drawer/index.d.ts",
|
|
265
|
+
"default": "./fesm2022/sd-angular-core-components-side-drawer.mjs"
|
|
266
|
+
},
|
|
259
267
|
"./services/api": {
|
|
260
268
|
"types": "./services/api/index.d.ts",
|
|
261
269
|
"default": "./fesm2022/sd-angular-core-services-api.mjs"
|
|
@@ -272,22 +280,18 @@
|
|
|
272
280
|
"types": "./services/docx/index.d.ts",
|
|
273
281
|
"default": "./fesm2022/sd-angular-core-services-docx.mjs"
|
|
274
282
|
},
|
|
275
|
-
"./services/license": {
|
|
276
|
-
"types": "./services/license/index.d.ts",
|
|
277
|
-
"default": "./fesm2022/sd-angular-core-services-license.mjs"
|
|
278
|
-
},
|
|
279
283
|
"./services/excel": {
|
|
280
284
|
"types": "./services/excel/index.d.ts",
|
|
281
285
|
"default": "./fesm2022/sd-angular-core-services-excel.mjs"
|
|
282
286
|
},
|
|
287
|
+
"./services/license": {
|
|
288
|
+
"types": "./services/license/index.d.ts",
|
|
289
|
+
"default": "./fesm2022/sd-angular-core-services-license.mjs"
|
|
290
|
+
},
|
|
283
291
|
"./services/loading": {
|
|
284
292
|
"types": "./services/loading/index.d.ts",
|
|
285
293
|
"default": "./fesm2022/sd-angular-core-services-loading.mjs"
|
|
286
294
|
},
|
|
287
|
-
"./components/splitter": {
|
|
288
|
-
"types": "./components/splitter/index.d.ts",
|
|
289
|
-
"default": "./fesm2022/sd-angular-core-components-splitter.mjs"
|
|
290
|
-
},
|
|
291
295
|
"./services/notify": {
|
|
292
296
|
"types": "./services/notify/index.d.ts",
|
|
293
297
|
"default": "./fesm2022/sd-angular-core-services-notify.mjs"
|
|
Binary file
|
|
Binary file
|