@sdcorejs/angular 19.0.7 → 19.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/assets/STYLE-GUIDE.md +13 -0
- package/components/autoid-inspector/index.d.ts +1 -7
- package/components/autoid-inspector/src/autoid-inspector.component.d.ts +22 -8
- package/components/autoid-inspector/src/models/autoid-element.model.d.ts +7 -7
- package/components/autoid-inspector/src/models/autoid-export-format.model.d.ts +17 -8
- package/components/autoid-inspector/src/models/autoid-inspector-config.model.d.ts +10 -5
- package/components/autoid-inspector/src/services/autoid-audit.service.d.ts +4 -4
- package/components/autoid-inspector/src/services/autoid-export.service.d.ts +7 -6
- package/components/autoid-inspector/src/services/autoid-scanner.service.d.ts +3 -3
- package/components/table/src/components/filter/column-filter/column-filter.component.d.ts +0 -1
- package/components/table/src/services/table-filter/table-filter.service.d.ts +1 -0
- package/components/table/src/services/table-local/table-local.util.d.ts +19 -0
- package/components/table/src/services/table-reorder/table-reorder.util.d.ts +29 -0
- package/components/table/src/services/table-selection/table-selection.util.d.ts +8 -0
- package/components/table/src/services/tree/tree.util.d.ts +10 -1
- package/components/table/src/table.component.d.ts +6 -10
- package/fesm2022/sdcorejs-angular-components-anchor.mjs +2 -3
- package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +195 -25
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-badge.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-button.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs +5 -6
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-editor.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-inform.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-operator.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-preview.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs +8 -8
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-section.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +6 -4
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-table.mjs +772 -810
- package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tree.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs +6 -7
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +4 -5
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +3 -3
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +4 -4
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip.mjs +4 -4
- package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs +16 -9
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date.mjs +5 -6
- package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs +5 -6
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs +2 -2
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs +5 -6
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input.mjs +3 -3
- package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-radio.mjs +3 -4
- package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-select.mjs +2 -2
- package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-switch.mjs +3 -4
- package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs +5 -7
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-layout.mjs +2 -3
- package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-api.mjs +1 -2
- package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-confirm.mjs +2 -2
- package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
- package/forms/date-range/src/date-range.component.d.ts +2 -0
- package/forms/input-number/src/input-number.component.d.ts +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -365,7 +365,13 @@ option: SdTableOption<Product> = {
|
|
|
365
365
|
});
|
|
366
366
|
return { items: res.data, total: res.total };
|
|
367
367
|
},
|
|
368
|
-
columns: [
|
|
368
|
+
columns: [
|
|
369
|
+
{ field: 'code', type: 'string', title: 'Mã', width: '120px' },
|
|
370
|
+
{ field: 'name', type: 'string', title: 'Tên', sortable: true },
|
|
371
|
+
{ field: 'status', type: 'values', title: 'Trạng thái',
|
|
372
|
+
useBadge: (val) => ({ color: val === 'ACTIVE' ? 'success' : 'secondary', title: val })
|
|
373
|
+
},
|
|
374
|
+
],
|
|
369
375
|
command: {
|
|
370
376
|
align: 'right',
|
|
371
377
|
commands: [
|
|
@@ -737,4 +743,4 @@ Core UI components expose runtime state via lowercase `data-*` attributes for e2
|
|
|
737
743
|
|
|
738
744
|
## License
|
|
739
745
|
|
|
740
|
-
MIT - see the LICENSE file.
|
|
746
|
+
MIT - see the LICENSE file.
|
package/assets/STYLE-GUIDE.md
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
14. [Custom theme](#14-custom-theme)
|
|
23
23
|
15. [Fonts & Images shipped](#15-fonts--images-shipped)
|
|
24
24
|
16. [What is NOT shipped](#16-what-is-not-shipped) — anti-confusion cho AI
|
|
25
|
+
17. [AI rendering guardrails](#17-ai-rendering-guardrails) — ưu tiên Core UI trước khi viết CSS mới
|
|
25
26
|
|
|
26
27
|
---
|
|
27
28
|
|
|
@@ -605,3 +606,15 @@ Tham chiếu qua `core/image.scss` utility hoặc trực tiếp `assets/images/<
|
|
|
605
606
|
| `modal` | dùng `<sd-modal>` |
|
|
606
607
|
|
|
607
608
|
> Lưu ý lớn nhất: **spacing scale đã đổi từ Bootstrap multiplier (1=4px, 2=8px…) sang px tuyệt đối**. `mb-3` trong Bootstrap = 16px; trong `@sdcorejs/angular` `mb-3` = **3px**. Reading code cũ cần convert (× 4) cẩn thận hoặc thay bằng `mb-16`.
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
## 17. AI rendering guardrails
|
|
613
|
+
|
|
614
|
+
Khi sinh UI mới, agent phải rà docs Core UI trước và ưu tiên component/utility đã có thay vì tự tạo class SCSS trong component.
|
|
615
|
+
|
|
616
|
+
- **Spacing layout dùng bội số 4px**: ưu tiên `4`, `8`, `12`, `16`, `24`, `32`... cho margin, padding, gap, gutter. Không sinh spacing lẻ như `3px`, `5px`, `7px` trừ khi có yêu cầu pixel-perfect rõ ràng.
|
|
617
|
+
- **Hạn chế class CSS cục bộ**: trước khi viết `.field-label`, `.status-pill`, `.detail-row`, `.cell-input`..., kiểm tra có utility class hoặc component `sd-*` phù hợp không. Chỉ thêm SCSS mới khi Core UI không có pattern tương đương.
|
|
618
|
+
- **View/read-only label + value**: dùng `<sd-view>` hoặc `[viewed]="true"` trên form component. Không tự dựng cặp label/value bằng class riêng cho các màn hình DETAIL.
|
|
619
|
+
- **Trạng thái, nhãn, counter**: dùng `<sd-badge>` hoặc `useBadge` của `<sd-table>`. Không tự viết badge/pill/status class trong component nếu chỉ để thể hiện trạng thái.
|
|
620
|
+
- **Input trong table hoặc vùng dense**: trong `<sd-table>`, inline filter, editable cell, toolbar/cell dày đặc, truyền `size="sm"` cho các form component hỗ trợ size như `<sd-input>`, `<sd-select>`, `<sd-autocomplete>`, `<sd-date>`, `<sd-date-range>`, `<sd-datetime>`, `<sd-input-number>`, `<sd-textarea>`, `<sd-chip>`, `<sd-chip-calendar>`, `<sd-input-color>`.
|
|
@@ -1,8 +1,2 @@
|
|
|
1
1
|
export * from './src/autoid-inspector.component';
|
|
2
|
-
export
|
|
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';
|
|
2
|
+
export { SD_AUTOID_INSPECTOR_CONFIGURATION, type SdAutoidInspectorConfiguration } from './src/models/autoid-inspector-config.model';
|
|
@@ -1,32 +1,41 @@
|
|
|
1
1
|
import { OnDestroy } from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { AutoidElement, AutoidAuditResult } from './models/autoid-element.model';
|
|
3
|
+
import { SdAutoidInspectorConfiguration } from './models/autoid-inspector-config.model';
|
|
4
|
+
import { AutoidE2eTarget, AutoidRobotExportContext } from './models/autoid-export-format.model';
|
|
4
5
|
import * as i0 from "@angular/core";
|
|
5
6
|
type Segment = 'audit' | 'elements' | 'export';
|
|
7
|
+
type RobotContextField = keyof AutoidRobotExportContext;
|
|
6
8
|
export declare class SdAutoidInspector implements OnDestroy {
|
|
7
9
|
#private;
|
|
8
10
|
enabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
9
|
-
config: import("@angular/core").InputSignal<
|
|
11
|
+
config: import("@angular/core").InputSignal<SdAutoidInspectorConfiguration | undefined>;
|
|
10
12
|
open: import("@angular/core").WritableSignal<boolean>;
|
|
11
13
|
segment: import("@angular/core").WritableSignal<Segment>;
|
|
12
14
|
filter: import("@angular/core").WritableSignal<string>;
|
|
13
|
-
elements: import("@angular/core").WritableSignal<
|
|
14
|
-
audit: import("@angular/core").WritableSignal<
|
|
15
|
+
elements: import("@angular/core").WritableSignal<AutoidElement[]>;
|
|
16
|
+
audit: import("@angular/core").WritableSignal<AutoidAuditResult | null>;
|
|
15
17
|
copyOk: import("@angular/core").WritableSignal<boolean>;
|
|
18
|
+
e2eExporting: import("@angular/core").WritableSignal<AutoidE2eTarget | null>;
|
|
19
|
+
e2eExportOk: import("@angular/core").WritableSignal<string | null>;
|
|
20
|
+
e2eExportError: import("@angular/core").WritableSignal<string | null>;
|
|
21
|
+
robotContextOpen: import("@angular/core").WritableSignal<boolean>;
|
|
22
|
+
robotExportContext: import("@angular/core").WritableSignal<AutoidRobotExportContext>;
|
|
16
23
|
highlightOn: import("@angular/core").WritableSignal<boolean>;
|
|
17
24
|
dismissed: import("@angular/core").WritableSignal<boolean>;
|
|
18
|
-
|
|
25
|
+
readonly e2eGeneratorHost: import("@angular/core").Signal<string | undefined>;
|
|
26
|
+
readonly hasRobotExportContext: import("@angular/core").Signal<boolean>;
|
|
27
|
+
filteredElements: import("@angular/core").Signal<AutoidElement[]>;
|
|
19
28
|
/**
|
|
20
29
|
* Elements not inside any sd-table — rendered in the main "Top-level" section.
|
|
21
30
|
*/
|
|
22
|
-
readonly topLevelElements: import("@angular/core").Signal<
|
|
31
|
+
readonly topLevelElements: import("@angular/core").Signal<AutoidElement[]>;
|
|
23
32
|
/**
|
|
24
33
|
* Map of `sd-table` autoid → its inner autoid elements. Tables themselves
|
|
25
34
|
* stay in `topLevelElements` (the table's own autoid is top-level).
|
|
26
35
|
*/
|
|
27
36
|
readonly tableGroups: import("@angular/core").Signal<{
|
|
28
37
|
scope: string;
|
|
29
|
-
items:
|
|
38
|
+
items: AutoidElement[];
|
|
30
39
|
}[]>;
|
|
31
40
|
readonly dataOpened: import("@angular/core").Signal<"true" | "false">;
|
|
32
41
|
readonly dataHighlightOn: import("@angular/core").Signal<"true" | "false">;
|
|
@@ -48,6 +57,11 @@ export declare class SdAutoidInspector implements OnDestroy {
|
|
|
48
57
|
exportJson: () => void;
|
|
49
58
|
exportMdPom: () => void;
|
|
50
59
|
exportMdTable: () => void;
|
|
60
|
+
openRobotExportContext: () => void;
|
|
61
|
+
closeRobotExportContext: () => void;
|
|
62
|
+
updateRobotExportContext: (field: RobotContextField, value: string) => void;
|
|
63
|
+
confirmRobotExport: () => Promise<void>;
|
|
64
|
+
exportE2eTest: (target: AutoidE2eTarget, context?: AutoidRobotExportContext) => Promise<boolean>;
|
|
51
65
|
onEscape(): void;
|
|
52
66
|
static ɵfac: i0.ɵɵFactoryDeclaration<SdAutoidInspector, never>;
|
|
53
67
|
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>;
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* Every field is OPTIONAL — only present when the component actually renders that attribute.
|
|
4
4
|
* All values are the raw DOM string (already "true"/"false" or stringified number/value).
|
|
5
5
|
*/
|
|
6
|
-
export interface
|
|
6
|
+
export interface AutoidElementState {
|
|
7
7
|
disabled?: string;
|
|
8
8
|
loading?: string;
|
|
9
9
|
empty?: string;
|
|
10
10
|
invalid?: string;
|
|
11
11
|
opened?: string;
|
|
12
12
|
count?: string;
|
|
13
|
-
/** Serialized DOM `data-value` (NOT `input.value`). Distinct from `
|
|
13
|
+
/** Serialized DOM `data-value` (NOT `input.value`). Distinct from `AutoidElement.text` field. */
|
|
14
14
|
dataValue?: string;
|
|
15
15
|
required?: string;
|
|
16
16
|
maxlength?: string;
|
|
@@ -21,7 +21,7 @@ export interface SdAutoidElementState {
|
|
|
21
21
|
title?: string;
|
|
22
22
|
message?: string;
|
|
23
23
|
}
|
|
24
|
-
export interface
|
|
24
|
+
export interface AutoidElement {
|
|
25
25
|
stt: number;
|
|
26
26
|
name: string;
|
|
27
27
|
autoid: string;
|
|
@@ -35,7 +35,7 @@ export interface SdAutoidElement {
|
|
|
35
35
|
xpath: string;
|
|
36
36
|
duplicate: boolean;
|
|
37
37
|
/** Runtime state attributes read from the DOM. Always an object — may be empty `{}`. */
|
|
38
|
-
state:
|
|
38
|
+
state: AutoidElementState;
|
|
39
39
|
/**
|
|
40
40
|
* `data-autoid` of the closest ancestor `<sd-table>` that contains this element,
|
|
41
41
|
* or `undefined` if this element is top-level (not inside any `sd-table`).
|
|
@@ -51,16 +51,16 @@ export interface SdAutoidElement {
|
|
|
51
51
|
/** Human-readable warning attached to a fallback element (only set when `missingAutoid`). */
|
|
52
52
|
warning?: string;
|
|
53
53
|
}
|
|
54
|
-
export interface
|
|
54
|
+
export interface AutoidMissing {
|
|
55
55
|
tag: string;
|
|
56
56
|
selector: string;
|
|
57
57
|
outerHtmlPreview: string;
|
|
58
58
|
nameHint: string;
|
|
59
59
|
}
|
|
60
|
-
export interface
|
|
60
|
+
export interface AutoidAuditResult {
|
|
61
61
|
total: number;
|
|
62
62
|
duplicates: Record<string, number>;
|
|
63
63
|
duplicateCount: number;
|
|
64
|
-
missing:
|
|
64
|
+
missing: AutoidMissing[];
|
|
65
65
|
missingCount: number;
|
|
66
66
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export interface
|
|
3
|
-
|
|
1
|
+
export type AutoidE2eTarget = 'playwright' | 'robot';
|
|
2
|
+
export interface AutoidRobotExportContext {
|
|
3
|
+
requirement?: string;
|
|
4
|
+
testCases?: string;
|
|
5
|
+
testData?: string;
|
|
6
|
+
precondition?: string;
|
|
7
|
+
component?: string;
|
|
8
|
+
storyLinkages?: string;
|
|
9
|
+
qcNotes?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AutoidExportMeta {
|
|
12
|
+
/** `location.pathname + location.search`, kept for back-compat with MD exports. */
|
|
4
13
|
pageUrl: string;
|
|
5
14
|
pageTitle: string;
|
|
6
15
|
timestamp: string;
|
|
@@ -10,16 +19,16 @@ export interface SdAutoidExportMeta {
|
|
|
10
19
|
pathname: string;
|
|
11
20
|
/** Raw `location.search` (incl. leading `?`), or `''`. */
|
|
12
21
|
search: string;
|
|
13
|
-
/** Parsed query string
|
|
22
|
+
/** Parsed query string as key/value map (last value wins on repeats). */
|
|
14
23
|
queryParams: Record<string, string>;
|
|
15
24
|
/**
|
|
16
|
-
* Angular route path params (`:id`,
|
|
25
|
+
* Angular route path params (`:id`, etc.) merged across the activated-route tree.
|
|
17
26
|
* Only present when an Angular `Router` is available at scan time; omitted otherwise.
|
|
18
27
|
*/
|
|
19
28
|
params?: Record<string, string>;
|
|
20
29
|
}
|
|
21
30
|
/** JSON export envelope: page meta + the scanned elements. */
|
|
22
|
-
export interface
|
|
23
|
-
meta:
|
|
24
|
-
elements: import('./autoid-element.model').
|
|
31
|
+
export interface AutoidExportJson {
|
|
32
|
+
meta: AutoidExportMeta;
|
|
33
|
+
elements: import('./autoid-element.model').AutoidElement[];
|
|
25
34
|
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
export interface SdAutoidInspectorConfiguration {
|
|
3
|
+
/** Base URL cua backend sinh E2E test, vi du `http://localhost:3012`. */
|
|
4
|
+
host?: string;
|
|
5
|
+
/** Selector phu them can audit (mac dinh component da cover sd-* form + sd-button). */
|
|
3
6
|
extraRequireSelectors?: string[];
|
|
4
|
-
/** Root scan,
|
|
7
|
+
/** Root scan, mac dinh document.body. */
|
|
5
8
|
root?: HTMLElement;
|
|
6
9
|
}
|
|
7
|
-
/**
|
|
8
|
-
export declare const
|
|
10
|
+
/** Cau hinh global cho AutoId Inspector. `[config]` tren component co the override theo instance. */
|
|
11
|
+
export declare const SD_AUTOID_INSPECTOR_CONFIGURATION: InjectionToken<SdAutoidInspectorConfiguration>;
|
|
12
|
+
/** Selector mac dinh coi la phai co data-autoid. */
|
|
13
|
+
export declare const AUTOID_DEFAULT_REQUIRE_SELECTORS: readonly string[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AutoidElement, AutoidAuditResult } from '../models/autoid-element.model';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
export declare class SdAutoidAuditService {
|
|
4
4
|
/**
|
|
@@ -6,10 +6,10 @@ export declare class SdAutoidAuditService {
|
|
|
6
6
|
* - duplicates: map autoid → count khi count > 1
|
|
7
7
|
* - missing: element khớp selector yêu cầu nhưng KHÔNG có [data-autoid]
|
|
8
8
|
*/
|
|
9
|
-
audit(elements:
|
|
10
|
-
requireSelectors?:
|
|
9
|
+
audit(elements: AutoidElement[], options?: {
|
|
10
|
+
requireSelectors?: readonly string[];
|
|
11
11
|
root?: HTMLElement;
|
|
12
|
-
}):
|
|
12
|
+
}): AutoidAuditResult;
|
|
13
13
|
private findMissing;
|
|
14
14
|
private buildSelectorPath;
|
|
15
15
|
private shortHtml;
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { AutoidElement } from '../models/autoid-element.model';
|
|
2
|
+
import { AutoidExportMeta } from '../models/autoid-export-format.model';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
export declare class SdAutoidExportService {
|
|
5
5
|
/**
|
|
6
6
|
* Có `meta` → bọc `{ meta, elements }` (kèm url/queryParams) để consumer biết trang/route.
|
|
7
7
|
* Không `meta` → giữ mảng thuần (back-compat cho caller cũ chỉ cần elements).
|
|
8
8
|
*/
|
|
9
|
-
toJson(elements:
|
|
9
|
+
toJson(elements: AutoidElement[], meta?: AutoidExportMeta): string;
|
|
10
10
|
/** Parse a `location.search` string into a flat key/value map (last value wins). */
|
|
11
11
|
parseQueryParams(search: string): Record<string, string>;
|
|
12
|
-
toCsv(elements:
|
|
12
|
+
toCsv(elements: AutoidElement[]): string;
|
|
13
13
|
/** POM TypeScript skeleton — copy ngay vào file Playwright/Cypress. */
|
|
14
|
-
toMarkdownPom(elements:
|
|
14
|
+
toMarkdownPom(elements: AutoidElement[], meta: AutoidExportMeta): string;
|
|
15
15
|
/** Markdown reference table, group FIRST by tableScope (top-level first, then per table), then by tag. */
|
|
16
|
-
toMarkdownTable(elements:
|
|
16
|
+
toMarkdownTable(elements: AutoidElement[], meta: AutoidExportMeta): string;
|
|
17
17
|
download(content: string, filename: string, mime: string): void;
|
|
18
|
+
downloadBlob(blob: Blob, filename: string): void;
|
|
18
19
|
copyToClipboard(content: string): Promise<void>;
|
|
19
20
|
/** Build a compact state summary string from defined state keys, e.g. "disabled=false; empty=true". */
|
|
20
21
|
private buildStateSummary;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AutoidElement } from '../models/autoid-element.model';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
export declare class SdAutoidScannerService {
|
|
4
4
|
/**
|
|
@@ -8,7 +8,7 @@ export declare class SdAutoidScannerService {
|
|
|
8
8
|
* (`autoid: ''`, xpath theo vị trí thẻ + cờ `missingAutoid` + warning) — để JSON xuất ra
|
|
9
9
|
* vẫn dùng được và dev biết chỗ cần bổ sung autoid.
|
|
10
10
|
*/
|
|
11
|
-
scan(root?: HTMLElement, requireSelectors?:
|
|
11
|
+
scan(root?: HTMLElement, requireSelectors?: readonly string[]): AutoidElement[];
|
|
12
12
|
/**
|
|
13
13
|
* Tìm các node khớp `requireSelectors` nhưng thiếu data-autoid (self + mọi descendant),
|
|
14
14
|
* thêm vào `result` dưới dạng phần tử fallback. Trả về `stt` kế tiếp.
|
|
@@ -17,7 +17,7 @@ export declare class SdAutoidScannerService {
|
|
|
17
17
|
/** XPath theo vị trí thẻ trong document, vd `(//sd-button)[2]`, khi không có autoid. */
|
|
18
18
|
private fallbackXpath;
|
|
19
19
|
/** Group element theo autoid để consumer lấy duplicate map. */
|
|
20
|
-
groupByAutoid(elements:
|
|
20
|
+
groupByAutoid(elements: AutoidElement[]): Record<string, AutoidElement[]>;
|
|
21
21
|
/**
|
|
22
22
|
* Read the optional `data-*` E2E state attributes off the same node.
|
|
23
23
|
* Only includes fields actually present on the DOM (skipped fields stay undefined).
|
|
@@ -22,7 +22,6 @@ export declare class ColumnFilterComponent {
|
|
|
22
22
|
display: string;
|
|
23
23
|
}[]>;
|
|
24
24
|
operatorValues: Signal<Operator[]>;
|
|
25
|
-
operatorWrapperClass: Signal<"mb-4 mr-2" | "mr-2">;
|
|
26
25
|
items: Signal<any[] | SdSearch | Signal<any[]>>;
|
|
27
26
|
constructor();
|
|
28
27
|
onFilterChange: () => void;
|
|
@@ -14,6 +14,7 @@ export declare class SdTableFilterService {
|
|
|
14
14
|
externalFilters: SdTableExternalFilter[] | undefined;
|
|
15
15
|
filterDefs: SdTableFilterDefDirective[] | undefined;
|
|
16
16
|
columnOperator?: Record<string, Operator>;
|
|
17
|
+
force?: boolean;
|
|
17
18
|
}) => TableFilterRegister;
|
|
18
19
|
static ɵfac: i0.ɵɵFactoryDeclaration<SdTableFilterService, never>;
|
|
19
20
|
static ɵprov: i0.ɵɵInjectableDeclaration<SdTableFilterService>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SdTableColumn } from '../../models/table-column.model';
|
|
2
|
+
import { SdTableItem } from '../../models/table-item.model';
|
|
3
|
+
import { SdTableOptionTree } from '../../models/table-option-tree.model';
|
|
4
|
+
import { SdTableFilterRequest } from '../table-filter/table-filter.model';
|
|
5
|
+
export interface FilterLocalItemsOption<T> {
|
|
6
|
+
type: 'local' | 'server';
|
|
7
|
+
columns: SdTableColumn<T>[];
|
|
8
|
+
tree?: SdTableOptionTree<T>;
|
|
9
|
+
}
|
|
10
|
+
export interface FilterLocalItemsResult<T, TItem> {
|
|
11
|
+
items: TItem[];
|
|
12
|
+
total: number;
|
|
13
|
+
treeSearchPredicate?: (data: T) => boolean;
|
|
14
|
+
}
|
|
15
|
+
type LocalFilterItem<T> = SdTableItem<T> | T;
|
|
16
|
+
export declare const hasActiveColumnFilter: <T>(rawColumnFilter?: Partial<Record<string, any>>, columns?: SdTableColumn<T>[]) => boolean;
|
|
17
|
+
export declare const matchesColumnFilter: <T>(data: T, columns?: SdTableColumn<T>[], rawColumnFilter?: Partial<Record<string, any>>) => boolean;
|
|
18
|
+
export declare const filterLocalItems: <T, TItem extends LocalFilterItem<T>>(localItems: TItem[], option: FilterLocalItemsOption<T>, filterInfo: SdTableFilterRequest<T>) => FilterLocalItemsResult<T, TItem>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SdTableItem } from '../../models/table-item.model';
|
|
2
|
+
export interface TableReorderOption<T> {
|
|
3
|
+
disabled?: (row: T, index: number) => boolean;
|
|
4
|
+
}
|
|
5
|
+
export interface CanSortReorderArgs<T> {
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
index: number;
|
|
8
|
+
dragItem: SdTableItem<T>;
|
|
9
|
+
allItems?: SdTableItem<T>[];
|
|
10
|
+
hasGroup?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface ReorderTableItemsArgs<T> {
|
|
13
|
+
items: SdTableItem<T>[];
|
|
14
|
+
renderedItems: SdTableItem<T>[];
|
|
15
|
+
previousRenderedIndex: number;
|
|
16
|
+
currentRenderedIndex: number;
|
|
17
|
+
localItems?: SdTableItem<T>[];
|
|
18
|
+
}
|
|
19
|
+
export interface ReorderTableItemsResult<T> {
|
|
20
|
+
items: SdTableItem<T>[];
|
|
21
|
+
localItems?: SdTableItem<T>[];
|
|
22
|
+
fromIndex: number;
|
|
23
|
+
toIndex: number;
|
|
24
|
+
}
|
|
25
|
+
export declare const isReorderDisabled: <T>(item: SdTableItem<T>, option?: TableReorderOption<T>, index?: number) => boolean;
|
|
26
|
+
export declare const sameReorderGroup: <T>(a: SdTableItem<T>, b: SdTableItem<T>, allItems: SdTableItem<T>[]) => boolean;
|
|
27
|
+
export declare const canSortReorder: <T>({ enabled, index, dragItem, allItems, hasGroup }: CanSortReorderArgs<T>) => boolean;
|
|
28
|
+
export declare const toReorderItemsIndex: <T>(renderedItems: SdTableItem<T>[], renderedIndex: number) => number;
|
|
29
|
+
export declare const reorderTableItems: <T>({ items, renderedItems, previousRenderedIndex, currentRenderedIndex, localItems, }: ReorderTableItemsArgs<T>) => ReorderTableItemsResult<T>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SdTableItem } from '../../models/table-item.model';
|
|
2
|
+
import { SdTableOptionTree } from '../../models/table-option-tree.model';
|
|
3
|
+
export declare const getSelectionRows: <T>(roots: SdTableItem<T>[], treeOpt?: SdTableOptionTree<T>) => SdTableItem<T>[];
|
|
4
|
+
export declare const getSelectedRowData: <T>(rows: SdTableItem<T>[]) => T[];
|
|
5
|
+
export declare const applyDefaultSelected: <T>(roots: SdTableItem<T>[], treeOpt: SdTableOptionTree<T> | undefined, defaultSelected?: (row: T) => boolean) => void;
|
|
6
|
+
export declare const resolveSelectAllState: <T>(visibleRows: SdTableItem<T>[]) => boolean;
|
|
7
|
+
export declare const restorePreservedSelection: <T>(visibleRows: SdTableItem<T>[], preservedSelectedMap: Map<string, SdTableItem<T>>) => void;
|
|
8
|
+
export declare const syncPreservedSelection: <T>(visibleRows: SdTableItem<T>[], preservedSelectedMap: Map<string, SdTableItem<T>>) => SdTableItem<T>[];
|
|
@@ -6,7 +6,7 @@ import { SdTableItem } from '../../models/table-item.model';
|
|
|
6
6
|
* thay vì truy cập `option.onExpandChildren` trực tiếp trên union (chỉ tồn tại
|
|
7
7
|
* ở nhánh lazy).
|
|
8
8
|
*/
|
|
9
|
-
export declare const isLazyTree: <T =
|
|
9
|
+
export declare const isLazyTree: <T = unknown>(option?: SdTableOptionTree<T>) => option is TableOptionTreeLazy<T>;
|
|
10
10
|
/**
|
|
11
11
|
* Key chứa mảng children trên object row.
|
|
12
12
|
* - `static`: lấy `childrenKey` đã cấu hình, mặc định `'children'`.
|
|
@@ -46,6 +46,15 @@ export declare const subtreeMatches: <T>(data: T, predicate: (data: T) => boolea
|
|
|
46
46
|
* bị mất khi từ khoá search đổi. Đây là bước "prune" của tính năng search-con.
|
|
47
47
|
*/
|
|
48
48
|
export declare const filterMatchingChildren: <T>(children: T[], predicate: (data: T) => boolean, option?: SdTableOptionTree) => T[];
|
|
49
|
+
export declare const getVisibleChildrenData: <T>(data: T, option: SdTableOptionTree<T>, predicate?: (data: T) => boolean) => T[];
|
|
50
|
+
export declare const saveTreeExpandState: <T>(rows: SdTableItem<T>[], expandState: Map<string, boolean>) => void;
|
|
51
|
+
export declare const clearTreeChildCache: <T>(rows: SdTableItem<T>[]) => void;
|
|
52
|
+
export declare const initTreeMeta: <T>(rows: SdTableItem<T>[], option: SdTableOptionTree<T>, args?: {
|
|
53
|
+
expandState?: Map<string, boolean>;
|
|
54
|
+
treeSearchPredicate?: (data: T) => boolean;
|
|
55
|
+
level?: number;
|
|
56
|
+
parentId?: string;
|
|
57
|
+
}) => void;
|
|
49
58
|
export declare const flattenTree: <T>(roots: SdTableItem<T>[], option?: SdTableOptionTree, visited?: Set<string>) => SdTableItem<T>[];
|
|
50
59
|
/** Thu thập mọi SdTableItem đã format trong cây (kể cả node đang collapse). */
|
|
51
60
|
export declare const collectFormattedTreeRows: <T>(roots: SdTableItem<T>[]) => SdTableItem<T>[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AfterViewInit, OnDestroy
|
|
1
|
+
import { AfterViewInit, OnDestroy } from '@angular/core';
|
|
2
2
|
import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
|
|
3
3
|
import { MatSort } from '@angular/material/sort';
|
|
4
4
|
import { MatTable } from '@angular/material/table';
|
|
@@ -11,7 +11,7 @@ import { SdMaterialFooterDefDirective } from './directives/sd-table-footer-def.d
|
|
|
11
11
|
import { SdTableTitleDefDirective } from './directives/sd-table-title-def.directive';
|
|
12
12
|
import { SdTableColumn } from './models/table-column.model';
|
|
13
13
|
import { SdTableOption } from './models/table-option.model';
|
|
14
|
-
import { SdTableFilterRequest, TableFilterRegister } from './services/table-filter/table-filter.model';
|
|
14
|
+
import { SdTableFilterRequest, TableFilterRegister, TableFilterValue } from './services/table-filter/table-filter.model';
|
|
15
15
|
import { CdkDrag, CdkDragDrop, CdkDropList } from '@angular/cdk/drag-drop';
|
|
16
16
|
import { SdQuickAction } from '@sdcorejs/angular/components/quick-action';
|
|
17
17
|
import { SdScrollDirective } from '@sdcorejs/angular/directives';
|
|
@@ -34,7 +34,7 @@ export declare class MatPaginatorIntlCro extends MatPaginatorIntl {
|
|
|
34
34
|
static ɵfac: i0.ɵɵFactoryDeclaration<MatPaginatorIntlCro, never>;
|
|
35
35
|
static ɵprov: i0.ɵɵInjectableDeclaration<MatPaginatorIntlCro>;
|
|
36
36
|
}
|
|
37
|
-
export declare class SdTable<T = unknown> implements
|
|
37
|
+
export declare class SdTable<T = unknown> implements AfterViewInit, OnDestroy {
|
|
38
38
|
#private;
|
|
39
39
|
autoIdInput: import("@angular/core").InputSignal<string | null | undefined>;
|
|
40
40
|
autoId: import("@angular/core").Signal<string | undefined>;
|
|
@@ -70,14 +70,13 @@ export declare class SdTable<T = unknown> implements OnInit, AfterViewInit, OnDe
|
|
|
70
70
|
filterRegister: TableFilterRegister;
|
|
71
71
|
key: string;
|
|
72
72
|
columnOperator: Record<string, Operator>;
|
|
73
|
-
columnFilter?:
|
|
74
|
-
cacheValues: Record<string,
|
|
73
|
+
columnFilter?: NonNullable<TableFilterValue['columnFilter']>;
|
|
74
|
+
cacheValues: Record<string, unknown[]>;
|
|
75
75
|
treeRevision: import("@angular/core").WritableSignal<number>;
|
|
76
76
|
exporting: import("@angular/core").WritableSignal<boolean>;
|
|
77
77
|
exportTitle: import("@angular/core").WritableSignal<string>;
|
|
78
78
|
tableConfiguration: ISdTableConfiguration | null;
|
|
79
79
|
constructor();
|
|
80
|
-
ngOnInit(): void;
|
|
81
80
|
ngAfterViewInit(): void;
|
|
82
81
|
ngOnDestroy(): void;
|
|
83
82
|
getFilterRequest: () => SdTableFilterRequest;
|
|
@@ -117,10 +116,7 @@ export declare class SdTable<T = unknown> implements OnInit, AfterViewInit, OnDe
|
|
|
117
116
|
groupContext: (header: SdTableItem<T>) => SdTableGroupDefContext<T>;
|
|
118
117
|
rowStyle: (row: SdTableItem<T>, index?: number) => Record<string, string> | null;
|
|
119
118
|
clearFilter: () => void;
|
|
120
|
-
setFilter: (args
|
|
121
|
-
columnFilter?: Record<string, any>;
|
|
122
|
-
externalFilter?: Record<string, any>;
|
|
123
|
-
}) => void;
|
|
119
|
+
setFilter: (args?: Pick<TableFilterValue, "columnFilter" | "externalFilter">) => void;
|
|
124
120
|
get dataItems(): T[];
|
|
125
121
|
get selectedItems(): T[];
|
|
126
122
|
detectChanges: () => void;
|
|
@@ -2,8 +2,7 @@ import * as i1$1 from '@angular/common';
|
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { input, inject, ElementRef, effect, Component, computed, output, ChangeDetectionStrategy, viewChild, contentChildren, booleanAttribute, signal, afterNextRender, untracked } from '@angular/core';
|
|
5
|
-
import {
|
|
6
|
-
import { BrowserUtilities } from '@sdcorejs/utils/fns';
|
|
5
|
+
import { Utilities, BrowserUtilities } from '@sdcorejs/utils/fns';
|
|
7
6
|
import { Subject, Subscription, debounceTime, fromEvent, take } from 'rxjs';
|
|
8
7
|
import * as i1 from '@angular/material/icon';
|
|
9
8
|
import { MatIconModule } from '@angular/material/icon';
|
|
@@ -13,7 +12,7 @@ class SdAnchorItem {
|
|
|
13
12
|
icon = input();
|
|
14
13
|
// Stable key dùng cho data-autoId. Nếu không truyền thì fallback về uuid (không stable giữa các lần render).
|
|
15
14
|
key = input(undefined);
|
|
16
|
-
id =
|
|
15
|
+
id = Utilities.generateUuid();
|
|
17
16
|
elementRef = inject(ElementRef);
|
|
18
17
|
constructor() {
|
|
19
18
|
effect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdcorejs-angular-components-anchor.mjs","sources":["../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-item/anchor-item.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-item/anchor-item.component.html","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-nav/anchor-nav.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-nav/anchor-nav.component.html","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor/anchor.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor/anchor.component.html","../../../projects/sdcorejs-angular/components/anchor/sdcorejs-angular-components-anchor.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, ElementRef, effect, inject, input } from '@angular/core';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IAnchorItem } from '../../models';\n\n@Component({\n selector: 'sd-anchor-item',\n templateUrl: './anchor-item.component.html',\n styleUrls: ['./anchor-item.component.scss'],\n imports: [CommonModule],\n standalone: true,\n})\nexport class SdAnchorItem implements IAnchorItem {\n title = input.required<string>();\n icon = input<string | undefined>();\n // Stable key dùng cho data-autoId. Nếu không truyền thì fallback về uuid (không stable giữa các lần render).\n key = input<string | undefined>(undefined);\n id: string = uuidv4();\n elementRef = inject(ElementRef);\n\n constructor() {\n effect(() => {\n if (this.title()) {\n this.elementRef.nativeElement.removeAttribute('title');\n }\n });\n }\n}\n","<section>\n <ng-content></ng-content>\n</section>\n","import { ChangeDetectionStrategy, Component, OnDestroy, computed, input, output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MatIconModule } from '@angular/material/icon';\nimport { Color } from '@sdcorejs/utils/models';\nimport { Subject, Subscription, debounceTime } from 'rxjs';\n\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\n\n@Component({\n selector: 'anchor-nav',\n templateUrl: './anchor-nav.component.html',\n styleUrl: './anchor-nav.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, MatIconModule],\n standalone: true,\n})\n// eslint-disable-next-line @angular-eslint/component-class-suffix\nexport class AnchorNav implements OnDestroy {\n sections = input.required<readonly SdAnchorItem[]>();\n activeSectionId = input<string>('');\n ellipsis = input<boolean>(false);\n sidebarWidth = input<string>('');\n // autoId được forward từ <sd-anchor>. Derive per-item autoId theo `key` của item (nếu có).\n parentAutoId = input<string | undefined | null>(undefined);\n color = input<Color>('primary');\n\n // CSS var binding cho active state — map SdColor → global token `--sd-{color}`.\n // SCSS đọc qua `var(--anchor-active-color)` cho border + text + icon.\n cssActiveVar = computed(() => `var(--sd-${this.color()})`);\n\n itemAutoId(section: SdAnchorItem): string | undefined {\n const parent = this.parentAutoId();\n const key = section.key();\n return parent && key ? `${parent}-${key}` : undefined;\n }\n\n clickSection = output<string>();\n\n #delay = 200;\n #clickSectionSubject = new Subject<string>();\n #subscription = new Subscription();\n\n constructor() {\n this.#subscription.add(\n this.#clickSectionSubject\n .pipe(debounceTime(this.#delay))\n .subscribe((id: string) => this.clickSection.emit(id))\n );\n }\n\n onClickSection = (id: string): void => {\n this.#clickSectionSubject.next(id);\n };\n\n ngOnDestroy(): void {\n this.#subscription.unsubscribe();\n }\n}\n","<div\n class=\"c-anchor-list\"\n [style.width]=\"sidebarWidth()\"\n [style.--anchor-active-color]=\"cssActiveVar()\">\n @for (section of sections(); track section.id) {\n <div\n class=\"c-anchor-list-item\"\n [class.active]=\"section.id === activeSectionId()\"\n (click)=\"onClickSection(section.id)\"\n (keydown.enter)=\"onClickSection(section.id)\"\n [attr.data-autoId]=\"itemAutoId(section)\"\n tabindex=\"0\">\n @if (section.icon()) {\n <mat-icon class=\"c-anchor-list-item-icon\">{{ section.icon() }}</mat-icon>\n }\n <div class=\"c-anchor-list-item-text\" [class.ellipsis]=\"ellipsis()\">\n {{ section.title() }}\n </div>\n </div>\n }\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n OnDestroy,\n afterNextRender,\n booleanAttribute,\n computed,\n contentChildren,\n effect,\n input,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { BrowserUtilities } from '@sdcorejs/utils/fns';\nimport { Color } from '@sdcorejs/utils/models';\nimport { Subscription, fromEvent, take } from 'rxjs';\nimport { AnchorNav } from '../anchor-nav/anchor-nav.component';\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\n\n@Component({\n selector: 'sd-anchor',\n templateUrl: './anchor.component.html',\n styleUrls: ['./anchor.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, AnchorNav],\n standalone: true,\n})\nexport class SdAnchor implements OnDestroy {\n wrapper = viewChild.required<ElementRef>('wrapper');\n sections = contentChildren(SdAnchorItem);\n\n readonly autoIdInput = input<string | undefined | null>(undefined, { alias: 'autoId' });\n readonly autoId = computed(() => (this.autoIdInput() ? `components-anchor-${this.autoIdInput()}` : undefined));\n\n sidebarWidth = input<string>('200px');\n ellipsis = input(false, { transform: booleanAttribute });\n overScroll = input(false, { transform: booleanAttribute });\n // Mobile: default ẩn nav (sidebar TOC chiếm chỗ trên màn hình hẹp).\n // Consumer truyền `[hideNav]=\"false\"` để force hiện trên mobile.\n hideNav = input(BrowserUtilities.isMobile(), { transform: booleanAttribute });\n // Màu highlight active nav (text + icon + vertical bar). Default 'primary'.\n color = input<Color>('primary');\n\n activeSectionId = signal<string>('');\n\n #initialized = false;\n #isClickScrolling = false;\n #clickScrollSubscription: Subscription | null = null;\n #intersectionObserver: IntersectionObserver | null = null;\n #visibleSections = new Set<Element>();\n #timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n #timeoutScrollFallback = 200;\n\n constructor() {\n afterNextRender(() => {\n this.#initialized = true;\n if (!this.hideNav()) {\n this.#registerIntersectionObserver();\n }\n });\n\n // Lắng nghe thay đổi sections để đăng ký lại observe section\n effect(() => {\n this.sections();\n if (!this.hideNav() && this.#initialized) {\n untracked(() => this.#registerIntersectionObserver());\n }\n });\n }\n\n #registerIntersectionObserver(): void {\n this.#cleanIntersectionObserver();\n const wrapperEl = this.wrapper().nativeElement;\n\n // Brower API IntersectionObserver sẽ hỗ trợ khi nào 1 section được hiện ra trong wrapperEl\n this.#intersectionObserver = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n // Nếu section mới đi vào vùng nhìn thấy -> add vào set\n this.#visibleSections.add(entry.target);\n } else {\n // Nếu section đã đi ra khỏi vùng nhìn thấy -> xóa khỏi Set\n this.#visibleSections.delete(entry.target);\n }\n }\n\n // Nếu đang scroll bởi click section thì return luôn, k phải quét qua tìm vùng section được active\n if (this.#isClickScrolling) {\n return;\n }\n\n for (const section of this.sections()) {\n // Kiểm tra xem DOM của section nào đang nằm trong danh sách đang nhìn thấy để active chính xác\n if (this.#visibleSections.has(section.elementRef.nativeElement)) {\n if (this.activeSectionId() !== section.id) {\n this.activeSectionId.set(section.id);\n }\n break;\n }\n }\n },\n { root: wrapperEl, threshold: 0 }\n );\n\n // Đăng ký theo dõi từng section có trong anchor\n for (const section of this.sections()) {\n this.#intersectionObserver.observe(section.elementRef.nativeElement);\n }\n }\n\n scrollSectionByClick(idSectionTarget: string): void {\n this.activeSectionId.set(idSectionTarget);\n const targetSection = this.sections().find(s => s.id === idSectionTarget)?.elementRef;\n if (!targetSection) {\n return;\n }\n this.#cleanScrollSectionByClickObserver();\n this.#isClickScrolling = true;\n\n const wrapperEl = this.wrapper().nativeElement;\n const targetElement = targetSection.nativeElement;\n\n const prevScrollTop = wrapperEl.scrollTop; // Lưu lại vị trí cuộn hiện tại của container\n const scrollTop = prevScrollTop + targetElement.getBoundingClientRect().top - wrapperEl.getBoundingClientRect().top; // Vị trí section cần scroll tới\n\n // Đăng ký sự kiện nếu đã được scroll xong\n this.#clickScrollSubscription = fromEvent(wrapperEl, 'scrollend')\n .pipe(take(1))\n .subscribe(() => {\n this.#isClickScrolling = false;\n });\n\n // Nếu sectionTarget đã ở đúng vị trí (click nhưng không scroll) thì sau #timeoutScrollFallback kích hoạt lại IntersectionObserver\n this.#timeoutId = setTimeout(() => {\n if (wrapperEl.scrollTop === prevScrollTop) {\n this.#isClickScrolling = false;\n this.#clickScrollSubscription?.unsubscribe();\n }\n }, this.#timeoutScrollFallback);\n\n wrapperEl.scrollTo({ top: scrollTop, behavior: 'smooth' });\n }\n\n #cleanScrollSectionByClickObserver = (): void => {\n if (this.#timeoutId) {\n clearTimeout(this.#timeoutId);\n }\n this.#clickScrollSubscription?.unsubscribe();\n };\n\n #cleanIntersectionObserver = (): void => {\n this.#intersectionObserver?.disconnect();\n this.#visibleSections.clear();\n };\n\n ngOnDestroy(): void {\n this.#cleanScrollSectionByClickObserver();\n this.#cleanIntersectionObserver();\n }\n}\n","<div class=\"c-anchor-vertical\" [ngClass]=\"{ 'c-stop-scroll-propagation': !overScroll() }\" #wrapper>\n <div class=\"c-anchor-content\">\n <ng-content></ng-content>\n </div>\n\n @if (!hideNav()) {\n <div class=\"c-anchor-list\" [style.flex-basis]=\"sidebarWidth()\">\n <anchor-nav\n [sections]=\"sections()\"\n [ellipsis]=\"ellipsis()\"\n [sidebarWidth]=\"sidebarWidth()\"\n [activeSectionId]=\"activeSectionId()\"\n [parentAutoId]=\"autoId()\"\n [color]=\"color()\"\n (clickSection)=\"scrollSectionByClick($event)\">\n </anchor-nav>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["uuidv4"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sdcorejs-angular-components-anchor.mjs","sources":["../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-item/anchor-item.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-item/anchor-item.component.html","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-nav/anchor-nav.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-nav/anchor-nav.component.html","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor/anchor.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor/anchor.component.html","../../../projects/sdcorejs-angular/components/anchor/sdcorejs-angular-components-anchor.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, ElementRef, effect, inject, input } from '@angular/core';\nimport { IAnchorItem } from '../../models';\nimport { Utilities } from '@sdcorejs/utils/fns';\n\n@Component({\n selector: 'sd-anchor-item',\n templateUrl: './anchor-item.component.html',\n styleUrls: ['./anchor-item.component.scss'],\n imports: [CommonModule],\n standalone: true,\n})\nexport class SdAnchorItem implements IAnchorItem {\n title = input.required<string>();\n icon = input<string | undefined>();\n // Stable key dùng cho data-autoId. Nếu không truyền thì fallback về uuid (không stable giữa các lần render).\n key = input<string | undefined>(undefined);\n id: string = Utilities.generateUuid();\n elementRef = inject(ElementRef);\n\n constructor() {\n effect(() => {\n if (this.title()) {\n this.elementRef.nativeElement.removeAttribute('title');\n }\n });\n }\n}\n","<section>\n <ng-content></ng-content>\n</section>\n","import { ChangeDetectionStrategy, Component, OnDestroy, computed, input, output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MatIconModule } from '@angular/material/icon';\nimport { Color } from '@sdcorejs/utils/models';\nimport { Subject, Subscription, debounceTime } from 'rxjs';\n\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\n\n@Component({\n selector: 'anchor-nav',\n templateUrl: './anchor-nav.component.html',\n styleUrl: './anchor-nav.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, MatIconModule],\n standalone: true,\n})\n// eslint-disable-next-line @angular-eslint/component-class-suffix\nexport class AnchorNav implements OnDestroy {\n sections = input.required<readonly SdAnchorItem[]>();\n activeSectionId = input<string>('');\n ellipsis = input<boolean>(false);\n sidebarWidth = input<string>('');\n // autoId được forward từ <sd-anchor>. Derive per-item autoId theo `key` của item (nếu có).\n parentAutoId = input<string | undefined | null>(undefined);\n color = input<Color>('primary');\n\n // CSS var binding cho active state — map SdColor → global token `--sd-{color}`.\n // SCSS đọc qua `var(--anchor-active-color)` cho border + text + icon.\n cssActiveVar = computed(() => `var(--sd-${this.color()})`);\n\n itemAutoId(section: SdAnchorItem): string | undefined {\n const parent = this.parentAutoId();\n const key = section.key();\n return parent && key ? `${parent}-${key}` : undefined;\n }\n\n clickSection = output<string>();\n\n #delay = 200;\n #clickSectionSubject = new Subject<string>();\n #subscription = new Subscription();\n\n constructor() {\n this.#subscription.add(\n this.#clickSectionSubject\n .pipe(debounceTime(this.#delay))\n .subscribe((id: string) => this.clickSection.emit(id))\n );\n }\n\n onClickSection = (id: string): void => {\n this.#clickSectionSubject.next(id);\n };\n\n ngOnDestroy(): void {\n this.#subscription.unsubscribe();\n }\n}\n","<div\n class=\"c-anchor-list\"\n [style.width]=\"sidebarWidth()\"\n [style.--anchor-active-color]=\"cssActiveVar()\">\n @for (section of sections(); track section.id) {\n <div\n class=\"c-anchor-list-item\"\n [class.active]=\"section.id === activeSectionId()\"\n (click)=\"onClickSection(section.id)\"\n (keydown.enter)=\"onClickSection(section.id)\"\n [attr.data-autoId]=\"itemAutoId(section)\"\n tabindex=\"0\">\n @if (section.icon()) {\n <mat-icon class=\"c-anchor-list-item-icon\">{{ section.icon() }}</mat-icon>\n }\n <div class=\"c-anchor-list-item-text\" [class.ellipsis]=\"ellipsis()\">\n {{ section.title() }}\n </div>\n </div>\n }\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n OnDestroy,\n afterNextRender,\n booleanAttribute,\n computed,\n contentChildren,\n effect,\n input,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { BrowserUtilities } from '@sdcorejs/utils/fns';\nimport { Color } from '@sdcorejs/utils/models';\nimport { Subscription, fromEvent, take } from 'rxjs';\nimport { AnchorNav } from '../anchor-nav/anchor-nav.component';\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\n\n@Component({\n selector: 'sd-anchor',\n templateUrl: './anchor.component.html',\n styleUrls: ['./anchor.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, AnchorNav],\n standalone: true,\n})\nexport class SdAnchor implements OnDestroy {\n wrapper = viewChild.required<ElementRef>('wrapper');\n sections = contentChildren(SdAnchorItem);\n\n readonly autoIdInput = input<string | undefined | null>(undefined, { alias: 'autoId' });\n readonly autoId = computed(() => (this.autoIdInput() ? `components-anchor-${this.autoIdInput()}` : undefined));\n\n sidebarWidth = input<string>('200px');\n ellipsis = input(false, { transform: booleanAttribute });\n overScroll = input(false, { transform: booleanAttribute });\n // Mobile: default ẩn nav (sidebar TOC chiếm chỗ trên màn hình hẹp).\n // Consumer truyền `[hideNav]=\"false\"` để force hiện trên mobile.\n hideNav = input(BrowserUtilities.isMobile(), { transform: booleanAttribute });\n // Màu highlight active nav (text + icon + vertical bar). Default 'primary'.\n color = input<Color>('primary');\n\n activeSectionId = signal<string>('');\n\n #initialized = false;\n #isClickScrolling = false;\n #clickScrollSubscription: Subscription | null = null;\n #intersectionObserver: IntersectionObserver | null = null;\n #visibleSections = new Set<Element>();\n #timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n #timeoutScrollFallback = 200;\n\n constructor() {\n afterNextRender(() => {\n this.#initialized = true;\n if (!this.hideNav()) {\n this.#registerIntersectionObserver();\n }\n });\n\n // Lắng nghe thay đổi sections để đăng ký lại observe section\n effect(() => {\n this.sections();\n if (!this.hideNav() && this.#initialized) {\n untracked(() => this.#registerIntersectionObserver());\n }\n });\n }\n\n #registerIntersectionObserver(): void {\n this.#cleanIntersectionObserver();\n const wrapperEl = this.wrapper().nativeElement;\n\n // Brower API IntersectionObserver sẽ hỗ trợ khi nào 1 section được hiện ra trong wrapperEl\n this.#intersectionObserver = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n // Nếu section mới đi vào vùng nhìn thấy -> add vào set\n this.#visibleSections.add(entry.target);\n } else {\n // Nếu section đã đi ra khỏi vùng nhìn thấy -> xóa khỏi Set\n this.#visibleSections.delete(entry.target);\n }\n }\n\n // Nếu đang scroll bởi click section thì return luôn, k phải quét qua tìm vùng section được active\n if (this.#isClickScrolling) {\n return;\n }\n\n for (const section of this.sections()) {\n // Kiểm tra xem DOM của section nào đang nằm trong danh sách đang nhìn thấy để active chính xác\n if (this.#visibleSections.has(section.elementRef.nativeElement)) {\n if (this.activeSectionId() !== section.id) {\n this.activeSectionId.set(section.id);\n }\n break;\n }\n }\n },\n { root: wrapperEl, threshold: 0 }\n );\n\n // Đăng ký theo dõi từng section có trong anchor\n for (const section of this.sections()) {\n this.#intersectionObserver.observe(section.elementRef.nativeElement);\n }\n }\n\n scrollSectionByClick(idSectionTarget: string): void {\n this.activeSectionId.set(idSectionTarget);\n const targetSection = this.sections().find(s => s.id === idSectionTarget)?.elementRef;\n if (!targetSection) {\n return;\n }\n this.#cleanScrollSectionByClickObserver();\n this.#isClickScrolling = true;\n\n const wrapperEl = this.wrapper().nativeElement;\n const targetElement = targetSection.nativeElement;\n\n const prevScrollTop = wrapperEl.scrollTop; // Lưu lại vị trí cuộn hiện tại của container\n const scrollTop = prevScrollTop + targetElement.getBoundingClientRect().top - wrapperEl.getBoundingClientRect().top; // Vị trí section cần scroll tới\n\n // Đăng ký sự kiện nếu đã được scroll xong\n this.#clickScrollSubscription = fromEvent(wrapperEl, 'scrollend')\n .pipe(take(1))\n .subscribe(() => {\n this.#isClickScrolling = false;\n });\n\n // Nếu sectionTarget đã ở đúng vị trí (click nhưng không scroll) thì sau #timeoutScrollFallback kích hoạt lại IntersectionObserver\n this.#timeoutId = setTimeout(() => {\n if (wrapperEl.scrollTop === prevScrollTop) {\n this.#isClickScrolling = false;\n this.#clickScrollSubscription?.unsubscribe();\n }\n }, this.#timeoutScrollFallback);\n\n wrapperEl.scrollTo({ top: scrollTop, behavior: 'smooth' });\n }\n\n #cleanScrollSectionByClickObserver = (): void => {\n if (this.#timeoutId) {\n clearTimeout(this.#timeoutId);\n }\n this.#clickScrollSubscription?.unsubscribe();\n };\n\n #cleanIntersectionObserver = (): void => {\n this.#intersectionObserver?.disconnect();\n this.#visibleSections.clear();\n };\n\n ngOnDestroy(): void {\n this.#cleanScrollSectionByClickObserver();\n this.#cleanIntersectionObserver();\n }\n}\n","<div class=\"c-anchor-vertical\" [ngClass]=\"{ 'c-stop-scroll-propagation': !overScroll() }\" #wrapper>\n <div class=\"c-anchor-content\">\n <ng-content></ng-content>\n </div>\n\n @if (!hideNav()) {\n <div class=\"c-anchor-list\" [style.flex-basis]=\"sidebarWidth()\">\n <anchor-nav\n [sections]=\"sections()\"\n [ellipsis]=\"ellipsis()\"\n [sidebarWidth]=\"sidebarWidth()\"\n [activeSectionId]=\"activeSectionId()\"\n [parentAutoId]=\"autoId()\"\n [color]=\"color()\"\n (clickSection)=\"scrollSectionByClick($event)\">\n </anchor-nav>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|